fishhook是一个非常简单的库,它能动态替换运行在IOS模拟器或设备上Mach-o文件的符号表。是facebook的一个开源工具,github地址:
https://github.com/facebook/fishhook
使用方法如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | #import <dlfcn.h> #import <UIKit/UIKit.h> #import "AppDelegate.h" #import "fishhook.h" static int (*orig_close)(int); static int (*orig_open)(const char *, int, ...); void save_original_symbols() { orig_close = dlsym(RTLD_DEFAULT, "close"); orig_open = dlsym(RTLD_DEFAULT, "open"); } int my_close(int fd) { printf("Calling real close(%d)\n", fd); return orig_close(fd); } int my_open(const char *path, int oflag, ...) { va_list ap = {0}; mode_t mode = 0; if ((oflag & O_CREAT) != 0) { // mode only applies to O_CREAT va_start(ap, oflag); mode = va_arg(ap, int); va_end(ap); printf("Calling real open('%s', %d, %d)\n", path, oflag, mode); return orig_open(path, oflag, mode); } else { printf("Calling real open('%s', %d)\n", path, oflag); return orig_open(path, oflag, mode); } } int main(int argc, char * argv[]) { @autoreleasepool { save_original_symbols(); rebind_symbols((struct rebinding[2]){{"close", my_close}, {"open", my_open}}, 2); // Open our own binary and print out first 4 bytes (which is the same // for all Mach-O binaries on a given architecture) int fd = open(argv[0], O_RDONLY); uint32_t magic_number = 0; read(fd, &magic_number, 4); printf("Mach-O Magic Number: %x \n", magic_number); close(fd); return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } } |
运行原理:
dyld绑定lazy和non-lazy符号通过更新__DATA段中的__la_symbol_ptr节和__nl_symbol_ptr节。fishhook通过定位每一个符号的名字,并使用自定义的函数地址来替换。
__nl_symbol_ptr是一个指向non-lazily绑定数据的指针数组。(它们在库加载的时候绑定)。__la_symbol_ptr也是一个指向导入函数的数组指针,不过是第一个调用该符号时使用dyld_stub_binder来填充的。(也可能告诉dyld在启动时绑定)。为了找到这些连接符号的名字,我们需要通过一个间接的符号表(在__LINKEDIT段中),这个而这个间接的符号表保存的就是符号表(也在__LINKEDIT段中)的索引。我们可以indirect_symbol_table[nl_symbol_ptr->reserved1+ nl_symbol_ptr的索引]来找到确定的位置。而符号表中是一个nlist结构的数组,这个结构中包含了该符号在字符串表(也在__LINKEDIT段中)中的索引。所以对于每个__la_symbol_ptr节和__nl_symbol_ptr节中的指针,我们都可以找到该符号对应的名称,然后通过比较字符串是不是我们要hook的字符串,如果是的话,那就把该section对应的指针替换成我们自定义的函数地址。
查找符号名称的流程大致如下:
官方给的这个图中nlist结构的字符串表偏移好像是错的,给出的是70026,应该是70018.
Permalink
太复杂,看不懂…..
Permalink
可以先从前面的文章开始看…
Permalink
更不懂了。。。