diff options
author | comex | 2015-01-28 00:46:51 -0500 |
---|---|---|
committer | comex | 2015-01-28 00:46:51 -0500 |
commit | 4b14cb631b3f37502d76fe22aa4d6cd582cf00e4 (patch) | |
tree | b5ab9897d5102e6366dc346fe53d28597a28f797 /lib | |
parent | initial commit of SafetyDance app (diff) | |
download | substitute-4b14cb631b3f37502d76fe22aa4d6cd582cf00e4.tar.gz |
some more stuff compiles
Diffstat (limited to 'lib')
-rw-r--r-- | lib/darwin/inject.c | 8 | ||||
-rw-r--r-- | lib/darwin/mach-decls.h | 31 | ||||
-rw-r--r-- | lib/darwin/stop-other-threads.c | 2 | ||||
-rw-r--r-- | lib/darwin/thread-state.h | 24 | ||||
-rw-r--r-- | lib/darwin/unrestrict.c | 163 | ||||
-rw-r--r-- | lib/substitute-internal.h | 4 | ||||
-rw-r--r-- | lib/substitute.h | 6 |
7 files changed, 202 insertions, 36 deletions
diff --git a/lib/darwin/inject.c b/lib/darwin/inject.c index a74b057..76ecbcb 100644 --- a/lib/darwin/inject.c +++ b/lib/darwin/inject.c @@ -2,7 +2,7 @@ #include "substitute.h" #include "substitute-internal.h" #include "darwin/read.h" -#include "darwin/thread-state.h" +#include "darwin/mach-decls.h" #include <mach/mach.h> #include <mach-o/dyld_images.h> #include <dlfcn.h> @@ -13,12 +13,6 @@ #include <stdio.h> #include <stdbool.h> -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); - extern const struct dyld_all_image_infos *_dyld_get_all_image_infos(); #define DEFINE_STRUCTS diff --git a/lib/darwin/mach-decls.h b/lib/darwin/mach-decls.h new file mode 100644 index 0000000..29ea908 --- /dev/null +++ b/lib/darwin/mach-decls.h @@ -0,0 +1,31 @@ +#pragma once +#include <stdint.h> + +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; +}; +#define _x86_thread_state_32_flavor 1 +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; +}; +#define _x86_thread_state_64_flavor 4 +struct _arm_thread_state_32 { + uint32_t r[13], sp, lr, pc, cpsr; +}; +#define _arm_thread_state_32_flavor 9 +struct _arm_thread_state_64 { + uint64_t x[29], fp, lr, sp, pc; + uint32_t cpsr, pad; +}; +#define _arm_thread_state_64_flavor 6 + +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); +kern_return_t mach_vm_region(vm_map_t, mach_vm_address_t *, mach_vm_size_t *, vm_region_flavor_t, vm_region_info_t, mach_msg_type_number_t *, mach_port_t *); + diff --git a/lib/darwin/stop-other-threads.c b/lib/darwin/stop-other-threads.c index 1975b47..b35c04c 100644 --- a/lib/darwin/stop-other-threads.c +++ b/lib/darwin/stop-other-threads.c @@ -1,6 +1,6 @@ #include "substitute.h" #include "substitute-internal.h" -#include "darwin/thread-state.h" +#include "darwin/mach-decls.h" #include <pthread.h> #include <mach/mach.h> #include <CoreFoundation/CoreFoundation.h> diff --git a/lib/darwin/thread-state.h b/lib/darwin/thread-state.h deleted file mode 100644 index 0bae7be..0000000 --- a/lib/darwin/thread-state.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once -#include <stdint.h> - -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; -}; -#define _x86_thread_state_32_flavor 1 -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; -}; -#define _x86_thread_state_64_flavor 4 -struct _arm_thread_state_32 { - uint32_t r[13], sp, lr, pc, cpsr; -}; -#define _arm_thread_state_32_flavor 9 -struct _arm_thread_state_64 { - uint64_t x[29], fp, lr, sp, pc; - uint32_t cpsr, pad; -}; -#define _arm_thread_state_64_flavor 6 - diff --git a/lib/darwin/unrestrict.c b/lib/darwin/unrestrict.c new file mode 100644 index 0000000..4fd90da --- /dev/null +++ b/lib/darwin/unrestrict.c @@ -0,0 +1,163 @@ +#include "substitute.h" +#include "substitute-internal.h" +#include "darwin/mach-decls.h" +#include <unistd.h> +#include <mach/vm_region.h> + +static int unrestrict_macho_header(void *header, size_t size, bool *did_modify_p) { + *did_modify_p = false; + struct mach_header *mh = header; + if (mh->magic != MH_MAGIC && mh->magic != MH_MAGIC_64) + return SUBSTITUTE_ERR_MISC; + size_t off = mh->magic == MH_MAGIC_64 ? sizeof(struct mach_header_64) + : sizeof(struct mach_header); + for (uint32_t i = 0; i < mh->ncmds; i++) { + if (off > size || size - off < sizeof(struct load_command)) + break; /* whatever */ + struct load_command *lc = header + off; + if (lc->cmdsize > size - off) + break; + #define CASES(code...) \ + if (lc->cmd == LC_SEGMENT) { \ + typedef struct segment_command segment_command_y; \ + typedef struct section section_y; \ + code \ + } else if (lc->cmd == LC_SEGMENT_64) { \ + typedef struct segment_command_64 segment_command_y; \ + typedef struct section_64 section_y; \ + code \ + } + CASES( + segment_command_y *sc = (void *) lc; + if (lc->cmdsize < sizeof(*sc) || + sc->nsects > (lc->cmdsize - sizeof(*sc)) / sizeof(struct section)) + return SUBSTITUTE_ERR_MISC; + if (!strncmp(sc->segname, "__RESTRICT", 16)) { + section_y *sect = (void *) (sc + 1); + for (uint32_t i = 0; i < sc->nsects; i++, sect++) { + if (!strncmp(sect->sectname, "__restrict", 16)) { + strcpy(sect->sectname, "\xf0\x9f\x92\xa9"); + *did_modify_p =true; + } + } + } + ) + #undef CASES + + if (off + lc->cmdsize < off) + return SUBSTITUTE_ERR_MISC; + off += lc->cmdsize; + } + return SUBSTITUTE_OK; +} + +EXPORT +int substitute_ios_unrestrict(pid_t pid, bool should_resume) { + mach_port_t task; + kern_return_t kr = task_for_pid(mach_task_self(), pid, &task); + if (kr) + return SUBSTITUTE_ERR_TASK_FOR_PID; + + int ret; + vm_address_t header_addr = 0; + + int retries = 0; + int wait_us = 1; +setback: + while (1) { + /* if calling from unrestrict-me, the process might not have transitioned + * yet. if it has, then TASK_DYLD_INFO will be filled with 0. */ + struct task_dyld_info tdi; + mach_msg_type_number_t cnt = TASK_DYLD_INFO_COUNT; + + kern_return_t kr = task_info(task, TASK_DYLD_INFO, (void *) &tdi, &cnt); + if (kr || cnt != TASK_DYLD_INFO_COUNT) { + ret = SUBSTITUTE_ERR_MISC; + goto fail; + } + if (tdi.all_image_info_size == 0) + break; + if (retries++ == 20) { + ret = SUBSTITUTE_ERR_MISC; + goto fail; + } + wait_us *= 2; + if (wait_us > 100000) + wait_us = 100000; + while (usleep(wait_us)) + ; + } + + /* alrighty then, let's look at the damage. find the first readable + * segment */ + mach_vm_address_t segm_addr = 0; + mach_vm_size_t segm_size = 0; + vm_region_basic_info_data_64_t info; + mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT_64; + mach_port_t object_name; + while (1) { + kr = mach_vm_region(task, &segm_addr, &segm_size, VM_REGION_BASIC_INFO_64, + (vm_region_info_t) &info, &info_count, &object_name); + if (kr == KERN_INVALID_ADDRESS) { + /* nothing! maybe it's not there *yet*? this actually is possible */ + goto setback; + } else if (kr) { + ret = SUBSTITUTE_ERR_VM; + goto fail; + } + if (info.protection) + break; + + segm_addr++; + } + + size_t toread = 0x4000; + if (segm_size < toread) + toread = segm_size; + if ((kr = vm_allocate(mach_task_self(), &header_addr, toread, + VM_FLAGS_ANYWHERE))) { + ret = SUBSTITUTE_ERR_MISC; + goto fail; + } + mach_vm_size_t actual = toread; + kr = mach_vm_read_overwrite(task, segm_addr, toread, header_addr, + &actual); + if (kr || actual != toread) { + ret = SUBSTITUTE_ERR_MISC; + goto fail; + } + + bool did_modify; + if ((ret = unrestrict_macho_header((void *) header_addr, toread, + &did_modify))) + goto fail; + + if (did_modify) { + if ((kr = vm_protect(mach_task_self(), header_addr, toread, + FALSE, info.protection))) { + ret = SUBSTITUTE_ERR_VM; + goto fail; + } + vm_prot_t cur, max; + if ((kr = mach_vm_remap(task, &segm_addr, toread, 0, + VM_FLAGS_OVERWRITE, + mach_task_self(), header_addr, FALSE, + &cur, &max, info.inheritance))) { + ret = SUBSTITUTE_ERR_VM; + goto fail; + } + } + + ret = SUBSTITUTE_OK; +fail: + if (should_resume) { + if ((kr = task_resume(task))) + ret = SUBSTITUTE_ERR_MISC; + } + mach_port_deallocate(mach_task_self(), task); + if (header_addr) + vm_deallocate(mach_task_self(), header_addr, toread); + return ret; +} + + diff --git a/lib/substitute-internal.h b/lib/substitute-internal.h index 3fd35bc..b378989 100644 --- a/lib/substitute-internal.h +++ b/lib/substitute-internal.h @@ -63,7 +63,7 @@ enum { * can happen are really complicated and dumb, but generally one solution * is to be root */ SUBSTITUTE_ERR_TASK_FOR_PID = 1000, - + SUBSTITUTE_ERR_TIMEOUT = 1000, SUBSTITUTE_ERR_MISC, }; @@ -85,4 +85,6 @@ struct shuttle { int substitute_dlopen_in_pid(int pid, const char *filename, int options, const struct shuttle *shuttle, size_t nshuttle, char **error); + +int substitute_ios_unrestrict(pid_t pid, bool should_resume); #endif diff --git a/lib/substitute.h b/lib/substitute.h index bdd63e0..8764bcf 100644 --- a/lib/substitute.h +++ b/lib/substitute.h @@ -172,9 +172,9 @@ struct substitute_import_hook { * This can be used to 'hook' functions or even exported variables. Compared * to substitute_hook_functions, it has the following advantages: * - * - Because it does not require the ability to patch executable code; - * accordingly, it can (from a technical rather than policy perspective) be - * used in sandboxed environments like iOS or PaX MPROTECT. + * - It does not require the ability to patch executable code; accordingly, it + * can (from a technical rather than policy perspective) be used in sandboxed + * environments like iOS or PaX MPROTECT. * - On platforms without RELRO or similar, it is thread safe, as the patches * are done using atomic instructions. * - It does not require architecture specific code. |