diff --git a/Helper/main.m b/Helper/main.m index 924261f..31b0594 100644 --- a/Helper/main.m +++ b/Helper/main.m @@ -8,9 +8,54 @@ #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 + + extern mach_msg_return_t SBReloadIconForIdentifier(mach_port_t machport, const char* identifier); @interface SBSHomeScreenService : NSObject - (void)reloadIcons; @@ -176,38 +221,111 @@ int runLdid(NSArray* args, NSString** output, NSString** errorOutput) return WEXITSTATUS(status); } -NSString* dumpEntitlements(NSString* binaryPath) +NSDictionary* dumpEntitlements(NSString* binaryPath) { - NSString* output; - NSString* errorOutput; + char* entitlementsData = NULL; + uint32_t entitlementsLength = 0; - int ldidRet = runLdid(@[@"-e", binaryPath], &output, &errorOutput); + FILE* machoFile = fopen(binaryPath.UTF8String, "rb"); + struct mach_header_universal header; + fread(&header,sizeof(header),1,machoFile); - NSLog(@"entitlements dump exited with status %d", ldidRet); + if(header.magic == FAT_MAGIC || header.magic == FAT_CIGAM) + { + fseek(machoFile,0,SEEK_SET); + + struct fat_header fatHeader; + fread(&fatHeader,sizeof(fatHeader),1,machoFile); + + 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; + } + + fseek(machoFile,s32(fatArch.offset, swpFat),SEEK_SET); + struct mach_header_universal header; + fread(&header,sizeof(header),1,machoFile); + + 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 = s32(fatArch.offset, swpFat) + 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 = 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++) + { + 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); + } - NSLog(@"- dump error output start -"); - - printMultilineNSString(errorOutput); - - NSLog(@"- dump error output end -"); - - NSLog(@"- dumped entitlements output start -"); - - printMultilineNSString(output); - - NSLog(@"- dumped entitlements output end -"); - - return output; -} - -NSDictionary* dumpEntitlementsDict(NSString* binaryPath) -{ - NSString* entitlementsString = dumpEntitlements(binaryPath); - NSData* plistData = [entitlementsString dataUsingEncoding:NSUTF8StringEncoding]; - NSError *error; - NSPropertyListFormat format; - NSDictionary* plist = [NSPropertyListSerialization propertyListWithData:plistData options:NSPropertyListImmutable format:&format error:&error]; - return plist; + return nil; } BOOL signApp(NSString* appPath, NSError** error) @@ -227,8 +345,8 @@ BOOL signApp(NSString* appPath, NSError** error) NSString* errorOutput; int ldidRet; - NSString* entitlements = dumpEntitlements(executablePath); - if(entitlements.length == 0) + NSDictionary* entitlements = dumpEntitlements(executablePath); + if(!entitlements) { NSLog(@"app main binary has no entitlements, signing app with fallback entitlements..."); // app has no entitlements, sign with fallback entitlements diff --git a/Helper/uicache.m b/Helper/uicache.m index 7199274..1a2f8d9 100644 --- a/Helper/uicache.m +++ b/Helper/uicache.m @@ -6,7 +6,7 @@ // uicache on steroids -extern NSDictionary* dumpEntitlementsDict(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 = dumpEntitlementsDict(appExecutablePath); + NSDictionary* entitlements = dumpEntitlements(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 = dumpEntitlementsDict(pluginExecutablePath); + NSDictionary* pluginEntitlements = dumpEntitlements(pluginExecutablePath); if(pluginEntitlements) { pluginDict[@"Entitlements"] = pluginEntitlements; diff --git a/Installer/TrollInstaller/TrollInstaller/ViewController.m b/Installer/TrollInstaller/TrollInstaller/ViewController.m index c656e6f..9a9303d 100644 --- a/Installer/TrollInstaller/TrollInstaller/ViewController.m +++ b/Installer/TrollInstaller/TrollInstaller/ViewController.m @@ -239,6 +239,8 @@ int writeRemountPrivatePreboot(void) [self updateStatus:@"Done!"]; + NSLog(@"%@", helperOutput); + // Print installed message if(ret == 0) { diff --git a/PersistenceHelper/TSPHRootViewController.m b/PersistenceHelper/TSPHRootViewController.m index bbe5ed5..e08a4e9 100644 --- a/PersistenceHelper/TSPHRootViewController.m +++ b/PersistenceHelper/TSPHRootViewController.m @@ -76,6 +76,19 @@ [refreshAppRegistrationsSpecifier setProperty:@YES forKey:@"enabled"]; refreshAppRegistrationsSpecifier.buttonAction = @selector(refreshAppRegistrations); [_specifiers addObject:refreshAppRegistrationsSpecifier]; + + PSSpecifier* uninstallTrollStoreSpecifier = [PSSpecifier preferenceSpecifierNamed:@"Uninstall TrollStore" + target:self + set:nil + get:nil + detail:nil + cell:PSButtonCell + edit:nil]; + uninstallTrollStoreSpecifier.identifier = @"uninstallTrollStore"; + [uninstallTrollStoreSpecifier setProperty:@YES forKey:@"enabled"]; + [uninstallTrollStoreSpecifier setProperty:NSClassFromString(@"PSDeleteButtonCell") forKey:@"cellClass"]; + uninstallTrollStoreSpecifier.buttonAction = @selector(uninstallTrollStorePressed); + [_specifiers addObject:uninstallTrollStoreSpecifier]; } else { @@ -201,6 +214,22 @@ [downloadTask resume]; } +- (void)uninstallTrollStorePressed +{ + UIAlertController* uninstallWarningAlert = [UIAlertController alertControllerWithTitle:@"Warning" message:@"About to uninstall TrollStore and all of the apps installed by it. Continue?" preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction* cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]; + [uninstallWarningAlert addAction:cancelAction]; + + UIAlertAction* continueAction = [UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action) + { + spawnRoot(helperPath(), @[@"uninstall-trollstore"]); + exit(0); + }]; + [uninstallWarningAlert addAction:continueAction]; + + [self presentViewController:uninstallWarningAlert animated:YES completion:nil]; +} - (void)uninstallPersistenceHelperPressed { diff --git a/_compile/build_full.sh b/_compile/build_full.sh index 2da9433..67ac02d 100755 --- a/_compile/build_full.sh +++ b/_compile/build_full.sh @@ -47,3 +47,19 @@ cd out COPYFILE_DISABLE=1 tar -czvf TrollStore.tar ./TrollStore.app rm -rf ./TrollStore.app cd - + +# Step five: compile installer +xcodebuild -project ../Installer/TrollInstaller/TrollInstaller.xcodeproj -scheme TrollInstaller -destination generic/platform=iOS -archivePath ./out/Installer.xcarchive archive + +if [[ -f "./out/Installer.xcarchive/Products/Applications/TrollInstaller.app/embedded.mobileprovision" ]]; then + rm ./out/Installer.xcarchive/Products/Applications/TrollInstaller.app/embedded.mobileprovision +fi + +ldid -s ./out/Installer.xcarchive/Products/Applications/TrollInstaller.app +mkdir ./out/Payload +mv ./out/Installer.xcarchive/Products/Applications/TrollInstaller.app ./out/Payload/TrollInstaller.app +cd out +zip -vr TrollInstaller.ipa Payload +cd - +rm -rf ./out/Payload +rm -rf ./out/Installer.xcarchive \ No newline at end of file