patchfinder64.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977
  1. //
  2. // patchfinder64.c
  3. // extra_recipe
  4. //
  5. // Created by xerub on 06/06/2017.
  6. // Copyright © 2017 xerub. All rights reserved.
  7. //
  8. #include <assert.h>
  9. #include <stdint.h>
  10. #include <string.h>
  11. typedef unsigned long long addr_t;
  12. #define IS64(image) (*(uint8_t *)(image) & 1)
  13. #define MACHO(p) ((*(unsigned int *)(p) & ~1) == 0xfeedface)
  14. /* generic stuff *************************************************************/
  15. #define UCHAR_MAX 255
  16. static unsigned char *
  17. boyermoore_horspool_memmem(const unsigned char* haystack, size_t hlen,
  18. const unsigned char* needle, size_t nlen)
  19. {
  20. size_t last, scan = 0;
  21. size_t bad_char_skip[UCHAR_MAX + 1]; /* Officially called:
  22. * bad character shift */
  23. /* Sanity checks on the parameters */
  24. if (nlen <= 0 || !haystack || !needle)
  25. return NULL;
  26. /* ---- Preprocess ---- */
  27. /* Initialize the table to default value */
  28. /* When a character is encountered that does not occur
  29. * in the needle, we can safely skip ahead for the whole
  30. * length of the needle.
  31. */
  32. for (scan = 0; scan <= UCHAR_MAX; scan = scan + 1)
  33. bad_char_skip[scan] = nlen;
  34. /* C arrays have the first byte at [0], therefore:
  35. * [nlen - 1] is the last byte of the array. */
  36. last = nlen - 1;
  37. /* Then populate it with the analysis of the needle */
  38. for (scan = 0; scan < last; scan = scan + 1)
  39. bad_char_skip[needle[scan]] = last - scan;
  40. /* ---- Do the matching ---- */
  41. /* Search the haystack, while the needle can still be within it. */
  42. while (hlen >= nlen)
  43. {
  44. /* scan from the end of the needle */
  45. for (scan = last; haystack[scan] == needle[scan]; scan = scan - 1)
  46. if (scan == 0) /* If the first byte matches, we've found it. */
  47. return (void *)haystack;
  48. /* otherwise, we need to skip some bytes and start again.
  49. Note that here we are getting the skip value based on the last byte
  50. of needle, no matter where we didn't match. So if needle is: "abcd"
  51. then we are skipping based on 'd' and that value will be 4, and
  52. for "abcdd" we again skip on 'd' but the value will be only 1.
  53. The alternative of pretending that the mismatched character was
  54. the last character is slower in the normal case (E.g. finding
  55. "abcd" in "...azcd..." gives 4 by using 'd' but only
  56. 4-2==2 using 'z'. */
  57. hlen -= bad_char_skip[haystack[last]];
  58. haystack += bad_char_skip[haystack[last]];
  59. }
  60. return NULL;
  61. }
  62. /* disassembler **************************************************************/
  63. static int HighestSetBit(int N, uint32_t imm)
  64. {
  65. int i;
  66. for (i = N - 1; i >= 0; i--) {
  67. if (imm & (1 << i)) {
  68. return i;
  69. }
  70. }
  71. return -1;
  72. }
  73. static uint64_t ZeroExtendOnes(unsigned M, unsigned N) // zero extend M ones to N width
  74. {
  75. (void)N;
  76. return ((uint64_t)1 << M) - 1;
  77. }
  78. static uint64_t RORZeroExtendOnes(unsigned M, unsigned N, unsigned R)
  79. {
  80. uint64_t val = ZeroExtendOnes(M, N);
  81. if (R == 0) {
  82. return val;
  83. }
  84. return ((val >> R) & (((uint64_t)1 << (N - R)) - 1)) | ((val & (((uint64_t)1 << R) - 1)) << (N - R));
  85. }
  86. static uint64_t Replicate(uint64_t val, unsigned bits)
  87. {
  88. uint64_t ret = val;
  89. unsigned shift;
  90. for (shift = bits; shift < 64; shift += bits) { // XXX actually, it is either 32 or 64
  91. ret |= (val << shift);
  92. }
  93. return ret;
  94. }
  95. static int DecodeBitMasks(unsigned immN, unsigned imms, unsigned immr, int immediate, uint64_t *newval)
  96. {
  97. unsigned levels, S, R, esize;
  98. int len = HighestSetBit(7, (immN << 6) | (~imms & 0x3F));
  99. if (len < 1) {
  100. return -1;
  101. }
  102. levels = (unsigned) ZeroExtendOnes(len, 6);
  103. if (immediate && (imms & levels) == levels) {
  104. return -1;
  105. }
  106. S = imms & levels;
  107. R = immr & levels;
  108. esize = 1 << len;
  109. *newval = Replicate(RORZeroExtendOnes(S + 1, esize, R), esize);
  110. return 0;
  111. }
  112. static int DecodeMov(uint32_t opcode, uint64_t total, int first, uint64_t *newval)
  113. {
  114. unsigned o = (opcode >> 29) & 3;
  115. unsigned k = (opcode >> 23) & 0x3F;
  116. unsigned rn, rd;
  117. uint64_t i;
  118. if (k == 0x24 && o == 1) { // MOV (bitmask imm) <=> ORR (immediate)
  119. unsigned s = (opcode >> 31) & 1;
  120. unsigned N = (opcode >> 22) & 1;
  121. if (s == 0 && N != 0) {
  122. return -1;
  123. }
  124. rn = (opcode >> 5) & 0x1F;
  125. if (rn == 31) {
  126. unsigned imms = (opcode >> 10) & 0x3F;
  127. unsigned immr = (opcode >> 16) & 0x3F;
  128. return DecodeBitMasks(N, imms, immr, 1, newval);
  129. }
  130. } else if (k == 0x25) { // MOVN/MOVZ/MOVK
  131. unsigned s = (opcode >> 31) & 1;
  132. unsigned h = (opcode >> 21) & 3;
  133. if (s == 0 && h > 1) {
  134. return -1;
  135. }
  136. i = (opcode >> 5) & 0xFFFF;
  137. h *= 16;
  138. i <<= h;
  139. if (o == 0) { // MOVN
  140. *newval = ~i;
  141. return 0;
  142. } else if (o == 2) { // MOVZ
  143. *newval = i;
  144. return 0;
  145. } else if (o == 3 && !first) { // MOVK
  146. *newval = (total & ~((uint64_t)0xFFFF << h)) | i;
  147. return 0;
  148. }
  149. } else if ((k | 1) == 0x23 && !first) { // ADD (immediate)
  150. unsigned h = (opcode >> 22) & 3;
  151. if (h > 1) {
  152. return -1;
  153. }
  154. rd = opcode & 0x1F;
  155. rn = (opcode >> 5) & 0x1F;
  156. if (rd != rn) {
  157. return -1;
  158. }
  159. i = (opcode >> 10) & 0xFFF;
  160. h *= 12;
  161. i <<= h;
  162. if (o & 2) { // SUB
  163. *newval = total - i;
  164. return 0;
  165. } else { // ADD
  166. *newval = total + i;
  167. return 0;
  168. }
  169. }
  170. return -1;
  171. }
  172. /* patchfinder ***************************************************************/
  173. static addr_t
  174. step64(const uint8_t *buf, addr_t start, size_t length, uint32_t what, uint32_t mask)
  175. {
  176. addr_t end = start + length;
  177. while (start < end) {
  178. uint32_t x = *(uint32_t *)(buf + start);
  179. if ((x & mask) == what) {
  180. return start;
  181. }
  182. start += 4;
  183. }
  184. return 0;
  185. }
  186. // str8 = step64_back(kernel, ref, ref - bof, INSN_STR8);
  187. static addr_t
  188. step64_back(const uint8_t *buf, addr_t start, size_t length, uint32_t what, uint32_t mask)
  189. {
  190. addr_t end = start - length;
  191. while (start >= end) {
  192. uint32_t x = *(uint32_t *)(buf + start);
  193. if ((x & mask) == what) {
  194. return start;
  195. }
  196. start -= 4;
  197. }
  198. return 0;
  199. }
  200. // Finds start of function
  201. static addr_t
  202. bof64(const uint8_t *buf, addr_t start, addr_t where)
  203. {
  204. for (; where >= start; where -= 4) {
  205. uint32_t op = *(uint32_t *)(buf + where);
  206. if ((op & 0xFFC003FF) == 0x910003FD) {
  207. unsigned delta = (op >> 10) & 0xFFF;
  208. //printf("%x: ADD X29, SP, #0x%x\n", where, delta);
  209. if ((delta & 0xF) == 0) {
  210. addr_t prev = where - ((delta >> 4) + 1) * 4;
  211. uint32_t au = *(uint32_t *)(buf + prev);
  212. if ((au & 0xFFC003E0) == 0xA98003E0) {
  213. //printf("%x: STP x, y, [SP,#-imm]!\n", prev);
  214. return prev;
  215. }
  216. }
  217. }
  218. }
  219. return 0;
  220. }
  221. static addr_t
  222. xref64(const uint8_t *buf, addr_t start, addr_t end, addr_t what)
  223. {
  224. addr_t i;
  225. uint64_t value[32];
  226. memset(value, 0, sizeof(value));
  227. end &= ~3;
  228. for (i = start & ~3; i < end; i += 4) {
  229. uint32_t op = *(uint32_t *)(buf + i);
  230. unsigned reg = op & 0x1F;
  231. if ((op & 0x9F000000) == 0x90000000) {
  232. signed adr = ((op & 0x60000000) >> 18) | ((op & 0xFFFFE0) << 8);
  233. //printf("%llx: ADRP X%d, 0x%llx\n", i, reg, ((long long)adr << 1) + (i & ~0xFFF));
  234. value[reg] = ((long long)adr << 1) + (i & ~0xFFF);
  235. /*} else if ((op & 0xFFE0FFE0) == 0xAA0003E0) {
  236. unsigned rd = op & 0x1F;
  237. unsigned rm = (op >> 16) & 0x1F;
  238. //printf("%llx: MOV X%d, X%d\n", i, rd, rm);
  239. value[rd] = value[rm];*/
  240. } else if ((op & 0xFF000000) == 0x91000000) {
  241. unsigned rn = (op >> 5) & 0x1F;
  242. unsigned shift = (op >> 22) & 3;
  243. unsigned imm = (op >> 10) & 0xFFF;
  244. if (shift == 1) {
  245. imm <<= 12;
  246. } else {
  247. //assert(shift == 0);
  248. if (shift > 1) continue;
  249. }
  250. //printf("%llx: ADD X%d, X%d, 0x%x\n", i, reg, rn, imm);
  251. value[reg] = value[rn] + imm;
  252. } else if ((op & 0xF9C00000) == 0xF9400000) {
  253. unsigned rn = (op >> 5) & 0x1F;
  254. unsigned imm = ((op >> 10) & 0xFFF) << 3;
  255. //printf("%llx: LDR X%d, [X%d, 0x%x]\n", i, reg, rn, imm);
  256. if (!imm) continue; // XXX not counted as true xref
  257. value[reg] = value[rn] + imm; // XXX address, not actual value
  258. /*} else if ((op & 0xF9C00000) == 0xF9000000) {
  259. unsigned rn = (op >> 5) & 0x1F;
  260. unsigned imm = ((op >> 10) & 0xFFF) << 3;
  261. //printf("%llx: STR X%d, [X%d, 0x%x]\n", i, reg, rn, imm);
  262. if (!imm) continue; // XXX not counted as true xref
  263. value[rn] = value[rn] + imm; // XXX address, not actual value*/
  264. } else if ((op & 0x9F000000) == 0x10000000) {
  265. signed adr = ((op & 0x60000000) >> 18) | ((op & 0xFFFFE0) << 8);
  266. //printf("%llx: ADR X%d, 0x%llx\n", i, reg, ((long long)adr >> 11) + i);
  267. value[reg] = ((long long)adr >> 11) + i;
  268. } else if ((op & 0xFF000000) == 0x58000000) {
  269. unsigned adr = (op & 0xFFFFE0) >> 3;
  270. //printf("%llx: LDR X%d, =0x%llx\n", i, reg, adr + i);
  271. value[reg] = adr + i; // XXX address, not actual value
  272. }
  273. if (value[reg] == what) {
  274. return i;
  275. }
  276. }
  277. return 0;
  278. }
  279. static addr_t
  280. calc64(const uint8_t *buf, addr_t start, addr_t end, int which)
  281. {
  282. addr_t i;
  283. uint64_t value[32];
  284. memset(value, 0, sizeof(value));
  285. end &= ~3;
  286. for (i = start & ~3; i < end; i += 4) {
  287. uint32_t op = *(uint32_t *)(buf + i);
  288. unsigned reg = op & 0x1F;
  289. if ((op & 0x9F000000) == 0x90000000) {
  290. signed adr = ((op & 0x60000000) >> 18) | ((op & 0xFFFFE0) << 8);
  291. //printf("%llx: ADRP X%d, 0x%llx\n", i, reg, ((long long)adr << 1) + (i & ~0xFFF));
  292. value[reg] = ((long long)adr << 1) + (i & ~0xFFF);
  293. /*} else if ((op & 0xFFE0FFE0) == 0xAA0003E0) {
  294. unsigned rd = op & 0x1F;
  295. unsigned rm = (op >> 16) & 0x1F;
  296. //printf("%llx: MOV X%d, X%d\n", i, rd, rm);
  297. value[rd] = value[rm];*/
  298. } else if ((op & 0xFF000000) == 0x91000000) {
  299. unsigned rn = (op >> 5) & 0x1F;
  300. unsigned shift = (op >> 22) & 3;
  301. unsigned imm = (op >> 10) & 0xFFF;
  302. if (shift == 1) {
  303. imm <<= 12;
  304. } else {
  305. //assert(shift == 0);
  306. if (shift > 1) continue;
  307. }
  308. //printf("%llx: ADD X%d, X%d, 0x%x\n", i, reg, rn, imm);
  309. value[reg] = value[rn] + imm;
  310. } else if ((op & 0xF9C00000) == 0xF9400000) {
  311. unsigned rn = (op >> 5) & 0x1F;
  312. unsigned imm = ((op >> 10) & 0xFFF) << 3;
  313. //printf("%llx: LDR X%d, [X%d, 0x%x]\n", i, reg, rn, imm);
  314. if (!imm) continue; // XXX not counted as true xref
  315. value[reg] = value[rn] + imm; // XXX address, not actual value
  316. } else if ((op & 0xF9C00000) == 0xF9000000) {
  317. unsigned rn = (op >> 5) & 0x1F;
  318. unsigned imm = ((op >> 10) & 0xFFF) << 3;
  319. //printf("%llx: STR X%d, [X%d, 0x%x]\n", i, reg, rn, imm);
  320. if (!imm) continue; // XXX not counted as true xref
  321. value[rn] = value[rn] + imm; // XXX address, not actual value
  322. } else if ((op & 0x9F000000) == 0x10000000) {
  323. signed adr = ((op & 0x60000000) >> 18) | ((op & 0xFFFFE0) << 8);
  324. //printf("%llx: ADR X%d, 0x%llx\n", i, reg, ((long long)adr >> 11) + i);
  325. value[reg] = ((long long)adr >> 11) + i;
  326. } else if ((op & 0xFF000000) == 0x58000000) {
  327. unsigned adr = (op & 0xFFFFE0) >> 3;
  328. //printf("%llx: LDR X%d, =0x%llx\n", i, reg, adr + i);
  329. value[reg] = adr + i; // XXX address, not actual value
  330. }
  331. }
  332. return value[which];
  333. }
  334. static addr_t
  335. calc64mov(const uint8_t *buf, addr_t start, addr_t end, int which)
  336. {
  337. addr_t i;
  338. uint64_t value[32];
  339. memset(value, 0, sizeof(value));
  340. end &= ~3;
  341. for (i = start & ~3; i < end; i += 4) {
  342. uint32_t op = *(uint32_t *)(buf + i);
  343. unsigned reg = op & 0x1F;
  344. uint64_t newval;
  345. int rv = DecodeMov(op, value[reg], 0, &newval);
  346. if (rv == 0) {
  347. if (((op >> 31) & 1) == 0) {
  348. newval &= 0xFFFFFFFF;
  349. }
  350. value[reg] = newval;
  351. }
  352. }
  353. return value[which];
  354. }
  355. static addr_t
  356. find_call64(const uint8_t *buf, addr_t start, size_t length)
  357. {
  358. return step64(buf, start, length, 0x94000000, 0xFC000000);
  359. }
  360. static addr_t
  361. follow_call64(const uint8_t *buf, addr_t call)
  362. {
  363. long long w;
  364. w = *(uint32_t *)(buf + call) & 0x3FFFFFF;
  365. w <<= 64 - 26;
  366. w >>= 64 - 26 - 2;
  367. return call + w;
  368. }
  369. static addr_t
  370. follow_cbz(const uint8_t *buf, addr_t cbz)
  371. {
  372. return cbz + ((*(int *)(buf + cbz) & 0x3FFFFE0) << 10 >> 13);
  373. }
  374. /* kernel iOS10 **************************************************************/
  375. #include <fcntl.h>
  376. #include <stdio.h>
  377. #include <stdlib.h>
  378. #include <unistd.h>
  379. #include <mach-o/loader.h>
  380. #ifndef __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__
  381. #define __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__
  382. #endif
  383. #ifdef __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__
  384. #include <mach/mach.h>
  385. size_t kread_electra(uint64_t where, void *p, size_t size);
  386. #endif
  387. static uint8_t *kernel = NULL;
  388. static size_t kernel_size = 0;
  389. static addr_t xnucore_base = 0;
  390. static addr_t xnucore_size = 0;
  391. static addr_t prelink_base = 0;
  392. static addr_t prelink_size = 0;
  393. static addr_t cstring_base = 0;
  394. static addr_t cstring_size = 0;
  395. static addr_t pstring_base = 0;
  396. static addr_t pstring_size = 0;
  397. static addr_t kerndumpbase = -1;
  398. static addr_t kernel_entry = 0;
  399. static void *kernel_mh = 0;
  400. static addr_t kernel_delta = 0;
  401. int
  402. init_kernel(addr_t base, const char *filename)
  403. {
  404. size_t rv;
  405. uint8_t buf[0x4000];
  406. unsigned i, j;
  407. const struct mach_header *hdr = (struct mach_header *)buf;
  408. const uint8_t *q;
  409. addr_t min = -1;
  410. addr_t max = 0;
  411. int is64 = 0;
  412. #ifdef __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__
  413. #define close(f)
  414. rv = kread_electra(base, buf, sizeof(buf));
  415. if (rv != sizeof(buf)) {
  416. return -1;
  417. }
  418. #else /* __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ */
  419. int fd = open(filename, O_RDONLY);
  420. if (fd < 0) {
  421. return -1;
  422. }
  423. rv = read(fd, buf, sizeof(buf));
  424. if (rv != sizeof(buf)) {
  425. close(fd);
  426. return -1;
  427. }
  428. #endif /* __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ */
  429. if (!MACHO(buf)) {
  430. close(fd);
  431. return -1;
  432. }
  433. if (IS64(buf)) {
  434. is64 = 4;
  435. }
  436. q = buf + sizeof(struct mach_header) + is64;
  437. for (i = 0; i < hdr->ncmds; i++) {
  438. const struct load_command *cmd = (struct load_command *)q;
  439. if (cmd->cmd == LC_SEGMENT_64) {
  440. const struct segment_command_64 *seg = (struct segment_command_64 *)q;
  441. if (min > seg->vmaddr) {
  442. min = seg->vmaddr;
  443. }
  444. if (max < seg->vmaddr + seg->vmsize) {
  445. max = seg->vmaddr + seg->vmsize;
  446. }
  447. if (!strcmp(seg->segname, "__TEXT_EXEC")) {
  448. xnucore_base = seg->vmaddr;
  449. xnucore_size = seg->filesize;
  450. }
  451. if (!strcmp(seg->segname, "__PLK_TEXT_EXEC")) {
  452. prelink_base = seg->vmaddr;
  453. prelink_size = seg->filesize;
  454. }
  455. if (!strcmp(seg->segname, "__TEXT")) {
  456. const struct section_64 *sec = (struct section_64 *)(seg + 1);
  457. for (j = 0; j < seg->nsects; j++) {
  458. if (!strcmp(sec[j].sectname, "__cstring")) {
  459. cstring_base = sec[j].addr;
  460. cstring_size = sec[j].size;
  461. }
  462. }
  463. }
  464. if (!strcmp(seg->segname, "__PRELINK_TEXT")) {
  465. const struct section_64 *sec = (struct section_64 *)(seg + 1);
  466. for (j = 0; j < seg->nsects; j++) {
  467. if (!strcmp(sec[j].sectname, "__text")) {
  468. pstring_base = sec[j].addr;
  469. pstring_size = sec[j].size;
  470. }
  471. }
  472. }
  473. if (!strcmp(seg->segname, "__LINKEDIT")) {
  474. kernel_delta = seg->vmaddr - min - seg->fileoff;
  475. }
  476. }
  477. if (cmd->cmd == LC_UNIXTHREAD) {
  478. uint32_t *ptr = (uint32_t *)(cmd + 1);
  479. uint32_t flavor = ptr[0];
  480. struct {
  481. uint64_t x[29]; /* General purpose registers x0-x28 */
  482. uint64_t fp; /* Frame pointer x29 */
  483. uint64_t lr; /* Link register x30 */
  484. uint64_t sp; /* Stack pointer x31 */
  485. uint64_t pc; /* Program counter */
  486. uint32_t cpsr; /* Current program status register */
  487. } *thread = (void *)(ptr + 2);
  488. if (flavor == 6) {
  489. kernel_entry = thread->pc;
  490. }
  491. }
  492. q = q + cmd->cmdsize;
  493. }
  494. kerndumpbase = min;
  495. xnucore_base -= kerndumpbase;
  496. prelink_base -= kerndumpbase;
  497. cstring_base -= kerndumpbase;
  498. pstring_base -= kerndumpbase;
  499. kernel_size = max - min;
  500. #ifdef __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__
  501. kernel = malloc(kernel_size);
  502. if (!kernel) {
  503. return -1;
  504. }
  505. rv = kread_electra(kerndumpbase, kernel, kernel_size);
  506. if (rv != kernel_size) {
  507. free(kernel);
  508. return -1;
  509. }
  510. kernel_mh = kernel + base - min;
  511. (void)filename;
  512. #undef close
  513. #else /* __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ */
  514. kernel = calloc(1, kernel_size);
  515. if (!kernel) {
  516. close(fd);
  517. return -1;
  518. }
  519. q = buf + sizeof(struct mach_header) + is64;
  520. for (i = 0; i < hdr->ncmds; i++) {
  521. const struct load_command *cmd = (struct load_command *)q;
  522. if (cmd->cmd == LC_SEGMENT_64) {
  523. const struct segment_command_64 *seg = (struct segment_command_64 *)q;
  524. size_t sz = pread(fd, kernel + seg->vmaddr - min, seg->filesize, seg->fileoff);
  525. if (sz != seg->filesize) {
  526. close(fd);
  527. free(kernel);
  528. return -1;
  529. }
  530. if (!kernel_mh) {
  531. kernel_mh = kernel + seg->vmaddr - min;
  532. }
  533. printf("%s\n", seg->segname);
  534. if (!strcmp(seg->segname, "__LINKEDIT")) {
  535. kernel_delta = seg->vmaddr - min - seg->fileoff;
  536. }
  537. }
  538. q = q + cmd->cmdsize;
  539. }
  540. close(fd);
  541. (void)base;
  542. #endif /* __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ */
  543. return 0;
  544. }
  545. void
  546. term_kernel(void)
  547. {
  548. free(kernel);
  549. }
  550. /* these operate on VA ******************************************************/
  551. #define INSN_RET 0xD65F03C0, 0xFFFFFFFF
  552. #define INSN_CALL 0x94000000, 0xFC000000
  553. #define INSN_B 0x14000000, 0xFC000000
  554. #define INSN_CBZ 0x34000000, 0xFC000000
  555. #define INSN_ADRP 0x90000000, 0x9F000000
  556. addr_t
  557. find_register_value(addr_t where, int reg)
  558. {
  559. addr_t val;
  560. addr_t bof = 0;
  561. where -= kerndumpbase;
  562. if (where > xnucore_base) {
  563. bof = bof64(kernel, xnucore_base, where);
  564. if (!bof) {
  565. bof = xnucore_base;
  566. }
  567. } else if (where > prelink_base) {
  568. bof = bof64(kernel, prelink_base, where);
  569. if (!bof) {
  570. bof = prelink_base;
  571. }
  572. }
  573. val = calc64(kernel, bof, where, reg);
  574. if (!val) {
  575. return 0;
  576. }
  577. return val + kerndumpbase;
  578. }
  579. addr_t
  580. find_reference_electra(addr_t to, int n, int prelink)
  581. {
  582. addr_t ref, end;
  583. addr_t base = xnucore_base;
  584. addr_t size = xnucore_size;
  585. if (prelink) {
  586. base = prelink_base;
  587. size = prelink_size;
  588. }
  589. if (n <= 0) {
  590. n = 1;
  591. }
  592. end = base + size;
  593. to -= kerndumpbase;
  594. do {
  595. ref = xref64(kernel, base, end, to);
  596. if (!ref) {
  597. return 0;
  598. }
  599. base = ref + 4;
  600. } while (--n > 0);
  601. return ref + kerndumpbase;
  602. }
  603. addr_t
  604. find_strref_electra(const char *string, int n, int prelink)
  605. {
  606. uint8_t *str;
  607. addr_t base = cstring_base;
  608. addr_t size = cstring_size;
  609. if (prelink) {
  610. base = pstring_base;
  611. size = pstring_size;
  612. }
  613. str = boyermoore_horspool_memmem(kernel + base, size, (uint8_t *)string, strlen(string));
  614. if (!str) {
  615. return 0;
  616. }
  617. return find_reference_electra(str - kernel + kerndumpbase, n, prelink);
  618. }
  619. /****** fun *******/
  620. addr_t find_add_x0_x0_0x40_ret(void) {
  621. addr_t off;
  622. uint32_t *k;
  623. k = (uint32_t *)(kernel + xnucore_base);
  624. for (off = 0; off < xnucore_size - 4; off += 4, k++) {
  625. if (k[0] == 0x91010000 && k[1] == 0xD65F03C0) {
  626. return off + xnucore_base + kerndumpbase;
  627. }
  628. }
  629. k = (uint32_t *)(kernel + prelink_base);
  630. for (off = 0; off < prelink_size - 4; off += 4, k++) {
  631. if (k[0] == 0x91010000 && k[1] == 0xD65F03C0) {
  632. return off + prelink_base + kerndumpbase;
  633. }
  634. }
  635. return 0;
  636. }
  637. uint64_t find_allproc_electra(void) {
  638. // Find the first reference to the string
  639. addr_t ref = find_strref_electra("\"pgrp_add : pgrp is dead adding process\"", 1, 0);
  640. if (!ref) {
  641. return 0;
  642. }
  643. ref -= kerndumpbase;
  644. uint64_t start = bof64(kernel, xnucore_base, ref);
  645. if (!start) {
  646. return 0;
  647. }
  648. // Find AND W8, W8, #0xFFFFDFFF - it's a pretty distinct instruction
  649. addr_t weird_instruction = 0;
  650. for (int i = 4; i < 4*0x100; i+=4) {
  651. uint32_t op = *(uint32_t *)(kernel + ref + i);
  652. if (op == 0x12127908) {
  653. weird_instruction = ref+i;
  654. break;
  655. }
  656. }
  657. if (!weird_instruction) {
  658. return 0;
  659. }
  660. uint64_t val = calc64(kernel, start, weird_instruction - 8, 8);
  661. if (!val) {
  662. printf("Failed to calculate x8");
  663. return 0;
  664. }
  665. return val + kerndumpbase;
  666. }
  667. uint64_t find_copyout_electra(void) {
  668. // Find the first reference to the string
  669. addr_t ref = find_strref_electra("\"%s(%p, %p, %lu) - transfer too large\"", 2, 0);
  670. if (!ref) {
  671. return 0;
  672. }
  673. ref -= kerndumpbase;
  674. uint64_t start = 0;
  675. for (int i = 4; i < 0x100*4; i+=4) {
  676. uint32_t op = *(uint32_t*)(kernel+ref-i);
  677. if (op == 0xd10143ff) { // SUB SP, SP, #0x50
  678. start = ref-i;
  679. break;
  680. }
  681. }
  682. if (!start) {
  683. return 0;
  684. }
  685. return start + kerndumpbase;
  686. }
  687. uint64_t find_bzero_electra(void) {
  688. // Just find SYS #3, c7, c4, #1, X3, then get the start of that function
  689. addr_t off;
  690. uint32_t *k;
  691. k = (uint32_t *)(kernel + xnucore_base);
  692. for (off = 0; off < xnucore_size - 4; off += 4, k++) {
  693. if (k[0] == 0xd50b7423) {
  694. off += xnucore_base;
  695. break;
  696. }
  697. }
  698. uint64_t start = bof64(kernel, xnucore_base, off);
  699. if (!start) {
  700. return 0;
  701. }
  702. return start + kerndumpbase;
  703. }
  704. addr_t find_bcopy_electra(void) {
  705. // Jumps straight into memmove after switching x0 and x1 around
  706. // Guess we just find the switch and that's it
  707. addr_t off;
  708. uint32_t *k;
  709. k = (uint32_t *)(kernel + xnucore_base);
  710. for (off = 0; off < xnucore_size - 4; off += 4, k++) {
  711. if (k[0] == 0xAA0003E3 && k[1] == 0xAA0103E0 && k[2] == 0xAA0303E1 && k[3] == 0xd503201F) {
  712. return off + xnucore_base + kerndumpbase;
  713. }
  714. }
  715. k = (uint32_t *)(kernel + prelink_base);
  716. for (off = 0; off < prelink_size - 4; off += 4, k++) {
  717. if (k[0] == 0xAA0003E3 && k[1] == 0xAA0103E0 && k[2] == 0xAA0303E1 && k[3] == 0xd503201F) {
  718. return off + prelink_base + kerndumpbase;
  719. }
  720. }
  721. return 0;
  722. }
  723. uint64_t find_rootvnode(void) {
  724. // Find the first reference to the string
  725. addr_t ref = find_strref_electra("/var/run/.vfs_rsrc_streams_%p%x", 1, 0);
  726. if (!ref) {
  727. return 0;
  728. }
  729. ref -= kerndumpbase;
  730. uint64_t start = bof64(kernel, xnucore_base, ref);
  731. if (!start) {
  732. return 0;
  733. }
  734. // Find MOV X9, #0x2000000000 - it's a pretty distinct instruction
  735. addr_t weird_instruction = 0;
  736. for (int i = 4; i < 4*0x100; i+=4) {
  737. uint32_t op = *(uint32_t *)(kernel + ref - i);
  738. if (op == 0xB25B03E9) {
  739. weird_instruction = ref-i;
  740. break;
  741. }
  742. }
  743. if (!weird_instruction) {
  744. return 0;
  745. }
  746. uint64_t val = calc64(kernel, start, weird_instruction, 8);
  747. if (!val) {
  748. return 0;
  749. }
  750. return val + kerndumpbase;
  751. }
  752. addr_t find_trustcache_electra(void) {
  753. addr_t call, func, val;
  754. addr_t ref = find_strref_electra("com.apple.MobileFileIntegrity", 1, 1);
  755. if (!ref) {
  756. return 0;
  757. }
  758. ref -= kerndumpbase;
  759. call = step64(kernel, ref, 32, INSN_CALL);
  760. if (!call) {
  761. return 0;
  762. }
  763. call = step64(kernel, call+4, 32, INSN_CALL);
  764. func = follow_call64(kernel, call);
  765. if (!func) {
  766. return 0;
  767. }
  768. val = calc64(kernel, func, func + 16, 8);
  769. if (!val) {
  770. return 0;
  771. }
  772. return val + kerndumpbase;
  773. }
  774. addr_t find_amficache_electra(void) {
  775. addr_t call, func, bof, val;
  776. addr_t ref = find_strref_electra("com.apple.MobileFileIntegrity", 1, 1);
  777. if (!ref) {
  778. return 0;
  779. }
  780. ref -= kerndumpbase;
  781. call = step64(kernel, ref, 32, INSN_CALL);
  782. if (!call) {
  783. return 0;
  784. }
  785. call = step64(kernel, call+4, 32, INSN_CALL);
  786. func = follow_call64(kernel, call);
  787. if (!func) {
  788. return 0;
  789. }
  790. bof = bof64(kernel, func - 256, func);
  791. if (!bof) {
  792. return 0;
  793. }
  794. val = calc64(kernel, bof, func, 9);
  795. if (!val) {
  796. return 0;
  797. }
  798. return val + kerndumpbase;
  799. }
  800. addr_t find_realhost(void) {
  801. uint64_t val = kerndumpbase;
  802. addr_t ref1 = find_strref_electra("\"ipc_init: kmem_suballoc of ipc_kernel_copy_map failed\"", 1, 0);
  803. ref1 -= kerndumpbase;
  804. addr_t ref2 = find_strref_electra("\"ipc_host_init\"", 1, 0);
  805. ref2 -= kerndumpbase;
  806. addr_t call = ref2;
  807. call = step64(kernel, call+4, 32, INSN_CALL); // panic
  808. call = step64(kernel, call+4, 32, INSN_CALL); // something about
  809. call = step64(kernel, call+4, 32, INSN_CALL); // allocing ports
  810. call = step64(kernel, call+4, 32, INSN_CALL); // _lck_mtx_lock
  811. call -= 4; // previous insn
  812. uint32_t mov_opcode = *(uint32_t*)(kernel+call);
  813. // must be mov x0, xm
  814. if ((mov_opcode & 0xAA0003E0) != 0xAA0003E0) {
  815. return 0;
  816. }
  817. uint8_t xm = (mov_opcode & 0x1F0000) >> 16;
  818. uint32_t *insn = (uint32_t*)(kernel+ref1);
  819. int i = 0;
  820. // adrp xX, #_realhost@PAGE
  821. for (i = 0; i != ref2 - ref1; ++i) {
  822. if ((insn[i] & xm) == xm && (insn[i] & 0x9F000000) == 0x90000000)
  823. break;
  824. }
  825. if (i == ref2 - ref1) {
  826. return 0;
  827. }
  828. // get pc
  829. val += ((uint8_t*)(insn + i) - kernel) & ~0xfff;
  830. // don't ask, I wrote this at 5am
  831. val += (insn[i]<<9 & 0x1ffffc000) | (insn[i]>>17 & 0x3000);
  832. // add xX, xX, #_realhost@PAGEOFF
  833. ++i;
  834. // xd == xX, xn == xX, SS == 00
  835. if ((insn[i]&0x1f) != xm || ((insn[i]>>5)&0x1f) != xm || ((insn[i]>>22)&3) != 0) {
  836. return 0;
  837. }
  838. val += (insn[i]>>10) & 0xfff;
  839. return val;
  840. }
  841. addr_t find_zone_map_ref(void) {
  842. // \"Nothing being freed to the zone_map. start = end = %p\\n\"
  843. uint64_t val = kerndumpbase;
  844. addr_t ref = find_strref_electra("\"Nothing being freed to the zone_map. start = end = %p\\n\"", 1, 0);
  845. ref -= kerndumpbase;
  846. // skip add & adrp for panic str
  847. ref -= 8;
  848. // adrp xX, #_zone_map@PAGE
  849. ref = step64_back(kernel, ref, 30, INSN_ADRP);
  850. uint32_t *insn = (uint32_t*)(kernel+ref);
  851. // get pc
  852. val += ((uint8_t*)(insn) - kernel) & ~0xfff;
  853. uint8_t xm = *insn & 0x1f;
  854. // don't ask, I wrote this at 5am
  855. val += (*insn<<9 & 0x1ffffc000) | (*insn>>17 & 0x3000);
  856. // ldr x, [xX, #_zone_map@PAGEOFF]
  857. ++insn;
  858. if ((*insn & 0xF9C00000) != 0xF9400000) {
  859. return 0;
  860. }
  861. // xd == xX, xn == xX,
  862. if ((*insn&0x1f) != xm || ((*insn>>5)&0x1f) != xm) {
  863. return 0;
  864. }
  865. val += ((*insn >> 10) & 0xFFF) << 3;
  866. return val;
  867. }