summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Bingner <sam@bingner.com>2018-12-21 14:02:36 -1000
committerSam Bingner <sam@bingner.com>2018-12-21 14:02:36 -1000
commitee8a0cfb5148f3376fbfe7103354811c6b69c64f (patch)
treeab6fa4ef53220bd99635b9e4cf60560f05ee10d7
parentcf517d0809b21acd87c3df7acb7552d6226b0e2c (diff)
Also check amfi cache before injecting
-rw-r--r--inject.m130
-rw-r--r--kern_funcs.c25
-rw-r--r--patchfinder64.c83
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 <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <mach-o/loader.h>
#include <assert.h>
#include <stdint.h>
#include <string.h>
@@ -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 <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <mach-o/loader.h>
-
#ifdef __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__
#include <mach/mach.h>
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;
}