From 5bb621c4fe0ca07276d7f1d683a3c28f41b13323 Mon Sep 17 00:00:00 2001 From: opa334 Date: Sun, 4 Sep 2022 03:04:09 +0200 Subject: [PATCH 01/11] 1.0.4 --- Helper/control | 2 +- Helper/main.m | 85 ++++++++++++++------------ PersistenceHelper/Resources/Info.plist | 2 +- PersistenceHelper/control | 2 +- Store/Resources/Info.plist | 2 +- Store/control | 2 +- 6 files changed, 51 insertions(+), 44 deletions(-) diff --git a/Helper/control b/Helper/control index d89e573..855c170 100644 --- a/Helper/control +++ b/Helper/control @@ -1,6 +1,6 @@ Package: com.opa334.trollstoreroothelper Name: trollstoreroothelper -Version: 1.0.3 +Version: 1.0.4 Architecture: iphoneos-arm Description: An awesome tool of some sort!! Maintainer: opa334 diff --git a/Helper/main.m b/Helper/main.m index 75b9ef0..4bdbc81 100644 --- a/Helper/main.m +++ b/Helper/main.m @@ -230,6 +230,9 @@ NSDictionary* dumpEntitlements(NSString* binaryPath) struct mach_header_universal header; fread(&header,sizeof(header),1,machoFile); + uint32_t archOffset = 0; + + // Get arch offset if FAT binary if(header.magic == FAT_MAGIC || header.magic == FAT_CIGAM) { fseek(machoFile,0,SEEK_SET); @@ -250,57 +253,61 @@ NSDictionary* dumpEntitlements(NSString* binaryPath) continue; } - fseek(machoFile,s32(fatArch.offset, swpFat),SEEK_SET); - struct mach_header_universal header; - fread(&header,sizeof(header),1,machoFile); + archOffset = s32(fatArch.offset, swpFat); + break; + } + } - BOOL swp = header.magic == MH_CIGAM_UNIVERSAL; + fseek(machoFile,archOffset,SEEK_SET); + fread(&header,sizeof(header),1,machoFile); - // This code is cursed, don't stare at it too long or it will stare back at you - uint32_t offset = s32(fatArch.offset, swpFat) + sizeof(header); - for(int c = 0; c < s32(header.ncmds, swp); c++) + if(header.magic == MH_MAGIC_UNIVERSAL || header.magic == MH_CIGAM_UNIVERSAL) + { + BOOL swp = header.magic == MH_CIGAM_UNIVERSAL; + // This code is cursed, don't stare at it too long or it will stare back at you + uint32_t offset = archOffset + sizeof(header); + for(int c = 0; c < s32(header.ncmds, swp); c++) + { + fseek(machoFile,offset,SEEK_SET); + struct load_command cmd; + fread(&cmd,sizeof(cmd),1,machoFile); + uint32_t normalizedCmd = s32(cmd.cmd,swp); + if(normalizedCmd == LC_CODE_SIGNATURE) { + struct linkedit_data_command codeSignCommand; fseek(machoFile,offset,SEEK_SET); - struct load_command cmd; - fread(&cmd,sizeof(cmd),1,machoFile); - uint32_t normalizedCmd = s32(cmd.cmd,swp); - if(normalizedCmd == LC_CODE_SIGNATURE) + fread(&codeSignCommand,sizeof(codeSignCommand),1,machoFile); + uint32_t codeSignCmdOffset = archOffset + s32(codeSignCommand.dataoff, swp); + fseek(machoFile, codeSignCmdOffset, SEEK_SET); + struct CSSuperBlob superBlob; + fread(&superBlob, sizeof(superBlob), 1, machoFile); + if(SWAP32(superBlob.magic) == CS_MAGIC_EMBEDDED_SIGNATURE) // YES starting here everything is swapped no matter if CIGAM or MAGIC... { - struct linkedit_data_command codeSignCommand; - fseek(machoFile,offset,SEEK_SET); - fread(&codeSignCommand,sizeof(codeSignCommand),1,machoFile); - uint32_t codeSignCmdOffset = s32(fatArch.offset, swpFat) + s32(codeSignCommand.dataoff, swp); - fseek(machoFile, codeSignCmdOffset, SEEK_SET); - struct CSSuperBlob superBlob; - fread(&superBlob, sizeof(superBlob), 1, machoFile); - if(SWAP32(superBlob.magic) == CS_MAGIC_EMBEDDED_SIGNATURE) + uint32_t itemCount = SWAP32(superBlob.count); + for(int i = 0; i < itemCount; i++) { - uint32_t itemCount = SWAP32(superBlob.count); - for(int i = 0; i < itemCount; i++) + fseek(machoFile, codeSignCmdOffset + sizeof(superBlob) + i * sizeof(struct CSBlob),SEEK_SET); + struct CSBlob blob; + fread(&blob, sizeof(struct CSBlob), 1, machoFile); + fseek(machoFile, codeSignCmdOffset + SWAP32(blob.offset),SEEK_SET); + uint32_t blobMagic; + fread(&blobMagic, sizeof(uint32_t), 1, machoFile); + if(SWAP32(blobMagic) == CS_MAGIC_EMBEDDED_ENTITLEMENTS) { - fseek(machoFile, codeSignCmdOffset + sizeof(superBlob) + i * sizeof(struct CSBlob),SEEK_SET); - struct CSBlob blob; - fread(&blob, sizeof(struct CSBlob), 1, machoFile); - fseek(machoFile, codeSignCmdOffset + SWAP32(blob.offset),SEEK_SET); - uint32_t blobMagic; - fread(&blobMagic, sizeof(uint32_t), 1, machoFile); - if(SWAP32(blobMagic) == CS_MAGIC_EMBEDDED_ENTITLEMENTS) - { - uint32_t entitlementsLengthTmp; - fread(&entitlementsLengthTmp, sizeof(uint32_t), 1, machoFile); - entitlementsLength = SWAP32(entitlementsLengthTmp); - entitlementsData = malloc(entitlementsLength - 8); - fread(&entitlementsData[0], entitlementsLength - 8, 1, machoFile); - break; - } + uint32_t entitlementsLengthTmp; + fread(&entitlementsLengthTmp, sizeof(uint32_t), 1, machoFile); + entitlementsLength = SWAP32(entitlementsLengthTmp); + entitlementsData = malloc(entitlementsLength - 8); + fread(&entitlementsData[0], entitlementsLength - 8, 1, machoFile); + break; } } - - break; } - offset += cmd.cmdsize; + break; } + + offset += cmd.cmdsize; } } diff --git a/PersistenceHelper/Resources/Info.plist b/PersistenceHelper/Resources/Info.plist index 597db31..2818f6d 100644 --- a/PersistenceHelper/Resources/Info.plist +++ b/PersistenceHelper/Resources/Info.plist @@ -52,7 +52,7 @@ iPhoneOS CFBundleVersion - 1.0.3 + 1.0.4 LSRequiresIPhoneOS UIDeviceFamily diff --git a/PersistenceHelper/control b/PersistenceHelper/control index 7315cc5..36422fa 100644 --- a/PersistenceHelper/control +++ b/PersistenceHelper/control @@ -1,6 +1,6 @@ Package: com.opa334.trollstorehelper Name: TrollStore Helper -Version: 1.0.3 +Version: 1.0.4 Architecture: iphoneos-arm Description: Helper app to install and manage TrollStore! Maintainer: opa334 diff --git a/Store/Resources/Info.plist b/Store/Resources/Info.plist index a399920..1b107f7 100644 --- a/Store/Resources/Info.plist +++ b/Store/Resources/Info.plist @@ -50,7 +50,7 @@ iPhoneOS CFBundleVersion - 1.0.3 + 1.0.4 LSRequiresIPhoneOS UIDeviceFamily diff --git a/Store/control b/Store/control index 68b7e5c..808c568 100644 --- a/Store/control +++ b/Store/control @@ -1,6 +1,6 @@ Package: com.opa334.trollstore Name: TrollStore -Version: 1.0.3 +Version: 1.0.4 Architecture: iphoneos-arm Description: An awesome application! Maintainer: opa334 From 06e4075a26d67cd22be0bf8e414026916ad156c6 Mon Sep 17 00:00:00 2001 From: opa334 Date: Sun, 4 Sep 2022 15:37:49 +0200 Subject: [PATCH 02/11] 1.0.5 --- Helper/control | 2 +- Helper/main.m | 82 +++++++++++++++---- .../TrollInstaller/exploit/kernel_base.c | 21 ++++- PersistenceHelper/Resources/Info.plist | 2 +- PersistenceHelper/control | 2 +- Store/Resources/Info.plist | 2 +- Store/TSAppTableViewController.m | 10 ++- Store/TSApplicationsManager.h | 1 + Store/TSApplicationsManager.m | 9 ++ Store/TSSceneDelegate.m | 7 +- Store/control | 2 +- Store/entitlements.plist | 2 + 12 files changed, 108 insertions(+), 34 deletions(-) diff --git a/Helper/control b/Helper/control index 855c170..630a2bf 100644 --- a/Helper/control +++ b/Helper/control @@ -1,6 +1,6 @@ Package: com.opa334.trollstoreroothelper Name: trollstoreroothelper -Version: 1.0.4 +Version: 1.0.5 Architecture: iphoneos-arm Description: An awesome tool of some sort!! Maintainer: opa334 diff --git a/Helper/main.m b/Helper/main.m index 4bdbc81..24d70f5 100644 --- a/Helper/main.m +++ b/Helper/main.m @@ -378,6 +378,19 @@ BOOL signApp(NSString* appPath, NSError** error) return ldidRet == 0; } +void applyPatchesToInfoDictionary(NSString* appPath) +{ + NSURL* appURL = [NSURL fileURLWithPath:appPath]; + NSURL* infoPlistURL = [appURL URLByAppendingPathComponent:@"Info.plist"]; + NSMutableDictionary* infoDictM = [[NSDictionary dictionaryWithContentsOfURL:infoPlistURL error:nil] mutableCopy]; + if(!infoDictM) return; + + // enable notifications + infoDictM[@"SBAppUsesLocalNotifications"] = @1; + + [infoDictM writeToURL:infoPlistURL error:nil]; +} + // 170: failed to create container for app bundle // 171: a non trollstore app with the same identifier is already installled // 172: no info.plist found in app @@ -388,6 +401,8 @@ int installApp(NSString* appPath, BOOL sign, BOOL force, NSError** error) NSString* appId = appIdForAppPath(appPath); if(!appId) return 172; + applyPatchesToInfoDictionary(appPath); + if(sign) { // if it fails to sign, we don't care @@ -427,13 +442,25 @@ int installApp(NSString* appPath, BOOL sign, BOOL force, NSError** error) // Mark app as TrollStore app [[NSFileManager defaultManager] createFileAtPath:trollStoreMarkURL.path contents:[NSData data] attributes:nil]; - // Apply correct permissions - NSDirectoryEnumerator *enumerator = [[NSFileManager defaultManager] enumeratorAtURL:[NSURL fileURLWithPath:appPath] includingPropertiesForKeys:nil options:0 errorHandler:nil]; + // Apply correct permissions (First run, set everything to 644, owner 33) NSURL* fileURL; + NSDirectoryEnumerator *enumerator = [[NSFileManager defaultManager] enumeratorAtURL:[NSURL fileURLWithPath:appPath] includingPropertiesForKeys:nil options:0 errorHandler:nil]; while(fileURL = [enumerator nextObject]) { NSString* filePath = fileURL.path; chown(filePath.UTF8String, 33, 33); + chmod(filePath.UTF8String, 0644); + } + + // Apply correct permissions (Second run, set executables and directories to 0755) + enumerator = [[NSFileManager defaultManager] enumeratorAtURL:[NSURL fileURLWithPath:appPath] includingPropertiesForKeys:nil options:0 errorHandler:nil]; + while(fileURL = [enumerator nextObject]) + { + NSString* filePath = fileURL.path; + + BOOL isDir; + [[NSFileManager defaultManager] fileExistsAtPath:fileURL.path isDirectory:&isDir]; + if([filePath.lastPathComponent isEqualToString:@"Info.plist"]) { NSDictionary* infoDictionary = [NSDictionary dictionaryWithContentsOfFile:filePath]; @@ -444,10 +471,15 @@ int installApp(NSString* appPath, BOOL sign, BOOL force, NSError** error) chmod(executablePath.UTF8String, 0755); } } - else if([filePath.pathExtension isEqualToString:@"dylib"]) + else if(!isDir && [filePath.pathExtension isEqualToString:@"dylib"]) { chmod(filePath.UTF8String, 0755); } + else if(isDir) + { + // apparently all dirs are writable by default + chmod(filePath.UTF8String, 0755); + } } // chown 0 all root binaries @@ -509,17 +541,10 @@ int installApp(NSString* appPath, BOOL sign, BOOL force, NSError** error) } } -int uninstallApp(NSString* appId, NSError** error) +int uninstallApp(NSString* appPath, NSString* appId, NSError** error) { - NSString* appPath = appPathForAppId(appId, error); - if(!appPath) return 1; - LSApplicationProxy* appProxy = [LSApplicationProxy applicationProxyForIdentifier:appId]; - NSLog(@"appProxy: %@", appProxy); - - MCMContainer *appContainer = [objc_getClass("MCMAppDataContainer") containerWithIdentifier:appId createIfNecessary:NO existed:nil error:nil]; - NSLog(@"1"); NSString *containerPath = [appContainer url].path; if(containerPath) { @@ -531,8 +556,8 @@ int uninstallApp(NSString* appId, NSError** error) // delete group container paths [[appProxy groupContainerURLs] enumerateKeysAndObjectsUsingBlock:^(NSString* groupID, NSURL* groupURL, BOOL* stop) { - [[NSFileManager defaultManager] removeItemAtURL:groupURL error:nil]; NSLog(@"deleting %@", groupURL); + [[NSFileManager defaultManager] removeItemAtURL:groupURL error:nil]; }]; // delete app plugin paths @@ -541,15 +566,15 @@ int uninstallApp(NSString* appId, NSError** error) NSURL* pluginURL = pluginProxy.dataContainerURL; if(pluginURL) { - [[NSFileManager defaultManager] removeItemAtPath:pluginURL.path error:error]; - NSLog(@"deleting %@", pluginURL.path); + NSLog(@"deleting %@", pluginURL); + [[NSFileManager defaultManager] removeItemAtURL:pluginURL error:error]; } } // unregister app registerPath((char*)appPath.UTF8String, 1); - NSLog(@"deleting %@", [appPath stringByDeletingLastPathComponent]); + NSLog(@"deleting %@", [appPath stringByDeletingLastPathComponent]); // delete app BOOL deleteSuc = [[NSFileManager defaultManager] removeItemAtPath:[appPath stringByDeletingLastPathComponent] error:error]; if(deleteSuc) @@ -562,6 +587,22 @@ int uninstallApp(NSString* appId, NSError** error) } } +int uninstallAppByPath(NSString* appPath, NSError** error) +{ + if(!appPath) return 1; + NSString* appId = appIdForAppPath(appPath); + if(!appId) return 1; + return uninstallApp(appPath, appId, error); +} + +int uninstallAppById(NSString* appId, NSError** error) +{ + if(!appId) return 1; + NSString* appPath = appPathForAppId(appId, error); + if(!appPath) return 1; + return uninstallApp(appPath, appId, error); +} + // 166: IPA does not exist or is not accessible // 167: IPA does not appear to contain an app @@ -604,7 +645,7 @@ void uninstallAllApps(void) { for(NSString* appPath in trollStoreInstalledAppBundlePaths()) { - uninstallApp(appIdForAppPath(appPath), nil); + uninstallAppById(appIdForAppPath(appPath), nil); } } @@ -818,8 +859,13 @@ int main(int argc, char *argv[], char *envp[]) { { if(argc <= 2) return -3; NSString* appId = [NSString stringWithUTF8String:argv[2]]; - ret = uninstallApp(appId, &error); - } else if([cmd isEqualToString:@"install-trollstore"]) + ret = uninstallAppById(appId, &error); + } else if([cmd isEqualToString:@"uninstall-path"]) + { + if(argc <= 2) return -3; + NSString* appPath = [NSString stringWithUTF8String:argv[2]]; + ret = uninstallAppByPath(appPath, &error); + }else if([cmd isEqualToString:@"install-trollstore"]) { if(argc <= 2) return -3; NSString* tsTar = [NSString stringWithUTF8String:argv[2]]; diff --git a/Installer/TrollInstaller/TrollInstaller/exploit/kernel_base.c b/Installer/TrollInstaller/TrollInstaller/exploit/kernel_base.c index 5c40f51..4d67ec7 100644 --- a/Installer/TrollInstaller/TrollInstaller/exploit/kernel_base.c +++ b/Installer/TrollInstaller/TrollInstaller/exploit/kernel_base.c @@ -10,6 +10,7 @@ #include #include #include +#import extern void badLog(const char*, ...); @@ -53,18 +54,30 @@ uint64_t kernel_base_from_holder(mach_port_t holder, uint64_t holder_addr) struct utsname u; uname(&u); uint64_t off_task_bsd_info; - + #if __arm64e__ - if (strstr(u.machine, "iPhone14,")) + cpu_subtype_t cpuFamily = 0; + size_t cpuFamilySize = sizeof(cpuFamily); + sysctlbyname("hw.cpufamily", &cpuFamily, &cpuFamilySize, NULL, 0); + + bool isA15OrNewer; + if (cpuFamily == CPUFAMILY_ARM_BLIZZARD_AVALANCHE) { + isA15OrNewer = true; + } + else { + isA15OrNewer = false; + } + + if (isA15OrNewer) { off_task_bsd_info = 0x3c8; // ios15.1 a15 // proc_t::task_bsd_info } else { - off_task_bsd_info = 0x3b8; //; iOS15.1 a12 // proc_t::task_bsd_info + off_task_bsd_info = 0x3b8; //; iOS15.1 a12-a14 // proc_t::task_bsd_info } #else - off_task_bsd_info = 0x3A0; + off_task_bsd_info = 0x3A0; // a9-a11 #endif g_self_proc = xpaci(kread64(self_task + off_task_bsd_info)); diff --git a/PersistenceHelper/Resources/Info.plist b/PersistenceHelper/Resources/Info.plist index 2818f6d..c89c107 100644 --- a/PersistenceHelper/Resources/Info.plist +++ b/PersistenceHelper/Resources/Info.plist @@ -52,7 +52,7 @@ iPhoneOS CFBundleVersion - 1.0.4 + 1.0.5 LSRequiresIPhoneOS UIDeviceFamily diff --git a/PersistenceHelper/control b/PersistenceHelper/control index 36422fa..980a5ec 100644 --- a/PersistenceHelper/control +++ b/PersistenceHelper/control @@ -1,6 +1,6 @@ Package: com.opa334.trollstorehelper Name: TrollStore Helper -Version: 1.0.4 +Version: 1.0.5 Architecture: iphoneos-arm Description: Helper app to install and manage TrollStore! Maintainer: opa334 diff --git a/Store/Resources/Info.plist b/Store/Resources/Info.plist index 1b107f7..9684759 100644 --- a/Store/Resources/Info.plist +++ b/Store/Resources/Info.plist @@ -50,7 +50,7 @@ iPhoneOS CFBundleVersion - 1.0.4 + 1.0.5 LSRequiresIPhoneOS UIDeviceFamily diff --git a/Store/TSAppTableViewController.m b/Store/TSAppTableViewController.m index cd11afc..72549ce 100644 --- a/Store/TSAppTableViewController.m +++ b/Store/TSAppTableViewController.m @@ -55,7 +55,15 @@ { NSString* appPath = [[TSApplicationsManager sharedInstance] installedAppPaths][indexPath.row]; NSString* appId = [[TSApplicationsManager sharedInstance] appIdForAppPath:appPath]; - [[TSApplicationsManager sharedInstance] uninstallApp:appId]; + + if(appId) + { + [[TSApplicationsManager sharedInstance] uninstallApp:appId]; + } + else + { + [[TSApplicationsManager sharedInstance] uninstallAppByPath:appPath]; + } } } diff --git a/Store/TSApplicationsManager.h b/Store/TSApplicationsManager.h index 2b238f7..b8f8a41 100644 --- a/Store/TSApplicationsManager.h +++ b/Store/TSApplicationsManager.h @@ -17,5 +17,6 @@ - (int)installIpa:(NSString*)pathToIpa force:(BOOL)force; - (int)installIpa:(NSString*)pathToIpa; - (int)uninstallApp:(NSString*)appId; +- (int)uninstallAppByPath:(NSString*)path; @end \ No newline at end of file diff --git a/Store/TSApplicationsManager.m b/Store/TSApplicationsManager.m index 957a3eb..57294c2 100644 --- a/Store/TSApplicationsManager.m +++ b/Store/TSApplicationsManager.m @@ -100,9 +100,18 @@ - (int)uninstallApp:(NSString*)appId { + if(!appId) return -200; int ret = spawnRoot(helperPath(), @[@"uninstall", appId]); [[NSNotificationCenter defaultCenter] postNotificationName:@"ApplicationsChanged" object:nil]; return ret; } +- (int)uninstallAppByPath:(NSString*)path +{ + if(!path) return -200; + int ret = spawnRoot(helperPath(), @[@"uninstall-path", path]); + [[NSNotificationCenter defaultCenter] postNotificationName:@"ApplicationsChanged" object:nil]; + return ret; +} + @end \ No newline at end of file diff --git a/Store/TSSceneDelegate.m b/Store/TSSceneDelegate.m index 55b1a1d..a09325c 100644 --- a/Store/TSSceneDelegate.m +++ b/Store/TSSceneDelegate.m @@ -77,13 +77,8 @@ NSURL* url = context.URL; if (url != nil && [url isFileURL]) { [url startAccessingSecurityScopedResource]; - NSURL* tmpCopyURL = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:url.lastPathComponent]]; - - [[NSFileManager defaultManager] copyItemAtURL:url toURL:tmpCopyURL error:nil]; - void (^doneBlock)(BOOL) = ^(BOOL shouldExit) { - [[NSFileManager defaultManager] removeItemAtURL:tmpCopyURL error:nil]; [url stopAccessingSecurityScopedResource]; [[NSFileManager defaultManager] removeItemAtURL:url error:nil]; @@ -105,7 +100,7 @@ { // Update TrollStore itself NSLog(@"Updating TrollStore..."); - int ret = spawnRoot(helperPath(), @[@"install-trollstore", tmpCopyURL.path]); + int ret = spawnRoot(helperPath(), @[@"install-trollstore", url.path]); doneBlock(ret == 0); NSLog(@"Updated TrollStore!"); } diff --git a/Store/control b/Store/control index 808c568..812c349 100644 --- a/Store/control +++ b/Store/control @@ -1,6 +1,6 @@ Package: com.opa334.trollstore Name: TrollStore -Version: 1.0.4 +Version: 1.0.5 Architecture: iphoneos-arm Description: An awesome application! Maintainer: opa334 diff --git a/Store/entitlements.plist b/Store/entitlements.plist index e3a4663..b1b4f33 100644 --- a/Store/entitlements.plist +++ b/Store/entitlements.plist @@ -30,5 +30,7 @@ com.apple.private.uninstall.deletion + com.apple.private.security.storage.MobileDocuments + \ No newline at end of file From 388a89c3a9b5f29b33822e0d829c6ededa6e2483 Mon Sep 17 00:00:00 2001 From: Nathan <87825638+verygenericname@users.noreply.github.com> Date: Sun, 4 Sep 2022 12:35:52 -0400 Subject: [PATCH 03/11] Update IOGPU.c --- Installer/TrollInstaller/TrollInstaller/exploit/IOGPU.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Installer/TrollInstaller/TrollInstaller/exploit/IOGPU.c b/Installer/TrollInstaller/TrollInstaller/exploit/IOGPU.c index 99b328f..26f39e9 100644 --- a/Installer/TrollInstaller/TrollInstaller/exploit/IOGPU.c +++ b/Installer/TrollInstaller/TrollInstaller/exploit/IOGPU.c @@ -53,6 +53,7 @@ int IOGPU_get_command_queue_extra_refills_needed(void) uname(&u); // iPhone 7 + // iPod 7 // iPhone 11 // iPhone 12 // iPhone 13 @@ -60,6 +61,7 @@ int IOGPU_get_command_queue_extra_refills_needed(void) // iPad Pro (10.5-inch, WiFi) if ( strstr(u.machine, "iPhone9,") + || strstr(u.machine, "iPod9,") || strstr(u.machine, "iPhone12,") || strstr(u.machine, "iPhone13,") || strstr(u.machine, "iPhone14,") From 5659a84c57f8ee24ae43342b171df6269ee571ff Mon Sep 17 00:00:00 2001 From: Luke Noble Date: Sun, 4 Sep 2022 19:48:20 +0100 Subject: [PATCH 04/11] Info.plist fast path for apps already CT-signed Apps declaring TSBundlePreSigned = YES in their Info.plist will not be signed by TrollStore --- Helper/main.m | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Helper/main.m b/Helper/main.m index 24d70f5..c1e2105 100644 --- a/Helper/main.m +++ b/Helper/main.m @@ -346,6 +346,19 @@ BOOL signApp(NSString* appPath, NSError** error) NSString* executablePath = [appPath stringByAppendingPathComponent:executable]; if(![[NSFileManager defaultManager] fileExistsAtPath:executablePath]) return NO; + + NSObject *tsBundleIsPreSigned = appInfoDict[@"TSBundlePreSigned"]; + if([tsBundleIsPreSigned isKindOfClass:[NSNumber class]]) + { + + // if TSBundlePreSigned = YES, this bundle has been externally signed so we can skip over signing it now + NSNumber *tsBundleIsPreSignedNum = (NSNumber *)tsBundleIsPreSigned; + if([tsBundleIsPreSignedNum boolValue] == YES) + { + NSLog(@"[signApp] taking fast path for app which declares it has already been CT-signed (%@)", executablePath); + return YES; + } + } NSString* certPath = [trollStoreAppPath() stringByAppendingPathComponent:@"cert.p12"]; NSString* certArg = [@"-K" stringByAppendingPathComponent:certPath]; From d909eee3fe16cec3a4050925cbe8f22a63effd9b Mon Sep 17 00:00:00 2001 From: Luke Noble Date: Sun, 4 Sep 2022 21:18:59 +0100 Subject: [PATCH 05/11] Handle apps already signed with a custom root --- Helper/main.m | 368 +++++++++++++++++++++++++++-------------------- Helper/uicache.m | 8 +- 2 files changed, 220 insertions(+), 156 deletions(-) diff --git a/Helper/main.m b/Helper/main.m index c1e2105..e12712d 100644 --- a/Helper/main.m +++ b/Helper/main.m @@ -8,53 +8,10 @@ #import #import "CoreServices.h" #import "Shared.h" -#import -#import -#import -#import -#import -#import -#import -#import #import #import - -#ifdef __LP64__ -#define segment_command_universal segment_command_64 -#define mach_header_universal mach_header_64 -#define MH_MAGIC_UNIVERSAL MH_MAGIC_64 -#define MH_CIGAM_UNIVERSAL MH_CIGAM_64 -#else -#define segment_command_universal segment_command -#define mach_header_universal mach_header -#define MH_MAGIC_UNIVERSAL MH_MAGIC -#define MH_CIGAM_UNIVERSAL MH_CIGAM -#endif - -#define SWAP32(x) ((((x) & 0xff000000) >> 24) | (((x) & 0xff0000) >> 8) | (((x) & 0xff00) << 8) | (((x) & 0xff) << 24)) -uint32_t s32(uint32_t toSwap, BOOL shouldSwap) -{ - return shouldSwap ? SWAP32(toSwap) : toSwap; -} - -#define CPU_SUBTYPE_ARM64E_NEW_ABI 0x80000002 - -struct CSSuperBlob { - uint32_t magic; - uint32_t length; - uint32_t count; -}; - -struct CSBlob { - uint32_t type; - uint32_t offset; -}; - -#define CS_MAGIC_EMBEDDED_SIGNATURE 0xfade0cc0 -#define CS_MAGIC_EMBEDDED_SIGNATURE_REVERSED 0xc00cdefa -#define CS_MAGIC_EMBEDDED_ENTITLEMENTS 0xfade7171 - +#import extern mach_msg_return_t SBReloadIconForIdentifier(mach_port_t machport, const char* identifier); @interface SBSHomeScreenService : NSObject @@ -65,6 +22,26 @@ extern NSString* BKSOpenApplicationOptionKeyActivateForEvent; extern void BKSTerminateApplicationForReasonAndReportWithDescription(NSString *bundleID, int reasonID, bool report, NSString *description); + +typedef CF_OPTIONS(uint32_t, SecCSFlags) { + kSecCSDefaultFlags = 0 +}; + + +#define kSecCSRequirementInformation 1 << 2 +#define kSecCSSigningInformation 1 << 1 + +typedef struct __SecCode const *SecStaticCodeRef; + +extern CFStringRef kSecCodeInfoEntitlementsDict; +extern CFStringRef kSecCodeInfoCertificates; +extern CFStringRef kSecPolicyAppleiPhoneApplicationSigning; +extern CFStringRef kSecPolicyLeafMarkerOid; + +OSStatus SecStaticCodeCreateWithPathAndAttributes(CFURLRef path, SecCSFlags flags, CFDictionaryRef attributes, SecStaticCodeRef *staticCode); +OSStatus SecCodeCopySigningInformation(SecStaticCodeRef code, SecCSFlags flags, CFDictionaryRef *information); +CFDataRef SecCertificateCopyExtensionValue(SecCertificateRef certificate, CFTypeRef extensionOID, bool *isCritical); + #define kCFPreferencesNoContainer CFSTR("kCFPreferencesNoContainer") typedef CFPropertyListRef (*_CFPreferencesCopyValueWithContainerType)(CFStringRef key, CFStringRef applicationID, CFStringRef userName, CFStringRef hostName, CFStringRef containerPath); @@ -221,118 +198,189 @@ int runLdid(NSArray* args, NSString** output, NSString** errorOutput) return WEXITSTATUS(status); } -NSDictionary* dumpEntitlements(NSString* binaryPath) +SecStaticCodeRef getStaticCodeRef(NSString *binaryPath) { - char* entitlementsData = NULL; - uint32_t entitlementsLength = 0; + + if(binaryPath == nil) + { + return NULL; + } + + CFURLRef binaryURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, (__bridge CFStringRef)binaryPath, kCFURLPOSIXPathStyle, false); + if(binaryURL == NULL) + { + NSLog(@"[getStaticCodeRef] failed to get URL to binary %@", binaryPath); + return NULL; + } + + SecStaticCodeRef codeRef = NULL; + OSStatus result; + + result = SecStaticCodeCreateWithPathAndAttributes(binaryURL, kSecCSDefaultFlags, NULL, &codeRef); + + CFRelease(binaryURL); + + if(result != errSecSuccess) + { + NSLog(@"[getStaticCodeRef] failed to create static code for binary %@", binaryPath); + return NULL; + } + + return codeRef; +} - FILE* machoFile = fopen(binaryPath.UTF8String, "rb"); - struct mach_header_universal header; - fread(&header,sizeof(header),1,machoFile); +NSDictionary* dumpEntitlements(SecStaticCodeRef codeRef) +{ + + if(codeRef == NULL) + { + NSLog(@"[dumpEntitlements] attempting to dump entitlements without a StaticCodeRef"); + return nil; + } + + CFDictionaryRef signingInfo = NULL; + OSStatus result; + + result = SecCodeCopySigningInformation(codeRef, kSecCSRequirementInformation, &signingInfo); + + if(result != errSecSuccess) + { + NSLog(@"[dumpEntitlements] failed to copy signing info from static code"); + return nil; + } + + NSDictionary *entitlementsNSDict = nil; + + CFDictionaryRef entitlements = CFDictionaryGetValue(signingInfo, kSecCodeInfoEntitlementsDict); + if(entitlements == NULL) + { + NSLog(@"[dumpEntitlements] no entitlements specified"); + } + else if(CFGetTypeID(entitlements) != CFDictionaryGetTypeID()) + { + NSLog(@"[dumpEntitlements] invalid entitlements"); + } + else + { + entitlementsNSDict = (__bridge NSDictionary *)(entitlements); + NSLog(@"[dumpEntitlements] dumped %@", entitlementsNSDict); + } + + CFRelease(signingInfo); + return entitlementsNSDict; +} - uint32_t archOffset = 0; +NSDictionary* dumpEntitlementsFromBinaryAtPath(NSString *binaryPath) +{ + // This function is intended for one-shot checks. Main-event functions should retain/release their own SecStaticCodeRefs + + if(binaryPath == nil) + { + return nil; + } + + SecStaticCodeRef codeRef = getStaticCodeRef(binaryPath); + if(codeRef == NULL) + { + return nil; + } + + NSDictionary *entitlements = dumpEntitlements(codeRef); + CFRelease(codeRef); + + return entitlements; +} - // Get arch offset if FAT binary - if(header.magic == FAT_MAGIC || header.magic == FAT_CIGAM) - { - fseek(machoFile,0,SEEK_SET); +BOOL certificateHasDataForExtensionOID(SecCertificateRef certificate, CFStringRef oidString) +{ + + if(certificate == NULL || oidString == NULL) + { + NSLog(@"[certificateHasDataForExtensionOID] attempted to check null certificate or OID"); + return NO; + } + + CFDataRef extensionData = SecCertificateCopyExtensionValue(certificate, oidString, NULL); + if(extensionData != NULL) + { + CFRelease(extensionData); + return YES; + } + + return NO; +} - struct fat_header fatHeader; - fread(&fatHeader,sizeof(fatHeader),1,machoFile); +BOOL codeCertChainContainsFakeAppStoreExtensions(SecStaticCodeRef codeRef) +{ + + if(codeRef == NULL) + { + NSLog(@"[codeCertChainContainsFakeAppStoreExtensions] attempted to check cert chain of null static code object"); + return NO; + } + + CFDictionaryRef signingInfo = NULL; + OSStatus result; + + result = SecCodeCopySigningInformation(codeRef, kSecCSSigningInformation, &signingInfo); + + if(result != errSecSuccess) + { + NSLog(@"[codeCertChainContainsFakeAppStoreExtensions] failed to copy signing info from static code"); + return NO; + } + + CFArrayRef certificates = CFDictionaryGetValue(signingInfo, kSecCodeInfoCertificates); - BOOL swpFat = fatHeader.magic == FAT_CIGAM; - - for(int i = 0; i < s32(fatHeader.nfat_arch, swpFat); i++) - { - struct fat_arch fatArch; - fseek(machoFile,sizeof(fatHeader) + sizeof(fatArch) * i,SEEK_SET); - fread(&fatArch,sizeof(fatArch),1,machoFile); - - if(s32(fatArch.cputype, swpFat) != CPU_TYPE_ARM64) - { - continue; - } - - archOffset = s32(fatArch.offset, swpFat); - break; - } - } - - fseek(machoFile,archOffset,SEEK_SET); - fread(&header,sizeof(header),1,machoFile); - - if(header.magic == MH_MAGIC_UNIVERSAL || header.magic == MH_CIGAM_UNIVERSAL) - { - BOOL swp = header.magic == MH_CIGAM_UNIVERSAL; - // This code is cursed, don't stare at it too long or it will stare back at you - uint32_t offset = archOffset + sizeof(header); - for(int c = 0; c < s32(header.ncmds, swp); c++) - { - fseek(machoFile,offset,SEEK_SET); - struct load_command cmd; - fread(&cmd,sizeof(cmd),1,machoFile); - uint32_t normalizedCmd = s32(cmd.cmd,swp); - if(normalizedCmd == LC_CODE_SIGNATURE) - { - struct linkedit_data_command codeSignCommand; - fseek(machoFile,offset,SEEK_SET); - fread(&codeSignCommand,sizeof(codeSignCommand),1,machoFile); - uint32_t codeSignCmdOffset = archOffset + s32(codeSignCommand.dataoff, swp); - fseek(machoFile, codeSignCmdOffset, SEEK_SET); - struct CSSuperBlob superBlob; - fread(&superBlob, sizeof(superBlob), 1, machoFile); - if(SWAP32(superBlob.magic) == CS_MAGIC_EMBEDDED_SIGNATURE) // YES starting here everything is swapped no matter if CIGAM or MAGIC... - { - uint32_t itemCount = SWAP32(superBlob.count); - for(int i = 0; i < itemCount; i++) - { - fseek(machoFile, codeSignCmdOffset + sizeof(superBlob) + i * sizeof(struct CSBlob),SEEK_SET); - struct CSBlob blob; - fread(&blob, sizeof(struct CSBlob), 1, machoFile); - fseek(machoFile, codeSignCmdOffset + SWAP32(blob.offset),SEEK_SET); - uint32_t blobMagic; - fread(&blobMagic, sizeof(uint32_t), 1, machoFile); - if(SWAP32(blobMagic) == CS_MAGIC_EMBEDDED_ENTITLEMENTS) - { - uint32_t entitlementsLengthTmp; - fread(&entitlementsLengthTmp, sizeof(uint32_t), 1, machoFile); - entitlementsLength = SWAP32(entitlementsLengthTmp); - entitlementsData = malloc(entitlementsLength - 8); - fread(&entitlementsData[0], entitlementsLength - 8, 1, machoFile); - break; - } - } - } - - break; - } - - offset += cmd.cmdsize; - } - } - - fclose(machoFile); - - NSData* entitlementsNSData = nil; - - if(entitlementsData) - { - entitlementsNSData = [NSData dataWithBytes:entitlementsData length:entitlementsLength]; - free(entitlementsData); - } - - if(entitlementsNSData) - { - NSDictionary* plist = [NSPropertyListSerialization propertyListWithData:entitlementsNSData options:NSPropertyListImmutable format:nil error:nil]; - NSLog(@"%@ dumped entitlements %@", binaryPath, plist); - return plist; - } - else - { - NSLog(@"Failed to dump entitlements of %@... This is bad", binaryPath); - } - - return nil; + // If we match the standard Apple policy, we are signed properly, but we haven't been deliberately signed with a custom root + + SecPolicyRef genuineApplePolicy = SecPolicyCreateWithProperties(kSecPolicyAppleiPhoneApplicationSigning, NULL); + SecTrustRef genuineAppleTrust = NULL; + SecTrustCreateWithCertificates(certificates, genuineApplePolicy, &genuineAppleTrust); + + if(SecTrustEvaluateWithError(genuineAppleTrust, nil)) + { + CFRelease(genuineAppleTrust); + CFRelease(genuineApplePolicy); + CFRelease(signingInfo); + + NSLog(@"[codeCertChainContainsFakeAppStoreExtensions] found certificate extension, but was issued by Apple"); + return NO; + } + + // We haven't matched Apple, so keep going. Are we using a custom root that would take the App Store fastpath? + CFRelease(genuineAppleTrust); + CFRelease(genuineApplePolicy); + + // Cert chain should be of length 3 + if(CFArrayGetCount(certificates) != 3) + { + CFRelease(signingInfo); + + NSLog(@"[codeCertChainContainsFakeAppStoreExtensions] certificate chain length != 3"); + return NO; + } + + const void *keys[1] = { kSecPolicyLeafMarkerOid }; + const void *values[1] = { CFSTR("1.2.840.113635.100.6.1.3") }; + CFDictionaryRef customPolicyOptions = CFDictionaryCreate(NULL, keys, values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + + // AppleCodeSigning only checks for the codeSigning EKU by default + SecPolicyRef customRootPolicy = SecPolicyCreateWithProperties(kSecPolicyAppleCodeSigning, customPolicyOptions); + SecTrustRef customRootTrust = NULL; + + // Need to add our certificate chain to the anchor as it is expected to be a self-signed root + SecTrustCreateWithCertificates(certificates, customRootPolicy, &customRootTrust); + SecTrustSetAnchorCertificates(customRootTrust, certificates); + + BOOL evaluatesToCustomAnchor = SecTrustEvaluateWithError(customRootTrust, nil); + + CFRelease(customRootTrust); + CFRelease(customRootPolicy); + CFRelease(customPolicyOptions); + + CFRelease(signingInfo); + return evaluatesToCustomAnchor; } BOOL signApp(NSString* appPath, NSError** error) @@ -355,17 +403,33 @@ BOOL signApp(NSString* appPath, NSError** error) NSNumber *tsBundleIsPreSignedNum = (NSNumber *)tsBundleIsPreSigned; if([tsBundleIsPreSignedNum boolValue] == YES) { - NSLog(@"[signApp] taking fast path for app which declares it has already been CT-signed (%@)", executablePath); + NSLog(@"[signApp] taking fast path for app which declares it has already been signed (%@)", executablePath); return YES; } } + + SecStaticCodeRef codeRef = getStaticCodeRef(executablePath); + if(codeRef == NULL) + { + NSLog(@"[signApp] failed to get static code, can't derive entitlements from %@", executablePath); + return NO; + } + + if(codeCertChainContainsFakeAppStoreExtensions(codeRef)) + { + NSLog(@"[signApp] taking fast path for app signed using a custom root certificate (%@)", executablePath); + CFRelease(codeRef); + return YES; + } NSString* certPath = [trollStoreAppPath() stringByAppendingPathComponent:@"cert.p12"]; NSString* certArg = [@"-K" stringByAppendingPathComponent:certPath]; NSString* errorOutput; int ldidRet; - NSDictionary* entitlements = dumpEntitlements(executablePath); + NSDictionary* entitlements = dumpEntitlements(codeRef); + CFRelease(codeRef); + if(!entitlements) { NSLog(@"app main binary has no entitlements, signing app with fallback entitlements..."); diff --git a/Helper/uicache.m b/Helper/uicache.m index 1a2f8d9..97bfeb1 100644 --- a/Helper/uicache.m +++ b/Helper/uicache.m @@ -6,7 +6,7 @@ // uicache on steroids -extern NSDictionary* dumpEntitlements(NSString* binaryPath); +extern NSDictionary* dumpEntitlementsFromBinaryAtPath(NSString* binaryPath); NSDictionary* constructGroupsContainersForEntitlements(NSDictionary* entitlements, BOOL systemGroups) { @@ -118,7 +118,7 @@ void registerPath(char* cPath, int unregister) // Add entitlements NSString* appExecutablePath = [path stringByAppendingPathComponent:appInfoPlist[@"CFBundleExecutable"]]; - NSDictionary* entitlements = dumpEntitlements(appExecutablePath); + NSDictionary* entitlements = dumpEntitlementsFromBinaryAtPath(appExecutablePath); if(entitlements) { dictToRegister[@"Entitlements"] = entitlements; @@ -185,7 +185,7 @@ void registerPath(char* cPath, int unregister) // Add entitlements NSString* pluginExecutablePath = [pluginPath stringByAppendingPathComponent:pluginInfoPlist[@"CFBundleExecutable"]]; - NSDictionary* pluginEntitlements = dumpEntitlements(pluginExecutablePath); + NSDictionary* pluginEntitlements = dumpEntitlementsFromBinaryAtPath(pluginExecutablePath); if(pluginEntitlements) { pluginDict[@"Entitlements"] = pluginEntitlements; @@ -247,4 +247,4 @@ void registerPath(char* cPath, int unregister) NSLog(@"Error: Unable to unregister %@", path); } } -} \ No newline at end of file +} From fa642e8d06fcbaa9c178a2d8c2a7f8e34813f3ad Mon Sep 17 00:00:00 2001 From: opa334 Date: Mon, 5 Sep 2022 14:48:06 +0200 Subject: [PATCH 06/11] Fix app plugins --- Helper/uicache.m | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Helper/uicache.m b/Helper/uicache.m index 1a2f8d9..85f22e9 100644 --- a/Helper/uicache.m +++ b/Helper/uicache.m @@ -139,6 +139,9 @@ void registerPath(char* cPath, int unregister) dictToRegister[@"IsDeletable"] = @0; dictToRegister[@"Path"] = path; dictToRegister[@"IsContainerized"] = @(constructContainerizationForEntitlements(entitlements)); + dictToRegister[@"SignerOrganization"] = @"Apple Inc."; + dictToRegister[@"SignatureVersion"] = @132352; + dictToRegister[@"SignerIdentity"] = @"Apple iPhone OS Application Signing"; NSString* teamIdentifier = constructTeamIdentifierForEntitlements(entitlements); if(teamIdentifier) dictToRegister[@"TeamIdentifier"] = teamIdentifier; @@ -206,6 +209,9 @@ void registerPath(char* cPath, int unregister) pluginDict[@"Path"] = pluginPath; pluginDict[@"PluginOwnerBundleID"] = appBundleID; pluginDict[@"IsContainerized"] = @(constructContainerizationForEntitlements(pluginEntitlements)); + pluginDict[@"SignerOrganization"] = @"Apple Inc."; + pluginDict[@"SignatureVersion"] = @132352; + pluginDict[@"SignerIdentity"] = @"Apple iPhone OS Application Signing"; NSString* pluginTeamIdentifier = constructTeamIdentifierForEntitlements(pluginEntitlements); if(pluginTeamIdentifier) pluginDict[@"TeamIdentifier"] = pluginTeamIdentifier; From 4f870c1a822ec1437eb3df8b454468bce9878722 Mon Sep 17 00:00:00 2001 From: opa334 Date: Mon, 5 Sep 2022 15:09:31 +0200 Subject: [PATCH 07/11] Revert "Merge pull request #63 from luken11/signing-fast-path" This reverts commit a0dc58a4c0465609dbdb340913e780347daa98ea, reversing changes made to fa642e8d06fcbaa9c178a2d8c2a7f8e34813f3ad. --- Helper/main.m | 379 +++++++++++++++++++---------------------------- Helper/uicache.m | 8 +- 2 files changed, 155 insertions(+), 232 deletions(-) diff --git a/Helper/main.m b/Helper/main.m index e12712d..24d70f5 100644 --- a/Helper/main.m +++ b/Helper/main.m @@ -8,10 +8,53 @@ #import #import "CoreServices.h" #import "Shared.h" +#import +#import +#import +#import +#import +#import +#import +#import #import #import -#import + +#ifdef __LP64__ +#define segment_command_universal segment_command_64 +#define mach_header_universal mach_header_64 +#define MH_MAGIC_UNIVERSAL MH_MAGIC_64 +#define MH_CIGAM_UNIVERSAL MH_CIGAM_64 +#else +#define segment_command_universal segment_command +#define mach_header_universal mach_header +#define MH_MAGIC_UNIVERSAL MH_MAGIC +#define MH_CIGAM_UNIVERSAL MH_CIGAM +#endif + +#define SWAP32(x) ((((x) & 0xff000000) >> 24) | (((x) & 0xff0000) >> 8) | (((x) & 0xff00) << 8) | (((x) & 0xff) << 24)) +uint32_t s32(uint32_t toSwap, BOOL shouldSwap) +{ + return shouldSwap ? SWAP32(toSwap) : toSwap; +} + +#define CPU_SUBTYPE_ARM64E_NEW_ABI 0x80000002 + +struct CSSuperBlob { + uint32_t magic; + uint32_t length; + uint32_t count; +}; + +struct CSBlob { + uint32_t type; + uint32_t offset; +}; + +#define CS_MAGIC_EMBEDDED_SIGNATURE 0xfade0cc0 +#define CS_MAGIC_EMBEDDED_SIGNATURE_REVERSED 0xc00cdefa +#define CS_MAGIC_EMBEDDED_ENTITLEMENTS 0xfade7171 + extern mach_msg_return_t SBReloadIconForIdentifier(mach_port_t machport, const char* identifier); @interface SBSHomeScreenService : NSObject @@ -22,26 +65,6 @@ extern NSString* BKSOpenApplicationOptionKeyActivateForEvent; extern void BKSTerminateApplicationForReasonAndReportWithDescription(NSString *bundleID, int reasonID, bool report, NSString *description); - -typedef CF_OPTIONS(uint32_t, SecCSFlags) { - kSecCSDefaultFlags = 0 -}; - - -#define kSecCSRequirementInformation 1 << 2 -#define kSecCSSigningInformation 1 << 1 - -typedef struct __SecCode const *SecStaticCodeRef; - -extern CFStringRef kSecCodeInfoEntitlementsDict; -extern CFStringRef kSecCodeInfoCertificates; -extern CFStringRef kSecPolicyAppleiPhoneApplicationSigning; -extern CFStringRef kSecPolicyLeafMarkerOid; - -OSStatus SecStaticCodeCreateWithPathAndAttributes(CFURLRef path, SecCSFlags flags, CFDictionaryRef attributes, SecStaticCodeRef *staticCode); -OSStatus SecCodeCopySigningInformation(SecStaticCodeRef code, SecCSFlags flags, CFDictionaryRef *information); -CFDataRef SecCertificateCopyExtensionValue(SecCertificateRef certificate, CFTypeRef extensionOID, bool *isCritical); - #define kCFPreferencesNoContainer CFSTR("kCFPreferencesNoContainer") typedef CFPropertyListRef (*_CFPreferencesCopyValueWithContainerType)(CFStringRef key, CFStringRef applicationID, CFStringRef userName, CFStringRef hostName, CFStringRef containerPath); @@ -198,189 +221,118 @@ int runLdid(NSArray* args, NSString** output, NSString** errorOutput) return WEXITSTATUS(status); } -SecStaticCodeRef getStaticCodeRef(NSString *binaryPath) +NSDictionary* dumpEntitlements(NSString* binaryPath) { - - if(binaryPath == nil) - { - return NULL; - } - - CFURLRef binaryURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, (__bridge CFStringRef)binaryPath, kCFURLPOSIXPathStyle, false); - if(binaryURL == NULL) - { - NSLog(@"[getStaticCodeRef] failed to get URL to binary %@", binaryPath); - return NULL; - } - - SecStaticCodeRef codeRef = NULL; - OSStatus result; - - result = SecStaticCodeCreateWithPathAndAttributes(binaryURL, kSecCSDefaultFlags, NULL, &codeRef); - - CFRelease(binaryURL); - - if(result != errSecSuccess) - { - NSLog(@"[getStaticCodeRef] failed to create static code for binary %@", binaryPath); - return NULL; - } - - return codeRef; -} + char* entitlementsData = NULL; + uint32_t entitlementsLength = 0; -NSDictionary* dumpEntitlements(SecStaticCodeRef codeRef) -{ - - if(codeRef == NULL) - { - NSLog(@"[dumpEntitlements] attempting to dump entitlements without a StaticCodeRef"); - return nil; - } - - CFDictionaryRef signingInfo = NULL; - OSStatus result; - - result = SecCodeCopySigningInformation(codeRef, kSecCSRequirementInformation, &signingInfo); - - if(result != errSecSuccess) - { - NSLog(@"[dumpEntitlements] failed to copy signing info from static code"); - return nil; - } - - NSDictionary *entitlementsNSDict = nil; - - CFDictionaryRef entitlements = CFDictionaryGetValue(signingInfo, kSecCodeInfoEntitlementsDict); - if(entitlements == NULL) - { - NSLog(@"[dumpEntitlements] no entitlements specified"); - } - else if(CFGetTypeID(entitlements) != CFDictionaryGetTypeID()) - { - NSLog(@"[dumpEntitlements] invalid entitlements"); - } - else - { - entitlementsNSDict = (__bridge NSDictionary *)(entitlements); - NSLog(@"[dumpEntitlements] dumped %@", entitlementsNSDict); - } - - CFRelease(signingInfo); - return entitlementsNSDict; -} + FILE* machoFile = fopen(binaryPath.UTF8String, "rb"); + struct mach_header_universal header; + fread(&header,sizeof(header),1,machoFile); -NSDictionary* dumpEntitlementsFromBinaryAtPath(NSString *binaryPath) -{ - // This function is intended for one-shot checks. Main-event functions should retain/release their own SecStaticCodeRefs - - if(binaryPath == nil) - { - return nil; - } - - SecStaticCodeRef codeRef = getStaticCodeRef(binaryPath); - if(codeRef == NULL) - { - return nil; - } - - NSDictionary *entitlements = dumpEntitlements(codeRef); - CFRelease(codeRef); - - return entitlements; -} + uint32_t archOffset = 0; -BOOL certificateHasDataForExtensionOID(SecCertificateRef certificate, CFStringRef oidString) -{ - - if(certificate == NULL || oidString == NULL) - { - NSLog(@"[certificateHasDataForExtensionOID] attempted to check null certificate or OID"); - return NO; - } - - CFDataRef extensionData = SecCertificateCopyExtensionValue(certificate, oidString, NULL); - if(extensionData != NULL) - { - CFRelease(extensionData); - return YES; - } - - return NO; -} + // Get arch offset if FAT binary + if(header.magic == FAT_MAGIC || header.magic == FAT_CIGAM) + { + fseek(machoFile,0,SEEK_SET); -BOOL codeCertChainContainsFakeAppStoreExtensions(SecStaticCodeRef codeRef) -{ - - if(codeRef == NULL) - { - NSLog(@"[codeCertChainContainsFakeAppStoreExtensions] attempted to check cert chain of null static code object"); - return NO; - } - - CFDictionaryRef signingInfo = NULL; - OSStatus result; - - result = SecCodeCopySigningInformation(codeRef, kSecCSSigningInformation, &signingInfo); - - if(result != errSecSuccess) - { - NSLog(@"[codeCertChainContainsFakeAppStoreExtensions] failed to copy signing info from static code"); - return NO; - } - - CFArrayRef certificates = CFDictionaryGetValue(signingInfo, kSecCodeInfoCertificates); + struct fat_header fatHeader; + fread(&fatHeader,sizeof(fatHeader),1,machoFile); - // If we match the standard Apple policy, we are signed properly, but we haven't been deliberately signed with a custom root - - SecPolicyRef genuineApplePolicy = SecPolicyCreateWithProperties(kSecPolicyAppleiPhoneApplicationSigning, NULL); - SecTrustRef genuineAppleTrust = NULL; - SecTrustCreateWithCertificates(certificates, genuineApplePolicy, &genuineAppleTrust); - - if(SecTrustEvaluateWithError(genuineAppleTrust, nil)) - { - CFRelease(genuineAppleTrust); - CFRelease(genuineApplePolicy); - CFRelease(signingInfo); - - NSLog(@"[codeCertChainContainsFakeAppStoreExtensions] found certificate extension, but was issued by Apple"); - return NO; - } - - // We haven't matched Apple, so keep going. Are we using a custom root that would take the App Store fastpath? - CFRelease(genuineAppleTrust); - CFRelease(genuineApplePolicy); - - // Cert chain should be of length 3 - if(CFArrayGetCount(certificates) != 3) - { - CFRelease(signingInfo); - - NSLog(@"[codeCertChainContainsFakeAppStoreExtensions] certificate chain length != 3"); - return NO; - } - - const void *keys[1] = { kSecPolicyLeafMarkerOid }; - const void *values[1] = { CFSTR("1.2.840.113635.100.6.1.3") }; - CFDictionaryRef customPolicyOptions = CFDictionaryCreate(NULL, keys, values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - - // AppleCodeSigning only checks for the codeSigning EKU by default - SecPolicyRef customRootPolicy = SecPolicyCreateWithProperties(kSecPolicyAppleCodeSigning, customPolicyOptions); - SecTrustRef customRootTrust = NULL; - - // Need to add our certificate chain to the anchor as it is expected to be a self-signed root - SecTrustCreateWithCertificates(certificates, customRootPolicy, &customRootTrust); - SecTrustSetAnchorCertificates(customRootTrust, certificates); - - BOOL evaluatesToCustomAnchor = SecTrustEvaluateWithError(customRootTrust, nil); - - CFRelease(customRootTrust); - CFRelease(customRootPolicy); - CFRelease(customPolicyOptions); - - CFRelease(signingInfo); - return evaluatesToCustomAnchor; + BOOL swpFat = fatHeader.magic == FAT_CIGAM; + + for(int i = 0; i < s32(fatHeader.nfat_arch, swpFat); i++) + { + struct fat_arch fatArch; + fseek(machoFile,sizeof(fatHeader) + sizeof(fatArch) * i,SEEK_SET); + fread(&fatArch,sizeof(fatArch),1,machoFile); + + if(s32(fatArch.cputype, swpFat) != CPU_TYPE_ARM64) + { + continue; + } + + archOffset = s32(fatArch.offset, swpFat); + break; + } + } + + fseek(machoFile,archOffset,SEEK_SET); + fread(&header,sizeof(header),1,machoFile); + + if(header.magic == MH_MAGIC_UNIVERSAL || header.magic == MH_CIGAM_UNIVERSAL) + { + BOOL swp = header.magic == MH_CIGAM_UNIVERSAL; + // This code is cursed, don't stare at it too long or it will stare back at you + uint32_t offset = archOffset + sizeof(header); + for(int c = 0; c < s32(header.ncmds, swp); c++) + { + fseek(machoFile,offset,SEEK_SET); + struct load_command cmd; + fread(&cmd,sizeof(cmd),1,machoFile); + uint32_t normalizedCmd = s32(cmd.cmd,swp); + if(normalizedCmd == LC_CODE_SIGNATURE) + { + struct linkedit_data_command codeSignCommand; + fseek(machoFile,offset,SEEK_SET); + fread(&codeSignCommand,sizeof(codeSignCommand),1,machoFile); + uint32_t codeSignCmdOffset = archOffset + s32(codeSignCommand.dataoff, swp); + fseek(machoFile, codeSignCmdOffset, SEEK_SET); + struct CSSuperBlob superBlob; + fread(&superBlob, sizeof(superBlob), 1, machoFile); + if(SWAP32(superBlob.magic) == CS_MAGIC_EMBEDDED_SIGNATURE) // YES starting here everything is swapped no matter if CIGAM or MAGIC... + { + uint32_t itemCount = SWAP32(superBlob.count); + for(int i = 0; i < itemCount; i++) + { + fseek(machoFile, codeSignCmdOffset + sizeof(superBlob) + i * sizeof(struct CSBlob),SEEK_SET); + struct CSBlob blob; + fread(&blob, sizeof(struct CSBlob), 1, machoFile); + fseek(machoFile, codeSignCmdOffset + SWAP32(blob.offset),SEEK_SET); + uint32_t blobMagic; + fread(&blobMagic, sizeof(uint32_t), 1, machoFile); + if(SWAP32(blobMagic) == CS_MAGIC_EMBEDDED_ENTITLEMENTS) + { + uint32_t entitlementsLengthTmp; + fread(&entitlementsLengthTmp, sizeof(uint32_t), 1, machoFile); + entitlementsLength = SWAP32(entitlementsLengthTmp); + entitlementsData = malloc(entitlementsLength - 8); + fread(&entitlementsData[0], entitlementsLength - 8, 1, machoFile); + break; + } + } + } + + break; + } + + offset += cmd.cmdsize; + } + } + + fclose(machoFile); + + NSData* entitlementsNSData = nil; + + if(entitlementsData) + { + entitlementsNSData = [NSData dataWithBytes:entitlementsData length:entitlementsLength]; + free(entitlementsData); + } + + if(entitlementsNSData) + { + NSDictionary* plist = [NSPropertyListSerialization propertyListWithData:entitlementsNSData options:NSPropertyListImmutable format:nil error:nil]; + NSLog(@"%@ dumped entitlements %@", binaryPath, plist); + return plist; + } + else + { + NSLog(@"Failed to dump entitlements of %@... This is bad", binaryPath); + } + + return nil; } BOOL signApp(NSString* appPath, NSError** error) @@ -394,42 +346,13 @@ BOOL signApp(NSString* appPath, NSError** error) NSString* executablePath = [appPath stringByAppendingPathComponent:executable]; if(![[NSFileManager defaultManager] fileExistsAtPath:executablePath]) return NO; - - NSObject *tsBundleIsPreSigned = appInfoDict[@"TSBundlePreSigned"]; - if([tsBundleIsPreSigned isKindOfClass:[NSNumber class]]) - { - - // if TSBundlePreSigned = YES, this bundle has been externally signed so we can skip over signing it now - NSNumber *tsBundleIsPreSignedNum = (NSNumber *)tsBundleIsPreSigned; - if([tsBundleIsPreSignedNum boolValue] == YES) - { - NSLog(@"[signApp] taking fast path for app which declares it has already been signed (%@)", executablePath); - return YES; - } - } - - SecStaticCodeRef codeRef = getStaticCodeRef(executablePath); - if(codeRef == NULL) - { - NSLog(@"[signApp] failed to get static code, can't derive entitlements from %@", executablePath); - return NO; - } - - if(codeCertChainContainsFakeAppStoreExtensions(codeRef)) - { - NSLog(@"[signApp] taking fast path for app signed using a custom root certificate (%@)", executablePath); - CFRelease(codeRef); - return YES; - } NSString* certPath = [trollStoreAppPath() stringByAppendingPathComponent:@"cert.p12"]; NSString* certArg = [@"-K" stringByAppendingPathComponent:certPath]; NSString* errorOutput; int ldidRet; - NSDictionary* entitlements = dumpEntitlements(codeRef); - CFRelease(codeRef); - + NSDictionary* entitlements = dumpEntitlements(executablePath); if(!entitlements) { NSLog(@"app main binary has no entitlements, signing app with fallback entitlements..."); diff --git a/Helper/uicache.m b/Helper/uicache.m index f88ac1b..85f22e9 100644 --- a/Helper/uicache.m +++ b/Helper/uicache.m @@ -6,7 +6,7 @@ // uicache on steroids -extern NSDictionary* dumpEntitlementsFromBinaryAtPath(NSString* binaryPath); +extern NSDictionary* dumpEntitlements(NSString* binaryPath); NSDictionary* constructGroupsContainersForEntitlements(NSDictionary* entitlements, BOOL systemGroups) { @@ -118,7 +118,7 @@ void registerPath(char* cPath, int unregister) // Add entitlements NSString* appExecutablePath = [path stringByAppendingPathComponent:appInfoPlist[@"CFBundleExecutable"]]; - NSDictionary* entitlements = dumpEntitlementsFromBinaryAtPath(appExecutablePath); + NSDictionary* entitlements = dumpEntitlements(appExecutablePath); if(entitlements) { dictToRegister[@"Entitlements"] = entitlements; @@ -188,7 +188,7 @@ void registerPath(char* cPath, int unregister) // Add entitlements NSString* pluginExecutablePath = [pluginPath stringByAppendingPathComponent:pluginInfoPlist[@"CFBundleExecutable"]]; - NSDictionary* pluginEntitlements = dumpEntitlementsFromBinaryAtPath(pluginExecutablePath); + NSDictionary* pluginEntitlements = dumpEntitlements(pluginExecutablePath); if(pluginEntitlements) { pluginDict[@"Entitlements"] = pluginEntitlements; @@ -253,4 +253,4 @@ void registerPath(char* cPath, int unregister) NSLog(@"Error: Unable to unregister %@", path); } } -} +} \ No newline at end of file From f864807df7ed06c4116702891f78dbdabc80f1da Mon Sep 17 00:00:00 2001 From: opa334 Date: Mon, 5 Sep 2022 15:15:41 +0200 Subject: [PATCH 08/11] 1.0.6 --- Helper/control | 2 +- PersistenceHelper/Resources/Info.plist | 2 +- PersistenceHelper/control | 2 +- Store/Resources/Info.plist | 2 +- Store/control | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Helper/control b/Helper/control index 630a2bf..be35717 100644 --- a/Helper/control +++ b/Helper/control @@ -1,6 +1,6 @@ Package: com.opa334.trollstoreroothelper Name: trollstoreroothelper -Version: 1.0.5 +Version: 1.0.6 Architecture: iphoneos-arm Description: An awesome tool of some sort!! Maintainer: opa334 diff --git a/PersistenceHelper/Resources/Info.plist b/PersistenceHelper/Resources/Info.plist index c89c107..4953dbf 100644 --- a/PersistenceHelper/Resources/Info.plist +++ b/PersistenceHelper/Resources/Info.plist @@ -52,7 +52,7 @@ iPhoneOS CFBundleVersion - 1.0.5 + 1.0.6 LSRequiresIPhoneOS UIDeviceFamily diff --git a/PersistenceHelper/control b/PersistenceHelper/control index 980a5ec..f7a86f8 100644 --- a/PersistenceHelper/control +++ b/PersistenceHelper/control @@ -1,6 +1,6 @@ Package: com.opa334.trollstorehelper Name: TrollStore Helper -Version: 1.0.5 +Version: 1.0.6 Architecture: iphoneos-arm Description: Helper app to install and manage TrollStore! Maintainer: opa334 diff --git a/Store/Resources/Info.plist b/Store/Resources/Info.plist index 9684759..da5e09f 100644 --- a/Store/Resources/Info.plist +++ b/Store/Resources/Info.plist @@ -50,7 +50,7 @@ iPhoneOS CFBundleVersion - 1.0.5 + 1.0.6 LSRequiresIPhoneOS UIDeviceFamily diff --git a/Store/control b/Store/control index 812c349..6b0fccc 100644 --- a/Store/control +++ b/Store/control @@ -1,6 +1,6 @@ Package: com.opa334.trollstore Name: TrollStore -Version: 1.0.5 +Version: 1.0.6 Architecture: iphoneos-arm Description: An awesome application! Maintainer: opa334 From 0a5a8aefbed07ae32670c9e3b26d1c40093f8aaf Mon Sep 17 00:00:00 2001 From: Luke Noble Date: Mon, 5 Sep 2022 20:39:17 +0100 Subject: [PATCH 09/11] Improve existing certificate checks for fast-path --- Helper/main.m | 405 +++++++++++++++++++++++++++++------------------ Helper/uicache.m | 8 +- 2 files changed, 259 insertions(+), 154 deletions(-) diff --git a/Helper/main.m b/Helper/main.m index 24d70f5..481ad4f 100644 --- a/Helper/main.m +++ b/Helper/main.m @@ -8,52 +8,10 @@ #import #import "CoreServices.h" #import "Shared.h" -#import -#import -#import -#import -#import -#import -#import -#import #import #import - -#ifdef __LP64__ -#define segment_command_universal segment_command_64 -#define mach_header_universal mach_header_64 -#define MH_MAGIC_UNIVERSAL MH_MAGIC_64 -#define MH_CIGAM_UNIVERSAL MH_CIGAM_64 -#else -#define segment_command_universal segment_command -#define mach_header_universal mach_header -#define MH_MAGIC_UNIVERSAL MH_MAGIC -#define MH_CIGAM_UNIVERSAL MH_CIGAM -#endif - -#define SWAP32(x) ((((x) & 0xff000000) >> 24) | (((x) & 0xff0000) >> 8) | (((x) & 0xff00) << 8) | (((x) & 0xff) << 24)) -uint32_t s32(uint32_t toSwap, BOOL shouldSwap) -{ - return shouldSwap ? SWAP32(toSwap) : toSwap; -} - -#define CPU_SUBTYPE_ARM64E_NEW_ABI 0x80000002 - -struct CSSuperBlob { - uint32_t magic; - uint32_t length; - uint32_t count; -}; - -struct CSBlob { - uint32_t type; - uint32_t offset; -}; - -#define CS_MAGIC_EMBEDDED_SIGNATURE 0xfade0cc0 -#define CS_MAGIC_EMBEDDED_SIGNATURE_REVERSED 0xc00cdefa -#define CS_MAGIC_EMBEDDED_ENTITLEMENTS 0xfade7171 +#import extern mach_msg_return_t SBReloadIconForIdentifier(mach_port_t machport, const char* identifier); @@ -65,6 +23,27 @@ extern NSString* BKSOpenApplicationOptionKeyActivateForEvent; extern void BKSTerminateApplicationForReasonAndReportWithDescription(NSString *bundleID, int reasonID, bool report, NSString *description); +typedef CF_OPTIONS(uint32_t, SecCSFlags) { + kSecCSDefaultFlags = 0 +}; + + +#define kSecCSRequirementInformation 1 << 2 +#define kSecCSSigningInformation 1 << 1 + +typedef struct __SecCode const *SecStaticCodeRef; + +extern CFStringRef kSecCodeInfoEntitlementsDict; +extern CFStringRef kSecCodeInfoCertificates; +extern CFStringRef kSecPolicyAppleiPhoneApplicationSigning; +extern CFStringRef kSecPolicyAppleiPhoneProfileApplicationSigning; +extern CFStringRef kSecPolicyLeafMarkerOid; + +OSStatus SecStaticCodeCreateWithPathAndAttributes(CFURLRef path, SecCSFlags flags, CFDictionaryRef attributes, SecStaticCodeRef *staticCode); +OSStatus SecCodeCopySigningInformation(SecStaticCodeRef code, SecCSFlags flags, CFDictionaryRef *information); +CFDataRef SecCertificateCopyExtensionValue(SecCertificateRef certificate, CFTypeRef extensionOID, bool *isCritical); +void SecPolicySetOptionsValue(SecPolicyRef policy, CFStringRef key, CFTypeRef value); + #define kCFPreferencesNoContainer CFSTR("kCFPreferencesNoContainer") typedef CFPropertyListRef (*_CFPreferencesCopyValueWithContainerType)(CFStringRef key, CFStringRef applicationID, CFStringRef userName, CFStringRef hostName, CFStringRef containerPath); @@ -221,118 +200,215 @@ int runLdid(NSArray* args, NSString** output, NSString** errorOutput) return WEXITSTATUS(status); } -NSDictionary* dumpEntitlements(NSString* binaryPath) +SecStaticCodeRef getStaticCodeRef(NSString *binaryPath) { - char* entitlementsData = NULL; - uint32_t entitlementsLength = 0; + + if(binaryPath == nil) + { + return NULL; + } + + CFURLRef binaryURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, (__bridge CFStringRef)binaryPath, kCFURLPOSIXPathStyle, false); + if(binaryURL == NULL) + { + NSLog(@"[getStaticCodeRef] failed to get URL to binary %@", binaryPath); + return NULL; + } + + SecStaticCodeRef codeRef = NULL; + OSStatus result; + + result = SecStaticCodeCreateWithPathAndAttributes(binaryURL, kSecCSDefaultFlags, NULL, &codeRef); + + CFRelease(binaryURL); + + if(result != errSecSuccess) + { + NSLog(@"[getStaticCodeRef] failed to create static code for binary %@", binaryPath); + return NULL; + } + + return codeRef; +} - FILE* machoFile = fopen(binaryPath.UTF8String, "rb"); - struct mach_header_universal header; - fread(&header,sizeof(header),1,machoFile); +NSDictionary* dumpEntitlements(SecStaticCodeRef codeRef) +{ + + if(codeRef == NULL) + { + NSLog(@"[dumpEntitlements] attempting to dump entitlements without a StaticCodeRef"); + return nil; + } + + CFDictionaryRef signingInfo = NULL; + OSStatus result; + + result = SecCodeCopySigningInformation(codeRef, kSecCSRequirementInformation, &signingInfo); + + if(result != errSecSuccess) + { + NSLog(@"[dumpEntitlements] failed to copy signing info from static code"); + return nil; + } + + NSDictionary *entitlementsNSDict = nil; + + CFDictionaryRef entitlements = CFDictionaryGetValue(signingInfo, kSecCodeInfoEntitlementsDict); + if(entitlements == NULL) + { + NSLog(@"[dumpEntitlements] no entitlements specified"); + } + else if(CFGetTypeID(entitlements) != CFDictionaryGetTypeID()) + { + NSLog(@"[dumpEntitlements] invalid entitlements"); + } + else + { + entitlementsNSDict = (__bridge NSDictionary *)(entitlements); + NSLog(@"[dumpEntitlements] dumped %@", entitlementsNSDict); + } + + CFRelease(signingInfo); + return entitlementsNSDict; +} - uint32_t archOffset = 0; +NSDictionary* dumpEntitlementsFromBinaryAtPath(NSString *binaryPath) +{ + // This function is intended for one-shot checks. Main-event functions should retain/release their own SecStaticCodeRefs + + if(binaryPath == nil) + { + return nil; + } + + SecStaticCodeRef codeRef = getStaticCodeRef(binaryPath); + if(codeRef == NULL) + { + return nil; + } + + NSDictionary *entitlements = dumpEntitlements(codeRef); + CFRelease(codeRef); + + return entitlements; +} - // Get arch offset if FAT binary - if(header.magic == FAT_MAGIC || header.magic == FAT_CIGAM) - { - fseek(machoFile,0,SEEK_SET); +BOOL certificateHasDataForExtensionOID(SecCertificateRef certificate, CFStringRef oidString) +{ + + if(certificate == NULL || oidString == NULL) + { + NSLog(@"[certificateHasDataForExtensionOID] attempted to check null certificate or OID"); + return NO; + } + + CFDataRef extensionData = SecCertificateCopyExtensionValue(certificate, oidString, NULL); + if(extensionData != NULL) + { + CFRelease(extensionData); + return YES; + } + + return NO; +} - struct fat_header fatHeader; - fread(&fatHeader,sizeof(fatHeader),1,machoFile); +BOOL codeCertChainContainsFakeAppStoreExtensions(SecStaticCodeRef codeRef) +{ + + if(codeRef == NULL) + { + NSLog(@"[codeCertChainContainsFakeAppStoreExtensions] attempted to check cert chain of null static code object"); + return NO; + } + + CFDictionaryRef signingInfo = NULL; + OSStatus result; + + result = SecCodeCopySigningInformation(codeRef, kSecCSSigningInformation, &signingInfo); + + if(result != errSecSuccess) + { + NSLog(@"[codeCertChainContainsFakeAppStoreExtensions] failed to copy signing info from static code"); + return NO; + } + + CFArrayRef certificates = CFDictionaryGetValue(signingInfo, kSecCodeInfoCertificates); - BOOL swpFat = fatHeader.magic == FAT_CIGAM; - - for(int i = 0; i < s32(fatHeader.nfat_arch, swpFat); i++) - { - struct fat_arch fatArch; - fseek(machoFile,sizeof(fatHeader) + sizeof(fatArch) * i,SEEK_SET); - fread(&fatArch,sizeof(fatArch),1,machoFile); - - if(s32(fatArch.cputype, swpFat) != CPU_TYPE_ARM64) - { - continue; - } - - archOffset = s32(fatArch.offset, swpFat); - break; - } - } - - fseek(machoFile,archOffset,SEEK_SET); - fread(&header,sizeof(header),1,machoFile); - - if(header.magic == MH_MAGIC_UNIVERSAL || header.magic == MH_CIGAM_UNIVERSAL) - { - BOOL swp = header.magic == MH_CIGAM_UNIVERSAL; - // This code is cursed, don't stare at it too long or it will stare back at you - uint32_t offset = archOffset + sizeof(header); - for(int c = 0; c < s32(header.ncmds, swp); c++) - { - fseek(machoFile,offset,SEEK_SET); - struct load_command cmd; - fread(&cmd,sizeof(cmd),1,machoFile); - uint32_t normalizedCmd = s32(cmd.cmd,swp); - if(normalizedCmd == LC_CODE_SIGNATURE) - { - struct linkedit_data_command codeSignCommand; - fseek(machoFile,offset,SEEK_SET); - fread(&codeSignCommand,sizeof(codeSignCommand),1,machoFile); - uint32_t codeSignCmdOffset = archOffset + s32(codeSignCommand.dataoff, swp); - fseek(machoFile, codeSignCmdOffset, SEEK_SET); - struct CSSuperBlob superBlob; - fread(&superBlob, sizeof(superBlob), 1, machoFile); - if(SWAP32(superBlob.magic) == CS_MAGIC_EMBEDDED_SIGNATURE) // YES starting here everything is swapped no matter if CIGAM or MAGIC... - { - uint32_t itemCount = SWAP32(superBlob.count); - for(int i = 0; i < itemCount; i++) - { - fseek(machoFile, codeSignCmdOffset + sizeof(superBlob) + i * sizeof(struct CSBlob),SEEK_SET); - struct CSBlob blob; - fread(&blob, sizeof(struct CSBlob), 1, machoFile); - fseek(machoFile, codeSignCmdOffset + SWAP32(blob.offset),SEEK_SET); - uint32_t blobMagic; - fread(&blobMagic, sizeof(uint32_t), 1, machoFile); - if(SWAP32(blobMagic) == CS_MAGIC_EMBEDDED_ENTITLEMENTS) - { - uint32_t entitlementsLengthTmp; - fread(&entitlementsLengthTmp, sizeof(uint32_t), 1, machoFile); - entitlementsLength = SWAP32(entitlementsLengthTmp); - entitlementsData = malloc(entitlementsLength - 8); - fread(&entitlementsData[0], entitlementsLength - 8, 1, machoFile); - break; - } - } - } - - break; - } - - offset += cmd.cmdsize; - } - } - - fclose(machoFile); - - NSData* entitlementsNSData = nil; - - if(entitlementsData) - { - entitlementsNSData = [NSData dataWithBytes:entitlementsData length:entitlementsLength]; - free(entitlementsData); - } - - if(entitlementsNSData) - { - NSDictionary* plist = [NSPropertyListSerialization propertyListWithData:entitlementsNSData options:NSPropertyListImmutable format:nil error:nil]; - NSLog(@"%@ dumped entitlements %@", binaryPath, plist); - return plist; - } - else - { - NSLog(@"Failed to dump entitlements of %@... This is bad", binaryPath); - } - - return nil; + // If we match the standard Apple policy, we are signed properly, but we haven't been deliberately signed with a custom root + + SecPolicyRef appleAppStorePolicy = SecPolicyCreateWithProperties(kSecPolicyAppleiPhoneApplicationSigning, NULL); + + SecTrustRef trust = NULL; + SecTrustCreateWithCertificates(certificates, appleAppStorePolicy, &trust); + + if(SecTrustEvaluateWithError(trust, nil)) + { + CFRelease(trust); + CFRelease(appleAppStorePolicy); + CFRelease(signingInfo); + + NSLog(@"[codeCertChainContainsFakeAppStoreExtensions] found certificate extension, but was issued by Apple (App Store)"); + return NO; + } + + // We haven't matched Apple, so keep going. Is the app profile signed? + + CFRelease(appleAppStorePolicy); + + SecPolicyRef appleProfileSignedPolicy = SecPolicyCreateWithProperties(kSecPolicyAppleiPhoneProfileApplicationSigning, NULL); + if(SecTrustSetPolicies(trust, appleProfileSignedPolicy) != errSecSuccess) + { + NSLog(@"[codeCertChainContainsFakeAppStoreExtensions] error replacing trust policy to check for profile-signed app"); + CFRelease(trust); + CFRelease(signingInfo); + return NO; + } + + if(SecTrustEvaluateWithError(trust, nil)) + { + CFRelease(trust); + CFRelease(appleProfileSignedPolicy); + CFRelease(signingInfo); + + NSLog(@"[codeCertChainContainsFakeAppStoreExtensions] found certificate extension, but was issued by Apple (profile-signed)"); + return NO; + } + + // Still haven't matched Apple. Are we using a custom root that would take the App Store fastpath? + CFRelease(appleProfileSignedPolicy); + + // Cert chain should be of length 3 + if(CFArrayGetCount(certificates) != 3) + { + CFRelease(signingInfo); + + NSLog(@"[codeCertChainContainsFakeAppStoreExtensions] certificate chain length != 3"); + return NO; + } + + // AppleCodeSigning only checks for the codeSigning EKU by default + SecPolicyRef customRootPolicy = SecPolicyCreateWithProperties(kSecPolicyAppleCodeSigning, NULL); + SecPolicySetOptionsValue(customRootPolicy, CFSTR("LeafMarkerOid"), CFSTR("1.2.840.113635.100.6.1.3")); + + if(SecTrustSetPolicies(trust, customRootPolicy) != errSecSuccess) + { + NSLog(@"[codeCertChainContainsFakeAppStoreExtensions] error replacing trust policy to check for custom root"); + CFRelease(trust); + CFRelease(signingInfo); + return NO; + } + + // Need to add our certificate chain to the anchor as it is expected to be a self-signed root + SecTrustSetAnchorCertificates(trust, certificates); + + BOOL evaluatesToCustomAnchor = SecTrustEvaluateWithError(trust, nil); + NSLog(@"[codeCertChainContainsFakeAppStoreExtensions] app signed with non-Apple certificate %@ using valid custom certificates", evaluatesToCustomAnchor ? @"IS" : @"is NOT"); + + CFRelease(trust); + CFRelease(customRootPolicy); + CFRelease(signingInfo); + + return evaluatesToCustomAnchor; } BOOL signApp(NSString* appPath, NSError** error) @@ -346,13 +422,42 @@ BOOL signApp(NSString* appPath, NSError** error) NSString* executablePath = [appPath stringByAppendingPathComponent:executable]; if(![[NSFileManager defaultManager] fileExistsAtPath:executablePath]) return NO; + + NSObject *tsBundleIsPreSigned = appInfoDict[@"TSBundlePreSigned"]; + if([tsBundleIsPreSigned isKindOfClass:[NSNumber class]]) + { + + // if TSBundlePreSigned = YES, this bundle has been externally signed so we can skip over signing it now + NSNumber *tsBundleIsPreSignedNum = (NSNumber *)tsBundleIsPreSigned; + if([tsBundleIsPreSignedNum boolValue] == YES) + { + NSLog(@"[signApp] taking fast path for app which declares it has already been signed (%@)", executablePath); + return YES; + } + } + + SecStaticCodeRef codeRef = getStaticCodeRef(executablePath); + if(codeRef == NULL) + { + NSLog(@"[signApp] failed to get static code, can't derive entitlements from %@", executablePath); + return NO; + } + + if(codeCertChainContainsFakeAppStoreExtensions(codeRef)) + { + NSLog(@"[signApp] taking fast path for app signed using a custom root certificate (%@)", executablePath); + CFRelease(codeRef); + return YES; + } NSString* certPath = [trollStoreAppPath() stringByAppendingPathComponent:@"cert.p12"]; NSString* certArg = [@"-K" stringByAppendingPathComponent:certPath]; NSString* errorOutput; int ldidRet; - NSDictionary* entitlements = dumpEntitlements(executablePath); + NSDictionary* entitlements = dumpEntitlements(codeRef); + CFRelease(codeRef); + if(!entitlements) { NSLog(@"app main binary has no entitlements, signing app with fallback entitlements..."); diff --git a/Helper/uicache.m b/Helper/uicache.m index 85f22e9..6b5aa9a 100644 --- a/Helper/uicache.m +++ b/Helper/uicache.m @@ -6,7 +6,7 @@ // uicache on steroids -extern NSDictionary* dumpEntitlements(NSString* binaryPath); +extern NSDictionary* dumpEntitlementsFromBinaryAtPath(NSString* binaryPath); NSDictionary* constructGroupsContainersForEntitlements(NSDictionary* entitlements, BOOL systemGroups) { @@ -118,7 +118,7 @@ void registerPath(char* cPath, int unregister) // Add entitlements NSString* appExecutablePath = [path stringByAppendingPathComponent:appInfoPlist[@"CFBundleExecutable"]]; - NSDictionary* entitlements = dumpEntitlements(appExecutablePath); + NSDictionary* entitlements = dumpEntitlementsFromBinaryAtPath(appExecutablePath); if(entitlements) { dictToRegister[@"Entitlements"] = entitlements; @@ -188,7 +188,7 @@ void registerPath(char* cPath, int unregister) // Add entitlements NSString* pluginExecutablePath = [pluginPath stringByAppendingPathComponent:pluginInfoPlist[@"CFBundleExecutable"]]; - NSDictionary* pluginEntitlements = dumpEntitlements(pluginExecutablePath); + NSDictionary* pluginEntitlements = dumpEntitlementsFromBinaryAtPath(pluginExecutablePath); if(pluginEntitlements) { pluginDict[@"Entitlements"] = pluginEntitlements; @@ -253,4 +253,4 @@ void registerPath(char* cPath, int unregister) NSLog(@"Error: Unable to unregister %@", path); } } -} \ No newline at end of file +} From 4d2bfbf667a4108484448f43254e6b51575f73db Mon Sep 17 00:00:00 2001 From: opa334 Date: Tue, 6 Sep 2022 01:04:10 +0200 Subject: [PATCH 10/11] 1.0.7 --- Helper/main.m | 47 +++++++++++++------------- PersistenceHelper/Resources/Info.plist | 2 +- PersistenceHelper/control | 2 +- Store/Resources/Info.plist | 2 +- Store/TSApplicationsManager.m | 3 ++ Store/TSSettingsListController.m | 2 +- Store/control | 2 +- 7 files changed, 32 insertions(+), 28 deletions(-) diff --git a/Helper/main.m b/Helper/main.m index 481ad4f..f9c9d8e 100644 --- a/Helper/main.m +++ b/Helper/main.m @@ -202,7 +202,6 @@ int runLdid(NSArray* args, NSString** output, NSString** errorOutput) SecStaticCodeRef getStaticCodeRef(NSString *binaryPath) { - if(binaryPath == nil) { return NULL; @@ -233,7 +232,6 @@ SecStaticCodeRef getStaticCodeRef(NSString *binaryPath) NSDictionary* dumpEntitlements(SecStaticCodeRef codeRef) { - if(codeRef == NULL) { NSLog(@"[dumpEntitlements] attempting to dump entitlements without a StaticCodeRef"); @@ -295,7 +293,6 @@ NSDictionary* dumpEntitlementsFromBinaryAtPath(NSString *binaryPath) BOOL certificateHasDataForExtensionOID(SecCertificateRef certificate, CFStringRef oidString) { - if(certificate == NULL || oidString == NULL) { NSLog(@"[certificateHasDataForExtensionOID] attempted to check null certificate or OID"); @@ -314,7 +311,6 @@ BOOL certificateHasDataForExtensionOID(SecCertificateRef certificate, CFStringRe BOOL codeCertChainContainsFakeAppStoreExtensions(SecStaticCodeRef codeRef) { - if(codeRef == NULL) { NSLog(@"[codeCertChainContainsFakeAppStoreExtensions] attempted to check cert chain of null static code object"); @@ -325,7 +321,7 @@ BOOL codeCertChainContainsFakeAppStoreExtensions(SecStaticCodeRef codeRef) OSStatus result; result = SecCodeCopySigningInformation(codeRef, kSecCSSigningInformation, &signingInfo); - + if(result != errSecSuccess) { NSLog(@"[codeCertChainContainsFakeAppStoreExtensions] failed to copy signing info from static code"); @@ -333,14 +329,18 @@ BOOL codeCertChainContainsFakeAppStoreExtensions(SecStaticCodeRef codeRef) } CFArrayRef certificates = CFDictionaryGetValue(signingInfo, kSecCodeInfoCertificates); + if(certificates == NULL || CFArrayGetCount(certificates) == 0) + { + return NO; + } // If we match the standard Apple policy, we are signed properly, but we haven't been deliberately signed with a custom root SecPolicyRef appleAppStorePolicy = SecPolicyCreateWithProperties(kSecPolicyAppleiPhoneApplicationSigning, NULL); - + SecTrustRef trust = NULL; SecTrustCreateWithCertificates(certificates, appleAppStorePolicy, &trust); - + if(SecTrustEvaluateWithError(trust, nil)) { CFRelease(trust); @@ -350,7 +350,7 @@ BOOL codeCertChainContainsFakeAppStoreExtensions(SecStaticCodeRef codeRef) NSLog(@"[codeCertChainContainsFakeAppStoreExtensions] found certificate extension, but was issued by Apple (App Store)"); return NO; } - + // We haven't matched Apple, so keep going. Is the app profile signed? CFRelease(appleAppStorePolicy); @@ -397,7 +397,7 @@ BOOL codeCertChainContainsFakeAppStoreExtensions(SecStaticCodeRef codeRef) CFRelease(signingInfo); return NO; } - + // Need to add our certificate chain to the anchor as it is expected to be a self-signed root SecTrustSetAnchorCertificates(trust, certificates); @@ -413,8 +413,6 @@ BOOL codeCertChainContainsFakeAppStoreExtensions(SecStaticCodeRef codeRef) BOOL signApp(NSString* appPath, NSError** error) { - if(!isLdidInstalled()) return NO; - NSDictionary* appInfoDict = [NSDictionary dictionaryWithContentsOfFile:[appPath stringByAppendingPathComponent:@"Info.plist"]]; if(!appInfoDict) return NO; @@ -437,18 +435,21 @@ BOOL signApp(NSString* appPath, NSError** error) } SecStaticCodeRef codeRef = getStaticCodeRef(executablePath); - if(codeRef == NULL) + if(codeRef != NULL) { - NSLog(@"[signApp] failed to get static code, can't derive entitlements from %@", executablePath); - return NO; - } - - if(codeCertChainContainsFakeAppStoreExtensions(codeRef)) - { - NSLog(@"[signApp] taking fast path for app signed using a custom root certificate (%@)", executablePath); - CFRelease(codeRef); - return YES; + if(codeCertChainContainsFakeAppStoreExtensions(codeRef)) + { + NSLog(@"[signApp] taking fast path for app signed using a custom root certificate (%@)", executablePath); + CFRelease(codeRef); + return YES; + } } + else + { + NSLog(@"[signApp] failed to get static code, can't derive entitlements from %@, continuing anways...", executablePath); + } + + if(!isLdidInstalled()) return NO; NSString* certPath = [trollStoreAppPath() stringByAppendingPathComponent:@"cert.p12"]; NSString* certArg = [@"-K" stringByAppendingPathComponent:certPath]; @@ -499,6 +500,7 @@ void applyPatchesToInfoDictionary(NSString* appPath) // 170: failed to create container for app bundle // 171: a non trollstore app with the same identifier is already installled // 172: no info.plist found in app +// 173: app is not signed and cannot be signed because ldid not installed or didn't work int installApp(NSString* appPath, BOOL sign, BOOL force, NSError** error) { NSLog(@"[installApp force = %d]", force); @@ -510,8 +512,7 @@ int installApp(NSString* appPath, BOOL sign, BOOL force, NSError** error) if(sign) { - // if it fails to sign, we don't care - signApp(appPath, error); + if(!signApp(appPath, error)) return 173; } BOOL existed; diff --git a/PersistenceHelper/Resources/Info.plist b/PersistenceHelper/Resources/Info.plist index 4953dbf..15e42bc 100644 --- a/PersistenceHelper/Resources/Info.plist +++ b/PersistenceHelper/Resources/Info.plist @@ -52,7 +52,7 @@ iPhoneOS CFBundleVersion - 1.0.6 + 1.0.7 LSRequiresIPhoneOS UIDeviceFamily diff --git a/PersistenceHelper/control b/PersistenceHelper/control index f7a86f8..eb49441 100644 --- a/PersistenceHelper/control +++ b/PersistenceHelper/control @@ -1,6 +1,6 @@ Package: com.opa334.trollstorehelper Name: TrollStore Helper -Version: 1.0.6 +Version: 1.0.7 Architecture: iphoneos-arm Description: Helper app to install and manage TrollStore! Maintainer: opa334 diff --git a/Store/Resources/Info.plist b/Store/Resources/Info.plist index da5e09f..4ad618f 100644 --- a/Store/Resources/Info.plist +++ b/Store/Resources/Info.plist @@ -50,7 +50,7 @@ iPhoneOS CFBundleVersion - 1.0.6 + 1.0.7 LSRequiresIPhoneOS UIDeviceFamily diff --git a/Store/TSApplicationsManager.m b/Store/TSApplicationsManager.m index 57294c2..328c7f9 100644 --- a/Store/TSApplicationsManager.m +++ b/Store/TSApplicationsManager.m @@ -72,6 +72,9 @@ case 172: errorDescription = @"The app does not seem to contain an Info.plist"; break; + case 173: + errorDescription = @"The app is not signed with a fake CoreTrust certificate and ldid does not seem to be installed. Make sure ldid is installed in the settings tab and try again."; + break; } NSError* error = [NSError errorWithDomain:TrollStoreErrorDomain code:code userInfo:@{NSLocalizedDescriptionKey : errorDescription}]; diff --git a/Store/TSSettingsListController.m b/Store/TSSettingsListController.m index 99a3d83..2885116 100644 --- a/Store/TSSettingsListController.m +++ b/Store/TSSettingsListController.m @@ -192,7 +192,7 @@ } PSSpecifier* otherGroupSpecifier = [PSSpecifier emptyGroupSpecifier]; - [otherGroupSpecifier setProperty:[NSString stringWithFormat:@"TrollStore %@\n\n© 2022 Lars Fröder (opa334)\n\nCredits:\n@LinusHenze: CoreTrust bug\n@zhuowei: CoreTrust bug writeup and cert\n@ProcursusTeam: uicache and ldid build\n@cstar_ow: uicache\n@saurik: ldid", getTrollStoreVersion()] forKey:@"footerText"]; + [otherGroupSpecifier setProperty:[NSString stringWithFormat:@"TrollStore %@\n\n© 2022 Lars Fröder (opa334)\n\nCredits:\n@LinusHenze: CoreTrust bug\n@zhuowei: CoreTrust bug writeup and cert\n@lunotech11: Some contributions\n@ProcursusTeam: uicache and ldid build\n@cstar_ow: uicache\n@saurik: ldid", getTrollStoreVersion()] forKey:@"footerText"]; [_specifiers addObject:otherGroupSpecifier]; // Uninstall TrollStore diff --git a/Store/control b/Store/control index 6b0fccc..c215f6c 100644 --- a/Store/control +++ b/Store/control @@ -1,6 +1,6 @@ Package: com.opa334.trollstore Name: TrollStore -Version: 1.0.6 +Version: 1.0.7 Architecture: iphoneos-arm Description: An awesome application! Maintainer: opa334 From 7d0f525f51e71f31aa3e965534f1793b3611f533 Mon Sep 17 00:00:00 2001 From: opa334 Date: Tue, 6 Sep 2022 01:04:45 +0200 Subject: [PATCH 11/11] Fix intendation --- Helper/main.m | 406 +++++++++++++++++++++++++------------------------- 1 file changed, 203 insertions(+), 203 deletions(-) diff --git a/Helper/main.m b/Helper/main.m index f9c9d8e..6228fa7 100644 --- a/Helper/main.m +++ b/Helper/main.m @@ -24,7 +24,7 @@ extern NSString* BKSOpenApplicationOptionKeyActivateForEvent; extern void BKSTerminateApplicationForReasonAndReportWithDescription(NSString *bundleID, int reasonID, bool report, NSString *description); typedef CF_OPTIONS(uint32_t, SecCSFlags) { - kSecCSDefaultFlags = 0 + kSecCSDefaultFlags = 0 }; @@ -202,213 +202,213 @@ int runLdid(NSArray* args, NSString** output, NSString** errorOutput) SecStaticCodeRef getStaticCodeRef(NSString *binaryPath) { - if(binaryPath == nil) - { - return NULL; - } - - CFURLRef binaryURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, (__bridge CFStringRef)binaryPath, kCFURLPOSIXPathStyle, false); - if(binaryURL == NULL) - { - NSLog(@"[getStaticCodeRef] failed to get URL to binary %@", binaryPath); - return NULL; - } - - SecStaticCodeRef codeRef = NULL; - OSStatus result; - - result = SecStaticCodeCreateWithPathAndAttributes(binaryURL, kSecCSDefaultFlags, NULL, &codeRef); - - CFRelease(binaryURL); - - if(result != errSecSuccess) - { - NSLog(@"[getStaticCodeRef] failed to create static code for binary %@", binaryPath); - return NULL; - } - - return codeRef; + if(binaryPath == nil) + { + return NULL; + } + + CFURLRef binaryURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, (__bridge CFStringRef)binaryPath, kCFURLPOSIXPathStyle, false); + if(binaryURL == NULL) + { + NSLog(@"[getStaticCodeRef] failed to get URL to binary %@", binaryPath); + return NULL; + } + + SecStaticCodeRef codeRef = NULL; + OSStatus result; + + result = SecStaticCodeCreateWithPathAndAttributes(binaryURL, kSecCSDefaultFlags, NULL, &codeRef); + + CFRelease(binaryURL); + + if(result != errSecSuccess) + { + NSLog(@"[getStaticCodeRef] failed to create static code for binary %@", binaryPath); + return NULL; + } + + return codeRef; } NSDictionary* dumpEntitlements(SecStaticCodeRef codeRef) { - if(codeRef == NULL) - { - NSLog(@"[dumpEntitlements] attempting to dump entitlements without a StaticCodeRef"); - return nil; - } - - CFDictionaryRef signingInfo = NULL; - OSStatus result; - - result = SecCodeCopySigningInformation(codeRef, kSecCSRequirementInformation, &signingInfo); - - if(result != errSecSuccess) - { - NSLog(@"[dumpEntitlements] failed to copy signing info from static code"); - return nil; - } - - NSDictionary *entitlementsNSDict = nil; - - CFDictionaryRef entitlements = CFDictionaryGetValue(signingInfo, kSecCodeInfoEntitlementsDict); - if(entitlements == NULL) - { - NSLog(@"[dumpEntitlements] no entitlements specified"); - } - else if(CFGetTypeID(entitlements) != CFDictionaryGetTypeID()) - { - NSLog(@"[dumpEntitlements] invalid entitlements"); - } - else - { - entitlementsNSDict = (__bridge NSDictionary *)(entitlements); - NSLog(@"[dumpEntitlements] dumped %@", entitlementsNSDict); - } - - CFRelease(signingInfo); - return entitlementsNSDict; + if(codeRef == NULL) + { + NSLog(@"[dumpEntitlements] attempting to dump entitlements without a StaticCodeRef"); + return nil; + } + + CFDictionaryRef signingInfo = NULL; + OSStatus result; + + result = SecCodeCopySigningInformation(codeRef, kSecCSRequirementInformation, &signingInfo); + + if(result != errSecSuccess) + { + NSLog(@"[dumpEntitlements] failed to copy signing info from static code"); + return nil; + } + + NSDictionary *entitlementsNSDict = nil; + + CFDictionaryRef entitlements = CFDictionaryGetValue(signingInfo, kSecCodeInfoEntitlementsDict); + if(entitlements == NULL) + { + NSLog(@"[dumpEntitlements] no entitlements specified"); + } + else if(CFGetTypeID(entitlements) != CFDictionaryGetTypeID()) + { + NSLog(@"[dumpEntitlements] invalid entitlements"); + } + else + { + entitlementsNSDict = (__bridge NSDictionary *)(entitlements); + NSLog(@"[dumpEntitlements] dumped %@", entitlementsNSDict); + } + + CFRelease(signingInfo); + return entitlementsNSDict; } NSDictionary* dumpEntitlementsFromBinaryAtPath(NSString *binaryPath) { - // This function is intended for one-shot checks. Main-event functions should retain/release their own SecStaticCodeRefs - - if(binaryPath == nil) - { - return nil; - } - - SecStaticCodeRef codeRef = getStaticCodeRef(binaryPath); - if(codeRef == NULL) - { - return nil; - } - - NSDictionary *entitlements = dumpEntitlements(codeRef); - CFRelease(codeRef); - - return entitlements; + // This function is intended for one-shot checks. Main-event functions should retain/release their own SecStaticCodeRefs + + if(binaryPath == nil) + { + return nil; + } + + SecStaticCodeRef codeRef = getStaticCodeRef(binaryPath); + if(codeRef == NULL) + { + return nil; + } + + NSDictionary *entitlements = dumpEntitlements(codeRef); + CFRelease(codeRef); + + return entitlements; } BOOL certificateHasDataForExtensionOID(SecCertificateRef certificate, CFStringRef oidString) { - if(certificate == NULL || oidString == NULL) - { - NSLog(@"[certificateHasDataForExtensionOID] attempted to check null certificate or OID"); - return NO; - } - - CFDataRef extensionData = SecCertificateCopyExtensionValue(certificate, oidString, NULL); - if(extensionData != NULL) - { - CFRelease(extensionData); - return YES; - } - - return NO; + if(certificate == NULL || oidString == NULL) + { + NSLog(@"[certificateHasDataForExtensionOID] attempted to check null certificate or OID"); + return NO; + } + + CFDataRef extensionData = SecCertificateCopyExtensionValue(certificate, oidString, NULL); + if(extensionData != NULL) + { + CFRelease(extensionData); + return YES; + } + + return NO; } BOOL codeCertChainContainsFakeAppStoreExtensions(SecStaticCodeRef codeRef) { - if(codeRef == NULL) - { - NSLog(@"[codeCertChainContainsFakeAppStoreExtensions] attempted to check cert chain of null static code object"); - return NO; - } - - CFDictionaryRef signingInfo = NULL; - OSStatus result; + if(codeRef == NULL) + { + NSLog(@"[codeCertChainContainsFakeAppStoreExtensions] attempted to check cert chain of null static code object"); + return NO; + } + + CFDictionaryRef signingInfo = NULL; + OSStatus result; - result = SecCodeCopySigningInformation(codeRef, kSecCSSigningInformation, &signingInfo); + result = SecCodeCopySigningInformation(codeRef, kSecCSSigningInformation, &signingInfo); - if(result != errSecSuccess) - { - NSLog(@"[codeCertChainContainsFakeAppStoreExtensions] failed to copy signing info from static code"); - return NO; - } - - CFArrayRef certificates = CFDictionaryGetValue(signingInfo, kSecCodeInfoCertificates); + if(result != errSecSuccess) + { + NSLog(@"[codeCertChainContainsFakeAppStoreExtensions] failed to copy signing info from static code"); + return NO; + } + + CFArrayRef certificates = CFDictionaryGetValue(signingInfo, kSecCodeInfoCertificates); if(certificates == NULL || CFArrayGetCount(certificates) == 0) { return NO; } - // If we match the standard Apple policy, we are signed properly, but we haven't been deliberately signed with a custom root - - SecPolicyRef appleAppStorePolicy = SecPolicyCreateWithProperties(kSecPolicyAppleiPhoneApplicationSigning, NULL); + // If we match the standard Apple policy, we are signed properly, but we haven't been deliberately signed with a custom root + + SecPolicyRef appleAppStorePolicy = SecPolicyCreateWithProperties(kSecPolicyAppleiPhoneApplicationSigning, NULL); - SecTrustRef trust = NULL; - SecTrustCreateWithCertificates(certificates, appleAppStorePolicy, &trust); + SecTrustRef trust = NULL; + SecTrustCreateWithCertificates(certificates, appleAppStorePolicy, &trust); - if(SecTrustEvaluateWithError(trust, nil)) - { - CFRelease(trust); - CFRelease(appleAppStorePolicy); - CFRelease(signingInfo); - - NSLog(@"[codeCertChainContainsFakeAppStoreExtensions] found certificate extension, but was issued by Apple (App Store)"); - return NO; - } + if(SecTrustEvaluateWithError(trust, nil)) + { + CFRelease(trust); + CFRelease(appleAppStorePolicy); + CFRelease(signingInfo); + + NSLog(@"[codeCertChainContainsFakeAppStoreExtensions] found certificate extension, but was issued by Apple (App Store)"); + return NO; + } - // We haven't matched Apple, so keep going. Is the app profile signed? - - CFRelease(appleAppStorePolicy); - - SecPolicyRef appleProfileSignedPolicy = SecPolicyCreateWithProperties(kSecPolicyAppleiPhoneProfileApplicationSigning, NULL); - if(SecTrustSetPolicies(trust, appleProfileSignedPolicy) != errSecSuccess) - { - NSLog(@"[codeCertChainContainsFakeAppStoreExtensions] error replacing trust policy to check for profile-signed app"); - CFRelease(trust); - CFRelease(signingInfo); - return NO; - } - - if(SecTrustEvaluateWithError(trust, nil)) - { - CFRelease(trust); - CFRelease(appleProfileSignedPolicy); - CFRelease(signingInfo); - - NSLog(@"[codeCertChainContainsFakeAppStoreExtensions] found certificate extension, but was issued by Apple (profile-signed)"); - return NO; - } - - // Still haven't matched Apple. Are we using a custom root that would take the App Store fastpath? - CFRelease(appleProfileSignedPolicy); - - // Cert chain should be of length 3 - if(CFArrayGetCount(certificates) != 3) - { - CFRelease(signingInfo); - - NSLog(@"[codeCertChainContainsFakeAppStoreExtensions] certificate chain length != 3"); - return NO; - } - - // AppleCodeSigning only checks for the codeSigning EKU by default - SecPolicyRef customRootPolicy = SecPolicyCreateWithProperties(kSecPolicyAppleCodeSigning, NULL); - SecPolicySetOptionsValue(customRootPolicy, CFSTR("LeafMarkerOid"), CFSTR("1.2.840.113635.100.6.1.3")); - - if(SecTrustSetPolicies(trust, customRootPolicy) != errSecSuccess) - { - NSLog(@"[codeCertChainContainsFakeAppStoreExtensions] error replacing trust policy to check for custom root"); - CFRelease(trust); - CFRelease(signingInfo); - return NO; - } + // We haven't matched Apple, so keep going. Is the app profile signed? + + CFRelease(appleAppStorePolicy); + + SecPolicyRef appleProfileSignedPolicy = SecPolicyCreateWithProperties(kSecPolicyAppleiPhoneProfileApplicationSigning, NULL); + if(SecTrustSetPolicies(trust, appleProfileSignedPolicy) != errSecSuccess) + { + NSLog(@"[codeCertChainContainsFakeAppStoreExtensions] error replacing trust policy to check for profile-signed app"); + CFRelease(trust); + CFRelease(signingInfo); + return NO; + } + + if(SecTrustEvaluateWithError(trust, nil)) + { + CFRelease(trust); + CFRelease(appleProfileSignedPolicy); + CFRelease(signingInfo); + + NSLog(@"[codeCertChainContainsFakeAppStoreExtensions] found certificate extension, but was issued by Apple (profile-signed)"); + return NO; + } + + // Still haven't matched Apple. Are we using a custom root that would take the App Store fastpath? + CFRelease(appleProfileSignedPolicy); + + // Cert chain should be of length 3 + if(CFArrayGetCount(certificates) != 3) + { + CFRelease(signingInfo); + + NSLog(@"[codeCertChainContainsFakeAppStoreExtensions] certificate chain length != 3"); + return NO; + } + + // AppleCodeSigning only checks for the codeSigning EKU by default + SecPolicyRef customRootPolicy = SecPolicyCreateWithProperties(kSecPolicyAppleCodeSigning, NULL); + SecPolicySetOptionsValue(customRootPolicy, CFSTR("LeafMarkerOid"), CFSTR("1.2.840.113635.100.6.1.3")); + + if(SecTrustSetPolicies(trust, customRootPolicy) != errSecSuccess) + { + NSLog(@"[codeCertChainContainsFakeAppStoreExtensions] error replacing trust policy to check for custom root"); + CFRelease(trust); + CFRelease(signingInfo); + return NO; + } - // Need to add our certificate chain to the anchor as it is expected to be a self-signed root - SecTrustSetAnchorCertificates(trust, certificates); - - BOOL evaluatesToCustomAnchor = SecTrustEvaluateWithError(trust, nil); - NSLog(@"[codeCertChainContainsFakeAppStoreExtensions] app signed with non-Apple certificate %@ using valid custom certificates", evaluatesToCustomAnchor ? @"IS" : @"is NOT"); - - CFRelease(trust); - CFRelease(customRootPolicy); - CFRelease(signingInfo); - - return evaluatesToCustomAnchor; + // Need to add our certificate chain to the anchor as it is expected to be a self-signed root + SecTrustSetAnchorCertificates(trust, certificates); + + BOOL evaluatesToCustomAnchor = SecTrustEvaluateWithError(trust, nil); + NSLog(@"[codeCertChainContainsFakeAppStoreExtensions] app signed with non-Apple certificate %@ using valid custom certificates", evaluatesToCustomAnchor ? @"IS" : @"is NOT"); + + CFRelease(trust); + CFRelease(customRootPolicy); + CFRelease(signingInfo); + + return evaluatesToCustomAnchor; } BOOL signApp(NSString* appPath, NSError** error) @@ -420,33 +420,33 @@ BOOL signApp(NSString* appPath, NSError** error) NSString* executablePath = [appPath stringByAppendingPathComponent:executable]; if(![[NSFileManager defaultManager] fileExistsAtPath:executablePath]) return NO; - - NSObject *tsBundleIsPreSigned = appInfoDict[@"TSBundlePreSigned"]; - if([tsBundleIsPreSigned isKindOfClass:[NSNumber class]]) - { - - // if TSBundlePreSigned = YES, this bundle has been externally signed so we can skip over signing it now - NSNumber *tsBundleIsPreSignedNum = (NSNumber *)tsBundleIsPreSigned; - if([tsBundleIsPreSignedNum boolValue] == YES) - { - NSLog(@"[signApp] taking fast path for app which declares it has already been signed (%@)", executablePath); - return YES; - } - } - - SecStaticCodeRef codeRef = getStaticCodeRef(executablePath); - if(codeRef != NULL) - { + + NSObject *tsBundleIsPreSigned = appInfoDict[@"TSBundlePreSigned"]; + if([tsBundleIsPreSigned isKindOfClass:[NSNumber class]]) + { + + // if TSBundlePreSigned = YES, this bundle has been externally signed so we can skip over signing it now + NSNumber *tsBundleIsPreSignedNum = (NSNumber *)tsBundleIsPreSigned; + if([tsBundleIsPreSignedNum boolValue] == YES) + { + NSLog(@"[signApp] taking fast path for app which declares it has already been signed (%@)", executablePath); + return YES; + } + } + + SecStaticCodeRef codeRef = getStaticCodeRef(executablePath); + if(codeRef != NULL) + { if(codeCertChainContainsFakeAppStoreExtensions(codeRef)) { NSLog(@"[signApp] taking fast path for app signed using a custom root certificate (%@)", executablePath); CFRelease(codeRef); return YES; } - } + } else { - NSLog(@"[signApp] failed to get static code, can't derive entitlements from %@, continuing anways...", executablePath); + NSLog(@"[signApp] failed to get static code, can't derive entitlements from %@, continuing anways...", executablePath); } if(!isLdidInstalled()) return NO; @@ -456,9 +456,9 @@ BOOL signApp(NSString* appPath, NSError** error) NSString* errorOutput; int ldidRet; - NSDictionary* entitlements = dumpEntitlements(codeRef); - CFRelease(codeRef); - + NSDictionary* entitlements = dumpEntitlements(codeRef); + CFRelease(codeRef); + if(!entitlements) { NSLog(@"app main binary has no entitlements, signing app with fallback entitlements...");