1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267 |
- //
- // patchfinder64.c
- // extra_recipe
- //
- // Copyright © 2017 xerub. All rights reserved.
- //
- #include <assert.h>
- #include <stdint.h>
- #include <string.h>
- #include "kppkernel.h"
- #include "kpppatchfinder64.h"
- typedef unsigned long long addr_t;
- #define IS64(image) (*(uint8_t *)(image) & 1)
- #define MACHO(p) ((*(unsigned int *)(p) & ~1) == 0xfeedface)
- /* generic stuff *************************************************************/
- #define UCHAR_MAX 255
- static unsigned char *
- boyermoore_horspool_memmem(const unsigned char* haystack, size_t hlen,
- const unsigned char* needle, size_t nlen)
- {
- size_t last, scan = 0;
- size_t bad_char_skip[UCHAR_MAX + 1]; /* Officially called:
- * bad character shift */
- /* Sanity checks on the parameters */
- if (nlen <= 0 || !haystack || !needle)
- return NULL;
- /* ---- Preprocess ---- */
- /* Initialize the table to default value */
- /* When a character is encountered that does not occur
- * in the needle, we can safely skip ahead for the whole
- * length of the needle.
- */
- for (scan = 0; scan <= UCHAR_MAX; scan = scan + 1)
- bad_char_skip[scan] = nlen;
- /* C arrays have the first byte at [0], therefore:
- * [nlen - 1] is the last byte of the array. */
- last = nlen - 1;
- /* Then populate it with the analysis of the needle */
- for (scan = 0; scan < last; scan = scan + 1)
- bad_char_skip[needle[scan]] = last - scan;
- /* ---- Do the matching ---- */
- /* Search the haystack, while the needle can still be within it. */
- while (hlen >= nlen)
- {
- /* scan from the end of the needle */
- for (scan = last; haystack[scan] == needle[scan]; scan = scan - 1)
- if (scan == 0) /* If the first byte matches, we've found it. */
- return (void *)haystack;
- /* otherwise, we need to skip some bytes and start again.
- Note that here we are getting the skip value based on the last byte
- of needle, no matter where we didn't match. So if needle is: "abcd"
- then we are skipping based on 'd' and that value will be 4, and
- for "abcdd" we again skip on 'd' but the value will be only 1.
- The alternative of pretending that the mismatched character was
- the last character is slower in the normal case (E.g. finding
- "abcd" in "...azcd..." gives 4 by using 'd' but only
- 4-2==2 using 'z'. */
- hlen -= bad_char_skip[haystack[last]];
- haystack += bad_char_skip[haystack[last]];
- }
- return NULL;
- }
- /* disassembler **************************************************************/
- static int HighestSetBit(int N, uint32_t imm)
- {
- int i;
- for (i = N - 1; i >= 0; i--) {
- if (imm & (1 << i)) {
- return i;
- }
- }
- return -1;
- }
- static uint64_t ZeroExtendOnes(unsigned M, unsigned N) // zero extend M ones to N width
- {
- (void)N;
- return ((uint64_t)1 << M) - 1;
- }
- static uint64_t RORZeroExtendOnes(unsigned M, unsigned N, unsigned R)
- {
- uint64_t val = ZeroExtendOnes(M, N);
- if (R == 0) {
- return val;
- }
- return ((val >> R) & (((uint64_t)1 << (N - R)) - 1)) | ((val & (((uint64_t)1 << R) - 1)) << (N - R));
- }
- static uint64_t Replicate(uint64_t val, unsigned bits)
- {
- uint64_t ret = val;
- unsigned shift;
- for (shift = bits; shift < 64; shift += bits) { // XXX actually, it is either 32 or 64
- ret |= (val << shift);
- }
- return ret;
- }
- static int DecodeBitMasks(unsigned immN, unsigned imms, unsigned immr, int immediate, uint64_t *newval)
- {
- unsigned levels, S, R, esize;
- int len = HighestSetBit(7, (immN << 6) | (~imms & 0x3F));
- if (len < 1) {
- return -1;
- }
- levels = ZeroExtendOnes(len, 6);
- if (immediate && (imms & levels) == levels) {
- return -1;
- }
- S = imms & levels;
- R = immr & levels;
- esize = 1 << len;
- *newval = Replicate(RORZeroExtendOnes(S + 1, esize, R), esize);
- return 0;
- }
- static int DecodeMov(uint32_t opcode, uint64_t total, int first, uint64_t *newval)
- {
- unsigned o = (opcode >> 29) & 3;
- unsigned k = (opcode >> 23) & 0x3F;
- unsigned rn, rd;
- uint64_t i;
- if (k == 0x24 && o == 1) { // MOV (bitmask imm) <=> ORR (immediate)
- unsigned s = (opcode >> 31) & 1;
- unsigned N = (opcode >> 22) & 1;
- if (s == 0 && N != 0) {
- return -1;
- }
- rn = (opcode >> 5) & 0x1F;
- if (rn == 31) {
- unsigned imms = (opcode >> 10) & 0x3F;
- unsigned immr = (opcode >> 16) & 0x3F;
- return DecodeBitMasks(N, imms, immr, 1, newval);
- }
- } else if (k == 0x25) { // MOVN/MOVZ/MOVK
- unsigned s = (opcode >> 31) & 1;
- unsigned h = (opcode >> 21) & 3;
- if (s == 0 && h > 1) {
- return -1;
- }
- i = (opcode >> 5) & 0xFFFF;
- h *= 16;
- i <<= h;
- if (o == 0) { // MOVN
- *newval = ~i;
- return 0;
- } else if (o == 2) { // MOVZ
- *newval = i;
- return 0;
- } else if (o == 3 && !first) { // MOVK
- *newval = (total & ~((uint64_t)0xFFFF << h)) | i;
- return 0;
- }
- } else if ((k | 1) == 0x23 && !first) { // ADD (immediate)
- unsigned h = (opcode >> 22) & 3;
- if (h > 1) {
- return -1;
- }
- rd = opcode & 0x1F;
- rn = (opcode >> 5) & 0x1F;
- if (rd != rn) {
- return -1;
- }
- i = (opcode >> 10) & 0xFFF;
- h *= 12;
- i <<= h;
- if (o & 2) { // SUB
- *newval = total - i;
- return 0;
- } else { // ADD
- *newval = total + i;
- return 0;
- }
- }
- return -1;
- }
- /* patchfinder ***************************************************************/
- static addr_t
- step64(const uint8_t *buf, addr_t start, size_t length, uint32_t what, uint32_t mask)
- {
- addr_t end = start + length;
- while (start < end) {
- uint32_t x = *(uint32_t *)(buf + start);
- if ((x & mask) == what) {
- return start;
- }
- start += 4;
- }
- return 0;
- }
- static addr_t
- step64_back(const uint8_t *buf, addr_t start, size_t length, uint32_t what, uint32_t mask)
- {
- addr_t end = start - length;
- while (start >= end) {
- uint32_t x = *(uint32_t *)(buf + start);
- if ((x & mask) == what) {
- return start;
- }
- start -= 4;
- }
- return 0;
- }
- static addr_t
- bof64(const uint8_t *buf, addr_t start, addr_t where)
- {
- for (; where >= start; where -= 4) {
- uint32_t op = *(uint32_t *)(buf + where);
- if ((op & 0xFFC003FF) == 0x910003FD) {
- unsigned delta = (op >> 10) & 0xFFF;
- //printf("%x: ADD X29, SP, #0x%x\n", where, delta);
- if ((delta & 0xF) == 0) {
- addr_t prev = where - ((delta >> 4) + 1) * 4;
- uint32_t au = *(uint32_t *)(buf + prev);
- if ((au & 0xFFC003E0) == 0xA98003E0) {
- //printf("%x: STP x, y, [SP,#-imm]!\n", prev);
- return prev;
- }
- }
- }
- }
- return 0;
- }
- static addr_t
- xref64(const uint8_t *buf, addr_t start, addr_t end, addr_t what)
- {
- addr_t i;
- uint64_t value[32];
- memset(value, 0, sizeof(value));
- end &= ~3;
- for (i = start & ~3; i < end; i += 4) {
- uint32_t op = *(uint32_t *)(buf + i);
- unsigned reg = op & 0x1F;
- if ((op & 0x9F000000) == 0x90000000) {
- signed adr = ((op & 0x60000000) >> 18) | ((op & 0xFFFFE0) << 8);
- //printf("%llx: ADRP X%d, 0x%llx\n", i, reg, ((long long)adr << 1) + (i & ~0xFFF));
- value[reg] = ((long long)adr << 1) + (i & ~0xFFF);
- /*} else if ((op & 0xFFE0FFE0) == 0xAA0003E0) {
- unsigned rd = op & 0x1F;
- unsigned rm = (op >> 16) & 0x1F;
- //printf("%llx: MOV X%d, X%d\n", i, rd, rm);
- value[rd] = value[rm];*/
- } else if ((op & 0xFF000000) == 0x91000000) {
- unsigned rn = (op >> 5) & 0x1F;
- unsigned shift = (op >> 22) & 3;
- unsigned imm = (op >> 10) & 0xFFF;
- if (shift == 1) {
- imm <<= 12;
- } else {
- //assert(shift == 0);
- if (shift > 1) continue;
- }
- //printf("%llx: ADD X%d, X%d, 0x%x\n", i, reg, rn, imm);
- value[reg] = value[rn] + imm;
- } else if ((op & 0xF9C00000) == 0xF9400000) {
- unsigned rn = (op >> 5) & 0x1F;
- unsigned imm = ((op >> 10) & 0xFFF) << 3;
- //printf("%llx: LDR X%d, [X%d, 0x%x]\n", i, reg, rn, imm);
- if (!imm) continue; // XXX not counted as true xref
- value[reg] = value[rn] + imm; // XXX address, not actual value
- /*} else if ((op & 0xF9C00000) == 0xF9000000) {
- unsigned rn = (op >> 5) & 0x1F;
- unsigned imm = ((op >> 10) & 0xFFF) << 3;
- //printf("%llx: STR X%d, [X%d, 0x%x]\n", i, reg, rn, imm);
- if (!imm) continue; // XXX not counted as true xref
- value[rn] = value[rn] + imm; // XXX address, not actual value*/
- } else if ((op & 0x9F000000) == 0x10000000) {
- signed adr = ((op & 0x60000000) >> 18) | ((op & 0xFFFFE0) << 8);
- //printf("%llx: ADR X%d, 0x%llx\n", i, reg, ((long long)adr >> 11) + i);
- value[reg] = ((long long)adr >> 11) + i;
- } else if ((op & 0xFF000000) == 0x58000000) {
- unsigned adr = (op & 0xFFFFE0) >> 3;
- //printf("%llx: LDR X%d, =0x%llx\n", i, reg, adr + i);
- value[reg] = adr + i; // XXX address, not actual value
- }
- if (value[reg] == what) {
- return i;
- }
- }
- return 0;
- }
- static addr_t
- calc64(const uint8_t *buf, addr_t start, addr_t end, int which)
- {
- addr_t i;
- uint64_t value[32];
- memset(value, 0, sizeof(value));
- end &= ~3;
- for (i = start & ~3; i < end; i += 4) {
- uint32_t op = *(uint32_t *)(buf + i);
- unsigned reg = op & 0x1F;
- if ((op & 0x9F000000) == 0x90000000) {
- signed adr = ((op & 0x60000000) >> 18) | ((op & 0xFFFFE0) << 8);
- //printf("%llx: ADRP X%d, 0x%llx\n", i, reg, ((long long)adr << 1) + (i & ~0xFFF));
- value[reg] = ((long long)adr << 1) + (i & ~0xFFF);
- /*} else if ((op & 0xFFE0FFE0) == 0xAA0003E0) {
- unsigned rd = op & 0x1F;
- unsigned rm = (op >> 16) & 0x1F;
- //printf("%llx: MOV X%d, X%d\n", i, rd, rm);
- value[rd] = value[rm];*/
- } else if ((op & 0xFF000000) == 0x91000000) {
- unsigned rn = (op >> 5) & 0x1F;
- unsigned shift = (op >> 22) & 3;
- unsigned imm = (op >> 10) & 0xFFF;
- if (shift == 1) {
- imm <<= 12;
- } else {
- //assert(shift == 0);
- if (shift > 1) continue;
- }
- //printf("%llx: ADD X%d, X%d, 0x%x\n", i, reg, rn, imm);
- value[reg] = value[rn] + imm;
- } else if ((op & 0xF9C00000) == 0xF9400000) {
- unsigned rn = (op >> 5) & 0x1F;
- unsigned imm = ((op >> 10) & 0xFFF) << 3;
- //printf("%llx: LDR X%d, [X%d, 0x%x]\n", i, reg, rn, imm);
- if (!imm) continue; // XXX not counted as true xref
- value[reg] = value[rn] + imm; // XXX address, not actual value
- } else if ((op & 0xF9C00000) == 0xF9000000) {
- unsigned rn = (op >> 5) & 0x1F;
- unsigned imm = ((op >> 10) & 0xFFF) << 3;
- //printf("%llx: STR X%d, [X%d, 0x%x]\n", i, reg, rn, imm);
- if (!imm) continue; // XXX not counted as true xref
- value[rn] = value[rn] + imm; // XXX address, not actual value
- } else if ((op & 0x9F000000) == 0x10000000) {
- signed adr = ((op & 0x60000000) >> 18) | ((op & 0xFFFFE0) << 8);
- //printf("%llx: ADR X%d, 0x%llx\n", i, reg, ((long long)adr >> 11) + i);
- value[reg] = ((long long)adr >> 11) + i;
- } else if ((op & 0xFF000000) == 0x58000000) {
- unsigned adr = (op & 0xFFFFE0) >> 3;
- //printf("%llx: LDR X%d, =0x%llx\n", i, reg, adr + i);
- value[reg] = adr + i; // XXX address, not actual value
- }
- }
- return value[which];
- }
- static addr_t
- calc64mov(const uint8_t *buf, addr_t start, addr_t end, int which)
- {
- addr_t i;
- uint64_t value[32];
- memset(value, 0, sizeof(value));
- end &= ~3;
- for (i = start & ~3; i < end; i += 4) {
- uint32_t op = *(uint32_t *)(buf + i);
- unsigned reg = op & 0x1F;
- uint64_t newval;
- int rv = DecodeMov(op, value[reg], 0, &newval);
- if (rv == 0) {
- if (((op >> 31) & 1) == 0) {
- newval &= 0xFFFFFFFF;
- }
- value[reg] = newval;
- }
- }
- return value[which];
- }
- static addr_t
- find_call64(const uint8_t *buf, addr_t start, size_t length)
- {
- return step64(buf, start, length, 0x94000000, 0xFC000000);
- }
- static addr_t
- follow_call64(const uint8_t *buf, addr_t call)
- {
- long long w;
- w = *(uint32_t *)(buf + call) & 0x3FFFFFF;
- w <<= 64 - 26;
- w >>= 64 - 26 - 2;
- return call + w;
- }
- static addr_t
- follow_cbz(const uint8_t *buf, addr_t cbz)
- {
- return cbz + ((*(int *)(buf + cbz) & 0x3FFFFE0) << 10 >> 13);
- }
- /* kernel iOS10 **************************************************************/
- #include <fcntl.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <mach-o/loader.h>
- #ifdef __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__
- #include <mach/mach.h>
- size_t kpp_kread(uint64_t where, void *p, size_t size);
- #endif
- task_t tfp0;
- static uint8_t *kernel = NULL;
- static size_t kernel_size = 0;
- static addr_t xnucore_base = 0;
- static addr_t xnucore_size = 0;
- static addr_t prelink_base = 0;
- static addr_t prelink_size = 0;
- static addr_t cstring_base = 0;
- static addr_t cstring_size = 0;
- static addr_t pstring_base = 0;
- static addr_t pstring_size = 0;
- static addr_t kerndumpbase = -1;
- static addr_t kernel_entry = 0;
- static void *kernel_mh = 0;
- static addr_t kernel_delta = 0;
- int
- kpp_init_patchfinder(task_t taskfp0, addr_t base, const char *filename)
- {
- tfp0 = taskfp0;
-
- size_t rv;
- uint8_t buf[0x4000];
- unsigned i, j;
- const struct mach_header *hdr = (struct mach_header *)buf;
- const uint8_t *q;
- addr_t min = -1;
- addr_t max = 0;
- int is64 = 0;
-
- kpp_init_kernel(taskfp0);
- #ifdef __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__
- #define close(f)
- rv = tfp0_kpp_kread(base, buf, sizeof(buf));
- if (rv != sizeof(buf)) {
- printf("failed kread, got size: %zu \n", rv);
- return -1;
- }
- #else /* __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ */
- printf("this code right here has run ............. \n");
- int fd = open(filename, O_RDONLY);
- if (fd < 0) {
- printf("failed at open, got fd: %s \n", fd);
- return -1;
- }
- rv = rk32_via_tfp0(tfp0, fd);
- //rv = read(fd, buf, sizeof(buf));
- if (rv != sizeof(buf)) {
- close(fd);
- printf("failed at buf read, got rv: %d \n", rv);
- return -1;
- }
- #endif /* __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ */
- if (!MACHO(buf)) {
- close(fd);
- printf("failed macho, buf: %s \n", buf);
- return -1;
- }
- if (IS64(buf)) {
- is64 = 4;
- }
- q = buf + sizeof(struct mach_header) + is64;
- for (i = 0; i < hdr->ncmds; i++) {
- const struct load_command *cmd = (struct load_command *)q;
- if (cmd->cmd == LC_SEGMENT_64) {
- const struct segment_command_64 *seg = (struct segment_command_64 *)q;
- if (min > seg->vmaddr) {
- min = seg->vmaddr;
- }
- if (max < seg->vmaddr + seg->vmsize) {
- max = seg->vmaddr + seg->vmsize;
- }
- if (!strcmp(seg->segname, "__TEXT_EXEC")) {
- xnucore_base = seg->vmaddr;
- xnucore_size = seg->filesize;
- }
- if (!strcmp(seg->segname, "__PLK_TEXT_EXEC")) {
- prelink_base = seg->vmaddr;
- prelink_size = seg->filesize;
- }
- if (!strcmp(seg->segname, "__TEXT")) {
- const struct section_64 *sec = (struct section_64 *)(seg + 1);
- for (j = 0; j < seg->nsects; j++) {
- if (!strcmp(sec[j].sectname, "__cstring")) {
- cstring_base = sec[j].addr;
- cstring_size = sec[j].size;
- }
- }
- }
- if (!strcmp(seg->segname, "__PRELINK_TEXT")) {
- const struct section_64 *sec = (struct section_64 *)(seg + 1);
- for (j = 0; j < seg->nsects; j++) {
- if (!strcmp(sec[j].sectname, "__text")) {
- pstring_base = sec[j].addr;
- pstring_size = sec[j].size;
- }
- }
- }
- }
- if (cmd->cmd == LC_UNIXTHREAD) {
- uint32_t *ptr = (uint32_t *)(cmd + 1);
- uint32_t flavor = ptr[0];
- struct {
- uint64_t x[29]; /* General purpose registers x0-x28 */
- uint64_t fp; /* Frame pointer x29 */
- uint64_t lr; /* Link register x30 */
- uint64_t sp; /* Stack pointer x31 */
- uint64_t pc; /* Program counter */
- uint32_t cpsr; /* Current program status register */
- } *thread = (void *)(ptr + 2);
- if (flavor == 6) {
- kernel_entry = thread->pc;
- }
- }
- q = q + cmd->cmdsize;
- }
- kerndumpbase = min;
- xnucore_base -= kerndumpbase;
- prelink_base -= kerndumpbase;
- cstring_base -= kerndumpbase;
- pstring_base -= kerndumpbase;
- kernel_size = max - min;
- #ifdef __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__
- kernel = malloc(kernel_size);
- if (!kernel) {
- printf("failed to malloc kern \n");
- return -1;
- }
-
- rv = tfp0_kpp_kread(kerndumpbase, kernel, kernel_size);
- // rv = kpp_kread(kerndumpbase, kernel, kernel_size);
- if (rv != kernel_size) {
- free(kernel);
- printf("failed to kread kern, rv: %zu \n", rv);
- return -1;
- }
- kernel_mh = kernel + base - min;
- (void)filename;
- #undef close
- #else /* __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ */
- kernel = calloc(1, kernel_size);
- if (!kernel) {
- close(fd);
- printf("failed to calloc kern, kernel: %d \n", kernel);
- return -1;
- }
- q = buf + sizeof(struct mach_header) + is64;
- for (i = 0; i < hdr->ncmds; i++) {
- const struct load_command *cmd = (struct load_command *)q;
- if (cmd->cmd == LC_SEGMENT_64) {
- const struct segment_command_64 *seg = (struct segment_command_64 *)q;
- size_t sz = pread(fd, kernel + seg->vmaddr - min, seg->filesize, seg->fileoff);
- if (sz != seg->filesize) {
- close(fd);
- free(kernel);
- printf("sz != seg->filesize, sz: %zu", sz);
- return -1;
- }
- if (!kernel_mh) {
- kernel_mh = kernel + seg->vmaddr - min;
- }
- if (!strcmp(seg->segname, "__LINKEDIT")) {
- kernel_delta = seg->vmaddr - min - seg->fileoff;
- }
- }
- q = q + cmd->cmdsize;
- }
- close(fd);
- (void)base;
- #endif /* __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ */
- return 0;
- }
- void
- term_kernel(void)
- {
- free(kernel);
- }
- /* these operate on VA ******************************************************/
- #define INSN_RET 0xD65F03C0, 0xFFFFFFFF
- #define INSN_CALL 0x94000000, 0xFC000000
- #define INSN_B 0x14000000, 0xFC000000
- #define INSN_CBZ 0x34000000, 0xFC000000
- addr_t
- kpp_find_register_value(addr_t where, int reg)
- {
- addr_t val;
- addr_t bof = 0;
- where -= kerndumpbase;
- if (where > xnucore_base) {
- bof = bof64(kernel, xnucore_base, where);
- if (!bof) {
- bof = xnucore_base;
- }
- } else if (where > prelink_base) {
- bof = bof64(kernel, prelink_base, where);
- if (!bof) {
- bof = prelink_base;
- }
- }
- val = calc64(kernel, bof, where, reg);
- if (!val) {
- return 0;
- }
- return val + kerndumpbase;
- }
- addr_t
- kpp_find_reference(addr_t to, int n, int prelink)
- {
- addr_t ref, end;
- addr_t base = xnucore_base;
- addr_t size = xnucore_size;
- if (prelink) {
- base = prelink_base;
- size = prelink_size;
- }
- if (n <= 0) {
- n = 1;
- }
- end = base + size;
- to -= kerndumpbase;
- do {
- ref = xref64(kernel, base, end, to);
- if (!ref) {
- return 0;
- }
- base = ref + 4;
- } while (--n > 0);
- return ref + kerndumpbase;
- }
- addr_t
- kpp_find_strref(const char *string, int n, int prelink)
- {
- uint8_t *str;
- addr_t base = cstring_base;
- addr_t size = cstring_size;
- if (prelink) {
- base = pstring_base;
- size = pstring_size;
- }
- str = boyermoore_horspool_memmem(kernel + base, size, (uint8_t *)string, strlen(string));
- if (!str) {
- return 0;
- }
- return kpp_find_reference(str - kernel + kerndumpbase, n, prelink);
- }
- addr_t
- kpp_find_gPhysBase(void)
- {
- addr_t ret, val;
- // addr_t ref = kpp_find_strref("\"pmap_map_high_window_bd: insufficient pages", 1, 0);
- addr_t ref = kpp_find_strref("\"pmap_map_high_window_bd: area too large", 1, 0);
- if (!ref) {
- return 0;
- }
- ref -= kerndumpbase;
- ret = step64(kernel, ref, 64, INSN_RET);
- if (!ret) {
- return 0;
- }
- val = calc64(kernel, ref, ret, 8);
- if (!val) {
- return 0;
- }
- return val + kerndumpbase;
- }
- addr_t
- kpp_find_kernel_pmap(void)
- {
- addr_t call, bof, val;
- addr_t ref = kpp_find_strref("\"pmap_map_bd\"", 1, 0);
- if (!ref) {
- return 0;
- }
- ref -= kerndumpbase;
- call = step64_back(kernel, ref, 64, INSN_CALL);
- if (!call) {
- return 0;
- }
- bof = bof64(kernel, xnucore_base, call);
- if (!bof) {
- return 0;
- }
- val = calc64(kernel, bof, call, 2);
- if (!val) {
- return 0;
- }
- return val + kerndumpbase;
- }
- addr_t
- kpp_find_amfiret(void)
- {
- addr_t ret;
- addr_t ref = kpp_find_strref("AMFI: hook..execve() killing pid %u: %s\n", 1, 1);
- if (!ref) {
- return 0;
- }
- ref -= kerndumpbase;
- ret = step64(kernel, ref, 512, INSN_RET);
- if (!ret) {
- return 0;
- }
- return ret + kerndumpbase;
- }
- addr_t
- kpp_find_ret_0(void)
- {
- addr_t off;
- uint32_t *k;
- k = (uint32_t *)(kernel + xnucore_base);
- for (off = 0; off < xnucore_size - 4; off += 4, k++) {
- if (k[0] == 0xAA1F03E0 && k[1] == 0xD65F03C0) {
- return off + xnucore_base + kerndumpbase;
- }
- }
- k = (uint32_t *)(kernel + prelink_base);
- for (off = 0; off < prelink_size - 4; off += 4, k++) {
- if (k[0] == 0xAA1F03E0 && k[1] == 0xD65F03C0) {
- return off + prelink_base + kerndumpbase;
- }
- }
- return 0;
- }
- addr_t
- kpp_find_amfi_memcmpstub(void)
- {
- addr_t call, dest, reg;
- addr_t ref = kpp_find_strref("%s: Possible race detected. Rejecting.", 1, 1);
- if (!ref) {
- return 0;
- }
- ref -= kerndumpbase;
- call = step64_back(kernel, ref, 64, INSN_CALL);
- if (!call) {
- return 0;
- }
- dest = follow_call64(kernel, call);
- if (!dest) {
- return 0;
- }
- reg = calc64(kernel, dest, dest + 8, 16);
- if (!reg) {
- return 0;
- }
- return reg + kerndumpbase;
- }
- addr_t
- kpp_find_sbops(void)
- {
- addr_t off, what;
- uint8_t *str = boyermoore_horspool_memmem(kernel + pstring_base, pstring_size, (uint8_t *)"Seatbelt sandbox policy", sizeof("Seatbelt sandbox policy") - 1);
- if (!str) {
- return 0;
- }
- what = str - kernel + kerndumpbase;
- for (off = 0; off < kernel_size - prelink_base; off += 8) {
- if (*(uint64_t *)(kernel + prelink_base + off) == what) {
- return *(uint64_t *)(kernel + prelink_base + off + 24);
- }
- }
- return 0;
- }
- addr_t
- kpp_find_lwvm_mapio_patch(void)
- {
- addr_t call, dest, reg;
- addr_t ref = kpp_find_strref("_mapForIO", 1, 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);
- if (!call) {
- return 0;
- }
- dest = follow_call64(kernel, call);
- if (!dest) {
- return 0;
- }
- reg = calc64(kernel, dest, dest + 8, 16);
- if (!reg) {
- return 0;
- }
- return reg + kerndumpbase;
- }
- addr_t
- kpp_find_lwvm_mapio_newj(void)
- {
- addr_t call;
- addr_t ref = kpp_find_strref("_mapForIO", 1, 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);
- if (!call) {
- return 0;
- }
- call = step64(kernel, call + 4, 64, INSN_CALL);
- if (!call) {
- return 0;
- }
- call = step64_back(kernel, call, 64, INSN_B);
- if (!call) {
- return 0;
- }
- return call + 4 + kerndumpbase;
- }
- addr_t
- kpp_find_cpacr_write(void)
- {
- addr_t off;
- uint32_t *k;
- k = (uint32_t *)(kernel + xnucore_base);
- for (off = 0; off < xnucore_size - 4; off += 4, k++) {
- if (k[0] == 0xd5181040) {
- return off + xnucore_base + kerndumpbase;
- }
- }
- return 0;
- }
- addr_t
- kpp_find_str(const char *string)
- {
- uint8_t *str = boyermoore_horspool_memmem(kernel, kernel_size, (uint8_t *)string, strlen(string));
- if (!str) {
- return 0;
- }
- return str - kernel + kerndumpbase;
- }
- addr_t
- kpp_find_entry(void)
- {
- /* XXX returns an unslid address */
- return kernel_entry;
- }
- const unsigned char *
- kpp_find_mh(void)
- {
- return kernel_mh;
- }
- addr_t
- kpp_find_amfiops(void)
- {
- addr_t off, what;
- uint8_t *str = boyermoore_horspool_memmem(kernel + pstring_base, pstring_size, (uint8_t *)"Apple Mobile File Integrity", sizeof("Apple Mobile File Integrity") - 1);
- if (!str) {
- return 0;
- }
- what = str - kernel + kerndumpbase;
- /* XXX will only work on a dumped kernel */
- for (off = 0; off < kernel_size - prelink_base; off += 8) {
- if (*(uint64_t *)(kernel + prelink_base + off) == what) {
- return *(uint64_t *)(kernel + prelink_base + off + 0x18);
- }
- }
- return 0;
- }
- addr_t
- kpp_find_sysbootnonce(void)
- {
- addr_t off, what;
- uint8_t *str = boyermoore_horspool_memmem(kernel + cstring_base, cstring_size, (uint8_t *)"com.apple.System.boot-nonce", sizeof("com.apple.System.boot-nonce") - 1);
- if (!str) {
- return 0;
- }
- what = str - kernel + kerndumpbase;
- for (off = 0; off < kernel_size - xnucore_base; off += 8) {
- if (*(uint64_t *)(kernel + xnucore_base + off) == what) {
- return xnucore_base + off + 8 + 4 + kerndumpbase;
- }
- }
- return 0;
- }
- uint64_t find_copyout(void) {
- // Find the first reference to the string
- addr_t ref = kpp_find_strref("\"%s(%p, %p, %lu) - transfer too large\"", 2, 0);
- if (!ref) {
- return 0;
- }
- ref -= kerndumpbase;
-
- uint64_t start = 0;
- for (int i = 4; i < 0x100*4; i+=4) {
- uint32_t op = *(uint32_t*)(kernel+ref-i);
- if (op == 0xd10143ff) { // SUB SP, SP, #0x50
- start = ref-i;
- break;
- }
- }
- if (!start) {
- return 0;
- }
-
- return start + kerndumpbase;
- }
- uint64_t find_bzero(void) {
- // Just find SYS #3, c7, c4, #1, X3, then get the start of that function
- addr_t off;
- uint32_t *k;
- k = (uint32_t *)(kernel + xnucore_base);
- for (off = 0; off < xnucore_size - 4; off += 4, k++) {
- if (k[0] == 0xd50b7423) {
- off += xnucore_base;
- break;
- }
- }
-
- uint64_t start = bof64(kernel, xnucore_base, off);
- if (!start) {
- return 0;
- }
-
- return start + kerndumpbase;
- }
- addr_t find_bcopy(void) {
- // Jumps straight into memmove after switching x0 and x1 around
- // Guess we just find the switch and that's it
- addr_t off;
- uint32_t *k;
- k = (uint32_t *)(kernel + xnucore_base);
- for (off = 0; off < xnucore_size - 4; off += 4, k++) {
- if (k[0] == 0xAA0003E3 && k[1] == 0xAA0103E0 && k[2] == 0xAA0303E1 && k[3] == 0xd503201F) {
- return off + xnucore_base + kerndumpbase;
- }
- }
- k = (uint32_t *)(kernel + prelink_base);
- for (off = 0; off < prelink_size - 4; off += 4, k++) {
- if (k[0] == 0xAA0003E3 && k[1] == 0xAA0103E0 && k[2] == 0xAA0303E1 && k[3] == 0xd503201F) {
- return off + prelink_base + kerndumpbase;
- }
- }
- return 0;
- }
- addr_t kpp_find_trustcache(void) {
- addr_t call, func, val;
- addr_t ref = kpp_find_strref("com.apple.MobileFileIntegrity", 1, 1);
- if (!ref) {
- printf("didnt find string ref\n");
- return 0;
- }
- ref -= kerndumpbase;
- call = step64(kernel, ref, 32, INSN_CALL);
- if (!call) {
- printf("couldn't find the call\n");
- return 0;
- }
- call = step64(kernel, call+4, 32, INSN_CALL);
- func = follow_call64(kernel, call);
- if (!func) {
- printf("couldn't follow the call\n");
- return 0;
- }
- val = calc64(kernel, func, func + 16, 8);
- if (!val) {
- return 0;
- }
- return val + kerndumpbase;
- }
- addr_t kpp_find_amficache(void) {
- addr_t call, func, bof, val;
- addr_t ref = kpp_find_strref("com.apple.MobileFileIntegrity", 1, 1);
- if (!ref) {
- printf("didnt find string ref\n");
- return 0;
- }
- ref -= kerndumpbase;
- call = step64(kernel, ref, 32, INSN_CALL);
- if (!call) {
- printf("couldn't find the call\n");
- return 0;
- }
- call = step64(kernel, call+4, 32, INSN_CALL);
- func = follow_call64(kernel, call);
- if (!func) {
- printf("couldn't follow the call\n");
- return 0;
- }
- bof = bof64(kernel, func - 256, func);
- if (!bof) {
- printf("couldn't find the start of the function\n");
- return 0;
- }
- val = calc64(kernel, bof, func, 9);
- if (!val) {
- printf("couldn't find x9\n");
- return 0;
- }
- return val + kerndumpbase;
- }
- // #ifdef HAVE_MAIN
- /* extra_recipe **************************************************************/
- #define INSN_STR8 0xF9000000 | 8, 0xFFC00000 | 0x1F
- addr_t
- find_AGXCommandQueue_vtable(void)
- {
- addr_t val, str8;
- addr_t ref = kpp_find_strref("AGXCommandQueue", 1, 1);
- if (!ref) {
- return 0;
- }
- val = kpp_find_register_value(ref, 0);
- if (!val) {
- return 0;
- }
- ref = kpp_find_reference(val, 1, 1);
- if (!ref) {
- return 0;
- }
- ref -= kerndumpbase;
- str8 = step64(kernel, ref, 32, INSN_STR8);
- if (!str8) {
- return 0;
- }
- val = calc64(kernel, ref, str8, 8);
- if (!val) {
- return 0;
- }
- return val + kerndumpbase;
- }
- addr_t
- find_allproc(void)
- {
- addr_t val, bof, str8;
- addr_t ref = kpp_find_strref("\"pgrp_add : pgrp is dead adding process\"", 1, 0); // modified
- if (!ref) {
- return 0;
- }
- ref -= kerndumpbase;
- bof = bof64(kernel, xnucore_base, ref);
- if (!bof) {
- return 0;
- }
- str8 = step64_back(kernel, ref, ref - bof, INSN_STR8);
- if (!str8) {
- return 0;
- }
- val = calc64(kernel, bof, str8, 8);
- if (!val) {
- return 0;
- }
- return val + kerndumpbase;
- }
- addr_t
- find_call5(void)
- {
- addr_t bof;
- uint8_t gadget[] = { 0x95, 0x5A, 0x40, 0xF9, 0x68, 0x02, 0x40, 0xF9, 0x88, 0x5A, 0x00, 0xF9, 0x60, 0xA2, 0x40, 0xA9 };
- uint8_t *str = boyermoore_horspool_memmem(kernel + prelink_base, prelink_size, gadget, sizeof(gadget));
- if (!str) {
- return 0;
- }
- bof = bof64(kernel, prelink_base, str - kernel);
- if (!bof) {
- return 0;
- }
- return bof + kerndumpbase;
- }
- addr_t
- find_realhost(addr_t priv)
- {
- addr_t val;
- if (!priv) {
- return 0;
- }
- priv -= kerndumpbase;
- val = calc64(kernel, priv, priv + 12, 0);
- if (!val) {
- return 0;
- }
- return val + kerndumpbase;
- }
- #include <mach-o/nlist.h>
- addr_t
- find_symbol(const char *symbol)
- {
- unsigned i;
- const struct mach_header *hdr = kernel_mh;
- const uint8_t *q;
- int is64 = 0;
- if (IS64(hdr)) {
- is64 = 4;
- }
- /* XXX will only work on a decrypted kernel */
- if (!kernel_delta) {
- return 0;
- }
- /* XXX I should cache these. ohwell... */
- q = (uint8_t *)(hdr + 1) + is64;
- for (i = 0; i < hdr->ncmds; i++) {
- const struct load_command *cmd = (struct load_command *)q;
- if (cmd->cmd == LC_SYMTAB) {
- const struct symtab_command *sym = (struct symtab_command *)q;
- const char *stroff = (const char *)kernel + sym->stroff + kernel_delta;
- if (is64) {
- uint32_t k;
- const struct nlist_64 *s = (struct nlist_64 *)(kernel + sym->symoff + kernel_delta);
- for (k = 0; k < sym->nsyms; k++) {
- if (s[k].n_type & N_STAB) {
- continue;
- }
- if (s[k].n_value && (s[k].n_type & N_TYPE) != N_INDR) {
- if (!strcmp(symbol, stroff + s[k].n_un.n_strx)) {
- /* XXX this is an unslid address */
- return s[k].n_value;
- }
- }
- }
- }
- }
- q = q + cmd->cmdsize;
- }
- return 0;
- }
- /* g0blin ****z****************************************************************/
- addr_t find_sandbox_label_update_execve(void) {
-
- addr_t ref;
- for (int i = 1; (ref = kpp_find_strref("process-exec denied while updating label", i, 1)); i++) {
- if (ref) {
- printf("process-exec string at 0x%llx\n", ref);
- ref = ref - 0x368;
- printf("patch location -> 0x%llx\n", ref);
-
- return ref;
- }
- }
-
- // addr_t off, what;
- // uint8_t *str = boyermoore_horspool_memmem(kernel + pstring_base, pstring_size, (uint8_t *)"process-exec denied", sizeof("process-exec denied") - 1);
- // if (str) {
- // what = str - kernel + kerndumpbase;
- // for (off = 0; off < kernel_size - prelink_base; off += 8) {
- // if (*(uint64_t *)(kernel + prelink_base + off) == what) {
- // ref = *(uint64_t *)(kernel + prelink_base + off + 24);
- // printf("found process-exec denied at: 0x%llx\n", ref);
- // }
- // }
- // ref = ref - 0x368;
- // }
-
- return 0;
- }
- /* test **********************************************************************/
- /*
- int
- main(int argc, char **argv)
- {
- int rv;
- addr_t base = 0;
- const addr_t vm_kernel_slide = 0;
- rv = kpp_init_kernel(base, (argc > 1) ? argv[1] : "krnl");
- assert(rv == 0);
- addr_t AGXCommandQueue_vtable = find_AGXCommandQueue_vtable();
- printf("\t\t\t<string>0x%llx</string>\n", AGXCommandQueue_vtable - vm_kernel_slide);
- addr_t OSData_getMetaClass = find_symbol("__ZNK6OSData12getMetaClassEv");
- printf("\t\t\t<string>0x%llx</string>\n", OSData_getMetaClass);
- addr_t OSSerializer_serialize = find_symbol("__ZNK12OSSerializer9serializeEP11OSSerialize");
- printf("\t\t\t<string>0x%llx</string>\n", OSSerializer_serialize);
- addr_t k_uuid_copy = find_symbol("_uuid_copy");
- printf("\t\t\t<string>0x%llx</string>\n", k_uuid_copy);
- addr_t allproc = find_allproc();
- printf("\t\t\t<string>0x%llx</string>\n", allproc);
- addr_t realhost = find_realhost(find_symbol("_host_priv_self") + vm_kernel_slide);
- printf("\t\t\t<string>0x%llx</string>\n", realhost - vm_kernel_slide);
- addr_t call5 = find_call5();
- printf("\t\t\t<string>0x%llx</string>\n", call5 - vm_kernel_slide);
- assert(find_symbol("_rootvnode") == kpp_find_gPhysBase() + 0x38 - vm_kernel_slide);
- term_kernel();
- return 0;
- }*/
- // #endif /* HAVE_MAIN */
|