From ee8a0cfb5148f3376fbfe7103354811c6b69c64f Mon Sep 17 00:00:00 2001 From: Sam Bingner Date: Fri, 21 Dec 2018 14:02:36 -1000 Subject: Also check amfi cache before injecting --- inject.m | 130 +++++++++++++++++++++++++++++++++++++++++++++++++------- kern_funcs.c | 25 +++++++++-- patchfinder64.c | 83 +++++++----------------------------- 3 files changed, 152 insertions(+), 86 deletions(-) diff --git a/inject.m b/inject.m index 2ca834a..b6e2b21 100644 --- a/inject.m +++ b/inject.m @@ -38,6 +38,9 @@ struct hash_entry_t { uint16_t start; } __attribute__((packed)); +struct hash_entry_t amfiIndex[0x100]; +char *amfiData = NULL; + typedef uint8_t hash_t[TRUST_CDHASH_LEN]; mach_port_t try_restore_port() { @@ -53,15 +56,103 @@ mach_port_t try_restore_port() { fprintf(stderr, "unable to retrieve persisted port\n"); return MACH_PORT_NULL; } - + +void free_amfitab() { + if (amfiData != NULL) { + free(amfiData); + amfiData = NULL; + } +} + +bool init_amfitab(uint64_t amfitab) { + if (amfitab == 0) + return false; + + int rv = kread(amfitab, &amfiIndex, sizeof(amfiIndex)); + size_t len = 0; + + for(int i=0; i<0x100; i++) { + len += amfiIndex[i].num * 19; + } + free_amfitab(); + amfiData = malloc(len); + rv = kread(amfitab + sizeof(amfiIndex), amfiData, len); + return true; +} + +bool check_amfi(uint64_t amfitab, NSData *hashData) { + const char *hash = [hashData bytes]; + unsigned char idx = hash[0]; + hash++; + if (amfiData == NULL && !init_amfitab(amfitab)) { + return false; + } + if (amfiIndex[idx].num == 0 || amfiIndex[idx].start == 0) { + fprintf(stderr, "Nothing found to check in amficache (wrong?)\n"); + return false; + } + + char *amfiNext = amfiData + (amfiIndex[idx].start + amfiIndex[idx].num) * 19; + for (char *amfi = amfiData + amfiIndex[idx].start * 19; amfi < amfiNext; amfi += 19) { + if (memcmp(hash, amfi, 19) == 0) { + return true; + } + } + + return false; +} + +NSArray *filteredHashes(uint64_t trust_chain, NSDictionary *hashes, uint64_t amfitab) { + NSArray *result; + @autoreleasepool { + NSMutableDictionary *filtered = [hashes mutableCopy]; + for (NSData *cdhash in [filtered allKeys]) { + if (check_amfi(amfitab, cdhash)) { + printf("%s: already in amfi trustcache, not reinjecting\n", [filtered[cdhash] UTF8String]); + [filtered removeObjectForKey:cdhash]; + } + } + free_amfitab(); + struct trust_mem search; + search.next = trust_chain; + while (search.next != 0) { + uint64_t searchAddr = search.next; + kread(searchAddr, &search, sizeof(struct trust_mem)); + //printf("Checking %d entries at 0x%llx\n", search.count, searchAddr); + char *data = malloc(search.count * TRUST_CDHASH_LEN); + kread(searchAddr + sizeof(struct trust_mem), data, search.count * TRUST_CDHASH_LEN); + size_t data_size = search.count * TRUST_CDHASH_LEN; + + for (char *dataref = data; dataref <= data + data_size - TRUST_CDHASH_LEN; dataref += TRUST_CDHASH_LEN) { + NSData *cdhash = [NSData dataWithBytesNoCopy:dataref length:TRUST_CDHASH_LEN freeWhenDone:NO]; + NSString *hashName = filtered[cdhash]; + if (hashName != nil) { + printf("%s: already in dynamic trustcache, not reinjecting\n", [hashName UTF8String]); + [filtered removeObjectForKey:cdhash]; + if ([filtered count] == 0) { + free(data); + return nil; + } + } + } + free(data); + } + printf("Returning %lu keys\n", [[filtered allKeys] count]); + result = [[filtered allKeys] retain]; + } + return [result autorelease]; +} + int injectTrustCache(int argc, char* argv[], uint64_t trust_chain, uint64_t amficache) { + @autoreleasepool { struct trust_mem mem; uint64_t kernel_trust = 0; - + mem.next = rk64(trust_chain); + mem.count = 0; *(uint64_t *)&mem.uuid[0] = 0xabadbabeabadbabe; *(uint64_t *)&mem.uuid[8] = 0xabadbabeabadbabe; - NSMutableArray *hashes = [[NSMutableArray alloc] init]; + NSMutableDictionary *hashes = [NSMutableDictionary new]; SecStaticCodeRef staticCode; NSDictionary *info; @@ -89,16 +180,16 @@ int injectTrustCache(int argc, char* argv[], uint64_t trust_chain, uint64_t amfi NSUInteger algoIndex = [algos indexOfObject:@(cdHashTypeSHA256)]; if (cdhashes == nil) { - printf("%s: no cdhashes\n", argv[i]); + printf("%s: no cdhashes\n", argv[i]); } else if (algos == nil) { - printf("%s: no algos\n", argv[i]); + printf("%s: no algos\n", argv[i]); } else if (algoIndex == NSNotFound) { - printf("%s: does not have SHA256 hash\n", argv[i]); + printf("%s: does not have SHA256 hash\n", argv[i]); } else { NSData *cdhash = [cdhashes objectAtIndex:algoIndex]; if (cdhash != nil) { printf("%s: OK\n", argv[i]); - [hashes addObject:cdhash]; + hashes[cdhash] = @(argv[i]); } else { printf("%s: missing SHA256 cdhash entry\n", argv[i]); } @@ -112,29 +203,37 @@ int injectTrustCache(int argc, char* argv[], uint64_t trust_chain, uint64_t amfi [hashes release]; return 0; } - size_t length = (sizeof(mem) + numHashes * TRUST_CDHASH_LEN + 0xFFFF) & ~0xFFFF; - char *buffer = malloc(numHashes * TRUST_CDHASH_LEN); + + + NSArray *filtered = filteredHashes(mem.next, hashes, amficache); + int hashesToInject = [filtered count]; + printf("%d new hashes to inject\n", hashesToInject); + if (hashesToInject < 1) { + return numHashes; + } + + size_t length = (sizeof(mem) + hashesToInject * TRUST_CDHASH_LEN + 0xFFFF) & ~0xFFFF; + char *buffer = malloc(hashesToInject * TRUST_CDHASH_LEN); if (buffer == NULL) { fprintf(stderr, "Unable to allocate memory for cdhashes: %s\n", strerror(errno)); - [hashes release]; return -3; } char *curbuf = buffer; - for (NSData *hash in hashes) { + for (NSData *hash in filtered) { memcpy(curbuf, [hash bytes], TRUST_CDHASH_LEN); curbuf += TRUST_CDHASH_LEN; } kernel_trust = kmem_alloc(length); - - mem.count = numHashes; + + mem.count = hashesToInject; kwrite(kernel_trust, &mem, sizeof(mem)); kwrite(kernel_trust + sizeof(mem), buffer, mem.count * TRUST_CDHASH_LEN); wk64(trust_chain, kernel_trust); - [hashes release]; return numHashes; + } } - + int main(int argc, char* argv[]) { if (argc < 2) { fprintf(stderr,"Usage: inject /full/path/to/executable\n"); @@ -154,6 +253,7 @@ int main(int argc, char* argv[]) { uint64_t trust_chain = find_trustcache(); uint64_t amficache = find_amficache(); term_kernel(); + bzero(amfiIndex, sizeof(amfiIndex)); printf("Injecting to trust cache...\n"); int ninjected = injectTrustCache(argc, argv, trust_chain, amficache); printf("Successfully injected [%d/%d] to trust cache.\n", ninjected, argc - 1); diff --git a/kern_funcs.c b/kern_funcs.c index 967cb13..09e1e4f 100644 --- a/kern_funcs.c +++ b/kern_funcs.c @@ -72,10 +72,27 @@ uint32_t rk32(uint64_t kaddr) { } uint64_t rk64(uint64_t kaddr) { - uint64_t lower = rk32(kaddr); - uint64_t higher = rk32(kaddr+4); - uint64_t full = ((higher<<32) | lower); - return full; + kern_return_t err; + uint64_t val = 0; + mach_vm_size_t outsize = 0; + err = mach_vm_read_overwrite(tfp0, + (mach_vm_address_t)kaddr, + (mach_vm_size_t)sizeof(uint64_t), + (mach_vm_address_t)&val, + &outsize); + + if (err != KERN_SUCCESS){ + printf("tfp0 read failed %s addr: 0x%llx err:%x port:%x\n", mach_error_string(err), kaddr, err, tfp0); + sleep(3); + return 0; + } + + if (outsize != sizeof(uint64_t)){ + printf("tfp0 read was short (expected %lx, got %llx\n", sizeof(uint64_t), outsize); + sleep(3); + return 0; + } + return val; } uint64_t kmem_alloc(uint64_t size) { diff --git a/patchfinder64.c b/patchfinder64.c index 24e9b27..a550ce8 100644 --- a/patchfinder64.c +++ b/patchfinder64.c @@ -6,6 +6,11 @@ // Copyright © 2017 xerub. All rights reserved. // +#include +#include +#include +#include +#include #include #include #include @@ -17,6 +22,8 @@ typedef unsigned long long addr_t; #define MACHO(p) ((*(unsigned int *)(p) & ~1) == 0xfeedface) +#define REAL_ADDR(x) ((uint64_t)x + (uint64_t)kernel - (uint64_t)kernel_mh + (uint64_t)0xFFFFFFF007004000) + /* generic stuff *************************************************************/ #define UCHAR_MAX 255 @@ -417,12 +424,6 @@ follow_cbz(const uint8_t *buf, addr_t cbz) /* kernel iOS10 **************************************************************/ -#include -#include -#include -#include -#include - #ifdef __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ #include size_t kread(uint64_t where, void *p, size_t size); @@ -1020,78 +1021,26 @@ find_trustcache(void) addr_t find_amficache(void) { - addr_t cbz, call, func, val; - addr_t ref = find_strref("amfi_prevent_old_entitled_platform_binaries", 1, 1); + addr_t ref = find_strref("in-kernel", 1, 1); if (!ref) { - // iOS 11 - ref = find_strref("com.apple.MobileFileIntegrity", 0, 1); - if (!ref) { - return 0; - } - ref -= kerndumpbase; - call = step64(kernel, ref, 64, INSN_CALL); - if (!call) { - return 0; - } - call = step64(kernel, call + 4, 64, INSN_CALL); - goto okay; + return 0; } ref -= kerndumpbase; - cbz = step64(kernel, ref, 32, INSN_CBZ); - if (!cbz) { + //printf("ref at 0x%llx 0x%llx\n", ref, REAL_ADDR(ref)); + addr_t call = step64_back(kernel, ref, 32, INSN_CALL); + if (!call) { return 0; } - call = step64(kernel, follow_cbz(kernel, cbz), 4, INSN_CALL); -okay: + //printf("call at 0x%llx 0x%llx\n", call, REAL_ADDR(call)); if (!call) { return 0; } - func = follow_call64(kernel, call); + addr_t func = follow_call64(kernel, call); + //printf("func at 0x%llx 0x%llx\n", func, REAL_ADDR(func)); if (!func) { return 0; } - val = calc64(kernel, func, func + 16, 8); - if (!val) { - ref = find_strref("%s: only allowed process can check the trust cache", 1, 1); // Trying to find AppleMobileFileIntegrityUserClient::isCdhashInTrustCache - if (!ref) { - return 0; - } - ref -= kerndumpbase; - call = step64_back(kernel, ref, 11*4, INSN_CALL); - if (!call) { - return 0; - } - func = follow_call64(kernel, call); - if (!func) { - return 0; - } - call = step64(kernel, func, 8*4, INSN_CALL); - if (!call) { - return 0; - } - func = follow_call64(kernel, call); - if (!func) { - return 0; - } - call = step64(kernel, func, 8*4, INSN_CALL); - if (!call) { - return 0; - } - call = step64(kernel, call+4, 8*4, INSN_CALL); - if (!call) { - return 0; - } - func = follow_call64(kernel, call); - if (!func) { - return 0; - } - call = step64(kernel, func, 12*4, INSN_CALL); - if (!call) { - return 0; - } - - val = calc64(kernel, call, call + 6*4, 21); - } + addr_t val = calc64(kernel, func + 32, func + 40, 9); return val + kerndumpbase; } -- cgit v1.2.3