diff options
author | comex | 2015-01-20 21:48:38 -0500 |
---|---|---|
committer | comex | 2015-01-20 21:58:52 -0500 |
commit | c2728b5b3416d3bb2dedb62366a8e87e05d8629a (patch) | |
tree | 2b9bc6f8c365237ceeac980498d6b24df80b6fa3 | |
parent | revert THAT WHOLE THING because we can't actually use it for inject (diff) | |
download | substitute-c2728b5b3416d3bb2dedb62366a8e87e05d8629a.tar.gz |
...
-rw-r--r-- | Makefile | 27 | ||||
-rw-r--r-- | lib/darwin/inject-asm-raw.S | 113 | ||||
-rw-r--r-- | lib/darwin/inject.c | 254 | ||||
-rw-r--r-- | lib/darwin/interpose.c | 56 | ||||
-rw-r--r-- | lib/darwin/read.c | 22 | ||||
-rw-r--r-- | lib/darwin/read.h | 18 | ||||
-rw-r--r-- | test/test-inject.c | 17 |
7 files changed, 451 insertions, 56 deletions
@@ -39,9 +39,11 @@ out/transform-dis.o: $(GENERATED) LIB_OBJS := \ out/darwin/find-syms.o \ out/darwin/inject.o \ + out/darwin/inject-asm.o \ out/darwin/interpose.o \ out/darwin/objc-asm.o \ out/darwin/objc.o \ + out/darwin/read.o \ out/darwin/substrate-compat.o \ out/jump-dis.o \ out/transform-dis.o @@ -49,6 +51,28 @@ LIB_OBJS := \ out/libsubstitute.dylib: $(LIB_OBJS) $(CC) -o $@ $(LIB_OBJS) $(LIB_LDFLAGS) +# this doesn't need to be done on the building machine, just in case someone is +# trying to build with some Linux compiler that doesn't support all the +# architectures or something - meh +ASCLANG := clang -dynamiclib -nostartfiles -nodefaultlibs +out/inject-asm-raw-x86_64.o: lib/darwin/inject-asm-raw.S Makefile + $(ASCLANG) -arch x86_64 -o $@ $< +out/inject-asm-raw-i386.o: lib/darwin/inject-asm-raw.S Makefile + $(ASCLANG) -arch i386 -o $@ $< +out/inject-asm-raw-arm.o: lib/darwin/inject-asm-raw.S Makefile + $(ASCLANG) -arch armv7 -o $@ $< +out/inject-asm-raw-arm64.o: lib/darwin/inject-asm-raw.S Makefile + $(ASCLANG) -arch arm64 -o $@ $< +IAR_BINS := out/inject-asm-raw-x86_64.bin out/inject-asm-raw-i386.bin out/inject-asm-raw-arm.bin out/inject-asm-raw-arm64.bin +out/inject-asm.S: $(IAR_BINS) Makefile + for i in x86_64 i386 arm arm64; do \ + echo ".globl inject_start_$$i"; \ + echo "inject_start_$$i:"; \ + echo ".align 2"; \ + printf ".byte "; \ + xxd -i < out/inject-asm-raw-$$i.bin | xargs echo; \ + done > $@ + define define_test out/test-$(1): test/test-$(2).[cm]* $(HEADERS) $(GENERATED) Makefile out/libsubstitute.dylib $(3) -g -o $$@ $$< -Ilib -Isubstrate -Lout -lsubstitute @@ -70,6 +94,7 @@ $(eval $(call define_test,substrate,substrate,$(CXX) -std=c++98)) $(eval $(call define_test,imp-forwarding,imp-forwarding,$(CC) -std=c11 -framework Foundation -lobjc)) $(eval $(call define_test,objc-hook,objc-hook,$(CC) -std=c11 -framework Foundation -lsubstitute)) $(eval $(call define_test,interpose,interpose,$(CC) -std=c11 -lsubstitute)) +$(eval $(call define_test,inject,inject,$(CC) -std=c11 -lsubstitute)) out/insns-arm.o: test/insns-arm.S Makefile clang -arch armv7 -c -o $@ $< @@ -81,7 +106,7 @@ out/insns-libz-arm.o: test/insns-libz-arm.S Makefile out/insns-libz-thumb2.o: test/insns-libz-arm.S Makefile clang -arch armv7 -c -o $@ $< -DTHUMB2 -out/insns-%.bin: out/insns-%.o Makefile +out/%.bin: out/%.o Makefile segedit -extract __TEXT __text $@ $< clean: diff --git a/lib/darwin/inject-asm-raw.S b/lib/darwin/inject-asm-raw.S new file mode 100644 index 0000000..a8980c3 --- /dev/null +++ b/lib/darwin/inject-asm-raw.S @@ -0,0 +1,113 @@ +.text +.align 2 +/* sp -> {pthread_create, dlopen, dylib} */ +#if defined(__x86_64__) + lea -8(%rsp), %rdi /* thread */ + xor %rsi, %rsi /* attr */ + lea thread_func(%rip), %rdx /* start_routine */ + mov %rsp, %rcx /* arg */ + mov %rdi, %rsp + call *(%rcx) +/* suicide */ + mov $361, %rax /* bsdthread_terminate */ + xor %rdi, %rdi /* stackaddr */ + xor %rsi, %rsi /* freesize */ + xor %rdx, %rdx /* port */ + xor %rcx, %rcx /* sem */ + syscall +/* still here? */ + mov $0xbad, %rax + jmp *%rax + +thread_func: + mov 0x8(%rdi), %rax /* dlopen */ + mov 0x10(%rdi), %rdi /* dylib */ + xor %rsi, %rsi + jmp *%rax + +#elif defined(__i386__) + + mov %esp, %ecx + push %ecx /* arg */ + call 1f +1: + pop %eax + add $(thread_func - 1b), %eax + push %eax /* start_routine */ + xor %eax, %eax + push %eax /* attr */ + push %esp /* thread */ + call *(%ecx) +/* suicide */ + mov $361, %eax /* bsdthread_terminate */ + xor %edx, %edx + push %edx /* sem */ + push %edx /* port */ + push %edx /* freesize */ + push %edx /* stackaddr */ + syscall +/* still here? */ + mov $0xbad, %eax + jmp *%eax + +thread_func: + xor %edx, %edx + push %edx + mov 0x4(%esp), %ecx /* arg */ + mov 0x8(%ecx), %edx /* dylib */ + push %edx + mov 0x4(%ecx), %edx /* dlopen */ + push %edx + call *%eax + add $8, %esp + ret + +#elif defined(__arm__) + + sub sp, #4 + mov r0, sp + mov r1, #0 + adr r2, thread_func + add r3, sp, #4 + ldr r9, [r3] + blx r9 +/* suicide */ + mov r0, #0 + mov r1, #0 + mov r2, #0 + mov r3, #0 + mov r12, #361 + svc #0x80 +/* still here? */ + mov r0, #0xbad + bx r0 +thread_func: + ldr r2, [r0] + ldr r0, [r0, #4] + mov r1, #0 + bx r2 + +#elif defined(__arm64__) + sub sp, sp, #8 + mov x0, sp + mov x1, #0 + adr x2, 1f + add x3, sp, #4 + ldr x9, [x3] + blr x9 +/* suicide */ + mov x0, #0 + mov x1, #0 + mov x2, #0 + mov x3, #0 + mov x12, #361 /* ??? */ + svc #0x80 +/* still here? */ + mov x0, #0xbad + br x0 +1: + ldr x2, [x0] + ldr x0, [x0, #8] + mov x1, #0 + br x2 +#endif diff --git a/lib/darwin/inject.c b/lib/darwin/inject.c index a73c9aa..b314df6 100644 --- a/lib/darwin/inject.c +++ b/lib/darwin/inject.c @@ -1,6 +1,7 @@ #ifdef __APPLE__ #include "substitute.h" #include "substitute-internal.h" +#include "darwin/read.h" #include <mach/mach.h> #include <sys/param.h> #include <stdint.h> @@ -8,6 +9,7 @@ #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); #define DEFINE_STRUCTS @@ -44,8 +46,7 @@ struct dyld_all_image_infos_64 { dyld_image_infos_fields(uint64_t) }; -static int find_libs_in_task(mach_port_t task, uint64_t *dyld_addr_p, - uint64_t *libpthread_p, char **error) { +static int find_foreign_images(mach_port_t task, uint64_t *libdyld_p, uint64_t *libpthread_p, char **error) { struct task_dyld_info tdi; mach_msg_type_number_t cnt = TASK_DYLD_INFO_COUNT; @@ -64,7 +65,7 @@ static int find_libs_in_task(mach_port_t task, uint64_t *dyld_addr_p, char all_image_infos_buf[1024]; cnt = tdi.all_image_info_size; - mach_vm_size_t size = tdi.all_image_info_size; + mach_vm_size_t size; kr = mach_vm_read_overwrite(task, tdi.all_image_info_addr, tdi.all_image_info_size, (mach_vm_address_t) all_image_infos_buf, &size); if (kr || size != tdi.all_image_info_size) { @@ -84,8 +85,6 @@ static int find_libs_in_task(mach_port_t task, uint64_t *dyld_addr_p, return SUBSTITUTE_ERR_MISC; } - *dyld_addr_p = FIELD(dyldImageLoadAddress); - uint64_t info_array_addr = FIELD(infoArray); uint32_t info_array_count = FIELD(infoArrayCount); size_t info_array_elm_size = (is64 ? sizeof(uint64_t) : sizeof(uint32_t)) * 3; @@ -130,26 +129,29 @@ static int find_libs_in_task(mach_port_t task, uint64_t *dyld_addr_p, char path_buf[MAXPATHLEN+1]; size_t toread = MIN(MAXPATHLEN, -file_path & 0xfff); path_buf[toread] = '\0'; - kr = mach_vm_read_overwrite(task, (mach_vm_address_t) path_buf, toread, - load_address, &size); + kr = mach_vm_read_overwrite(task, file_path, toread, + (mach_vm_address_t) path_buf, &size); if (kr) { + printf("kr=%d <%p %p>\n", kr, (void *) file_path, path_buf); continue; } if (strlen(path_buf) == toread && toread < MAXPATHLEN) { /* get the rest... */ - kr = mach_vm_read_overwrite(task, (mach_vm_address_t) path_buf + toread, - MAXPATHLEN - toread, load_address + toread, - &size); + kr = mach_vm_read_overwrite(task, file_path + toread, MAXPATHLEN - toread, + (mach_vm_address_t) path_buf + toread, &size); if (kr) { continue; } path_buf[MAXPATHLEN] = '\0'; } - if (!strcmp(path_buf, "/usr/lib/libpthread.dylib")) { + if (!strcmp(path_buf, "/usr/lib/system/libdyld.dylib")) + *libdyld_p = load_address; + else if (!strcmp(path_buf, "/usr/lib/system/libpthread.dylib")) *libpthread_p = load_address; - return 0; - } + + if (*libdyld_p && *libpthread_p) + return SUBSTITUTE_OK; info_array_ptr += info_array_elm_size; } @@ -158,6 +160,196 @@ static int find_libs_in_task(mach_port_t task, uint64_t *dyld_addr_p, 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; + 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; + kern_return_t kr = mach_vm_remap(mach_task_self(), &hdr_buf, hdr_buf_size, 0, + VM_FLAGS_ANYWHERE, task, hdr_addr, /*copy*/ true, + &cur, &max, VM_INHERIT_NONE); + if (kr) { + asprintf(error, "mach_vm_remap(libdyld header): kr=%d", kr); + return SUBSTITUTE_ERR_MISC; + } + + struct mach_header *mh = (void *) hdr_buf; + if (mh->magic != MH_MAGIC && mh->magic != MH_MAGIC_64) { + asprintf(error, "bad magic in libdyld mach_header"); + ret = SUBSTITUTE_ERR_MISC; + goto fail; + } + + 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) + goto badmach; + + size_t total_size = mh_size + mh->sizeofcmds; + if (total_size > hdr_buf_size) { + vm_deallocate(mach_task_self(), (vm_offset_t) hdr_buf, (vm_size_t) hdr_buf_size); + hdr_buf_size = total_size; + kr = mach_vm_remap(mach_task_self(), &hdr_buf, hdr_buf_size, 0, + VM_FLAGS_ANYWHERE, task, hdr_addr, /*copy*/ true, + &cur, &max, VM_INHERIT_NONE); + if (kr) { + asprintf(error, "mach_vm_remap(libdyld header) #2: kr=%d", kr); + ret = SUBSTITUTE_ERR_MISC; + goto fail; + } + mh = (void *) hdr_buf; + } + + struct load_command *lc = (void *) mh + mh_size; + uint32_t export_off = 0, export_size = 0; + uint64_t slide = 0; + for (uint32_t i = 0; i < mh->ncmds; i++, lc = (void *) lc + lc->cmdsize) { + size_t remaining = total_size - ((void *) lc - (void *) mh); + if (remaining < sizeof(*lc) || remaining < lc->cmdsize) + goto badmach; + if (lc->cmd == LC_DYLD_INFO || lc->cmd == LC_DYLD_INFO_ONLY) { + struct dyld_info_command *dc = (void *) lc; + if (lc->cmdsize < sizeof(*dc)) + goto badmach; + export_off = dc->export_off; + export_size = dc->export_size; + } else if (lc->cmd == LC_SEGMENT) { + struct segment_command *sc = (void *) lc; + if (lc->cmdsize < sizeof(*sc)) + goto badmach; + if (sc->fileoff == 0) + slide = hdr_addr - sc->vmaddr; + } else if (lc->cmd == LC_SEGMENT_64) { + struct segment_command_64 *sc = (void *) lc; + if (lc->cmdsize < sizeof(*sc)) + goto badmach; + if (sc->fileoff == 0) + slide = hdr_addr - sc->vmaddr; + } + } + + if (export_off == 0) { + asprintf(error, "no LC_DYLD_INFO in libdyld header"); + ret = SUBSTITUTE_ERR_MISC; + goto fail; + } + lc = (void *) mh + mh_size; + + + uint64_t export_segoff, vmaddr, fileoff, filesize; + for (uint32_t i = 0; i < mh->ncmds; i++, lc = (void *) lc + lc->cmdsize) { + if (lc->cmd == LC_SEGMENT) { + struct segment_command *sc = (void *) lc; + vmaddr = sc->vmaddr; + fileoff = sc->fileoff; + filesize = sc->filesize; + } else if (lc->cmd == LC_SEGMENT_64) { + struct segment_command_64 *sc = (void *) lc; + vmaddr = sc->vmaddr; + fileoff = sc->fileoff; + filesize = sc->filesize; + } else { + continue; + } + export_segoff = (uint64_t) export_off - fileoff; + if (export_segoff < filesize) { + if (export_size > filesize - export_segoff) + goto badmach; + break; + } + } + + uint64_t linkedit_addr = vmaddr + slide; + mach_vm_address_t linkedit_buf; + kr = mach_vm_remap(mach_task_self(), &linkedit_buf, filesize, 0, + VM_FLAGS_ANYWHERE, task, linkedit_addr, /*copy*/ true, + &cur, &max, VM_INHERIT_NONE); + if (kr) { + asprintf(error, "mach_vm_remap(libdyld linkedit): kr=%d", kr); + ret = SUBSTITUTE_ERR_MISC; + goto fail; + } + + *linkedit_p = (void *) linkedit_buf; + *linkedit_size_p = (size_t) filesize; + *export_p = (void *) linkedit_buf + export_segoff; + *export_size_p = export_size; + + ret = SUBSTITUTE_OK; + goto fail; + +badmach: + asprintf(error, "bad Mach-O data in libdyld header"); + ret = SUBSTITUTE_ERR_MISC; + goto fail; +fail: + vm_deallocate(mach_task_self(), (vm_offset_t) hdr_buf, (vm_size_t) hdr_buf_size); + return ret; +} + +static bool find_export_symbol(void *export, size_t export_size, const char *name, + uint64_t hdr_addr, uint64_t *sym_addr_p) { + void *end = export + export_size; + void *ptr = export; + while (1) { + /* skip this symbol data */ + uint64_t size; + if (!read_leb128(&ptr, end, false, &size) || + size > (uint64_t) (end - ptr)) + return false; + ptr += size; + if (ptr == end) + return false; + uint8_t i, nedges = *(uint8_t *) ptr; + ptr++; + for (i = 0; i < nedges; i++) { + char *prefix; + if (!read_cstring(&ptr, end, &prefix)) + return false; + size_t prefix_len = (char *) ptr - prefix - 1; + uint64_t next_offset; + if (!read_leb128(&ptr, end, false, &next_offset)) + return false; + if (!strncmp(name, prefix, prefix_len)) { + if (next_offset > export_size) + return false; + ptr = export + next_offset; + name += prefix_len; + if (*name == '\0') + goto got_symbol; + break; + } + } + if (i == nedges) { + /* not found */ + return false; + } + } +got_symbol:; + uint64_t size, flags, hdr_off; + if (!read_leb128(&ptr, end, false, &size)) + return false; + if (!read_leb128(&ptr, end, false, &flags)) + return false; + if (flags & (EXPORT_SYMBOL_FLAGS_REEXPORT | EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER)) { + /* don't bother to support for now */ + return false; + } + if (!read_leb128(&ptr, end, false, &hdr_off)) + return false; + *sym_addr_p = hdr_addr + hdr_off; + return true; +} + EXPORT int substitute_dlopen_in_pid(int pid, const char *filename, int options, char **error) { mach_port_t task; @@ -169,12 +361,42 @@ int substitute_dlopen_in_pid(int pid, const char *filename, int options, char ** return SUBSTITUTE_ERR_TASK_FOR_PID; } - uint64_t dyld_addr, libpthread_addr; - if ((ret = find_libs_in_task(task, &dyld_addr, &libpthread_addr, error))) + uint64_t libdyld_addr, libpthread_addr; + if ((ret = find_foreign_images(task, &libdyld_addr, &libpthread_addr, error))) goto fail; + + struct { + uint64_t addr; + const char *symname; + uint64_t symaddr; + } libs[2] = { + {libdyld_addr, "_dlopen", 0}, + {libpthread_addr, "_pthread_create", 0} + }; + + 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))) + 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); + if (!fesr) { + asprintf(error, "couldn't find _dlopen in libdyld"); + ret = SUBSTITUTE_ERR_MISC; + goto fail; + } + } + printf("%p\n", (void *) libs[0].symaddr); + printf("%p\n", (void *) libs[0].symaddr); + (void) filename; (void) options; - printf("%p %p\n", (void *) dyld_addr, (void *) libpthread_addr); ret = 0; fail: diff --git a/lib/darwin/interpose.c b/lib/darwin/interpose.c index 06a357f..bf9ceb4 100644 --- a/lib/darwin/interpose.c +++ b/lib/darwin/interpose.c @@ -5,6 +5,7 @@ #include "substitute.h" #include "substitute-internal.h" +#include "darwin/read.h" struct interpose_state { size_t nsegments; @@ -16,39 +17,13 @@ struct interpose_state { segment_command_x *stack_segments[32]; }; -static uintptr_t read_leb128(void **ptr, void *end, bool is_signed) { - uintptr_t result = 0; - uint8_t *p = *ptr; - uint8_t bit; - unsigned int shift = 0; - do { - if (p >= (uint8_t *) end) - return 0; - bit = *p++; - uintptr_t k = bit & 0x7f; - if (shift < sizeof(uintptr_t) * 8) - result |= k << shift; - shift += 7; - } while (bit & 0x80); - if (is_signed && (bit & 0x40)) - result |= ~((uintptr_t) 0) << shift; - *ptr = p; - return result; -} - -static inline char *read_cstring(void **ptr, void *end) { - char *s = *ptr; - *ptr = s + strnlen(s, (char *) end - s); - return s; -} - static int try_bind_section(void *bind, size_t size, const struct interpose_state *st, bool lazy) { void *ptr = bind, *end = bind + size; - const char *sym = NULL; + char *sym = NULL; uint8_t type = lazy ? BIND_TYPE_POINTER : 0; - intptr_t addend = 0; - size_t offset = 0; + uint64_t addend = 0; + uint64_t offset = 0, added_offset; void *segment = NULL; while (ptr < end) { uint8_t byte = *(uint8_t *) ptr; @@ -56,7 +31,7 @@ static int try_bind_section(void *bind, size_t size, const struct interpose_stat uint8_t immediate = byte & BIND_IMMEDIATE_MASK; uint8_t opcode = byte & BIND_OPCODE_MASK; - uintptr_t count, stride; + uint64_t count, stride; switch(opcode) { case BIND_OPCODE_DONE: @@ -64,25 +39,26 @@ static int try_bind_section(void *bind, size_t size, const struct interpose_stat case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM: break; case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB: - read_leb128(&ptr, end, false); + read_leb128(&ptr, end, false, NULL); break; case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: - sym = read_cstring(&ptr, end); + read_cstring(&ptr, end, &sym); /* ignoring flags for now */ break; case BIND_OPCODE_SET_TYPE_IMM: type = immediate; break; case BIND_OPCODE_SET_ADDEND_SLEB: - addend = read_leb128(&ptr, end, true); + read_leb128(&ptr, end, true, &addend); break; case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: if (immediate < st->nsegments) segment = (void *) (st->segments[immediate]->vmaddr + st->slide); - offset = read_leb128(&ptr, end, false); + read_leb128(&ptr, end, false, &offset); break; case BIND_OPCODE_ADD_ADDR_ULEB: - offset += read_leb128(&ptr, end, false); + read_leb128(&ptr, end, false, &added_offset); + offset += added_offset; break; case BIND_OPCODE_DO_BIND: count = 1; @@ -90,15 +66,17 @@ static int try_bind_section(void *bind, size_t size, const struct interpose_stat goto bind; case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB: count = 1; - stride = read_leb128(&ptr, end, false) + sizeof(void *); + read_leb128(&ptr, end, false, &stride); + stride += sizeof(void *); goto bind; case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED: count = 1; stride = immediate * sizeof(void *) + sizeof(void *); goto bind; case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB: - count = read_leb128(&ptr, end, false); - stride = read_leb128(&ptr, end, false) + sizeof(void *); + read_leb128(&ptr, end, false, &count); + read_leb128(&ptr, end, false, &stride); + stride += sizeof(void *); goto bind; bind: if (segment && sym) { @@ -111,7 +89,7 @@ static int try_bind_section(void *bind, size_t size, const struct interpose_stat } if (i != st->nhooks) { while (count--) { - uintptr_t new = (uintptr_t) h->replacement + addend; + uintptr_t new = (uintptr_t) h->replacement + (intptr_t) addend; uintptr_t old; void *p = (void *) (segment + offset); switch (type) { diff --git a/lib/darwin/read.c b/lib/darwin/read.c new file mode 100644 index 0000000..2e5b746 --- /dev/null +++ b/lib/darwin/read.c @@ -0,0 +1,22 @@ +#include "darwin/read.h" +bool read_leb128(void **ptr, void *end, bool is_signed, uint64_t *out) { + uint64_t result = 0; + uint8_t *p = *ptr; + uint8_t bit; + unsigned int shift = 0; + do { + if (p >= (uint8_t *) end) + return false; + bit = *p++; + uint64_t k = bit & 0x7f; + if (shift < sizeof(uint64_t) * 8) + result |= k << shift; + shift += 7; + } while (bit & 0x80); + if (is_signed && (bit & 0x40)) + result |= ~((uint64_t) 0) << shift; + *ptr = p; + if (out) + *out = result; + return true; +} diff --git a/lib/darwin/read.h b/lib/darwin/read.h new file mode 100644 index 0000000..900d3d4 --- /dev/null +++ b/lib/darwin/read.h @@ -0,0 +1,18 @@ +#pragma once +#include <string.h> +#include <stdint.h> +#include <stdbool.h> + +bool read_leb128(void **ptr, void *end, bool is_signed, uint64_t *out); + +static inline bool read_cstring(void **ptr, void *end, char **out) { + char *s = *ptr; + size_t maxlen = (char *) end - s; + size_t len = strnlen(s, maxlen); + if (len == maxlen) + return false; + *out = s; + *ptr = s + len + 1; + return true; +} + diff --git a/test/test-inject.c b/test/test-inject.c new file mode 100644 index 0000000..6cf0404 --- /dev/null +++ b/test/test-inject.c @@ -0,0 +1,17 @@ +#include "substitute.h" +#include "substitute-internal.h" + +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> + +int main(int argc, char **argv) { + if (argc <= 1) { + printf("usage: test-inject <pid>\n"); + return 1; + } + int pid = atoi(argv[1]); + char *error = NULL; + int ret = substitute_dlopen_in_pid(pid, "/tmp/hello", 0, &error); + printf("ret=%d err=%s\n", ret, error); +} |