如何通用地Hook ELF可执行文件内部未导出的非共享库函数?
可行方案整理
针对未导出的ELF内部函数Hook需求,按优先级从高到低提供以下可落地的方案:
方案1:完全不修改原ELF,基于Linux内核uprobes/eBPF实现
这是当前最符合要求的方案,无需ptrace、无需手写shellcode、无需改动磁盘上的任何文件:
- 第一步先获取
foo函数在原ELF内的静态偏移:执行objdump -d ./elf | grep "<foo>:"即可拿到foo的段内偏移,例如输出为0000000000001234 <foo>:,则偏移为0x1234。 - 直接使用bcc工具集的
uprobe命令,或者编写极简eBPF程序,将钩子挂载到该偏移地址。当程序执行到foo入口时,内核会自动触发你的foo_hook逻辑,支持直接替换返回值、跳过原函数执行、或者执行完钩子后继续走原foo逻辑。 - 兼容性要求:Linux内核版本>=3.5,当前所有主流服务器、桌面发行版均满足该要求。
注意:该方案需要root权限执行
方案2:完全不修改原ELF,基于自定义动态链接器实现
如果你可以自定义动态链接器,不需要改动原ELF本身:
- 编译一个修改过的glibc动态链接器(ld-linux.so),在加载完原ELF到内存后、执行ELF入口代码前,添加以下逻辑:
- 加载你包含
foo_hook的共享对象到进程地址空间 - 找到原ELF代码段中所有调用
foo的指令,将调用地址替换为foo_hook的内存地址 - 恢复代码段只读权限后继续执行原程序
- 加载你包含
- 运行时仅需要指定动态链接器即可:
./ld-linux-modified.so ./elf
方案3:可修改原ELF(无需重新编译),基于二进制插桩工具实现
使用成熟的二进制插桩框架dyninst,全程不需要手写shellcode:
- 你只需要编写几十行C/C++代码,指定原ELF路径、
foo的偏移、以及foo_hook的函数指针,dyninst会自动完成以下操作:- 静态修改磁盘上的原ELF,添加对您的共享对象的依赖
- 替换所有内部对
foo的调用指向foo_hook - 自动处理所有重定位、权限修正逻辑,修改后的ELF可以直接运行,不需要额外依赖
内容的提问来源于stack exchange,提问作者Amit Botzer
相关产品推荐
相关产品推荐

