jmpews
## Prologue 当 shellcode 需要调用外部函数时, 此时无法得知外部函数地址, 并且由于目标外部函数没有导入, 所以也不存在 lazybind 的相关信息. 所以更具体的问题是, 在不允许注入 `dylib` 且仅能对 `executable binary` 进行 `patch shellcode` 的情况下获取外部未被导入的符号地址? #### 1. 伪造 `dynamic symbol` 信息, 手动触发 `stub_helper` #### 2. 获取 dyld 基址, 解析 dyld 文件, 获取 `dyld::dlopen` & `dyld:dlsym`(dyld实现同样实现了一份这类函数的拷贝) ## Somniloquy #### 1. 伪造 `dynamic symbol` 信息, 手动触发 `stub_helper` **失败, 但具有借鉴意义** 具体解释下, 首先需要明确: 1. `lazybind` 的过程中是根据外部函数的 `FunctionName` 进行查找绑定. 2. 每一个 `indirect_symtab` 中对应的外部需要绑定的符号, 未绑定之前的 `imp_ptr` 是 `stub_helper` 的地址, 第一个参数为 `dyld_info_command->lazy_bind_off` 的 `offset` 具体过程可以查看 `dyld` 源码 通过以上猜想, 可以对已有的 `Import Dynamic External Symbol` 进行伪造, 修改函数名为需要导入的函数名, 之后手动出发 `LazyBind` 过程, 就可以从 `imp_ptr` 获取到目标函数地址. 最后失败, **因为函数的名字段, 在 `__LINKEDIT segment`, 并且该 `Segment` 在映射时只有读的权限. (并且无法手动更改)** 这里对代码稍作提示: 1. 如何利用 trick 技巧获取 `Image Header`? 2. 代码中不能存在明文字符串(会放到 `__DATA segment`), 否则不能实现 `__TEXT segment` 无依赖, 利用 GV 实现, 可以避免. 3. fishhook 源码的灵活运用. ``` // // assembly.c // FuckTest // // Created by jmpews on 2018/4/15. // Copyright © 2018年 jmpews. All rights reserved. // #include <stdio.h> #include <mach-o/loader.h> #include <mach-o/dyld.h> #import <mach-o/nlist.h> #if 1 || defined(__LP64__) typedef struct mach_header_64 mach_header_t; typedef struct segment_command_64 segment_command_t; typedef struct section_64 section_t; typedef struct nlist_64 nlist_t; #define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT_64 #else typedef struct mach_header mach_header_t; typedef struct segment_command segment_command_t; typedef struct section section_t; typedef struct nlist nlist_t; #define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT #endif #define k___TEXT 0 #define k___DATA 1 #define k_printf 2 #define k_lazyBindInfo 3 #define k___LINKEDIT 4 #define k_dlopen 5 void *GlobalStringVariable[16] = {0}; typedef struct _FuncBindInfo { char *name; char *imp_ptr; } FuncBindInfo; // https://code.woboq.org/userspace/glibc/string/strcmp.c.html int INLstrcmp (const char *p1, const char *p2) { const unsigned char *s1 = (const unsigned char *) p1; const unsigned char *s2 = (const unsigned char *) p2; unsigned char c1, c2; do { c1 = (unsigned char) *s1++; c2 = (unsigned char) *s2++; if (c1 == '\0') return c1 - c2; } while (c1 == c2); return c1 - c2; } // https://en.wikibooks.org/wiki/C_Programming/string.h/strlen size_t INLstrlen(const char * str) { const char *s; for (s = str; *s; ++s) {} return(s - str); } // https://github.com/gcc-mirror/gcc/blob/master/libgcc/memcpy.c void *INLmemcpy(void *dest, const void *src, size_t len) { char *d = dest; const char *s = src; while (len--) *d++ = *s++; return dest; } void *bruteForceSearchMachoMagicNumber(void *p) { uintptr_t t = (uintptr_t)p; t = t & ~(0x4000 -1 ); while(*(uint32_t *)t != 0xFEEDFACF) { t = t - 0x4000; } return (void *)t; } struct segment_command_64 *getSegmentByName(struct mach_header_64 *header, char *segName) { struct load_command *load_cmd; struct segment_command_64 *seg_cmd_64; struct section_64 *sect_64; load_cmd = (struct load_command *)((uintptr_t)header + sizeof(struct mach_header_64)); for (int i = 0; i < header->ncmds; i++, load_cmd = (struct load_command *)((uintptr_t)load_cmd + load_cmd->cmdsize)) { if (load_cmd->cmd == LC_SEGMENT_64) { seg_cmd_64 = (struct segment_command_64 *)load_cmd; if (!INLstrcmp(seg_cmd_64->segname, segName)) { return seg_cmd_64; } } } return NULL; } struct section_64 *getSection64ByName(struct mach_header_64 *header, char *sectName) { struct load_command *load_cmd; struct segment_command_64 *seg_cmd_64; struct section_64 *sect_64; load_cmd = (struct load_command *)((uintptr_t)header + sizeof(struct mach_header_64)); for (int i = 0; i < header->ncmds; i++, load_cmd = (struct load_command *)((uintptr_t)load_cmd + load_cmd->cmdsize)) { if (load_cmd->cmd == LC_SEGMENT_64) { seg_cmd_64 = (struct segment_command_64 *)load_cmd; sect_64 = (struct section_64 *)((uintptr_t)seg_cmd_64 + sizeof(struct segment_command_64)); for (int j = 0; j < seg_cmd_64->nsects; j++, sect_64 = (struct section_64 *)((uintptr_t)sect_64 + sizeof(struct section_64))) { if (!INLstrcmp(sect_64->sectname, sectName)) { return sect_64; } } } } return NULL; } uintptr_t getImageASLRSlide(void *GV[], struct mach_header_64 *header) { struct segment_command_64 *seg_cmd_64 = getSegmentByName((struct mach_header_64 *)header, (char *)GV[k___TEXT]); uintptr_t slide = (uintptr_t)header - (uintptr_t)seg_cmd_64->vmaddr; return slide; } void getDynamicBindingInfo(void *GV[], section_t *section, intptr_t slide, nlist_t *symtab, char *strtab, uint32_t *indirect_symtab) { uint32_t *indirect_symbol_indices = indirect_symtab + section->reserved1; void **indirect_symbol_bindings = (void **)((uintptr_t)slide + section->addr); ((FuncBindInfo *)GV[k_lazyBindInfo])->name = NULL; ((FuncBindInfo *)GV[k_lazyBindInfo])->imp_ptr = NULL; for (uint i = 0; i < section->size / sizeof(void *); i++) { uint32_t symtab_index = indirect_symbol_indices[i]; if (symtab_index == INDIRECT_SYMBOL_ABS || symtab_index == INDIRECT_SYMBOL_LOCAL || symtab_index == (INDIRECT_SYMBOL_LOCAL | INDIRECT_SYMBOL_ABS)) { continue; } uint32_t strtab_offset = symtab[symtab_index].n_un.n_strx; char *symbol_name = strtab + strtab_offset; ((FuncBindInfo *)GV[k_lazyBindInfo])->name = symbol_name; ((FuncBindInfo *)GV[k_lazyBindInfo])->imp_ptr = &indirect_symbol_bindings[i]; if(INLstrcmp(&symbol_name[1], GV[k_printf]) == 0) { return; } } } void performDynamicBindingInfo(void *GV[], const struct mach_header *header, uintptr_t slide) { segment_command_t *cur_seg_cmd; segment_command_t *linkedit_segment = NULL; struct symtab_command* symtab_cmd = NULL; struct dysymtab_command* dysymtab_cmd = NULL; uintptr_t cur = (uintptr_t)header + sizeof(mach_header_t); for (uint i = 0; i < header->ncmds; i++, cur += cur_seg_cmd->cmdsize) { cur_seg_cmd = (segment_command_t *)cur; if (cur_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) { if (INLstrcmp(cur_seg_cmd->segname, GV[k___LINKEDIT]) == 0) { linkedit_segment = cur_seg_cmd; } } else if (cur_seg_cmd->cmd == LC_SYMTAB) { symtab_cmd = (struct symtab_command*)cur_seg_cmd; } else if (cur_seg_cmd->cmd == LC_DYSYMTAB) { dysymtab_cmd = (struct dysymtab_command*)cur_seg_cmd; } } if (!symtab_cmd || !dysymtab_cmd || !linkedit_segment || !dysymtab_cmd->nindirectsyms) { return; } // Find base symbol/string table addresses uintptr_t linkedit_base = (uintptr_t)slide + linkedit_segment->vmaddr - linkedit_segment->fileoff; nlist_t *symtab = (nlist_t *)(linkedit_base + symtab_cmd->symoff); char *strtab = (char *)(linkedit_base + symtab_cmd->stroff); // Get indirect symbol table (array of uint32_t indices into symbol table) uint32_t *indirect_symtab = (uint32_t *)(linkedit_base + dysymtab_cmd->indirectsymoff); cur = (uintptr_t)header + sizeof(mach_header_t); for (uint i = 0; i < header->ncmds; i++, cur += cur_seg_cmd->cmdsize) { cur_seg_cmd = (segment_command_t *)cur; if (cur_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) { if (INLstrcmp(cur_seg_cmd->segname, GV[k___DATA]) != 0) { continue; } for (uint j = 0; j < cur_seg_cmd->nsects; j++) { section_t *sect = (section_t *)(cur + sizeof(segment_command_t)) + j; if ((sect->flags & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS) { getDynamicBindingInfo(GV, sect, slide, symtab, strtab, indirect_symtab); } } } } } void *dynamicObtainExternalFunctionAddress(void *GV[]) { void *p; asm volatile ("adr x17, #0\n" "mov %[result], x17" : [result] "=r" (p) ); const struct mach_header *header = bruteForceSearchMachoMagicNumber(p); uintptr_t slide = getImageASLRSlide(GV, header); performDynamicBindingInfo(GV, header, slide); FuncBindInfo *printfBindInfo = (FuncBindInfo *)(GV[k_lazyBindInfo]); uintptr_t orig_imp; char orig_name[32]; uintptr_t *imp_ptr = printfBindInfo->imp_ptr; char *name = printfBindInfo->name; // backup origin lazy info INLmemcpy(orig_name, name, INLstrlen(name)); orig_imp = *imp_ptr; // fake lazy info char *dlopen_name = GV[k_dlopen]; INLmemcpy(name, dlopen_name, INLstrlen(dlopen_name)); asm volatile ("adr x17, #0\n" "sub x17, x17, %[imp_ptr]\n" "blr x17" : : [imp_ptr] "r" (imp_ptr) ); void *real_dlopen = (void *)*imp_ptr; return real_dlopen; } __attribute__((constructor)) void test() { FuncBindInfo fbi; GlobalStringVariable[k___DATA] = "__DATA"; GlobalStringVariable[k___TEXT] = "__TEXT"; GlobalStringVariable[k_dlopen] = "_dlopen"; GlobalStringVariable[k___LINKEDIT] = "__LINKEDIT"; GlobalStringVariable[k_lazyBindInfo] = &fbi; GlobalStringVariable[k_printf] = "printf"; void *dlopen_ptr; void *func = dynamicObtainExternalFunctionAddress; void *gv = GlobalStringVariable; __asm ("mov x0, %[gv]\n" "mov x17, %[func]\n" "blr x17\n" "mov %[result], x0" : [result] "=r" (dlopen_ptr) : [gv] "r" (gv), [func] "r" (func) ); } //int main(int argc, char *argv[]) { // printf("hello world"); // return 0; //} ``` 伪造动态查找符号, 获取 `stub_helper` 绑定的符号, 并恢复. ``` #if 0 FuncBindInfo *printfBindInfo = (FuncBindInfo *)(GV[k_lazyBindInfo]); uintptr_t orig_imp; char orig_name[32]; uintptr_t *imp_ptr = printfBindInfo->imp_ptr; char *name = printfBindInfo->name; // backup origin lazy info INLmemcpy(orig_name, name, INLstrlen(name)); orig_imp = *imp_ptr; // fake lazy info char *dlopen_name = GV[k_dlopen]; INLmemcpy(name, dlopen_name, INLstrlen(dlopen_name)); asm volatile ("adr x17, #0\n" "sub x17, x17, %[imp_ptr]\n" "blr x17" : : [imp_ptr] "r" (imp_ptr) ); void *real_dlopen = (void *)*imp_ptr; return real_dlopen; #endif ``` #### 2. 获取 dyld 基址, 解析 dyld 文件, 获取 `dyld::dlopen` & `dyld:dlsym`(dyld实现同样实现了一份这类函数的拷贝) 最后发现是, `dyld_stub_binder` 函数是在 `libdyld.dylib` 内的. ``` // // assembly.c // FuckTest // // Created by jmpews on 2018/4/15. // Copyright © 2018年 jmpews. All rights reserved. // #include <stdio.h> #include <mach-o/loader.h> #include <mach-o/dyld.h> #import <mach-o/nlist.h> #if 1 || defined(__LP64__) typedef struct mach_header_64 mach_header_t; typedef struct segment_command_64 segment_command_t; typedef struct section_64 section_t; typedef struct nlist_64 nlist_t; #define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT_64 #else typedef struct mach_header mach_header_t; typedef struct segment_command segment_command_t; typedef struct section section_t; typedef struct nlist nlist_t; #define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT #endif #define k___TEXT 0 #define k___DATA 1 #define k_printf 2 //#define k_lazyBindInfo 3 #define k___LINKEDIT 4 #define k__dlopen 5 #define k___got 6 #define k_dyld_stub_binder 7 #define k_dyld_stub_binder_address 8 #define k__dlopen_address 9 //#define k___TEXT __COUNTER__ //#define k___DATA __COUNTER__ //#define k_printf __COUNTER__ //#define k_lazyBindInfo __COUNTER__ //#define k___LINKEDIT __COUNTER__ //#define k_dlopen __COUNTER__ //#define k___got __COUNTER__ void *GlobalStringVariable[16] = {0}; typedef struct _FuncBindInfo { char *name; char *imp_ptr; } FuncBindInfo; // https://code.woboq.org/userspace/glibc/string/strcmp.c.html int INLstrcmp (const char *p1, const char *p2) { const unsigned char *s1 = (const unsigned char *) p1; const unsigned char *s2 = (const unsigned char *) p2; unsigned char c1, c2; do { c1 = (unsigned char) *s1++; c2 = (unsigned char) *s2++; if (c1 == '\0') return c1 - c2; } while (c1 == c2); return c1 - c2; } // https://en.wikibooks.org/wiki/C_Programming/string.h/strlen size_t INLstrlen(const char * str) { const char *s; for (s = str; *s; ++s) {} return(s - str); } // https://github.com/gcc-mirror/gcc/blob/master/libgcc/memcpy.c void *INLmemcpy(void *dest, const void *src, size_t len) { char *d = dest; const char *s = src; while (len--) *d++ = *s++; return dest; } void *bruteForceSearchMachoMagicNumber(void *p) { uintptr_t t = (uintptr_t)p; t = t & ~(0x4000 -1 ); while(*(uint32_t *)t != 0xFEEDFACF) { t = t - 0x4000; } return (void *)t; } struct segment_command_64 *getSegmentByName(struct mach_header_64 *header, char *segName) { struct load_command *load_cmd; struct segment_command_64 *seg_cmd_64; struct section_64 *sect_64; load_cmd = (struct load_command *)((uintptr_t)header + sizeof(struct mach_header_64)); for (int i = 0; i < header->ncmds; i++, load_cmd = (struct load_command *)((uintptr_t)load_cmd + load_cmd->cmdsize)) { if (load_cmd->cmd == LC_SEGMENT_64) { seg_cmd_64 = (struct segment_command_64 *)load_cmd; if (!INLstrcmp(seg_cmd_64->segname, segName)) { return seg_cmd_64; } } } return NULL; } struct section_64 *getSection64ByName(struct mach_header_64 *header, char *sectName) { struct load_command *load_cmd; struct segment_command_64 *seg_cmd_64; struct section_64 *sect_64; load_cmd = (struct load_command *)((uintptr_t)header + sizeof(struct mach_header_64)); for (int i = 0; i < header->ncmds; i++, load_cmd = (struct load_command *)((uintptr_t)load_cmd + load_cmd->cmdsize)) { if (load_cmd->cmd == LC_SEGMENT_64) { seg_cmd_64 = (struct segment_command_64 *)load_cmd; sect_64 = (struct section_64 *)((uintptr_t)seg_cmd_64 + sizeof(struct segment_command_64)); for (int j = 0; j < seg_cmd_64->nsects; j++, sect_64 = (struct section_64 *)((uintptr_t)sect_64 + sizeof(struct section_64))) { if (!INLstrcmp(sect_64->sectname, sectName)) { return sect_64; } } } } return NULL; } uintptr_t getImageASLRSlide(void *GV[], struct mach_header_64 *header) { struct segment_command_64 *seg_cmd_64 = getSegmentByName((struct mach_header_64 *)header, (char *)GV[k___TEXT]); uintptr_t slide = (uintptr_t)header - (uintptr_t)seg_cmd_64->vmaddr; return slide; } void iterateSymbolTable(void *GV[], struct mach_header *header) { segment_command_t *cur_seg_cmd; segment_command_t *linkedit_segment = NULL; segment_command_t *data_segment = NULL; segment_command_t *text_segment = NULL; struct symtab_command* symtab_cmd = NULL; uintptr_t cur = (uintptr_t)header + sizeof(mach_header_t); for (uint i = 0; i < header->ncmds; i++, cur += cur_seg_cmd->cmdsize) { cur_seg_cmd = (segment_command_t *)cur; if (cur_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) { if (INLstrcmp(cur_seg_cmd->segname, GV[k___LINKEDIT]) == 0) { linkedit_segment = cur_seg_cmd; } else if (INLstrcmp(cur_seg_cmd->segname, GV[k___DATA]) == 0) { data_segment = cur_seg_cmd; } else if (INLstrcmp(cur_seg_cmd->segname, GV[k___TEXT]) == 0) { text_segment = cur_seg_cmd; } } else if (cur_seg_cmd->cmd == LC_SYMTAB) { symtab_cmd = (struct symtab_command*)cur_seg_cmd; } } if (!symtab_cmd || !linkedit_segment) { return; } uintptr_t slide = (uintptr_t)header - (uintptr_t)text_segment->vmaddr; uintptr_t linkedit_base = (uintptr_t)slide + linkedit_segment->vmaddr - linkedit_segment->fileoff; nlist_t *symtab = (nlist_t *)(linkedit_base + symtab_cmd->symoff); char *strtab = (char *)(linkedit_base + symtab_cmd->stroff); for (uint i = 0; i < symtab_cmd->nsyms; i++) { uint32_t strtab_offset = symtab[i].n_un.n_strx; char *symbol_name = strtab + strtab_offset; // TODO: what you want !!! if(INLstrcmp(symbol_name, GV[k__dlopen]) == 0) { GV[k__dlopen_address] = symtab[i].n_value + slide; return; } } } void iterateLazySymbolTable(void *GV[], struct mach_header *header) { segment_command_t *cur_seg_cmd; segment_command_t *linkedit_segment = NULL; segment_command_t *data_segment = NULL; segment_command_t *text_segment = NULL; struct symtab_command* symtab_cmd = NULL; struct dysymtab_command* dysymtab_cmd = NULL; section_t *section; uintptr_t cur = (uintptr_t)header + sizeof(mach_header_t); for (uint i = 0; i < header->ncmds; i++, cur += cur_seg_cmd->cmdsize) { cur_seg_cmd = (segment_command_t *)cur; if (cur_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) { if (INLstrcmp(cur_seg_cmd->segname, GV[k___LINKEDIT]) == 0) { linkedit_segment = cur_seg_cmd; } else if (INLstrcmp(cur_seg_cmd->segname, GV[k___DATA]) == 0) { data_segment = cur_seg_cmd; } else if (INLstrcmp(cur_seg_cmd->segname, GV[k___TEXT]) == 0) { text_segment = cur_seg_cmd; } } else if (cur_seg_cmd->cmd == LC_SYMTAB) { symtab_cmd = (struct symtab_command*)cur_seg_cmd; } else if (cur_seg_cmd->cmd == LC_DYSYMTAB) { dysymtab_cmd = (struct dysymtab_command*)cur_seg_cmd; } } if (!symtab_cmd || !dysymtab_cmd || !linkedit_segment || !dysymtab_cmd->nindirectsyms) { return; } cur = (uintptr_t)data_segment; for (uint i = 0; i < data_segment->nsects; i++) { section_t *sect = (section_t *)(cur + sizeof(segment_command_t)) + i; if ((sect->flags & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS) { section = sect; } } uintptr_t slide = (uintptr_t)header - (uintptr_t)text_segment->vmaddr; uintptr_t linkedit_base = (uintptr_t)slide + linkedit_segment->vmaddr - linkedit_segment->fileoff; nlist_t *symtab = (nlist_t *)(linkedit_base + symtab_cmd->symoff); char *strtab = (char *)(linkedit_base + symtab_cmd->stroff); uint32_t *indirect_symtab = (uint32_t *)(linkedit_base + dysymtab_cmd->indirectsymoff); uint32_t *indirect_symbol_indices = indirect_symtab + section->reserved1; void **indirect_symbol_bindings = (void **)((uintptr_t)slide + section->addr); for (uint i = 0; i < section->size / sizeof(void *); i++) { uint32_t symtab_index = indirect_symbol_indices[i]; if (symtab_index == INDIRECT_SYMBOL_ABS || symtab_index == INDIRECT_SYMBOL_LOCAL || symtab_index == (INDIRECT_SYMBOL_LOCAL | INDIRECT_SYMBOL_ABS)) { continue; } uint32_t strtab_offset = symtab[symtab_index].n_un.n_strx; char *symbol_name = strtab + strtab_offset; // TODO: what you want !!! if (symtab_index == INDIRECT_SYMBOL_ABS || symtab_index == INDIRECT_SYMBOL_LOCAL || symtab_index == (INDIRECT_SYMBOL_LOCAL | INDIRECT_SYMBOL_ABS)) { continue; } } } void iterateNoneLazySymbolTable(void *GV[], struct mach_header *header) { segment_command_t *cur_seg_cmd; segment_command_t *linkedit_segment = NULL; segment_command_t *data_segment = NULL; segment_command_t *text_segment = NULL; struct symtab_command* symtab_cmd = NULL; struct dysymtab_command* dysymtab_cmd = NULL; section_t *section; uintptr_t cur = (uintptr_t)header + sizeof(mach_header_t); for (uint i = 0; i < header->ncmds; i++, cur += cur_seg_cmd->cmdsize) { cur_seg_cmd = (segment_command_t *)cur; if (cur_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) { if (INLstrcmp(cur_seg_cmd->segname, GV[k___LINKEDIT]) == 0) { linkedit_segment = cur_seg_cmd; } else if (INLstrcmp(cur_seg_cmd->segname, GV[k___DATA]) == 0) { data_segment = cur_seg_cmd; } else if (INLstrcmp(cur_seg_cmd->segname, GV[k___TEXT]) == 0) { text_segment = cur_seg_cmd; } } else if (cur_seg_cmd->cmd == LC_SYMTAB) { symtab_cmd = (struct symtab_command*)cur_seg_cmd; } else if (cur_seg_cmd->cmd == LC_DYSYMTAB) { dysymtab_cmd = (struct dysymtab_command*)cur_seg_cmd; } } if (!symtab_cmd || !dysymtab_cmd || !linkedit_segment || !dysymtab_cmd->nindirectsyms) { return; } section = getSection64ByName(header, GV[k___got]); uintptr_t slide = (uintptr_t)header - (uintptr_t)text_segment->vmaddr; uintptr_t linkedit_base = (uintptr_t)slide + linkedit_segment->vmaddr - linkedit_segment->fileoff; nlist_t *symtab = (nlist_t *)(linkedit_base + symtab_cmd->symoff); char *strtab = (char *)(linkedit_base + symtab_cmd->stroff); uint32_t *indirect_symtab = (uint32_t *)(linkedit_base + dysymtab_cmd->indirectsymoff); uint32_t *indirect_symbol_indices = indirect_symtab + section->reserved1; void **indirect_symbol_bindings = (void **)((uintptr_t)slide + section->addr); for (uint i = 0; i < section->size / sizeof(void *); i++) { uint32_t symtab_index = indirect_symbol_indices[i]; if (symtab_index == INDIRECT_SYMBOL_ABS || symtab_index == INDIRECT_SYMBOL_LOCAL || symtab_index == (INDIRECT_SYMBOL_LOCAL | INDIRECT_SYMBOL_ABS)) { continue; } uint32_t strtab_offset = symtab[symtab_index].n_un.n_strx; char *symbol_name = strtab + strtab_offset; if(INLstrcmp(symbol_name, GV[k_dyld_stub_binder]) == 0) { GV[k_dyld_stub_binder_address] = indirect_symbol_bindings[i]; return; } } } void performDynamicBindingInfo(void *GV[], const struct mach_header *header) { iterateNoneLazySymbolTable(GV, (struct mach_header *)header); } void *dynamicObtainExternalFunctionAddress(void *GV[]) { void *pc; asm volatile ("adr x17, #0\n" "mov %[result], x17" : [result] "=r" (pc) ); const struct mach_header *header = bruteForceSearchMachoMagicNumber(pc); performDynamicBindingInfo(GV, header); return GV[k_dyld_stub_binder_address]; } __attribute__((constructor)) void test() { GlobalStringVariable[k___DATA] = "__DATA"; GlobalStringVariable[k___TEXT] = "__TEXT"; GlobalStringVariable[k__dlopen] = "_dlopen"; GlobalStringVariable[k___LINKEDIT] = "__LINKEDIT"; GlobalStringVariable[k_printf] = "printf"; GlobalStringVariable[k___got] = "__got"; GlobalStringVariable[k_dyld_stub_binder] = "dyld_stub_binder"; void *dyld_stub_binder; void *func = dynamicObtainExternalFunctionAddress; void **gv = GlobalStringVariable; __asm ("mov x0, %[gv]\n" "mov x17, %[func]\n" "blr x17\n" "mov %[result], x0" : [result] "=r" (dyld_stub_binder) : [gv] "r" (gv), [func] "r" (func) ); struct mach_header *dyld_header; dyld_header = bruteForceSearchMachoMagicNumber(dyld_stub_binder); iterateSymbolTable(gv, dyld_header); printf("get _dlopen address %p\n", gv[k__dlopen_address]); } //int main(int argc, char *argv[]) { // printf("hello world"); // return 0; //} ```