diff options
author | comex | 2015-01-21 00:27:31 -0500 |
---|---|---|
committer | comex | 2015-01-21 00:27:31 -0500 |
commit | 21681b72291e3057577608aacf16a7841517135a (patch) | |
tree | 9a864fd2f9a7dc0e68a9d4e42aa191a8c50ae087 /lib/darwin/inject.c | |
parent | ... (diff) | |
download | substitute-21681b72291e3057577608aacf16a7841517135a.tar.gz |
woo, inject seems to work on all platforms
Diffstat (limited to 'lib/darwin/inject.c')
-rw-r--r-- | lib/darwin/inject.c | 182 |
1 files changed, 166 insertions, 16 deletions
diff --git a/lib/darwin/inject.c b/lib/darwin/inject.c index b314df6..fb35a10 100644 --- a/lib/darwin/inject.c +++ b/lib/darwin/inject.c @@ -10,6 +10,10 @@ kern_return_t mach_vm_read_overwrite(vm_map_t, mach_vm_address_t, mach_vm_size_t, mach_vm_address_t, mach_vm_size_t *); kern_return_t mach_vm_remap(vm_map_t, mach_vm_address_t *, mach_vm_size_t, mach_vm_offset_t, int, vm_map_t, mach_vm_address_t, boolean_t, vm_prot_t *, vm_prot_t *, vm_inherit_t); +kern_return_t mach_vm_write(vm_map_t, mach_vm_address_t, vm_offset_t, mach_msg_type_number_t); +kern_return_t mach_vm_allocate(vm_map_t, mach_vm_address_t *, mach_vm_size_t, int); +kern_return_t mach_vm_deallocate(vm_map_t, mach_vm_address_t, mach_vm_size_t); + #define DEFINE_STRUCTS @@ -47,6 +51,9 @@ struct dyld_all_image_infos_64 { }; static int find_foreign_images(mach_port_t task, uint64_t *libdyld_p, uint64_t *libpthread_p, char **error) { + *libdyld_p = 0; + *libpthread_p = 0; + struct task_dyld_info tdi; mach_msg_type_number_t cnt = TASK_DYLD_INFO_COUNT; @@ -73,7 +80,7 @@ static int find_foreign_images(mach_port_t task, uint64_t *libdyld_p, uint64_t * return SUBSTITUTE_ERR_MISC; } - bool is64 = tdi.all_image_info_format = TASK_DYLD_ALL_IMAGE_INFO_64; + bool is64 = tdi.all_image_info_format == TASK_DYLD_ALL_IMAGE_INFO_64; const struct dyld_all_image_infos_32 *aii32 = (void *) all_image_infos_buf; const struct dyld_all_image_infos_64 *aii64 = (void *) all_image_infos_buf; @@ -95,7 +102,6 @@ static int find_foreign_images(mach_port_t task, uint64_t *libdyld_p, uint64_t * asprintf(error, "unreasonable number of loaded libraries: %u", info_array_count); return SUBSTITUTE_ERR_MISC; } - size_t info_array_size = info_array_count * info_array_elm_size; void *info_array = malloc(info_array_count * info_array_elm_size); if (!info_array) @@ -105,6 +111,7 @@ static int find_foreign_images(mach_port_t task, uint64_t *libdyld_p, uint64_t * (mach_vm_address_t) info_array, &size); if (kr || size != info_array_size) { asprintf(error, "mach_vm_read_overwrite(info_array): kr=%d", kr); + free(info_array); return SUBSTITUTE_ERR_MISC; } @@ -147,30 +154,29 @@ static int find_foreign_images(mach_port_t task, uint64_t *libdyld_p, uint64_t * if (!strcmp(path_buf, "/usr/lib/system/libdyld.dylib")) *libdyld_p = load_address; - else if (!strcmp(path_buf, "/usr/lib/system/libpthread.dylib")) + else if (!strcmp(path_buf, "/usr/lib/system/libsystem_pthread.dylib")) *libpthread_p = load_address; - if (*libdyld_p && *libpthread_p) + if (*libdyld_p && *libpthread_p) { + free(info_array); return SUBSTITUTE_OK; + } info_array_ptr += info_array_elm_size; } - asprintf(error, "couldn't find libpthread"); + free(info_array); + asprintf(error, "couldn't find libdyld or libpthread"); return SUBSTITUTE_ERR_MISC; } static int get_foreign_image_export(mach_port_t task, uint64_t hdr_addr, void **linkedit_p, size_t *linkedit_size_p, void **export_p, size_t *export_size_p, - char **error) { - mach_vm_offset_t hdr_buf; + cpu_type_t *cputype_p, char **error) { + mach_vm_offset_t hdr_buf = 0; mach_vm_size_t hdr_buf_size; int ret; - if (hdr_addr & (PAGE_SIZE - 1)) { - asprintf(error, "unaligned mach_header"); - return SUBSTITUTE_ERR_MISC; - } vm_prot_t cur, max; hdr_buf_size = PAGE_SIZE; @@ -189,6 +195,8 @@ static int get_foreign_image_export(mach_port_t task, uint64_t hdr_addr, goto fail; } + *cputype_p = mh->cputype; + size_t mh_size = mh->magic == MH_MAGIC_64 ? sizeof(struct mach_header_64) : sizeof(struct mach_header); if (mh->sizeofcmds < mh_size || mh->sizeofcmds > 128*1024) @@ -350,9 +358,28 @@ got_symbol:; return true; } +struct _x86_thread_state_32 { + uint32_t eax, ebx, ecx, edx, edi, esi, ebp, esp; + uint32_t ss, eflags, eip, cs, ds, es, fs, gs; +}; +struct _x86_thread_state_64 { + uint64_t rax, rbx, rcx, rdx, rdi, rsi, rbp, rsp; + uint64_t r8, r9, r10, r11, r12, r13, r14, r15; + uint64_t rip, rflags, cs, fs, gs; +}; +struct _arm_thread_state_32 { + uint32_t r[13], sp, lr, pc, cpsr; +}; +struct _arm_thread_state_64 { + uint64_t x[29], fp, lr, sp, pc; + uint32_t cpsr, pad; +}; + + EXPORT int substitute_dlopen_in_pid(int pid, const char *filename, int options, char **error) { mach_port_t task; + mach_vm_address_t target_stack = 0; *error = NULL; kern_return_t kr = task_for_pid(mach_task_self(), pid, &task); int ret; @@ -374,15 +401,16 @@ int substitute_dlopen_in_pid(int pid, const char *filename, int options, char ** {libpthread_addr, "_pthread_create", 0} }; + cpu_type_t cputype; + for (int i = 0; i < 2; i++) { void *linkedit, *export; size_t linkedit_size, export_size; if ((ret = get_foreign_image_export(task, libs[i].addr, &linkedit, &linkedit_size, &export, &export_size, - error))) + &cputype, error))) goto fail; - printf("%p\n", (void *) libdyld_addr); bool fesr = find_export_symbol(export, export_size, libs[i].symname, libs[i].addr, &libs[i].symaddr); vm_deallocate(mach_task_self(), (vm_offset_t) linkedit, (vm_size_t) linkedit_size); @@ -392,14 +420,136 @@ int substitute_dlopen_in_pid(int pid, const char *filename, int options, char ** goto fail; } } - printf("%p\n", (void *) libs[0].symaddr); - printf("%p\n", (void *) libs[0].symaddr); - (void) filename; + extern char inject_page_start[], + inject_start_x86_64[], + inject_start_i386[], + inject_start_arm[], + inject_start_arm64[]; + + int target_page_size = cputype == CPU_TYPE_ARM64 ? 0x4000 : 0x1000; + kr = mach_vm_allocate(task, &target_stack, 2 * target_page_size, VM_FLAGS_ANYWHERE); + if (kr) { + asprintf(error, "couldn't allocate target stack"); + ret = SUBSTITUTE_ERR_OOM; + goto fail; + } + + mach_vm_address_t target_code_page = target_stack + target_page_size; + vm_prot_t cur, max; + kr = mach_vm_remap(task, &target_code_page, target_page_size, 0, + VM_FLAGS_OVERWRITE, mach_task_self(), + (mach_vm_address_t) inject_page_start, + /*copy*/ false, + &cur, &max, VM_INHERIT_NONE); + if (kr) { + asprintf(error, "couldn't remap target code"); + ret = SUBSTITUTE_ERR_VM; + goto fail; + } + + size_t filelen = strlen(filename); + if (filelen >= 0x400) { + asprintf(error, "you gave me a terrible filename (%s)", filename); + ret = SUBSTITUTE_ERR_MISC; + goto fail; + } + size_t filelen_rounded = (filelen + 7) & ~7; + + size_t baton_len = (cputype & CPU_ARCH_ABI64) ? 32 : 16; + mach_vm_address_t target_stack_top = target_stack + target_page_size + - baton_len - filelen_rounded; + char *stackbuf = calloc(baton_len + filelen_rounded, 1); + if (!stackbuf) { + ret = SUBSTITUTE_ERR_OOM; + goto fail; + } + strcpy(stackbuf + baton_len, filename); + + uint64_t vals[3] = {libs[1].symaddr, libs[0].symaddr, target_stack_top + baton_len}; + if (cputype & CPU_ARCH_ABI64) { + uint64_t *p = (void *) stackbuf; + p[0] = vals[0]; + p[1] = vals[1]; + p[2] = vals[2]; + } else { + uint32_t *p = (void *) stackbuf; + p[0] = (uint32_t) vals[0]; + p[1] = (uint32_t) vals[1]; + p[2] = (uint32_t) vals[2]; + } + + printf("target_stack=%llx\n", target_stack_top); + kr = mach_vm_write(task, target_stack_top, + (mach_vm_address_t) stackbuf, baton_len + filelen_rounded); + free(stackbuf); + if (kr) { + asprintf(error, "mach_vm_write(stack data): kr=%d", kr); + ret = SUBSTITUTE_ERR_MISC; + goto fail; + } + + union { + struct _x86_thread_state_32 x32; + struct _x86_thread_state_64 x64; + struct _arm_thread_state_32 a32; + struct _arm_thread_state_64 a64; + } u; + size_t state_size; + thread_state_flavor_t flavor; + memset(&u, 0, sizeof(u)); + + switch (cputype) { + case CPU_TYPE_X86_64: + u.x64.rsp = target_stack_top; + u.x64.rdi = target_stack_top; + u.x64.rip = target_code_page + (inject_start_x86_64 - inject_page_start); + state_size = sizeof(u.x64); + flavor = 4; + break; + case CPU_TYPE_I386: + u.x32.esp = target_stack_top; + u.x32.ecx = target_stack_top; + u.x32.eip = target_code_page + (inject_start_i386 - inject_page_start); + state_size = sizeof(u.x32); + flavor = 1; + break; + case CPU_TYPE_ARM: + u.a32.sp = target_stack_top; + u.a32.r[0] = target_stack_top; + u.a32.pc = target_code_page + (inject_start_arm - inject_page_start); + state_size = sizeof(u.a32); + flavor = 9; + break; + case CPU_TYPE_ARM64: + u.a64.sp = target_stack_top; + u.a64.x[0] = target_stack_top; + u.a64.pc = target_code_page + (inject_start_arm64 - inject_page_start); + state_size = sizeof(u.a64); + flavor = 6; + break; + } + + mach_port_t thread; + kr = thread_create_running(task, flavor, (thread_state_t) &u, + state_size / sizeof(int), &thread); + if (kr) { + asprintf(error, "thread_create_running: kr=%d", kr); + ret = SUBSTITUTE_ERR_MISC; + goto fail; + } + + target_stack = 0; + + /* it will terminate itself */ + mach_port_deallocate(mach_task_self(), thread); + (void) options; ret = 0; fail: + if (target_stack) + mach_vm_deallocate(task, target_stack, 2 * target_page_size); mach_port_deallocate(mach_task_self(), task); return ret; } |