123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849 |
- //
- // patchfinder64.c
- // extra_recipe
- //
- // Created by xerub on 06/06/2017.
- // Copyright © 2017 xerub. All rights reserved.
- //
- #include <assert.h>
- #include <stdint.h>
- #include <string.h>
- #include <mach-o/nlist.h>
- #include "patchfinder64.h"
- #include "kmem.h"
- #include "offsetof.h"
- #include "../kern_utils.h"
- #define CACHED_FIND_UINT64(name) CACHED_FIND(uint64_t, name)
- typedef uint64_t 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;
- }
- // str8 = step64_back(kernel, ref, ref - bof, INSN_STR8);
- 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;
- }
- // Finds start of function
- 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>
- #ifndef __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__
- #define __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__
- #endif
- #ifdef __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__
- #include <mach/mach.h>
- size_t kread(uint64_t where, void *p, size_t size);
- #endif
- 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 data_base = 0;
- static addr_t data_size = 0;
- static addr_t data_const_base = 0;
- static addr_t data_const_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
- init_kernel(addr_t base, const char *filename)
- {
- 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;
- #ifdef __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__
- #define close(f)
- rv = kread(base, buf, sizeof(buf));
- if (rv != sizeof(buf)) {
- return -1;
- }
- #else /* __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ */
- int fd = open(filename, O_RDONLY);
- if (fd < 0) {
- return -2;
- }
- rv = read(fd, buf, sizeof(buf));
- if (rv != sizeof(buf)) {
- close(fd);
- return -3;
- }
- #endif /* __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ */
- if (!MACHO(buf)) {
- close(fd);
- return -4;
- }
- 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 (!strcmp(seg->segname, "__LINKEDIT")) {
- kernel_delta = seg->vmaddr - min - seg->fileoff;
- }
- if (!strcmp(seg->segname, "__DATA")) {
- const struct section_64 *sec = (struct section_64 *)(seg + 1);
- for (j = 0; j < seg->nsects; j++) {
- if (!strcmp(sec[j].sectname, "__data")) {
- data_base = sec[j].addr;
- data_size = sec[j].size;
- }
- }
- }
- if (!strcmp(seg->segname, "__DATA_CONST")) {
- const struct section_64 *sec = (struct section_64 *)(seg + 1);
- for (j = 0; j < seg->nsects; j++) {
- data_const_base = sec[j].addr;
- data_const_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_IPHONE_OS_VERSION_MIN_REQUIRED__
- kernel = malloc(kernel_size);
- if (!kernel) {
- return -5;
- }
- rv = kread(kerndumpbase, kernel, kernel_size);
- if (rv != kernel_size) {
- free(kernel);
- return -6;
- }
- kernel_mh = kernel + base - min;
- (void)filename;
- #undef close
- #else /* __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ */
- kernel = calloc(1, kernel_size);
- if (!kernel) {
- close(fd);
- return -7;
- }
- 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);
- return -8;
- }
- 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_IPHONE_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
- #define INSN_ADRP 0x90000000, 0x9F000000
- addr_t
- 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
- 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
- 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 find_reference(str - kernel + kerndumpbase, n, prelink);
- }
- #import <Foundation/Foundation.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;
- }
- /****** fun *******/
- CACHED_FIND_UINT64(find_add_x0_x0_0x40_ret) {
- 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] == 0x91010000 && 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] == 0x91010000 && k[1] == 0xD65F03C0) {
- return off + prelink_base + kerndumpbase;
- }
- }
- return 0;
- }
- CACHED_FIND_UINT64(find_OSBoolean_True) {
- addr_t val;
- addr_t ref = find_strref("Delay Autounload", 0, 0);
- if (!ref) {
- return 0;
- }
- ref -= kerndumpbase;
- addr_t weird_instruction = 0;
- for (int i = 4; i < 4*0x100; i+=4) {
- uint32_t op = *(uint32_t *)(kernel + ref + i);
- if (op == 0x320003E0) {
- weird_instruction = ref+i;
- break;
- }
- }
- if (!weird_instruction) {
- return 0;
- }
- val = calc64(kernel, ref, weird_instruction, 8);
- if (!val) {
- return 0;
- }
- return rk64(val + kerndumpbase);
- }
- CACHED_FIND_UINT64(find_OSBoolean_False) {
- return find_OSBoolean_True() + 8;
- }
- CACHED_FIND_UINT64(find_osunserializexml) {
- addr_t ref = find_strref("OSUnserializeXML: %s near line %d\n", 1, 0);
- ref -= kerndumpbase;
- uint64_t start = bof64(kernel, xnucore_base, ref);
- return start + kerndumpbase;
- }
- CACHED_FIND_UINT64(find_cs_find_md) {
- addr_t match[6] = { 1, 0x14, 0x14, offset_sha1_init, offset_sha1_update, offset_sha1_final };
-
- addr_t ref = (addr_t)boyermoore_horspool_memmem(kernel + (data_const_base - kerndumpbase), data_const_size, (unsigned char*)match, sizeof(match));
-
- if (ref == 0) ref = (addr_t)boyermoore_horspool_memmem(kernel + (data_base - kerndumpbase), data_size, (unsigned char*)match, sizeof(match));
-
- if (ref == 0) return 0;
-
- addr_t *testing = (addr_t *)ref;
- addr_t *result = malloc(32);
- ref = ref - (addr_t)kernel + kerndumpbase;
-
- if (*(testing - 6) == 2 && *(testing + 6) != 2) {
- match[0] = ref;
- match[1] = ref - 0x30;
- match[2] = ref - 0x30 * 2;
- match[3] = ref - 0x30 * 3;
- } else if (*(testing - 6) != 2 && *(testing + 6) == 2) {
- match[0] = ref;
- match[1] = ref + 0x30;
- match[2] = ref + 0x30 * 2;
- match[3] = ref + 0x30 * 3;
- } else {
- return 0;
- }
-
- ref = (addr_t)boyermoore_horspool_memmem(kernel + (data_const_base - kerndumpbase), data_const_size, (unsigned char*)match, 8*4);
-
- if (ref != 0) return ref - (addr_t)kernel + kerndumpbase;
- return 0;
- }
|