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

如何使用LD_PRELOAD拦截普通符号?

如何用LD_PRELOAD拦截非动态符号?

LD_PRELOAD仅能拦截动态导出的符号,普通符号(未加入全局符号表的内部符号)无法直接通过常规LD_PRELOAD方式拦截,原因是动态链接器加载库时不会暴露这类符号,导致预加载库无法找到对应符号,出现你遇到的undefined symbol错误。以下是几种可行的解决方法:

方法1:修改目标库的符号可见性

通过objcopy将目标普通符号转为动态导出符号,让动态链接器能识别它:

# 先备份原库,避免破坏系统文件
cp /usr/lib64/libc-2.17.so /usr/lib64/libc-2.17.so.bak
# 将__opendirat设为全局可见(动态符号)
objcopy --add-symbol __opendirat=__opendirat:global /usr/lib64/libc-2.17.so

操作后用nm -D /usr/lib64/libc-2.17.so就能看到__opendirat,此时你的预加载库可以正常拦截该函数。若不想修改系统库,可复制一份libc到本地目录修改,再通过LD_LIBRARY_PATH指定使用修改后的库。

方法2:使用内联钩子(无需修改原库)

直接修改原库中目标函数的机器码,强制跳转到你的自定义实现,步骤如下:

  1. 用nm libc-2.17.so找到__opendirat在库中的偏移地址(比如0x123456);
  2. 编写钩子代码(以x86_64架构为例):
#include <stdio.h>
#include <sys/mman.h>
#include <dlfcn.h>
#include <stdint.h>

// 保存原函数指针
static int (*original___opendirat)(int, const char*) = NULL;

// 自定义拦截实现
int __opendirat(int fd, const char* path) {
    printf("已拦截__opendirat调用:fd=%d, path=%s\n", fd, path);
    return original___opendirat(fd, path);
}

// 程序加载时自动执行钩子初始化
__attribute__((constructor)) void init_hook() {
    // 获取libc的基地址
    void* libc_base = dlopen("/usr/lib64/libc-2.17.so", RTLD_LAZY);
    // 计算__opendirat的实际内存地址(基地址+偏移)
    uintptr_t target_addr = (uintptr_t)libc_base + 0x123456; // 替换为nm查到的偏移
    original___opendirat = (void*)target_addr;
    dlclose(libc_base);

    // 修改内存页权限为可写可执行
    uintptr_t page_addr = target_addr & ~(4095); // 对齐到页起始
    mprotect((void*)page_addr, 4096, PROT_READ | PROT_WRITE | PROT_EXEC);

    // 写入x86_64的跳转指令(jmp rel32)
    uint8_t jmp_code[] = {0xE9, 0x00, 0x00, 0x00, 0x00};
    int32_t offset = (uintptr_t)__opendirat - target_addr - 5; // 计算相对偏移
    memcpy(&jmp_code[1], &offset, sizeof(offset));
    memcpy((void*)target_addr, jmp_code, sizeof(jmp_code));

    // 恢复内存页权限为只读可执行
    mprotect((void*)page_addr, 4096, PROT_READ | PROT_EXEC);
}
  1. 编译预加载库:
gcc -shared -fPIC hook.cpp -o hook.so -ldl
  1. 运行目标程序时加载钩子:
LD_PRELOAD=./hook.so ./your_target_program

方法3:重编译目标库(需源码)

如果能获取libc源码,可在__opendirat函数定义处添加__attribute__((visibility("default"))),强制将其设为动态导出符号,重新编译libc后即可用常规LD_PRELOAD拦截。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 22:07:43