fishhook

fishhook是facebook提供的hook程序所使用的动态链接库的函数API的方法。原理就是通过重写__nl_symbol_ptr和__la_symbol_ptr存储的函数指针。具体情况可以直接查看fishhook的github主页的readme介绍以及fishhook的代码(readme写得算清楚,代码很少): https://github.com/facebook/fishhook

这里记录一下自己的一些理解:
1. 这种hook的方法(可以上app store吗?),对应windows平台下就是重写程序的导入表项,而且只能hook动态链接库的函数。__nl_symbol_ptr和__la_symbol_ptr这两个__DATA segement的secion存储着动态链接库的函数地址。前者是non-lazy,即非延时加载,在操作系统在程序启动时就会加载相应的动态链接库,并将相应的函数地址填入__nl_symbol_ptr;后者是lazy,即延时加载,是在程序使用到某个动态链接库的函数时才加载该动态链接库以及将相应的函数地址填入__la_symbol_ptr。(另外一种hook的方法,是改写要hook的函数的第一个指令(如果第一个指令大小不够容下一个跳转指令,就加上第二个指令,以此类推),将这个指令改写成一个跳转指令,而这个跳转指令跳转自己写的一个函数。但是,这种方法在iOS上不能实现,因为codesign机制:数字签名以及可执行权限页没有写权限。)
2. 涉及到的mach-o的相关结构:__DATA segment的__nl_symbol_ptr和__la_symbol_ptr section,可简单来说就是两个函数指针数组;__LINKEDIT segment的symbol table、dy(dy表示dynamic吗?)symbole table、string table。通过遍历__nl_symbol_ptr和__la_symbol_ptr中的每一项,比较每一项对应的函数名与想hook的函数名是否一样,如果一样,就重写相应位置。关键的地方就是可以通过__nl_symbol_ptr和__la_symbol_ptr的位置找出这个位置对应的函数名。流程为__nl_symbol_ptr/__la_symbol_ptr -> dysmbol table -> symbol table -> string table。
3. fishhook的关键逻辑就是rebind_symbols_for_image函数和perform_rebinding_with_section函数。

static void perform_rebinding_with_section(struct rebindings_entry *rebindings,
                                           section_t *section,
                                           intptr_t slide,
                                           nlist_t *symtab,
                                           char *strtab,
                                           uint32_t *indirect_symtab) {
  // section表示__nl_symbol_ptr或__la_symbol_ptr对应的section结构
  // slide表示动态链接库最终加载时的虚拟地址与动态链接库在静态链接时生成的虚拟地址的偏移
  // symtab表示符号表的起始位置,符号表,就是一个nlist_t结构的数组
  // strtab表示字符串表的起始位置,字符串表,就是一个字符数组,保存着程序所需要的所有字符串,一个接着一个
  // indirect_symtab表示非直接符号表的起始位置,indirect_symtab是通过dysymbol talbe得到的。像使用了动态链接库里的符号都属于非直接符号吧。indirect_symtab,就是一个整型数组,保存着对应符号在符号表数组的偏移(下标)

  // 这里是关键!!
  // indirect_symtab的起始位置加上section的reserved1这个偏移,就定位到section所对应的非直接符号表的位置。注意,这里的section是__nl_symbol_ptr或__la_symbol_ptr。其实fishhook的gitbub的readme里已经讲得清楚了,但是readme里是写成indirect_symbol_table[nl_symbol_ptr->reserved1]的,当时看的时候没有反应过来
  uint32_t *indirect_symbol_indices = indirect_symtab + section->reserved1;
  // section的addr加上slide就是__nl_symbol_ptr或__la_symbol_ptr在程序加载后的虚拟地址空间的起始地址
  void **indirect_symbol_bindings = (void **)((uintptr_t)slide + section->addr);
  ...
}
static void rebind_symbols_for_image(struct rebindings_entry *rebindings,
                                     const struct mach_header *header,
                                     intptr_t slide) {
...
  // 这里是为了得到linkedit segment对应的虚拟地址空间的起始地址。因为,symbol talbe, dytabol table,string table这些内容都是属于linkedit segment的。另外,这里为什么需要再减去linkedit_segment->fileoff呢?是因为symbol talbe, dytabol table,string table所对应的load command的offset成员(symoff/indirectsymoff/stroff)不是相对于linkedit segment的起始地址的偏移,而是相对于文件的起始位置的偏移,因此,这里减去linkedit_segment->fileoff就刚刚好了,由这里得到的linkedit_base加上symoff/indirectsymoff/stroff就得出了相应结构在程序加载后的虚拟地址了
  uintptr_t linkedit_base = (uintptr_t)slide + linkedit_segment->vmaddr - linkedit_segment->fileoff;
...
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值