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

如何在静态链接二进制文件中替换malloc调用?用户态热补丁咨询

静态链接二进制替换malloc的用户态热补丁方案

针对静态链接的C/C++二进制文件,无法用LD_PRELOAD劫持malloc的场景,用户态有多种类似内核ftrace的热补丁/动态插桩方案,无需修改源码或重新编译,直接在运行时或离线修改二进制实现函数替换:

1. 基于ptrace的手动动态插桩

这是最底层的用户态热补丁实现方式,核心是通过ptrace系统调用操控目标进程内存:

  • 核心步骤:
    • 解析目标二进制的ELF符号表,或通过调试信息/特征码扫描定位malloc函数的内存地址。
    • 用ptrace附加到目标进程并暂停它,读取malloc入口处的几条指令并保存(用于后续恢复或构造trampoline跳转)。
    • 将malloc入口指令替换为跳转指令(如x86的jmp),指向你自定义的malloc实现——自定义代码可以通过注入共享库到进程内存,或直接写入进程的可执行内存区域。
    • 恢复进程运行,此时所有malloc调用都会被劫持到你的实现。
  • 注意:需处理指令长度对齐问题,避免破坏原有指令逻辑;自定义malloc必须完全匹配原函数的参数、返回值和调用约定,多线程场景下还要保证线程安全。

2. Frida动态插桩框架

Frida是一款开箱即用的动态插桩工具,底层基于ptrace和代码注入,对静态链接程序的函数替换支持友好:

  • 示例脚本(JavaScript):
    // 先通过二进制符号表或内存扫描获取malloc的地址
    const mallocAddr = ptr("0x123456"); 
    // 保存原malloc函数的引用
    const originalMalloc = new NativeFunction(mallocAddr, 'pointer', ['size_t']);
    
    // 替换malloc调用
    Interceptor.replace(mallocAddr, new NativeCallback(function(size) {
        // 自定义逻辑:比如记录分配大小
        console.log(`malloc called with size: ${size}`);
        // 调用原malloc完成实际分配
        return originalMalloc(size);
    }, 'pointer', ['size_t']));
    
  • 执行方式:运行frida -n target_binary -l replace_malloc.js即可自动完成进程注入和函数替换,无需手动处理ptrace细节。

3. 离线二进制重写

如果不需要运行时动态替换,也可以直接修改静态链接的二进制文件本身:

  • 实现方式:用objcopy、patch工具或自定义ELF解析程序,找到malloc的符号地址,修改其入口指令为跳转至自定义函数;或遍历所有调用malloc的指令位置,修改跳转目标。
  • 注意:修改前需确保二进制文件可写,且修改后不会破坏ELF文件结构;若程序有代码签名,修改后可能无法正常运行。

4. Intel Pin动态二进制插桩

Intel Pin是一款面向性能分析和插桩的工具,支持在程序运行时拦截所有函数调用(包括静态链接函数):

  • 示例Pin工具代码(C++):
    #include "pin.H"
    #include <cstdio>
    
    // 自定义malloc实现
    void* MyMalloc(size_t size) {
        printf("Custom malloc triggered, size: %zu\n", size);
        // 调用原malloc完成分配
        return malloc(size);
    }
    
    // 拦截malloc的返回地址,替换为自定义函数的结果
    VOID ReplaceMalloc(ADDRINT* retAddr, size_t size) {
        *retAddr = (ADDRINT)MyMalloc(size);
    }
    
    // 注册插桩逻辑
    VOID InstrumentRoutine(RTN rtn, VOID* v) {
        if (RTN_Name(rtn) == "malloc") {
            RTN_ReplaceSignature(rtn, AFUNPTR(ReplaceMalloc),
                                 IARG_RETURN_IP, IARG_FUNCARG_ENTRYPOINT_VALUE, 0,
                                 IARG_END);
        }
    }
    
    int main(int argc, char* argv[]) {
        PIN_Init(argc, argv);
        RTN_AddInstrumentFunction(InstrumentRoutine, 0);
        PIN_StartProgram();
        return 0;
    }
    
  • 执行方式:编译Pin工具后,运行pin -t my_malloc_patch.so -- target_binary,Pin会自动完成指令插桩和函数替换。

核心注意事项

  • 函数兼容性:自定义malloc必须和原函数的参数、返回值、调用约定(如cdecl、fastcall)完全一致,否则会导致程序崩溃。
  • 线程安全:如果目标程序是多线程的,自定义实现必须保证线程安全,比如添加互斥锁避免竞态条件。
  • 权限:操作进程内存或修改二进制文件需要足够权限(如root),尤其是针对系统级进程。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 10:16:15