fishhook源码问题

fishhook的源码中有如下代码:

//找到__LINKEDIT的基地址
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);
//indirect symbol table
uint32_t *indirect_symtab = (uint32_t *)(linkedit_base + dysymtab_cmd->indirectsymoff);

对linkedit_base有点不理解:

  1. 这个值不就是header的内存地址吗?也就是MachO文件映射到内存后,文件开头位置0x0对应到内存的位置值

  2. MachO文件映射到内存后占用的内存大小就是MachO文件的大小吗?

  3. 看到有说VM大小应该是大于等于文件大小的,如果是这样,那计算符号表地址的时候是linkedit_base + symtab_cmd->symoff, symtab_cmd->symoff 的意思应该是符号表的位置相对于文件开头0x0的偏移量啊,感觉MachO文件里的各个地址应该是和内存里的地址一一对应才对啊

来个懂MachO的大佬说几句呀

映射是分段的 不然ASLR就白ASLR了,而且会有问题,例如bss(未初始化堆)在文件里是0大小,但是映射到内存的时候要把这部分空出来,也就是macho装载到内存之后比文件大
符号在LINKEDIT段里面,所以先从文件的加载指令里面找到当前段相对于加载开始位置的偏移(linkedit_base)然后再从中找符号表

意思是符号表的这个偏移量(symtab_cmd->symoff)或者字符串表的偏移量(symtab_cmd->stroff)是相对于__LINKEDIT段的真实内存起始地址而言的?而不是相对于MachO文件的header内存地址而言的 是吧?

符号表偏移是相对于文件开始位置的,但是映射到内存的时候应该按照vm_off这个内存偏移来找。

这个linkedit_base,通过 加内存偏移 减文件偏移 相当于是把文件偏移转换成了内存偏移。所以可以直接拿任何属于__linkedit的文件偏移加到这个值上变成内存地址

https://juejin.cn/post/7125330919925219336

这个 linkedit_base 既不是模块基址(但有可能是),也不是 __LINKEDIT 段的运行时地址。

因为 __LINKEDIT 段前面的段有可能 VM Size > File Size。

又因为符号表是在 __LINKEDIT 段,所以要计算 symtable 运行时地址,模块基址加上这些多映射的空间,再加上 symoff 才是正确的。

而这个 linkedit_base 正正就是 模块基址 + __LINKEDIT 段前面的段 (VM Size - File Size)差值之和。

1.这个值不就是header的内存地址吗?
不一定,系统shared_cache中的动态库,每个segment是经过aslr的,所以linkedit地址不一定是header地址
2.MachO文件映射到内存后占用的内存大小就是MachO文件的大小吗?
大小不同,以普通macho(非fat)为例,因为文件映射到内存以后,每个segment都会映射到更高的地址,所以模块占的整个内存块比整个macho要大,所以ida中显示的地址范围大小基本和内存一致,而非文件大小。