diff --git a/Exploits/fastPathSign/Makefile b/Exploits/fastPathSign/Makefile index c7ff624..e1a3981 100644 --- a/Exploits/fastPathSign/Makefile +++ b/Exploits/fastPathSign/Makefile @@ -9,4 +9,4 @@ $(TARGET): $(wildcard src/*.m src/*.c) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ clean: - @rm -f $(TARGET) \ No newline at end of file + @rm -f $(TARGET) diff --git a/Exploits/fastPathSign/src/coretrust_bug.c b/Exploits/fastPathSign/src/coretrust_bug.c index 7fbc1c1..5978529 100644 --- a/Exploits/fastPathSign/src/coretrust_bug.c +++ b/Exploits/fastPathSign/src/coretrust_bug.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -122,6 +121,12 @@ int apply_coretrust_bypass(const char *machoPath) { MachO *macho = macho_init_for_writing(machoPath); if (!macho) return -1; + + if (macho_is_encrypted(macho)) { + printf("Error: MachO is encrypted, please use a decrypted app!\n"); + macho_free(macho); + return 2; + } CS_SuperBlob *superblob = macho_read_code_signature(macho); if (!superblob) { @@ -137,8 +142,19 @@ int apply_coretrust_bypass(const char *machoPath) CS_DecodedBlob *mainCodeDirBlob = csd_superblob_find_blob(decodedSuperblob, CSSLOT_CODEDIRECTORY, NULL); CS_DecodedBlob *alternateCodeDirBlob = csd_superblob_find_blob(decodedSuperblob, CSSLOT_ALTERNATE_CODEDIRECTORIES, NULL); + CS_DecodedBlob *entitlementsBlob = csd_superblob_find_blob(decodedSuperblob, CSSLOT_ENTITLEMENTS, NULL); + CS_DecodedBlob *derEntitlementsBlob = csd_superblob_find_blob(decodedSuperblob, CSSLOT_DER_ENTITLEMENTS, NULL); + + if (!entitlementsBlob && !derEntitlementsBlob && macho->machHeader.filetype == MH_EXECUTE) { + printf("Error: Unable to find existing entitlements blobs in executable MachO, please make sure to ad-hoc sign with entitlements before running the bypass.\n"); + csd_blob_free(mainCodeDirBlob); + if (alternateCodeDirBlob) csd_blob_free(alternateCodeDirBlob); + macho_free(macho); + return -1; + } + if (!mainCodeDirBlob) { - printf("Error: Unable to find code directory, make sure the input binary is ad-hoc signed?\n"); + printf("Error: Unable to find code directory, make sure the input binary is ad-hoc signed.\n"); return -1; } diff --git a/Exploits/fastPathSign/src/external/include/choma/CSBlob.h b/Exploits/fastPathSign/src/external/include/choma/CSBlob.h index 5901e84..f779929 100644 --- a/Exploits/fastPathSign/src/external/include/choma/CSBlob.h +++ b/Exploits/fastPathSign/src/external/include/choma/CSBlob.h @@ -12,63 +12,74 @@ // Blob index typedef struct __BlobIndex { - uint32_t type; - uint32_t offset; + uint32_t type; + uint32_t offset; } CS_BlobIndex; // CMS superblob typedef struct __SuperBlob { - uint32_t magic; - uint32_t length; - uint32_t count; - CS_BlobIndex index[]; + uint32_t magic; + uint32_t length; + uint32_t count; + CS_BlobIndex index[]; } CS_SuperBlob; typedef struct __GenericBlob { - uint32_t magic; /* magic number */ - uint32_t length; /* total length of blob */ - char data[]; + uint32_t magic; /* magic number */ + uint32_t length; /* total length of blob */ + char data[]; } CS_GenericBlob; // CMS blob magic types enum { - CSBLOB_REQUIREMENT = 0xfade0c00, - CSBLOB_REQUIREMENTS = 0xfade0c01, - CSBLOB_CODEDIRECTORY = 0xfade0c02, - CSBLOB_EMBEDDED_SIGNATURE = 0xfade0cc0, - CSBLOB_DETACHED_SIGNATURE = 0xfade0cc1, - CSBLOB_ENTITLEMENTS = 0xfade7171, - CSBLOB_DER_ENTITLEMENTS = 0xfade7172, - CSBLOB_SIGNATURE_BLOB = 0xfade0b01 -} CS_BlobType; + CSMAGIC_REQUIREMENT = 0xfade0c00, + CSMAGIC_REQUIREMENTS = 0xfade0c01, + CSMAGIC_CODEDIRECTORY = 0xfade0c02, + CSMAGIC_EMBEDDED_SIGNATURE = 0xfade0cc0, + CSMAGIC_EMBEDDED_SIGNATURE_OLD = 0xfade0b02, + CSMAGIC_EMBEDDED_ENTITLEMENTS = 0xfade7171, + CSMAGIC_EMBEDDED_DER_ENTITLEMENTS = 0xfade7172, + CSMAGIC_DETACHED_SIGNATURE = 0xfade0cc1, + CSMAGIC_BLOBWRAPPER = 0xfade0b01, + CSMAGIC_EMBEDDED_LAUNCH_CONSTRAINT = 0xfade8181, +} CS_BlobMagic; enum { CSSLOT_CODEDIRECTORY = 0, - CSSLOT_INFOSLOT = 1, - CSSLOT_REQUIREMENTS = 2, - CSSLOT_RESOURCEDIR = 3, - CSSLOT_APPLICATION = 4, - CSSLOT_ENTITLEMENTS = 5, + CSSLOT_INFOSLOT = 1, + CSSLOT_REQUIREMENTS = 2, + CSSLOT_RESOURCEDIR = 3, + CSSLOT_APPLICATION = 4, + CSSLOT_ENTITLEMENTS = 5, CSSLOT_DER_ENTITLEMENTS = 7, - CSSLOT_ALTERNATE_CODEDIRECTORIES = 0x1000, - CSSLOT_ALTERNATE_CODEDIRECTORY_MAX = 5, - CSSLOT_ALTERNATE_CODEDIRECTORY_LIMIT = CSSLOT_ALTERNATE_CODEDIRECTORIES + CSSLOT_ALTERNATE_CODEDIRECTORY_MAX, - CSSLOT_SIGNATURESLOT = 0x10000 + CSSLOT_LAUNCH_CONSTRAINT_SELF = 8, + CSSLOT_LAUNCH_CONSTRAINT_PARENT = 9, + CSSLOT_LAUNCH_CONSTRAINT_RESPONSIBLE = 10, + CSSLOT_LIBRARY_CONSTRAINT = 11, + + CSSLOT_ALTERNATE_CODEDIRECTORIES = 0x1000, /* first alternate CodeDirectory, if any */ + CSSLOT_ALTERNATE_CODEDIRECTORY_MAX = 5, /* max number of alternate CD slots */ + CSSLOT_ALTERNATE_CODEDIRECTORY_LIMIT = CSSLOT_ALTERNATE_CODEDIRECTORIES + CSSLOT_ALTERNATE_CODEDIRECTORY_MAX, /* one past the last */ + + CSSLOT_SIGNATURESLOT = 0x10000, + CSSLOT_IDENTIFICATIONSLOT = 0x10001, + CSSLOT_TICKETSLOT = 0x10002, } CS_SlotType; typedef struct s_CS_DecodedBlob { - struct s_CS_DecodedBlob *next; - uint32_t type; - MemoryStream *stream; + struct s_CS_DecodedBlob *next; + uint32_t type; + MemoryStream *stream; } CS_DecodedBlob; typedef struct s_CS_DecodedSuperBlob { - uint32_t magic; - struct s_CS_DecodedBlob *firstBlob; + uint32_t magic; + struct s_CS_DecodedBlob *firstBlob; } CS_DecodedSuperBlob; // Convert blob magic to readable blob type string -char *cs_blob_magic_to_string(int magic); +const char *cs_blob_magic_to_string(uint32_t magic); +const char *cs_slot_type_to_string(uint32_t slotType); // Extract Code Signature to file int macho_extract_cs_to_file(MachO *macho, CS_SuperBlob *superblob); diff --git a/Exploits/fastPathSign/src/external/include/choma/FAT.h b/Exploits/fastPathSign/src/external/include/choma/FAT.h index 22faf05..102133b 100644 --- a/Exploits/fastPathSign/src/external/include/choma/FAT.h +++ b/Exploits/fastPathSign/src/external/include/choma/FAT.h @@ -30,11 +30,16 @@ FAT *fat_init_from_memory_stream(MemoryStream *stream); // Initialise a FAT structure using the path to the file FAT *fat_init_from_path(const char *filePath); -//FAT *fat_init_from_path_for_writing(const char *filePath); // Find macho with cputype and cpusubtype in FAT, returns NULL if not found MachO *fat_find_slice(FAT *fat, cpu_type_t cputype, cpu_subtype_t cpusubtype); +// Create a FAT structure from an array of MachO structures +FAT *fat_create_for_macho_array(char *firstInputPath, MachO **machoArray, int machoArrayCount); + +// Add a MachO to the FAT structure +int fat_add_macho(FAT *fat, MachO *macho); + // Free all elements of the FAT structure void fat_free(FAT *fat); diff --git a/Exploits/fastPathSign/src/external/include/choma/MachO.h b/Exploits/fastPathSign/src/external/include/choma/MachO.h index 5b92923..1b933ba 100644 --- a/Exploits/fastPathSign/src/external/include/choma/MachO.h +++ b/Exploits/fastPathSign/src/external/include/choma/MachO.h @@ -57,6 +57,12 @@ MachO *macho_init(MemoryStream *stream, struct fat_arch_64 archDescriptor); // Initialize a single slice macho for writing to it MachO *macho_init_for_writing(const char *filePath); +// Create an array of MachO objects from an array of paths +MachO **macho_array_create_for_paths(char **inputPaths, int inputPathsCount); + +// Check if a MachO is encrypted +bool macho_is_encrypted(MachO *macho); + void macho_free(MachO *macho); #endif // MACHO_SLICE_H \ No newline at end of file diff --git a/Exploits/fastPathSign/src/external/include/choma/MachOByteOrder.h b/Exploits/fastPathSign/src/external/include/choma/MachOByteOrder.h index 394dba7..f1b0a7b 100644 --- a/Exploits/fastPathSign/src/external/include/choma/MachOByteOrder.h +++ b/Exploits/fastPathSign/src/external/include/choma/MachOByteOrder.h @@ -99,6 +99,13 @@ applier(lc, dataoff); \ applier(lc, datasize); +#define ENCRYPTION_INFO_COMMAND_APPLY_BYTE_ORDER(eic, applier) \ + applier(eic, cmd); \ + applier(eic, cmdsize); \ + applier(eic, cryptoff); \ + applier(eic, cryptsize); \ + applier(eic, cryptid); + #define BLOB_INDEX_APPLY_BYTE_ORDER(bi, applier) \ applier(bi, type); \ applier(bi, offset); diff --git a/Exploits/fastPathSign/src/external/include/choma/PatchFinder.h b/Exploits/fastPathSign/src/external/include/choma/PatchFinder.h index b2ddd60..d15b0f4 100644 --- a/Exploits/fastPathSign/src/external/include/choma/PatchFinder.h +++ b/Exploits/fastPathSign/src/external/include/choma/PatchFinder.h @@ -6,6 +6,7 @@ #define METRIC_TYPE_FUNCTION_XREF 3 typedef struct PFSection { + MachO *macho; uint64_t fileoff; uint64_t vmaddr; uint64_t size; @@ -13,13 +14,16 @@ typedef struct PFSection { bool ownsCache; } PFSection; -PFSection *macho_patchfinder_create_section(MachO *macho, const char *filesetEntryId, const char *segName, const char *sectName); -int macho_patchfinder_cache_section(PFSection *section, MachO *fromMacho); -void macho_patchfinder_section_free(PFSection *section); +PFSection *pf_section_init_from_macho(MachO *macho, const char *filesetEntryId, const char *segName, const char *sectName); +int pf_section_read_at_relative_offset(PFSection *section, uint64_t rel, size_t size, void *outBuf); +int pf_section_read_at_address(PFSection *section, uint64_t vmaddr, void *outBuf, size_t size); +uint32_t pf_section_read32(PFSection *section, uint64_t vmaddr); +int pf_section_set_cached(PFSection *section, bool cached); +void pf_section_free(PFSection *section); + typedef struct MetricShared { uint32_t type; - PFSection *section; } MetricShared; @@ -39,6 +43,5 @@ typedef struct BytePatternMetric { BytePatternAlignment alignment; } BytePatternMetric; -BytePatternMetric *macho_patchfinder_create_byte_pattern_metric(PFSection *section, void *bytes, void *mask, size_t nbytes, BytePatternAlignment alignment); - -void macho_patchfinder_run_metric(MachO *macho, void *metric, void (^matchBlock)(uint64_t vmaddr, bool *stop)); +BytePatternMetric *pf_create_byte_pattern_metric(void *bytes, void *mask, size_t nbytes, BytePatternAlignment alignment); +void pf_section_run_metric(PFSection *section, void *metric, void (^matchBlock)(uint64_t vmaddr, bool *stop)); diff --git a/Exploits/fastPathSign/src/external/include/choma/Signing.h b/Exploits/fastPathSign/src/external/include/choma/Signing.h deleted file mode 100644 index 5a0d670..0000000 --- a/Exploits/fastPathSign/src/external/include/choma/Signing.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef SIGNING_H -#define SIGNING_H - -#include -#include -#include -#include -#include - -// int signWithRSA(const char *certificateFile, const char *inputFile, const char *outputFile); - -#endif // SIGNING_H \ No newline at end of file diff --git a/Exploits/fastPathSign/src/external/include/choma/Util.h b/Exploits/fastPathSign/src/external/include/choma/Util.h index acca0ab..4bbda41 100644 --- a/Exploits/fastPathSign/src/external/include/choma/Util.h +++ b/Exploits/fastPathSign/src/external/include/choma/Util.h @@ -1,6 +1,7 @@ #include #include +int memcmp_masked(const void *str1, const void *str2, unsigned char* mask, size_t n); uint64_t align_to_size(int size, int alignment); int count_digits(int64_t num); void print_hash(uint8_t *hash, size_t size); \ No newline at end of file diff --git a/Exploits/fastPathSign/src/external/lib/libchoma.a b/Exploits/fastPathSign/src/external/lib/libchoma.a index e71ff9b..e69e186 100644 Binary files a/Exploits/fastPathSign/src/external/lib/libchoma.a and b/Exploits/fastPathSign/src/external/lib/libchoma.a differ diff --git a/Exploits/fastPathSign/src/main.m b/Exploits/fastPathSign/src/main.m index 2cdb251..269e99b 100644 --- a/Exploits/fastPathSign/src/main.m +++ b/Exploits/fastPathSign/src/main.m @@ -11,7 +11,30 @@ char *extract_preferred_slice(const char *fatPath) FAT *fat = fat_init_from_path(fatPath); if (!fat) return NULL; MachO *macho = fat_find_preferred_slice(fat); - if (!macho) return NULL; + +#if TARGET_OS_MAC && !TARGET_OS_IPHONE + if (!macho) { + // Check for arm64v8 first + macho = fat_find_slice(fat, CPU_TYPE_ARM64, CPU_SUBTYPE_ARM64_V8); + if (!macho) { + // If that fails, check for regular arm64 + macho = fat_find_slice(fat, CPU_TYPE_ARM64, CPU_SUBTYPE_ARM64_ALL); + if (!macho) { + // If that fails, check for arm64e + macho = fat_find_slice(fat, CPU_TYPE_ARM64, CPU_SUBTYPE_ARM64E); + if (!macho) { + fat_free(fat); + return NULL; + } + } + } + } +#else + if (!macho) { + fat_free(fat); + return NULL; + } +#endif // TARGET_OS_MAC && !TARGET_OS_IPHONE char *temp = strdup("/tmp/XXXXXX"); int fd = mkstemp(temp); @@ -26,30 +49,6 @@ char *extract_preferred_slice(const char *fatPath) return temp; } -int apply_coretrust_bypass_wrapper(const char *inputPath, const char *outputPath) -{ - char *machoPath = extract_preferred_slice(inputPath); - printf("extracted best slice to %s\n", machoPath); - - int r = apply_coretrust_bypass(machoPath); - if (r != 0) { - free(machoPath); - return r; - } - - r = copyfile(machoPath, outputPath, 0, COPYFILE_ALL | COPYFILE_MOVE | COPYFILE_UNLINK); - if (r == 0) { - chmod(outputPath, 0755); - printf("Signed file! CoreTrust bypass eta now!!\n"); - } - else { - perror("copyfile"); - } - - free(machoPath); - return r; -} - int main(int argc, char *argv[]) { if (argc < 2) return -1; @@ -77,9 +76,11 @@ int main(int argc, char *argv[]) { printf("Applying CoreTrust bypass...\n"); - if (apply_coretrust_bypass(machoPath) != 0) { + r = apply_coretrust_bypass(machoPath); + + if (r != 0) { printf("Failed applying CoreTrust bypass\n"); - return -1; + return r; } if (copyfile(machoPath, input, 0, COPYFILE_ALL | COPYFILE_MOVE | COPYFILE_UNLINK) == 0) { diff --git a/README.md b/README.md index 45f6f10..227e436 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ TrollStore is a permasigned jailed app that can permanently install any IPA you open in it. -It works because of an AMFI/CoreTrust bug where iOS does not verify whether or not a root certificate used to sign a binary is legit. +It works because of an AMFI/CoreTrust bug where iOS does not correctly verify code signatures of binaries in which there are multiple signers. Supported versions: 14.0 - 16.6.1, 17.0 @@ -100,7 +100,7 @@ When your app is not sandboxed, you can spawn other binaries using posix_spawn, You can also add your own binaries into your app bundle. -Afterwards you can use the [spawnRoot function in TSUtil.m](./Shared/TSUtil.m#L77) to spawn the binary as root. +Afterwards you can use the [spawnRoot function in TSUtil.m](./Shared/TSUtil.m#L79) to spawn the binary as root. ### Things that are not possible using TrollStore @@ -110,8 +110,12 @@ Afterwards you can use the [spawnRoot function in TSUtil.m](./Shared/TSUtil.m#L7 ## Credits and Further Reading -[@LinusHenze](https://twitter.com/LinusHenze/) - Found the CoreTrust bug that allows TrollStore to work. +[@alfiecg_dev](https://twitter.com/alfiecg_dev/) - Found the CoreTrust bug that allows TrollStore to work through patchdiffing and worked on automating the bypass. + +Google Threat Analysis Group - Found the CoreTrust bug as part of an in-the-wild spyware chain and reported it to Apple. + +[@LinusHenze](https://twitter.com/LinusHenze) - Found the installd bypass used to install TrollStore on iOS 14-15.6.1 via TrollHelperOTA, as well as the original CoreTrust bug used in TrollStore 1.0. [Fugu15 Presentation](https://youtu.be/rPTifU1lG7Q) -[Write-Up on the CoreTrust bug with more information](https://worthdoingbadly.com/coretrust/). +[Write-Up on the first CoreTrust bug with more information](https://worthdoingbadly.com/coretrust/). diff --git a/RootHelper/external/include/choma/CSBlob.h b/RootHelper/external/include/choma/CSBlob.h index 5901e84..f779929 100644 --- a/RootHelper/external/include/choma/CSBlob.h +++ b/RootHelper/external/include/choma/CSBlob.h @@ -12,63 +12,74 @@ // Blob index typedef struct __BlobIndex { - uint32_t type; - uint32_t offset; + uint32_t type; + uint32_t offset; } CS_BlobIndex; // CMS superblob typedef struct __SuperBlob { - uint32_t magic; - uint32_t length; - uint32_t count; - CS_BlobIndex index[]; + uint32_t magic; + uint32_t length; + uint32_t count; + CS_BlobIndex index[]; } CS_SuperBlob; typedef struct __GenericBlob { - uint32_t magic; /* magic number */ - uint32_t length; /* total length of blob */ - char data[]; + uint32_t magic; /* magic number */ + uint32_t length; /* total length of blob */ + char data[]; } CS_GenericBlob; // CMS blob magic types enum { - CSBLOB_REQUIREMENT = 0xfade0c00, - CSBLOB_REQUIREMENTS = 0xfade0c01, - CSBLOB_CODEDIRECTORY = 0xfade0c02, - CSBLOB_EMBEDDED_SIGNATURE = 0xfade0cc0, - CSBLOB_DETACHED_SIGNATURE = 0xfade0cc1, - CSBLOB_ENTITLEMENTS = 0xfade7171, - CSBLOB_DER_ENTITLEMENTS = 0xfade7172, - CSBLOB_SIGNATURE_BLOB = 0xfade0b01 -} CS_BlobType; + CSMAGIC_REQUIREMENT = 0xfade0c00, + CSMAGIC_REQUIREMENTS = 0xfade0c01, + CSMAGIC_CODEDIRECTORY = 0xfade0c02, + CSMAGIC_EMBEDDED_SIGNATURE = 0xfade0cc0, + CSMAGIC_EMBEDDED_SIGNATURE_OLD = 0xfade0b02, + CSMAGIC_EMBEDDED_ENTITLEMENTS = 0xfade7171, + CSMAGIC_EMBEDDED_DER_ENTITLEMENTS = 0xfade7172, + CSMAGIC_DETACHED_SIGNATURE = 0xfade0cc1, + CSMAGIC_BLOBWRAPPER = 0xfade0b01, + CSMAGIC_EMBEDDED_LAUNCH_CONSTRAINT = 0xfade8181, +} CS_BlobMagic; enum { CSSLOT_CODEDIRECTORY = 0, - CSSLOT_INFOSLOT = 1, - CSSLOT_REQUIREMENTS = 2, - CSSLOT_RESOURCEDIR = 3, - CSSLOT_APPLICATION = 4, - CSSLOT_ENTITLEMENTS = 5, + CSSLOT_INFOSLOT = 1, + CSSLOT_REQUIREMENTS = 2, + CSSLOT_RESOURCEDIR = 3, + CSSLOT_APPLICATION = 4, + CSSLOT_ENTITLEMENTS = 5, CSSLOT_DER_ENTITLEMENTS = 7, - CSSLOT_ALTERNATE_CODEDIRECTORIES = 0x1000, - CSSLOT_ALTERNATE_CODEDIRECTORY_MAX = 5, - CSSLOT_ALTERNATE_CODEDIRECTORY_LIMIT = CSSLOT_ALTERNATE_CODEDIRECTORIES + CSSLOT_ALTERNATE_CODEDIRECTORY_MAX, - CSSLOT_SIGNATURESLOT = 0x10000 + CSSLOT_LAUNCH_CONSTRAINT_SELF = 8, + CSSLOT_LAUNCH_CONSTRAINT_PARENT = 9, + CSSLOT_LAUNCH_CONSTRAINT_RESPONSIBLE = 10, + CSSLOT_LIBRARY_CONSTRAINT = 11, + + CSSLOT_ALTERNATE_CODEDIRECTORIES = 0x1000, /* first alternate CodeDirectory, if any */ + CSSLOT_ALTERNATE_CODEDIRECTORY_MAX = 5, /* max number of alternate CD slots */ + CSSLOT_ALTERNATE_CODEDIRECTORY_LIMIT = CSSLOT_ALTERNATE_CODEDIRECTORIES + CSSLOT_ALTERNATE_CODEDIRECTORY_MAX, /* one past the last */ + + CSSLOT_SIGNATURESLOT = 0x10000, + CSSLOT_IDENTIFICATIONSLOT = 0x10001, + CSSLOT_TICKETSLOT = 0x10002, } CS_SlotType; typedef struct s_CS_DecodedBlob { - struct s_CS_DecodedBlob *next; - uint32_t type; - MemoryStream *stream; + struct s_CS_DecodedBlob *next; + uint32_t type; + MemoryStream *stream; } CS_DecodedBlob; typedef struct s_CS_DecodedSuperBlob { - uint32_t magic; - struct s_CS_DecodedBlob *firstBlob; + uint32_t magic; + struct s_CS_DecodedBlob *firstBlob; } CS_DecodedSuperBlob; // Convert blob magic to readable blob type string -char *cs_blob_magic_to_string(int magic); +const char *cs_blob_magic_to_string(uint32_t magic); +const char *cs_slot_type_to_string(uint32_t slotType); // Extract Code Signature to file int macho_extract_cs_to_file(MachO *macho, CS_SuperBlob *superblob); diff --git a/RootHelper/external/include/choma/FAT.h b/RootHelper/external/include/choma/FAT.h index 22faf05..102133b 100644 --- a/RootHelper/external/include/choma/FAT.h +++ b/RootHelper/external/include/choma/FAT.h @@ -30,11 +30,16 @@ FAT *fat_init_from_memory_stream(MemoryStream *stream); // Initialise a FAT structure using the path to the file FAT *fat_init_from_path(const char *filePath); -//FAT *fat_init_from_path_for_writing(const char *filePath); // Find macho with cputype and cpusubtype in FAT, returns NULL if not found MachO *fat_find_slice(FAT *fat, cpu_type_t cputype, cpu_subtype_t cpusubtype); +// Create a FAT structure from an array of MachO structures +FAT *fat_create_for_macho_array(char *firstInputPath, MachO **machoArray, int machoArrayCount); + +// Add a MachO to the FAT structure +int fat_add_macho(FAT *fat, MachO *macho); + // Free all elements of the FAT structure void fat_free(FAT *fat); diff --git a/RootHelper/external/include/choma/MachO.h b/RootHelper/external/include/choma/MachO.h index 5b92923..1b933ba 100644 --- a/RootHelper/external/include/choma/MachO.h +++ b/RootHelper/external/include/choma/MachO.h @@ -57,6 +57,12 @@ MachO *macho_init(MemoryStream *stream, struct fat_arch_64 archDescriptor); // Initialize a single slice macho for writing to it MachO *macho_init_for_writing(const char *filePath); +// Create an array of MachO objects from an array of paths +MachO **macho_array_create_for_paths(char **inputPaths, int inputPathsCount); + +// Check if a MachO is encrypted +bool macho_is_encrypted(MachO *macho); + void macho_free(MachO *macho); #endif // MACHO_SLICE_H \ No newline at end of file diff --git a/RootHelper/external/include/choma/MachOByteOrder.h b/RootHelper/external/include/choma/MachOByteOrder.h index 394dba7..f1b0a7b 100644 --- a/RootHelper/external/include/choma/MachOByteOrder.h +++ b/RootHelper/external/include/choma/MachOByteOrder.h @@ -99,6 +99,13 @@ applier(lc, dataoff); \ applier(lc, datasize); +#define ENCRYPTION_INFO_COMMAND_APPLY_BYTE_ORDER(eic, applier) \ + applier(eic, cmd); \ + applier(eic, cmdsize); \ + applier(eic, cryptoff); \ + applier(eic, cryptsize); \ + applier(eic, cryptid); + #define BLOB_INDEX_APPLY_BYTE_ORDER(bi, applier) \ applier(bi, type); \ applier(bi, offset); diff --git a/RootHelper/external/include/choma/PatchFinder.h b/RootHelper/external/include/choma/PatchFinder.h index b2ddd60..d15b0f4 100644 --- a/RootHelper/external/include/choma/PatchFinder.h +++ b/RootHelper/external/include/choma/PatchFinder.h @@ -6,6 +6,7 @@ #define METRIC_TYPE_FUNCTION_XREF 3 typedef struct PFSection { + MachO *macho; uint64_t fileoff; uint64_t vmaddr; uint64_t size; @@ -13,13 +14,16 @@ typedef struct PFSection { bool ownsCache; } PFSection; -PFSection *macho_patchfinder_create_section(MachO *macho, const char *filesetEntryId, const char *segName, const char *sectName); -int macho_patchfinder_cache_section(PFSection *section, MachO *fromMacho); -void macho_patchfinder_section_free(PFSection *section); +PFSection *pf_section_init_from_macho(MachO *macho, const char *filesetEntryId, const char *segName, const char *sectName); +int pf_section_read_at_relative_offset(PFSection *section, uint64_t rel, size_t size, void *outBuf); +int pf_section_read_at_address(PFSection *section, uint64_t vmaddr, void *outBuf, size_t size); +uint32_t pf_section_read32(PFSection *section, uint64_t vmaddr); +int pf_section_set_cached(PFSection *section, bool cached); +void pf_section_free(PFSection *section); + typedef struct MetricShared { uint32_t type; - PFSection *section; } MetricShared; @@ -39,6 +43,5 @@ typedef struct BytePatternMetric { BytePatternAlignment alignment; } BytePatternMetric; -BytePatternMetric *macho_patchfinder_create_byte_pattern_metric(PFSection *section, void *bytes, void *mask, size_t nbytes, BytePatternAlignment alignment); - -void macho_patchfinder_run_metric(MachO *macho, void *metric, void (^matchBlock)(uint64_t vmaddr, bool *stop)); +BytePatternMetric *pf_create_byte_pattern_metric(void *bytes, void *mask, size_t nbytes, BytePatternAlignment alignment); +void pf_section_run_metric(PFSection *section, void *metric, void (^matchBlock)(uint64_t vmaddr, bool *stop)); diff --git a/RootHelper/external/include/choma/Signing.h b/RootHelper/external/include/choma/Signing.h deleted file mode 100644 index 5a0d670..0000000 --- a/RootHelper/external/include/choma/Signing.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef SIGNING_H -#define SIGNING_H - -#include -#include -#include -#include -#include - -// int signWithRSA(const char *certificateFile, const char *inputFile, const char *outputFile); - -#endif // SIGNING_H \ No newline at end of file diff --git a/RootHelper/external/include/choma/Util.h b/RootHelper/external/include/choma/Util.h index acca0ab..4bbda41 100644 --- a/RootHelper/external/include/choma/Util.h +++ b/RootHelper/external/include/choma/Util.h @@ -1,6 +1,7 @@ #include #include +int memcmp_masked(const void *str1, const void *str2, unsigned char* mask, size_t n); uint64_t align_to_size(int size, int alignment); int count_digits(int64_t num); void print_hash(uint8_t *hash, size_t size); \ No newline at end of file diff --git a/RootHelper/external/lib/libchoma.a b/RootHelper/external/lib/libchoma.a index 0b3c84b..99c1d46 100644 Binary files a/RootHelper/external/lib/libchoma.a and b/RootHelper/external/lib/libchoma.a differ diff --git a/RootHelper/main.m b/RootHelper/main.m index c178ce9..7e339af 100644 --- a/RootHelper/main.m +++ b/RootHelper/main.m @@ -691,6 +691,11 @@ int signApp(NSString* appPath) if (r == 0) { NSLog(@"[%@] Applied CoreTrust bypass!", filePath); } + else if (r == 2) { + NSLog(@"[%@] Cannot apply CoreTrust bypass on an encrypted binary!", filePath); + fat_free(fat); + return 180; + } else { NSLog(@"[%@] CoreTrust bypass failed!!! :(", filePath); fat_free(fat); @@ -708,7 +713,7 @@ int signApp(NSString* appPath) if (requiresDevMode) { // Postpone trying to enable dev mode until after the app is (successfully) installed - return 180; + return 182; } return 0; @@ -770,6 +775,7 @@ void applyPatchesToInfoDictionary(NSString* appPath) // 172: no info.plist found in app // 173: app is not signed and cannot be signed because ldid not installed or didn't work // 174: +// 180: tried to sign encrypted binary int installApp(NSString* appPackagePath, BOOL sign, BOOL force, BOOL isTSUpdate, BOOL useInstalldMethod) { NSLog(@"[installApp force = %d]", force); @@ -799,9 +805,9 @@ int installApp(NSString* appPackagePath, BOOL sign, BOOL force, BOOL isTSUpdate, if(sign) { int signRet = signApp(appBundleToInstallPath); - // 180: app requires developer mode; non-fatal + // 182: app requires developer mode; non-fatal if(signRet != 0) { - if (signRet == 180) { + if (signRet == 182) { requiresDevMode = YES; } else { return signRet; @@ -948,7 +954,10 @@ int installApp(NSString* appPackagePath, BOOL sign, BOOL force, BOOL isTSUpdate, // Also permissions need to be fixed NSURL* updatedAppURL = findAppURLInBundleURL(appContainer.url); fixPermissionsOfAppBundle(updatedAppURL.path); - registerPath(updatedAppURL.path, 0, YES); + if (!registerPath(updatedAppURL.path, 0, YES)) { + [[NSFileManager defaultManager] removeItemAtURL:appContainer.url error:nil]; + return 181; + } // Handle developer mode after installing and registering the app, to ensure that we // don't arm developer mode but then fail to install the app @@ -958,12 +967,12 @@ int installApp(NSString* appPackagePath, BOOL sign, BOOL force, BOOL isTSUpdate, if (!alreadyEnabled) { NSLog(@"[installApp] app requires developer mode and we have successfully armed it"); // non-fatal - return 180; + return 182; } } else { NSLog(@"[installApp] failed to arm developer mode"); // fatal - return 181; + return 183; } } return 0; @@ -1070,6 +1079,7 @@ int uninstallAppById(NSString* appId, BOOL useCustomMethod) // 166: IPA does not exist or is not accessible // 167: IPA does not appear to contain an app +// 180: IPA contains an encrypted binary int installIpa(NSString* ipaPath, BOOL force, BOOL useInstalldMethod) { cleanRestrictions(); diff --git a/RootHelper/uicache.h b/RootHelper/uicache.h index cc1591b..3e18d32 100644 --- a/RootHelper/uicache.h +++ b/RootHelper/uicache.h @@ -1 +1 @@ -extern void registerPath(NSString* path, BOOL unregister, BOOL system); \ No newline at end of file +extern bool registerPath(NSString *path, BOOL unregister, BOOL forceSystem); \ No newline at end of file diff --git a/RootHelper/uicache.m b/RootHelper/uicache.m index 5aa3338..05d2ef3 100644 --- a/RootHelper/uicache.m +++ b/RootHelper/uicache.m @@ -81,8 +81,8 @@ NSDictionary *constructEnvironmentVariablesForContainerPath(NSString *containerP }; } -void registerPath(NSString *path, BOOL unregister, BOOL forceSystem) { - if (!path) return; +bool registerPath(NSString *path, BOOL unregister, BOOL forceSystem) { + if (!path) return false; LSApplicationWorkspace *workspace = [LSApplicationWorkspace defaultWorkspace]; if (unregister && ![[NSFileManager defaultManager] fileExistsAtPath:path]) { @@ -97,7 +97,7 @@ void registerPath(NSString *path, BOOL unregister, BOOL forceSystem) { NSDictionary *appInfoPlist = [NSDictionary dictionaryWithContentsOfFile:[path stringByAppendingPathComponent:@"Info.plist"]]; NSString *appBundleID = [appInfoPlist objectForKey:@"CFBundleIdentifier"]; - if([immutableAppBundleIdentifiers() containsObject:appBundleID.lowercaseString]) return; + if([immutableAppBundleIdentifiers() containsObject:appBundleID.lowercaseString]) return false; if (appBundleID && !unregister) { NSString *appExecutablePath = [path stringByAppendingPathComponent:appInfoPlist[@"CFBundleExecutable"]]; @@ -236,11 +236,19 @@ void registerPath(NSString *path, BOOL unregister, BOOL forceSystem) { if (![workspace registerApplicationDictionary:dictToRegister]) { NSLog(@"Error: Unable to register %@", path); + NSLog(@"Used dictionary: {"); + [dictToRegister enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSObject *obj, BOOL *stop) { + NSLog(@"%@ = %@", key, obj); + }]; + NSLog(@"}"); + return false; } } else { NSURL *url = [NSURL fileURLWithPath:path]; if (![workspace unregisterApplication:url]) { NSLog(@"Error: Unable to register %@", path); + return false; } } + return true; } diff --git a/TrollStore/TSApplicationsManager.m b/TrollStore/TSApplicationsManager.m index 5ce2010..d6a0195 100644 --- a/TrollStore/TSApplicationsManager.m +++ b/TrollStore/TSApplicationsManager.m @@ -75,9 +75,15 @@ extern NSUserDefaults* trollStoreUserDefaults(); errorDescription = @"The app you tried to install has the same identifier as a system app already installed on the device. The installation has been prevented to protect you from possible bootloops or other issues."; break; case 180: - errorDescription = @"The app was installed successfully, but requires developer mode to be enabled to run. After rebooting, select \"Turn On\" to enable developer mode."; + errorDescription = @"The app you tried to install contains encrypted binaries, which cannot have the CoreTrust bypass applied to them. Please ensure you install decrypted apps."; break; case 181: + errorDescription = @"Failed to add app to icon cache."; + break; + case 182: + errorDescription = @"The app was installed successfully, but requires developer mode to be enabled to run. After rebooting, select \"Turn On\" to enable developer mode."; + break; + case 183: errorDescription = @"Failed to enable developer mode."; break; }