inject_criticald.m 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540
  1. /* code comes from IB's triple_fetch inject_amfid.c */
  2. #include <dlfcn.h>
  3. #include <stdio.h>
  4. #include <unistd.h>
  5. #include <sys/types.h>
  6. #include <mach/mach.h>
  7. #include <mach-o/loader.h>
  8. #include <mach/error.h>
  9. #include <errno.h>
  10. #include <stdlib.h>
  11. #include <sys/sysctl.h>
  12. #include <dlfcn.h>
  13. #include <sys/mman.h>
  14. #include <spawn.h>
  15. #include <sys/stat.h>
  16. #include <pthread.h>
  17. #include <signal.h>
  18. #import <Foundation/Foundation.h>
  19. kern_return_t mach_vm_allocate
  20. (
  21. vm_map_t target,
  22. mach_vm_address_t *address,
  23. mach_vm_size_t size,
  24. int flags
  25. );
  26. kern_return_t mach_vm_write
  27. (
  28. vm_map_t target_task,
  29. mach_vm_address_t address,
  30. vm_offset_t data,
  31. mach_msg_type_number_t dataCnt
  32. );
  33. extern kern_return_t mach_vm_deallocate
  34. (
  35. vm_map_t target,
  36. mach_vm_address_t address,
  37. mach_vm_size_t size
  38. );
  39. kern_return_t mach_vm_read_overwrite(vm_map_t target_task, mach_vm_address_t address, mach_vm_size_t size, mach_vm_address_t data, mach_vm_size_t *outsize);
  40. kern_return_t mach_vm_region(vm_map_t target_task, mach_vm_address_t *address, mach_vm_size_t *size, vm_region_flavor_t flavor, vm_region_info_t info, mach_msg_type_number_t *infoCnt, mach_port_t *object_name);
  41. mach_port_t tfpzero = 0;
  42. uint64_t kalloc(vm_size_t size) {
  43. mach_vm_address_t address = 0;
  44. mach_vm_allocate(tfpzero, (mach_vm_address_t *)&address, size, VM_FLAGS_ANYWHERE);
  45. return address;
  46. }
  47. size_t kread(uint64_t where, void *p, size_t size) {
  48. int rv;
  49. size_t offset = 0;
  50. while (offset < size) {
  51. mach_vm_size_t sz, chunk = 2048;
  52. if (chunk > size - offset) {
  53. chunk = size - offset;
  54. }
  55. rv = mach_vm_read_overwrite(tfpzero, where + offset, chunk, (mach_vm_address_t)p + offset, &sz);
  56. if (rv || sz == 0) {
  57. printf("[fun_utils] error on kread(0x%016llx)\n", (offset + where));
  58. break;
  59. }
  60. offset += sz;
  61. }
  62. return offset;
  63. }
  64. uint32_t kread32(uint64_t where) {
  65. uint32_t out;
  66. kread(where, &out, sizeof(uint32_t));
  67. return out;
  68. }
  69. uint64_t kread64(uint64_t where) {
  70. uint64_t out;
  71. kread(where, &out, sizeof(uint64_t));
  72. return out;
  73. }
  74. size_t kwrite(uint64_t where, const void *p, size_t size) {
  75. int rv;
  76. size_t offset = 0;
  77. while (offset < size) {
  78. size_t chunk = 2048;
  79. if (chunk > size - offset) {
  80. chunk = size - offset;
  81. }
  82. rv = mach_vm_write(tfpzero, where + offset, (mach_vm_offset_t)p + offset, chunk);
  83. if (rv) {
  84. printf("[fun_utils] error on kwrite(0x%016llx)\n", (offset + where));
  85. break;
  86. }
  87. offset += chunk;
  88. }
  89. return offset;
  90. }
  91. void kwrite32(uint64_t where, uint32_t what) {
  92. uint32_t _what = what;
  93. kwrite(where, &_what, sizeof(uint32_t));
  94. }
  95. void kwrite64(uint64_t where, uint64_t what) {
  96. uint64_t _what = what;
  97. kwrite(where, &_what, sizeof(uint64_t));
  98. }
  99. uint64_t
  100. remote_alloc(mach_port_t task_port,
  101. uint64_t size)
  102. {
  103. kern_return_t err;
  104. mach_vm_offset_t remote_addr = 0;
  105. mach_vm_size_t remote_size = (mach_vm_size_t)size;
  106. err = mach_vm_allocate(task_port, &remote_addr, remote_size, 1); // ANYWHERE
  107. if (err != KERN_SUCCESS){
  108. NSLog(@"unable to allocate buffer in remote process\n");
  109. return 0;
  110. }
  111. return (uint64_t)remote_addr;
  112. }
  113. void
  114. remote_free(mach_port_t task_port,
  115. uint64_t base,
  116. uint64_t size)
  117. {
  118. kern_return_t err;
  119. err = mach_vm_deallocate(task_port, (mach_vm_address_t)base, (mach_vm_size_t)size);
  120. if (err != KERN_SUCCESS){
  121. NSLog(@"unabble to deallocate remote buffer\n");
  122. return;
  123. }
  124. return;
  125. }
  126. uint64_t
  127. alloc_and_fill_remote_buffer(mach_port_t task_port,
  128. uint64_t local_address,
  129. uint64_t length)
  130. {
  131. kern_return_t err;
  132. uint64_t remote_address = remote_alloc(task_port, length);
  133. err = mach_vm_write(task_port, remote_address, (mach_vm_offset_t)local_address, (mach_msg_type_number_t)length);
  134. if (err != KERN_SUCCESS){
  135. NSLog(@"unable to write to remote memory\n");
  136. return 0;
  137. }
  138. return remote_address;
  139. }
  140. void
  141. remote_read_overwrite(mach_port_t task_port,
  142. uint64_t remote_address,
  143. uint64_t local_address,
  144. uint64_t length)
  145. {
  146. kern_return_t err;
  147. mach_vm_size_t outsize = 0;
  148. err = mach_vm_read_overwrite(task_port, (mach_vm_address_t)remote_address, (mach_vm_size_t)length, (mach_vm_address_t)local_address, &outsize);
  149. if (err != KERN_SUCCESS){
  150. NSLog(@"remote read failed\n");
  151. return;
  152. }
  153. if (outsize != length){
  154. NSLog(@"remote read was short (expected %llx, got %llx\n", length, outsize);
  155. return;
  156. }
  157. }
  158. void
  159. remote_write(mach_port_t remote_task_port,
  160. uint64_t remote_address,
  161. uint64_t local_address,
  162. uint64_t length)
  163. {
  164. kern_return_t err = mach_vm_write(remote_task_port,
  165. (mach_vm_address_t)remote_address,
  166. (vm_offset_t)local_address,
  167. (mach_msg_type_number_t)length);
  168. if (err != KERN_SUCCESS) {
  169. NSLog(@"remote write failed: %s %x\n", mach_error_string(err), err);
  170. return;
  171. }
  172. }
  173. enum arg_type {
  174. ARG_LITERAL,
  175. ARG_BUFFER,
  176. ARG_BUFFER_PERSISTENT, // don't free the buffer after the call
  177. ARG_OUT_BUFFER,
  178. ARG_INOUT_BUFFER
  179. };
  180. typedef struct _arg_desc {
  181. uint64_t type;
  182. uint64_t value;
  183. uint64_t length;
  184. } arg_desc;
  185. #define REMOTE_LITERAL(val) &(arg_desc){ARG_LITERAL, (uint64_t)val, (uint64_t)0}
  186. #define REMOTE_BUFFER(ptr, size) &(arg_desc){ARG_BUFFER, (uint64_t)ptr, (uint64_t)size}
  187. #define REMOTE_CSTRING(str) &(arg_desc){ARG_BUFFER, (uint64_t)str, (uint64_t)(strlen(str)+1)}
  188. #define REMOTE_BUFFER_PERSISTENT(ptr, size) &(arg_desc){ARG_BUFFER_PERSISTENT, (uint64_t)ptr, (uint64_t)size}
  189. #define REMOTE_CSTRING_PERSISTENT(str) &(arg_desc){ARG_BUFFER_PERSISTENT, (uint64_t)str, (uint64_t)(strlen(str)+1)}
  190. #define REMOTE_OUT_BUFFER(ptr, size) &(arg_desc){ARG_OUT_BUFFER, (uint64_t)ptr, (uint64_t)size}
  191. #define REMOTE_INOUT_BUFFER(ptr, size) &(arg_desc){ARG_INOUT_BUFFER, (uint64_t)ptr, (uint64_t)size}
  192. uint64_t
  193. find_gadget_candidate(
  194. char** alternatives,
  195. size_t gadget_length)
  196. {
  197. void* haystack_start = (void*)atoi; // will do...
  198. size_t haystack_size = 100*1024*1024; // likewise...
  199. for (char* candidate = *alternatives; candidate != NULL; alternatives++) {
  200. void* found_at = memmem(haystack_start, haystack_size, candidate, gadget_length);
  201. if (found_at != NULL){
  202. NSLog(@"found at: %llx\n", (uint64_t)found_at);
  203. return (uint64_t)found_at;
  204. }
  205. }
  206. return 0;
  207. }
  208. uint64_t blr_x19_addr = 0;
  209. uint64_t
  210. find_blr_x19_gadget()
  211. {
  212. if (blr_x19_addr != 0){
  213. return blr_x19_addr;
  214. }
  215. char* blr_x19 = "\x60\x02\x3f\xd6";
  216. char* candidates[] = {blr_x19, NULL};
  217. blr_x19_addr = find_gadget_candidate(candidates, 4);
  218. return blr_x19_addr;
  219. }
  220. // no support for non-register args
  221. #define MAX_REMOTE_ARGS 8
  222. // not in iOS SDK headers:
  223. extern void
  224. _pthread_set_self(
  225. pthread_t p);
  226. uint64_t call_remote(mach_port_t task_port, void* fptr, int n_params, ...)
  227. {
  228. if (n_params > MAX_REMOTE_ARGS || n_params < 0){
  229. NSLog(@"unsupported number of arguments to remote function (%d)\n", n_params);
  230. return 0;
  231. }
  232. kern_return_t err;
  233. uint64_t remote_stack_base = 0;
  234. uint64_t remote_stack_size = 4*1024*1024;
  235. remote_stack_base = remote_alloc(task_port, remote_stack_size);
  236. uint64_t remote_stack_middle = remote_stack_base + (remote_stack_size/2);
  237. // create a new thread in the target
  238. // just using the mach thread API doesn't initialize the pthread thread-local-storage
  239. // which means that stuff which relies on that will crash
  240. // we can sort-of make that work by calling _pthread_set_self(NULL) in the target process
  241. // which will give the newly created thread the same TLS region as the main thread
  242. _STRUCT_ARM_THREAD_STATE64 thread_state = {{0}};
  243. mach_msg_type_number_t thread_stateCnt = sizeof(thread_state)/4;
  244. // we'll start the thread running and call _pthread_set_self first:
  245. thread_state.__sp = remote_stack_middle;
  246. thread_state.__pc = (uint64_t)_pthread_set_self;
  247. // set these up to put us into a predictable state we can monitor for:
  248. uint64_t loop_lr = find_blr_x19_gadget();
  249. thread_state.__x[19] = loop_lr;
  250. thread_state.__lr = loop_lr;
  251. // set the argument to NULL:
  252. thread_state.__x[0] = 0;
  253. mach_port_t thread_port = MACH_PORT_NULL;
  254. err = thread_create_running(task_port, ARM_THREAD_STATE64, (thread_state_t)&thread_state, thread_stateCnt, &thread_port);
  255. if (err != KERN_SUCCESS){
  256. NSLog(@"error creating thread in child: %s\n", mach_error_string(err));
  257. return 0;
  258. }
  259. // NSLog(@"new thread running in child: %x\n", thread_port);
  260. // wait for it to hit the loop:
  261. while(1){
  262. // monitor the thread until we see it's in the infinite loop indicating it's done:
  263. err = thread_get_state(thread_port, ARM_THREAD_STATE64, (thread_state_t)&thread_state, &thread_stateCnt);
  264. if (err != KERN_SUCCESS){
  265. NSLog(@"error getting thread state: %s\n", mach_error_string(err));
  266. return 0;
  267. }
  268. if (thread_state.__pc == loop_lr && thread_state.__x[19] == loop_lr){
  269. // thread has returned from the target function
  270. break;
  271. }
  272. }
  273. // the thread should now have pthread local storage
  274. // pause it:
  275. err = thread_suspend(thread_port);
  276. if (err != KERN_SUCCESS){
  277. NSLog(@"unable to suspend target thread\n");
  278. return 0;
  279. }
  280. /*
  281. err = thread_abort(thread_port);
  282. if (err != KERN_SUCCESS){
  283. NSLog(@"unable to get thread out of any traps\n");
  284. return 0;
  285. }
  286. */
  287. // set up for the actual target call:
  288. thread_state.__sp = remote_stack_middle;
  289. thread_state.__pc = (uint64_t)fptr;
  290. // set these up to put us into a predictable state we can monitor for:
  291. thread_state.__x[19] = loop_lr;
  292. thread_state.__lr = loop_lr;
  293. va_list ap;
  294. va_start(ap, n_params);
  295. arg_desc* args[MAX_REMOTE_ARGS] = {0};
  296. uint64_t remote_buffers[MAX_REMOTE_ARGS] = {0};
  297. //uint64_t remote_buffer_sizes[MAX_REMOTE_ARGS] = {0};
  298. for (int i = 0; i < n_params; i++){
  299. arg_desc* arg = va_arg(ap, arg_desc*);
  300. args[i] = arg;
  301. switch(arg->type){
  302. case ARG_LITERAL:
  303. {
  304. thread_state.__x[i] = arg->value;
  305. break;
  306. }
  307. case ARG_BUFFER:
  308. case ARG_BUFFER_PERSISTENT:
  309. case ARG_INOUT_BUFFER:
  310. {
  311. uint64_t remote_buffer = alloc_and_fill_remote_buffer(task_port, arg->value, arg->length);
  312. remote_buffers[i] = remote_buffer;
  313. thread_state.__x[i] = remote_buffer;
  314. break;
  315. }
  316. case ARG_OUT_BUFFER:
  317. {
  318. uint64_t remote_buffer = remote_alloc(task_port, arg->length);
  319. // NSLog(@"allocated a remote out buffer: %llx\n", remote_buffer);
  320. remote_buffers[i] = remote_buffer;
  321. thread_state.__x[i] = remote_buffer;
  322. break;
  323. }
  324. default:
  325. {
  326. NSLog(@"invalid argument type!\n");
  327. }
  328. }
  329. }
  330. va_end(ap);
  331. err = thread_set_state(thread_port, ARM_THREAD_STATE64, (thread_state_t)&thread_state, thread_stateCnt);
  332. if (err != KERN_SUCCESS){
  333. NSLog(@"error setting new thread state: %s\n", mach_error_string(err));
  334. return 0;
  335. }
  336. // NSLog(@"thread state updated in target: %x\n", thread_port);
  337. err = thread_resume(thread_port);
  338. if (err != KERN_SUCCESS){
  339. NSLog(@"unable to resume target thread\n");
  340. return 0;
  341. }
  342. while(1){
  343. // monitor the thread until we see it's in the infinite loop indicating it's done:
  344. err = thread_get_state(thread_port, ARM_THREAD_STATE64, (thread_state_t)&thread_state, &thread_stateCnt);
  345. if (err != KERN_SUCCESS){
  346. NSLog(@"error getting thread state: %s\n", mach_error_string(err));
  347. return 0;
  348. }
  349. if (thread_state.__pc == loop_lr/*&& thread_state.__x[19] == loop_lr*/){
  350. // thread has returned from the target function
  351. break;
  352. }
  353. // thread isn't in the infinite loop yet, let it continue
  354. }
  355. // deallocate the remote thread
  356. err = thread_terminate(thread_port);
  357. if (err != KERN_SUCCESS){
  358. NSLog(@"failed to terminate thread\n");
  359. return 0;
  360. }
  361. mach_port_deallocate(mach_task_self(), thread_port);
  362. // handle post-call argument cleanup/copying:
  363. for (int i = 0; i < MAX_REMOTE_ARGS; i++){
  364. arg_desc* arg = args[i];
  365. if (arg == NULL){
  366. break;
  367. }
  368. switch (arg->type){
  369. case ARG_BUFFER:
  370. {
  371. remote_free(task_port, remote_buffers[i], arg->length);
  372. break;
  373. }
  374. case ARG_INOUT_BUFFER:
  375. case ARG_OUT_BUFFER:
  376. {
  377. // copy the contents back:
  378. remote_read_overwrite(task_port, remote_buffers[i], arg->value, arg->length);
  379. remote_free(task_port, remote_buffers[i], arg->length);
  380. break;
  381. }
  382. }
  383. }
  384. uint64_t ret_val = thread_state.__x[0];
  385. // NSLog(@"remote function call return value: %llx\n", ret_val);
  386. // deallocate the stack in the target:
  387. remote_free(task_port, remote_stack_base, remote_stack_size);
  388. return ret_val;
  389. }
  390. uint64_t binary_load_address(mach_port_t tp) {
  391. kern_return_t err;
  392. mach_msg_type_number_t region_count = VM_REGION_BASIC_INFO_COUNT_64;
  393. memory_object_name_t object_name = MACH_PORT_NULL; /* unused */
  394. mach_vm_size_t target_first_size = 0x1000;
  395. mach_vm_address_t target_first_addr = 0x0;
  396. struct vm_region_basic_info_64 region = {0};
  397. err = mach_vm_region(tp,
  398. &target_first_addr,
  399. &target_first_size,
  400. VM_REGION_BASIC_INFO_64,
  401. (vm_region_info_t)&region,
  402. &region_count,
  403. &object_name);
  404. if (err != KERN_SUCCESS) {
  405. printf("failed to get the region\n");
  406. return -1;
  407. }
  408. return target_first_addr;
  409. }
  410. int main(int argc, char* argv[]) {
  411. uint32_t pid = atoi(argv[1]);
  412. char *loaded_dylib = argv[2];
  413. task_t remoteTask;
  414. kern_return_t kr = task_for_pid(mach_task_self(), pid, &remoteTask);
  415. if (kr != KERN_SUCCESS) {
  416. NSLog(@"Failed to get task for pid %u!", pid);
  417. return -1;
  418. }
  419. tfpzero = (mach_port_t)remoteTask;
  420. // NSLog(@"Trying to find the start of the main binary!");
  421. uint64_t actual_addr = binary_load_address(remoteTask);
  422. if (actual_addr == -1) {
  423. NSLog(@"Couldn't find the address");
  424. return -1;
  425. }
  426. NSLog(@"Address is at %016llx", actual_addr);
  427. uint64_t handler = call_remote(remoteTask, dlopen, 2, REMOTE_CSTRING(loaded_dylib), REMOTE_LITERAL(RTLD_NOW));
  428. if (handler != 0) {
  429. NSLog(@"No error occured!");
  430. } else {
  431. uint64_t error = call_remote(remoteTask, dlerror, 0);
  432. if (error == 0) {
  433. NSLog(@"Error occured, but dlerror returned NULL!");
  434. } else {
  435. uint64_t len = call_remote(remoteTask, strlen, 1, REMOTE_LITERAL(error));
  436. char* local_cstring = malloc(len+1);
  437. remote_read_overwrite(remoteTask, error, (uint64_t)local_cstring, len+1);
  438. NSLog(@"Error is %s", local_cstring);
  439. }
  440. return -1;
  441. }
  442. return 0;
  443. }