Skip to content

Commit

Permalink
Add builtin tweak signer & more refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
khanhduytran0 committed Aug 7, 2024
1 parent 350b99d commit 49e3b12
Show file tree
Hide file tree
Showing 18 changed files with 578 additions and 67 deletions.
61 changes: 29 additions & 32 deletions LCAppListViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,6 @@
#import "UIViewController+LCAlert.h"
#import "unarchive.h"

/*
#include <libgen.h>
#include <mach-o/fat.h>
#include <mach-o/loader.h>
#include <sys/mman.h>
#include <sys/stat.h>
*/

@implementation NSURL(hack)
- (BOOL)safari_isHTTPFamilyURL {
// Screw it, Apple
Expand Down Expand Up @@ -294,31 +286,36 @@ - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPa
return 80.0f;
}

- (void)deleteAppAtIndexPath:(NSIndexPath *)indexPath {
LCAppInfo* appInfo = [[LCAppInfo alloc] initWithBundlePath: [NSString stringWithFormat:@"%@/%@", self.bundlePath, self.objects[indexPath.row]]];
UIAlertController* uninstallAlert = [UIAlertController alertControllerWithTitle:@"Confirm Uninstallation" message:[NSString stringWithFormat:@"Are you sure you want to uninstall %@?", [appInfo displayName]] preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* uninstallApp = [UIAlertAction actionWithTitle:@"Uninstall" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action) {
NSError *error = nil;
[[NSFileManager defaultManager] removeItemAtPath:[NSString stringWithFormat:@"%@/%@", self.bundlePath, self.objects[indexPath.row]] error:&error];
if (error) {
[self showDialogTitle:@"Error" message:error.localizedDescription];
return;
- (void)deleteItemAtIndexPath:(NSIndexPath *)indexPath completionHandler:(void(^)(BOOL actionPerformed))handler {
NSString *path = [self.bundlePath stringByAppendingPathComponent:self.objects[indexPath.row]];
LCAppInfo* appInfo = [[LCAppInfo alloc] initWithBundlePath:path];
[self showConfirmationDialogTitle:@"Confirm Uninstallation"
message:[NSString stringWithFormat:@"Are you sure you want to uninstall %@?", appInfo.displayName]
destructive:YES
confirmButtonTitle:@"Uninstall"
handler:^(UIAlertAction * action) {
if (action.style != UIAlertActionStyleCancel) {
NSError *error = nil;
[NSFileManager.defaultManager removeItemAtPath:path error:&error];
if (error) {
[self showDialogTitle:@"Error" message:error.localizedDescription];
} else {
[self.objects removeObjectAtIndex:indexPath.row];
[self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}
}
[self.objects removeObjectAtIndex:indexPath.row];
[self.tableView deleteRowsAtIndexPaths:@[ indexPath ] withRowAnimation:UITableViewRowAnimationAutomatic];
handler(YES);
}];
[uninstallAlert addAction:uninstallApp];
UIAlertAction* cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil];
[uninstallAlert addAction:cancelAction];
[self presentViewController:uninstallAlert animated:YES completion:nil];
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
[self deleteAppAtIndexPath:indexPath];
}

- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
return self.objects[indexPath.row].length==0 ? UITableViewCellEditingStyleNone : UITableViewCellEditingStyleDelete;
- (UISwipeActionsConfiguration *) tableView:(UITableView *)tableView
trailingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath {
return [UISwipeActionsConfiguration configurationWithActions:@[
[UIContextualAction contextualActionWithStyle:UIContextualActionStyleDestructive
title:@"Delete" handler:^(UIContextualAction *action, __kindof UIView *sourceView, void (^completionHandler)(BOOL actionPerformed)) {
[self deleteItemAtIndexPath:indexPath completionHandler:completionHandler];
}]
]];
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
Expand Down Expand Up @@ -356,8 +353,9 @@ - (void)patchExecAndSignIfNeed:(NSIndexPath *)indexPath shouldSort:(BOOL)sortNam
int currentPatchRev = 5;
if ([info[@"LCPatchRevision"] intValue] < currentPatchRev) {
NSString *execPath = [NSString stringWithFormat:@"%@/%@", appPath, info[@"CFBundleExecutable"]];
NSString *error;
LCPatchExecutable(execPath.UTF8String, &error);
NSString *error = LCParseMachO(execPath.UTF8String, ^(const char *path, struct mach_header_64 *header) {
LCPatchExecSlice(path, header);
});
if (error) {
[self showDialogTitle:@"Error" message:error];
return;
Expand Down Expand Up @@ -409,7 +407,6 @@ - (void)patchExecAndSignIfNeed:(NSIndexPath *)indexPath shouldSort:(BOOL)sortNam
[info removeObjectForKey:@"LCBundleIdentifier"];

__block NSProgress *progress = [LCUtils signAppBundle:appPathURL

completionHandler:^(BOOL success, NSError *_Nullable error) {
dispatch_async(dispatch_get_main_queue(), ^{
if (error) {
Expand Down
30 changes: 25 additions & 5 deletions LCMachOUtils.m
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
@import Darwin;
@import Foundation;
@import MachO;
#import "LCUtils.h"

static uint32_t rnd32(uint32_t v, uint32_t r) {
r--;
Expand All @@ -21,7 +22,22 @@ static void insertDylibCommand(uint32_t cmd, const char *path, struct mach_heade
header->sizeofcmds += dylib->cmdsize;
}

static void patchExecSlice(const char *path, struct mach_header_64 *header) {
static void insertRPathCommand(const char *path, struct mach_header_64 *header) {
struct rpath_command *rpath = (struct rpath_command *)(sizeof(struct mach_header_64) + (void *)header+header->sizeofcmds);
rpath->cmd = LC_RPATH;
rpath->cmdsize = sizeof(struct rpath_command) + rnd32((uint32_t)strlen(path) + 1, 8);
rpath->path.offset = sizeof(struct rpath_command);
strncpy((void *)rpath + rpath->path.offset, path, strlen(path));
header->ncmds++;
header->sizeofcmds += rpath->cmdsize;
}

void LCPatchAddRPath(const char *path, struct mach_header_64 *header) {
insertRPathCommand("@executable_path/../../Tweaks", header);
insertRPathCommand("@loader_path", header);
}

void LCPatchExecSlice(const char *path, struct mach_header_64 *header) {
uint8_t *imageHeaderPtr = (uint8_t*)header + sizeof(struct mach_header_64);

// Literally convert an executable to a dylib
Expand Down Expand Up @@ -65,11 +81,14 @@ static void patchExecSlice(const char *path, struct mach_header_64 *header) {
}
}

void LCPatchExecutable(const char *path, NSString **error) {
NSString *LCParseMachO(const char *path, LCParseMachOCallback callback) {
int fd = open(path, O_RDWR, (mode_t)0600);
struct stat s;
fstat(fd, &s);
void *map = mmap(NULL, s.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (map == MAP_FAILED) {
return [NSString stringWithFormat:@"Failed to map %s: %s", path, strerror(errno)];
}

uint32_t magic = *(uint32_t *)map;
if (magic == FAT_CIGAM) {
Expand All @@ -78,17 +97,18 @@ void LCPatchExecutable(const char *path, NSString **error) {
struct fat_arch *arch = (struct fat_arch *)(map + sizeof(struct fat_header));
for (int i = 0; i < OSSwapInt32(header->nfat_arch); i++) {
if (OSSwapInt32(arch->cputype) == CPU_TYPE_ARM64) {
patchExecSlice(path, (struct mach_header_64 *)(map + OSSwapInt32(arch->offset)));
callback(path, (struct mach_header_64 *)(map + OSSwapInt32(arch->offset)));
}
arch = (struct fat_arch *)((void *)arch + sizeof(struct fat_arch));
}
} else if (magic == MH_MAGIC_64) {
patchExecSlice(path, (struct mach_header_64 *)map);
callback(path, (struct mach_header_64 *)map);
} else {
*error = @"32-bit app is not supported";
return @"32-bit app is not supported";
}

msync(map, s.st_size, MS_SYNC);
munmap(map, s.st_size);
close(fd);
return nil;
}
10 changes: 8 additions & 2 deletions LCTabBarController.m
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#import "LCAppListViewController.h"
#import "LCSettingsListController.h"
#import "LCTweakListViewController.h"
#import "LCTabBarController.h"

@implementation LCTabBarController
Expand All @@ -10,16 +11,21 @@ - (void)loadView {
LCAppListViewController* appTableVC = [LCAppListViewController new];
appTableVC.title = @"Apps";

LCTweakListViewController* tweakTableVC = [LCTweakListViewController new];
tweakTableVC.title = @"Tweaks";

LCSettingsListController* settingsListVC = [LCSettingsListController new];
settingsListVC.title = @"Settings";

UINavigationController* appNavigationController = [[UINavigationController alloc] initWithRootViewController:appTableVC];
UINavigationController* tweakNavigationController = [[UINavigationController alloc] initWithRootViewController:tweakTableVC];
UINavigationController* settingsNavigationController = [[UINavigationController alloc] initWithRootViewController:settingsListVC];

appNavigationController.tabBarItem.image = [UIImage systemImageNamed:@"square.stack.3d.up.fill"];
tweakNavigationController.tabBarItem.image = [UIImage systemImageNamed:@"wrench.and.screwdriver"];
settingsNavigationController.tabBarItem.image = [UIImage systemImageNamed:@"gear"];

self.viewControllers = @[appNavigationController, settingsNavigationController];
self.viewControllers = @[appNavigationController, tweakNavigationController, settingsNavigationController];
}

@end
4 changes: 4 additions & 0 deletions LCTweakListViewController.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
@import UIKit;

@interface LCTweakListViewController : UITableViewController <UIDocumentPickerDelegate>
@end
Loading

0 comments on commit 49e3b12

Please sign in to comment.