diff --git a/FixCydiaSubstrate.c b/FixCydiaSubstrate.c deleted file mode 100644 index 20a8d38..0000000 --- a/FixCydiaSubstrate.c +++ /dev/null @@ -1,33 +0,0 @@ -#include -#include -#include "fishhook/fishhook.h" - -// Provide _dyld_get_all_image_infos for CydiaSubstrate -struct dyld_all_image_infos *_alt_dyld_get_all_image_infos() { - static struct dyld_all_image_infos *result; - if (result) { - return result; - } - struct task_dyld_info dyld_info; - mach_vm_address_t image_infos; - mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT; - kern_return_t ret; - ret = task_info(mach_task_self_, - TASK_DYLD_INFO, - (task_info_t)&dyld_info, - &count); - if (ret != KERN_SUCCESS) { - return NULL; - } - image_infos = dyld_info.all_image_info_addr; - result = (struct dyld_all_image_infos *)image_infos; - return result; -} - -void init_fixCydiaSubstrate(void) { - void *orig__dyld_get_all_image_infos; - struct rebinding rebindings[] = (struct rebinding[]){ - {"_dyld_get_all_image_infos", _alt_dyld_get_all_image_infos, (void *)&orig__dyld_get_all_image_infos} - }; - rebind_symbols(rebindings, sizeof(rebindings)/sizeof(struct rebinding)); -} diff --git a/LCAppDelegate.h b/LCAppDelegate.h index 6cf0395..3b1d160 100644 --- a/LCAppDelegate.h +++ b/LCAppDelegate.h @@ -3,6 +3,6 @@ @interface LCAppDelegate : UIResponder @property (nonatomic, strong) UIWindow *window; -@property (nonatomic, strong) UINavigationController *rootViewController; +@property (nonatomic, strong) UIViewController *rootViewController; @end diff --git a/LCAppDelegate.m b/LCAppDelegate.m index 80efa94..ddcda1f 100644 --- a/LCAppDelegate.m +++ b/LCAppDelegate.m @@ -1,6 +1,6 @@ #import "LCAppDelegate.h" #import "LCJITLessSetupViewController.h" -#import "LCRootViewController.h" +#import "LCTabBarController.h" @implementation LCAppDelegate @@ -8,11 +8,11 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( UIViewController *viewController; if ([NSBundle.mainBundle.executablePath.lastPathComponent isEqualToString:@"JITLessSetup"]) { viewController = [[LCJITLessSetupViewController alloc] init]; + _rootViewController = [[UINavigationController alloc] initWithRootViewController:viewController]; } else { - viewController = [[LCRootViewController alloc] init]; + _rootViewController = [[LCTabBarController alloc] init]; } _window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; - _rootViewController = [[UINavigationController alloc] initWithRootViewController:viewController]; _window.rootViewController = _rootViewController; [_window makeKeyAndVisible]; return YES; diff --git a/LCRootViewController.m b/LCRootViewController.m index 8a7e2b8..3d9c66b 100644 --- a/LCRootViewController.m +++ b/LCRootViewController.m @@ -3,6 +3,7 @@ #import "LCUtils.h" #import "MBRoundProgressView.h" #import "UIKitPrivate.h" +#import "UIViewController+LCAlert.h" #import "unarchive.h" #import "AppInfo.h" @@ -135,17 +136,10 @@ - (void)loadView { [NSFileManager.defaultManager createDirectoryAtPath:self.tweakPath withIntermediateDirectories:NO attributes:nil error:nil]; // Setup action bar - self.title = @"LiveContainer"; self.navigationItem.rightBarButtonItems = @[ [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemPlay target:self action:@selector(launchButtonTapped)], [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(addButtonTapped)] ]; - - if (!LCUtils.certificateData) { - self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Setup JIT-less" style:UIBarButtonItemStylePlain target:self action:@selector(setupJITLessTapped)]; - } /* else { - self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Test JIT-less" style:UIBarButtonItemStylePlain target:self action:@selector(testJITLessTapped)]; - } */ } - (void)viewWillAppear:(BOOL)animated { @@ -153,67 +147,6 @@ - (void)viewWillAppear:(BOOL)animated { [self.tableView reloadData]; } -- (void)showDialogTitle:(NSString *)title message:(NSString *)message { - [self showDialogTitle:title message:message handler:nil]; -} -- (void)showDialogTitle:(NSString *)title message:(NSString *)message handler:(void(^)(UIAlertAction *))handler { - UIAlertController* alert = [UIAlertController alertControllerWithTitle:title - message:message - preferredStyle:UIAlertControllerStyleAlert]; - UIAlertAction* okAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:handler]; - [alert addAction:okAction]; - UIAlertAction* copyAction = [UIAlertAction actionWithTitle:@"Copy" style:UIAlertActionStyleDefault - handler:^(UIAlertAction * action) { - UIPasteboard.generalPasteboard.string = message; - if (handler) handler(action); - }]; - [alert addAction:copyAction]; - [self presentViewController:alert animated:YES completion:nil]; -} - -- (void)showInputDialogTitle:(NSString *)title message:(NSString *)message placeholder:(NSString *)placeholder callback:(NSString *(^)(NSString *inputText))callback { - UIAlertController *alert = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert]; - [alert addTextFieldWithConfigurationHandler:^(UITextField *textField) { - textField.placeholder = placeholder; - textField.clearButtonMode = UITextFieldViewModeWhileEditing; - textField.borderStyle = UITextBorderStyleRoundedRect; - }]; - UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { - UITextField *textField = alert.textFields[0]; - NSString *error = callback(textField.text.length == 0 ? placeholder : textField.text); - if (error) { - alert.message = error; - } else { - [self dismissViewControllerAnimated:YES completion:nil]; - } - }]; - okAction.shouldDismissHandler = ^{ - return NO; - }; - [alert addAction:okAction]; - [alert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]]; - [self presentViewController:alert animated:YES completion:nil]; -} - -- (void)setupJITLessTapped { - if (!LCUtils.isAppGroupSideStore) { - [self showDialogTitle:@"Error" message:@"Unsupported installation method. Please use SideStore to setup this feature."]; - return; - } - - NSError *error; - NSURL *url = [LCUtils archiveIPAWithSetupMode:YES error:&error]; - if (!url) { - [self showDialogTitle:@"Error" message:error.localizedDescription]; - return; - } - - [self showDialogTitle:@"Instruction" message:@"Setting up JIT-less allows you to use LiveContainer without having to enable JIT. LiveContainer needs to safely obtain the certificate from SideStore. Press OK to continue." - handler:^(UIAlertAction * action) { - [UIApplication.sharedApplication openURL:[NSURL URLWithString:[NSString stringWithFormat:@"sidestore://install?url=%@", url]] options:@{} completionHandler:nil]; - }]; -} - - (void)addButtonTapped { UIDocumentPickerViewController* documentPickerVC = [[UIDocumentPickerViewController alloc] initForOpeningContentTypes:@[[UTType typeWithFilenameExtension:@"ipa" conformingToType:UTTypeData]]]; documentPickerVC.allowsMultipleSelection = YES; diff --git a/LCSettingsListController.h b/LCSettingsListController.h new file mode 100644 index 0000000..603ba23 --- /dev/null +++ b/LCSettingsListController.h @@ -0,0 +1,6 @@ +#import +#import +#import + +@interface LCSettingsListController : PSListController +@end diff --git a/LCSettingsListController.m b/LCSettingsListController.m new file mode 100644 index 0000000..a03d70f --- /dev/null +++ b/LCSettingsListController.m @@ -0,0 +1,51 @@ +#import "LCSettingsListController.h" +#import "LCUtils.h" +#import "UIViewController+LCAlert.h" + +@implementation LCSettingsListController + +- (NSMutableArray*)specifiers { + if(!_specifiers) { + _specifiers = [NSMutableArray new]; + PSSpecifier* jitlessGroup = [PSSpecifier emptyGroupSpecifier]; + jitlessGroup.name = @"JIT-less"; + [jitlessGroup setProperty:@"JIT-less allows you to use LiveContainer without having to enable JIT. Requires SideStore." forKey:@"footerText"]; + [_specifiers addObject:jitlessGroup]; + + NSString *setupJITLessButtonName = LCUtils.certificateData ? @"JIT-less is set up" : @"Setup JIT-less"; + PSSpecifier* setupJITLessButton = [PSSpecifier preferenceSpecifierNamed:setupJITLessButtonName target:self set:nil get:nil detail:nil cell:PSButtonCell edit:nil]; + setupJITLessButton.identifier = @"setup-jitless"; + [setupJITLessButton setProperty:@(!LCUtils.certificateData) forKey:@"enabled"]; + setupJITLessButton.buttonAction = @selector(setupJITLessPressed); + [_specifiers addObject:setupJITLessButton]; + + PSSpecifier* signTweaksButton = [PSSpecifier preferenceSpecifierNamed:@"Sign tweaks" target:self set:nil get:nil detail:nil cell:PSButtonCell edit:nil]; + signTweaksButton.identifier = @"sign-tweaks"; + [signTweaksButton setProperty:@(!!LCUtils.certificateData) forKey:@"enabled"]; + signTweaksButton.buttonAction = @selector(signTweaksPressed); + [_specifiers addObject:signTweaksButton]; + } + return _specifiers; +} + +- (void)setupJITLessPressed { + if (!LCUtils.isAppGroupSideStore) { + [self showDialogTitle:@"Error" message:@"Unsupported installation method. Please use SideStore to setup this feature."]; + return; + } + + NSError *error; + NSURL *url = [LCUtils archiveIPAWithSetupMode:YES error:&error]; + if (!url) { + [self showDialogTitle:@"Error" message:error.localizedDescription]; + return; + } + + [UIApplication.sharedApplication openURL:[NSURL URLWithString:[NSString stringWithFormat:@"sidestore://install?url=%@", url]] options:@{} completionHandler:nil]; +} + +- (void)signTweaksPressed { + +} + +@end diff --git a/LCTabBarController.h b/LCTabBarController.h new file mode 100644 index 0000000..f3c2052 --- /dev/null +++ b/LCTabBarController.h @@ -0,0 +1,4 @@ +#import + +@interface LCTabBarController : UITabBarController +@end diff --git a/LCTabBarController.m b/LCTabBarController.m new file mode 100644 index 0000000..ac947e5 --- /dev/null +++ b/LCTabBarController.m @@ -0,0 +1,25 @@ +#import "LCRootViewController.h" +#import "LCSettingsListController.h" +#import "LCTabBarController.h" + +@implementation LCTabBarController + +- (void)loadView { + [super loadView]; + + LCRootViewController* appTableVC = [LCRootViewController new]; + appTableVC.title = @"Apps"; + + LCSettingsListController* settingsListVC = [LCSettingsListController new]; + settingsListVC.title = @"Settings"; + + UINavigationController* appNavigationController = [[UINavigationController alloc] initWithRootViewController:appTableVC]; + UINavigationController* settingsNavigationController = [[UINavigationController alloc] initWithRootViewController:settingsListVC]; + + appNavigationController.tabBarItem.image = [UIImage systemImageNamed:@"square.stack.3d.up.fill"]; + settingsNavigationController.tabBarItem.image = [UIImage systemImageNamed:@"gear"]; + + self.viewControllers = @[appNavigationController, settingsNavigationController]; +} + +@end diff --git a/LCUtils.m b/LCUtils.m index d5ce16a..e73f0a1 100644 --- a/LCUtils.m +++ b/LCUtils.m @@ -135,7 +135,13 @@ + (NSProgress *)signAppBundle:(NSURL *)path completionHandler:(void (^)(BOOL suc // Load libraries from Documents, yeah NSArray *signerFrameworks = @[@"OpenSSL.framework", @"Roxas.framework", @"AltStoreCore.framework"]; for (NSString *framework in signerFrameworks) { - [[NSBundle bundleWithURL:[storeFrameworksPath URLByAppendingPathComponent:framework]] loadAndReturnError:&error]; + NSBundle *frameworkBundle = [NSBundle bundleWithURL:[storeFrameworksPath URLByAppendingPathComponent:framework]]; + if (!frameworkBundle) { + //completionHandler(NO, error); + abort(); + return nil; + } + [frameworkBundle loadAndReturnError:&error]; if (error) { completionHandler(NO, error); return nil; @@ -159,7 +165,10 @@ + (NSString *)appGroupID { } + (BOOL)isAppGroupSideStore { - return [self.appGroupID containsString:@"com.SideStore.SideStore"]; + if (![self.appGroupID containsString:@"com.SideStore.SideStore"]) return NO; + NSURL *appGroupPath = [NSFileManager.defaultManager containerURLForSecurityApplicationGroupIdentifier:self.appGroupID]; + NSURL *storeBundlePath = [appGroupPath URLByAppendingPathComponent:@"Apps/com.SideStore.SideStore/App.app"]; + return [NSFileManager.defaultManager fileExistsAtPath:storeBundlePath.path]; } + (void)changeMainExecutableTo:(NSString *)exec error:(NSError **)error { diff --git a/Makefile b/Makefile index 36f2897..4230b88 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ CONFIG_BRANCH = $(shell git branch --show-current) CONFIG_COMMIT = $(shell git log --oneline | sed '2,10000000d' | cut -b 1-7) # Build the UI library -LiveContainerUI_FILES = LCAppDelegate.m LCJITLessSetupViewController.m LCRootViewController.m LCUtils.m MBRoundProgressView.m unarchive.m AppInfo.m +LiveContainerUI_FILES = LCAppDelegate.m LCJITLessSetupViewController.m LCRootViewController.m LCSettingsListController.m LCTabBarController.m LCUtils.m MBRoundProgressView.m unarchive.m AppInfo.m LiveContainerUI_CFLAGS = \ -fobjc-arc \ -DCONFIG_TYPE=\"$(CONFIG_TYPE)\" \ @@ -32,7 +32,7 @@ include $(THEOS_MAKE_PATH)/library.mk # Build the app APPLICATION_NAME = LiveContainer -$(APPLICATION_NAME)_FILES = dyld_bypass_validation.m main.m utils.m FixCydiaSubstrate.c fishhook/fishhook.c +$(APPLICATION_NAME)_FILES = dyld_bypass_validation.m main.m utils.m fishhook/fishhook.c NSBundle+FixCydiaSubstrate.m $(APPLICATION_NAME)_CODESIGN_FLAGS = -Sentitlements.xml $(APPLICATION_NAME)_CFLAGS = -fobjc-arc $(APPLICATION_NAME)_LDFLAGS = -e_LiveContainerMain -rpath @loader_path/Frameworks diff --git a/NSBundle+FixCydiaSubstrate.m b/NSBundle+FixCydiaSubstrate.m new file mode 100644 index 0000000..0bcbee8 --- /dev/null +++ b/NSBundle+FixCydiaSubstrate.m @@ -0,0 +1,13 @@ +#import + +@implementation NSBundle(FixCydiaSubstrate) + +- (NSString *)bundlePath { + NSString *path = self.bundleURL.path; + if ([path hasPrefix:@"/private"]) { + return path; + } + return [@"/private" stringByAppendingPathComponent:path]; +} + +@end diff --git a/TweakLoader.m b/TweakLoader.m index b997a10..93ad330 100644 --- a/TweakLoader.m +++ b/TweakLoader.m @@ -1,5 +1,7 @@ #import +#import #include +#include __attribute__((constructor)) static void TweakLoaderConstructor() { diff --git a/UIViewController+LCAlert.h b/UIViewController+LCAlert.h new file mode 100644 index 0000000..357684f --- /dev/null +++ b/UIViewController+LCAlert.h @@ -0,0 +1,9 @@ +#import + +@interface UIViewController(LCAlert) + +- (void)showDialogTitle:(NSString *)title message:(NSString *)message; +- (void)showDialogTitle:(NSString *)title message:(NSString *)message handler:(void(^)(UIAlertAction *))handler; +- (void)showInputDialogTitle:(NSString *)title message:(NSString *)message placeholder:(NSString *)placeholder callback:(NSString *(^)(NSString *inputText))callback; + +@end diff --git a/UIViewController+LCAlert.m b/UIViewController+LCAlert.m new file mode 100644 index 0000000..30aa9db --- /dev/null +++ b/UIViewController+LCAlert.m @@ -0,0 +1,48 @@ +#import "UIViewController+LCAlert.h" + +@implementation UIViewController(LCAlert) + +- (void)showDialogTitle:(NSString *)title message:(NSString *)message { + [self showDialogTitle:title message:message handler:nil]; +} + +- (void)showDialogTitle:(NSString *)title message:(NSString *)message handler:(void(^)(UIAlertAction *))handler { + UIAlertController* alert = [UIAlertController alertControllerWithTitle:title + message:message + preferredStyle:UIAlertControllerStyleAlert]; + UIAlertAction* okAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:handler]; + [alert addAction:okAction]; + UIAlertAction* copyAction = [UIAlertAction actionWithTitle:@"Copy" style:UIAlertActionStyleDefault + handler:^(UIAlertAction * action) { + UIPasteboard.generalPasteboard.string = message; + if (handler) handler(action); + }]; + [alert addAction:copyAction]; + [self presentViewController:alert animated:YES completion:nil]; +} + +- (void)showInputDialogTitle:(NSString *)title message:(NSString *)message placeholder:(NSString *)placeholder callback:(NSString *(^)(NSString *inputText))callback { + UIAlertController *alert = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert]; + [alert addTextFieldWithConfigurationHandler:^(UITextField *textField) { + textField.placeholder = placeholder; + textField.clearButtonMode = UITextFieldViewModeWhileEditing; + textField.borderStyle = UITextBorderStyleRoundedRect; + }]; + UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { + UITextField *textField = alert.textFields[0]; + NSString *error = callback(textField.text.length == 0 ? placeholder : textField.text); + if (error) { + alert.message = error; + } else { + [self dismissViewControllerAnimated:YES completion:nil]; + } + }]; + okAction.shouldDismissHandler = ^{ + return NO; + }; + [alert addAction:okAction]; + [alert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]]; + [self presentViewController:alert animated:YES completion:nil]; +} + +@end diff --git a/dyld_bypass_validation.m b/dyld_bypass_validation.m index 9f262da..e3718cb 100644 --- a/dyld_bypass_validation.m +++ b/dyld_bypass_validation.m @@ -81,6 +81,27 @@ static bool searchAndPatch(char *name, char *base, char *signature, int length, return redirectFunction(name, patchAddr, target); } +static struct dyld_all_image_infos *_alt_dyld_get_all_image_infos() { + static struct dyld_all_image_infos *result; + if (result) { + return result; + } + struct task_dyld_info dyld_info; + mach_vm_address_t image_infos; + mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT; + kern_return_t ret; + ret = task_info(mach_task_self_, + TASK_DYLD_INFO, + (task_info_t)&dyld_info, + &count); + if (ret != KERN_SUCCESS) { + return NULL; + } + image_infos = dyld_info.all_image_info_addr; + result = (struct dyld_all_image_infos *)image_infos; + return result; +} + static void *getDyldBase(void) { return (void *)_alt_dyld_get_all_image_infos()->dyldImageLoadAddress; } @@ -124,14 +145,6 @@ static int hooked___fcntl(int fildes, int cmd, void *param) { return __fcntl(fildes, cmd, param); } -static int hooked_fcntl(int fildes, int cmd, ...) { - va_list ap; - va_start(ap, cmd); - void *param = va_arg(ap, void *); - va_end(ap); - return hooked___fcntl(fildes, cmd, param); -} - void init_bypassDyldLibValidation() { static BOOL bypassed; if (bypassed) return; @@ -144,8 +157,8 @@ void init_bypassDyldLibValidation() { //signal(SIGBUS, SIG_IGN); char *dyldBase = getDyldBase(); - redirectFunction("mmap", mmap, hooked_mmap); - redirectFunction("fcntl", fcntl, hooked_fcntl); + //redirectFunction("mmap", mmap, hooked_mmap); + //redirectFunction("fcntl", fcntl, hooked_fcntl); searchAndPatch("dyld_mmap", dyldBase, mmapSig, sizeof(mmapSig), hooked_mmap); searchAndPatch("dyld_fcntl", dyldBase, fcntlSig, sizeof(fcntlSig), hooked___fcntl); } diff --git a/main.m b/main.m index df20da3..63cda6b 100644 --- a/main.m +++ b/main.m @@ -202,9 +202,6 @@ static void overwriteExecPath(NSString *bundlePath) { init_bypassDyldLibValidation(); } - // Bind _dyld_get_all_image_infos - init_fixCydiaSubstrate(); - // Locate dyld image name address const char **path = _CFGetProcessPath(); const char *oldPath = *path; diff --git a/utils.h b/utils.h index 7fdea2b..d8914a2 100644 --- a/utils.h +++ b/utils.h @@ -5,14 +5,12 @@ const char **_CFGetProgname(void); const char **_CFGetProcessPath(void); int _NSGetExecutablePath(char* buf, uint32_t* bufsize); -struct dyld_all_image_infos *_alt_dyld_get_all_image_infos(); const char *LCHomePath(); #define CS_DEBUGGED 0x10000000 int csops(pid_t pid, unsigned int ops, void *useraddr, size_t usersize); void init_bypassDyldLibValidation(); -void init_fixCydiaSubstrate(void); kern_return_t builtin_vm_protect(mach_port_name_t task, mach_vm_address_t address, mach_vm_size_t size, boolean_t set_max, vm_prot_t new_prot); uint64_t aarch64_get_tbnz_jump_address(uint32_t instruction, uint64_t pc);