You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Linux下无需重编译,如何覆盖静态库链接的可执行文件中的方法?

可行方案及实现步骤

针对你在Linux平台下的需求,无需重编译App1即可替换静态链接的DoSmth()函数是可行的,以下是几种实操方案:

方案1:符号重定向+动态库预加载

静态链接的可执行文件中,全局符号默认对外可见(除非编译时指定-fvisibility=hidden),我们可以通过修改符号表实现劫持:

  • 第一步:用objcopy修改App1的符号表,将原DoSmth重命名为备用名:
    objcopy --redefine-sym DoSmth=DoSmth_original App1
    
  • 第二步:将Lib2编译为动态库,确保导出DoSmth函数:
    gcc -fPIC -shared lib2.c -o libLib2.so
    
  • 第三步:创建App2,通过预加载Lib2启动修改后的App1。App2的代码示例(C语言):
    #include <unistd.h>
    #include <stdlib.h>
    
    int main() {
        setenv("LD_PRELOAD", "./libLib2.so", 1);
        execl("./App1", "App1", NULL);
        return 0;
    }
    
    编译App2后运行,App1会自动调用Lib2中的DoSmth。

注意:如果App1编译时使用了-fvisibility=hidden或符号被优化为局部,此方案失效。

方案2:Ptrace运行时指令劫持

通过ptrace系统调用跟踪App1进程,修改其指令流实现函数替换,适合无法修改App1二进制的场景:

  • 核心思路:App2作为父进程启动App1,附加到目标进程后,找到DoSmth的内存地址,将该地址的开头指令修改为跳转指令,指向Lib2中DoSmth的入口(需先将Lib2注入到App1的进程空间)。
  • 关键步骤:
    1. 编写Lib2的注入逻辑:通过远程调用dlopen将Lib2加载到App1进程(可借助ptrace写入系统调用参数并执行)。
    2. 用objdump -d App1定位DoSmth的起始地址。
    3. 替换该地址的指令为跳转指令(比如x86_64平台的jmp指令),指向Lib2中DoSmth的地址。

注意:此方案依赖CPU架构,需要处理内存权限、指令长度匹配等问题,实现复杂度较高。

方案3:二进制文件直接替换函数段

直接修改App1的二进制内容,替换原DoSmth的指令:

  • 第一步:用objdump -d App1找到DoSmth函数的二进制指令在文件中的偏移量和长度。
  • 第二步:将Lib2的DoSmth编译为位置无关代码,提取其原始二进制指令:
    gcc -c -fPIC lib2.c -o lib2.o
    objcopy -O binary --only-section=.text lib2.o do_smth.bin
    
  • 第三步:用dd命令将do_smth.bin的内容写入App1的对应偏移位置:
    dd if=do_smth.bin of=App1 bs=1 seek=<原DoSmth的文件偏移> conv=notrunc
    

注意:必须保证Lib2的DoSmth指令长度不超过原函数的长度,否则会破坏相邻代码导致崩溃;若原函数存在重定位信息,此方案无法直接使用。

内容的提问来源于stack exchange,提问作者Mike

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 06:42:50