fishhook 源码解读笔记

1. 源码分析


///
/// @param rebindings  需要重绑定的函数信息
/// @param section  __la_symbol_ptr  或 __nl_symbol_ptr section header (Load Commands -> LC_SEGMENT_64(__DATA) -> Section64 Header)
/// @param slide  mach-o 的偏移地址
/// @param symtab  Symbols (Symbol Table -> Symbols) 
/// @param strtab  String Table 
/// @param indirect_symtab   Indirect Symbols (Dynamic Symbol Table -> Indirect Symbols)

static void rcd_perform_rebinding_with_section(struct rcd_rebindings_entry *rebindings,
                                               section_t *section,
                                               intptr_t slide,
                                               nlist_t *symtab,
                                               char *strtab,
                                               uint32_t *indirect_symtab) {

//  indirect_symtab + section->reserved1 定位到 Indirect Symbols 中指定 section 段的符号的起始位置
  uint32_t *indirect_symbol_indices = indirect_symtab + section->reserved1;

// section 在内存中的真实地址
  void **indirect_symbol_bindings = (void **)((uintptr_t)slide + section->addr);

// 遍历 section 中的符号
  for (uint i = 0; i < section->size / sizeof(void *); i++) {

// 根据偏移量遍历  Indirect Symbols 中section 段的符号,并获取对应value (即符号在Symbols 中的位置的偏移量 )
    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;
    }


// 根据偏移量在 Symbols 中读取 String Table Index
    uint32_t strtab_offset = symtab[symtab_index].n_un.n_strx;

//  从String Table读取符号对应的名字
    char *symbol_name = strtab + strtab_offset;

// 需要重新绑定的符号信息,rebindings_nel 需要重新绑定的个数
    struct rcd_rebindings_entry *cur = rebindings;
    while (cur) {
      for (uint j = 0; j < cur->rebindings_nel; j++) {

     // 比较符号名是否相同,相同则替换,完成重新绑定
        if (strlen(symbol_name) > 1 &&
            strcmp(&symbol_name[1], cur->rebindings[j].name) == 0) {
          if (cur->rebindings[j].replaced != NULL &&
              indirect_symbol_bindings[i] != cur->rebindings[j].replacement) {
            *(cur->rebindings[j].replaced) = indirect_symbol_bindings[I];
          }
          indirect_symbol_bindings[i] = cur->rebindings[j].replacement;
          goto symbol_loop;
        }
      }
      cur = cur->next;
    }
  symbol_loop:;
  }
}


2. 举个例子

分析现有可执行文件,基于文件分析重绑定 NSLog 的流程

1、从 Load Commands 中查找 __la_symbol_ptr 、 __nl_symbol_ptr 段(section->flags 为 6 、7 )

image.png

2、首先查找到__nl_symbol_ptr , 获取 section->reserved1 (上图中的Indirect Sym Index), 得知 __nl_symbol_ptr 中的符号在 Indirect Symbols 的起始位置为 0x1f2 (498)

3、找到 Indirect Symbols ,从起始位置 + 0x1f2 * 4 处开始查找

image.png

Indirect Symbols 的起始位置为 0x18b8c8
__nl_symbol_ptr 中的符号在 Indirect Symbols 表的起始位置为 0x18b8c8 + 0x1f2 * 4 ,即为 0x18c090

image.png

4、查找到第一个符对应的值为 0x40000000,为特殊值(等于 INDIRECT_SYMBOL_ABS),继而遍历下一个得到 symtab_index = 0x5bbb

5、得到 symtab_index 后再前往Symbol Table,符号在Symbol Table 的位置偏移即为symtab_index

image.png

symtab_index = 0x5bbb
Symbol Table 的起始位置为 0x12c3c8

则 符号在Symbol Table 的地址为 0x12c3c8 + 0x5bbb *16,计算可得 0x187f78

image.png

6、根据计算的地址查找相关信息,可得知符号名称在 String Table 的偏移量为 0x257c4,即可前往String Table 查找符号对应的名称

image.png

String Table 起始位置为 0x18ce34
则符号名称的位置为 0x18ce34 + 0x257c4 == 0x 1b25f8

image.png

7、可读取到符号名称为FoundationURLRequestVMn,不等于我们要替换的NSLog,则回到第4步继续遍历下一个

8、符号在Indirect Symbols的顺序与在其在它所属段的顺序是一致的


image.png
image.png

因此找到名称相同的符号时可根据偏移量直接到所属section中修改符号最终绑定的位置

学习资料
iOS逆向工程 - fishhook原理

你可能感兴趣的:(fishhook 源码解读笔记)