iOS安全–facebook/fishhook

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]));
  }
}

运行的输出结果:Snip20150122_1

运行原理:

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.

本文链接:http://www.alonemonkey.com/ioss-fishhook.html

2条评论

    1. AloneMonkey

      可以先从前面的文章开始看…

Comments are closed.