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

无法通过dlsym获取stat系列函数原指针的技术求助

解决dlsym无法获取stat/lstat/fstat原始函数指针的问题

我来帮你排查下这个棘手的问题——你尝试Hook stat/lstat/fstat这几个函数,但用dlsym获取原始函数指针时,三个变量都返回NULL,连dlerror()都没给出任何错误信息,这确实挺让人困惑的。结合我处理这类Hook问题的经验,下面是几个常见的原因和对应的解决办法:

1. 必须使用RTLD_NEXT作为dlsym的第一个参数

dlsym默认的查找逻辑是从当前库开始找符号,而我们需要的是系统libc中的原始函数,所以必须传入RTLD_NEXT作为第一个参数,它会告诉dlsym去查找下一个定义该符号的共享库(也就是系统的libc)。

错误的写法可能是用了RTLD_DEFAULT或者直接传NULL,这会导致dlsym在当前Hook库中找不到符号,返回NULL。正确的调用示例:

#include <dlfcn.h>
// ...
original_stat = (stat_func)dlsym(RTLD_NEXT, "stat");

2. 编译共享库的选项必须正确

编译Hook共享库时,有几个关键选项不能少:

  • -fPIC:生成位置无关代码,这是共享库的必备条件
  • -shared:告诉编译器生成共享库而非可执行文件
  • -ldl:链接libdl库,因为dlsym/dlerror这些函数都来自这个库

完整的编译命令应该是:

gcc -fPIC -shared -o fakestat.so fakestat.c -ldl

如果漏了-ldl,可能会导致隐式链接失败,dlsym无法正常工作,甚至不会给出明确错误。

3. 注意系统对stat系列函数的宏定义替换

很多Linux系统的stat/lstat/fstat其实是宏定义,比如在glibc中,它们可能被替换为stat64/lstat64/fstat64(为了支持大文件)。这时候你直接用"stat"作为符号名调用dlsym,会找不到对应的函数。

解决方法是在代码开头先取消这些宏定义,让代码中的stat指向真实的函数:

#undef stat
#undef lstat
#undef fstat

这样再用dlsym(RTLD_NEXT, "stat")就能正确找到原始函数了。

4. 确保LD_PRELOAD的使用方式正确

加载Hook库时,要注意:

  • 如果共享库在当前目录,必须加上./,否则系统会去系统库路径查找,导致找不到:
    LD_PRELOAD=./fakestat.so ./test
    
  • 测试程序必须是动态链接的,如果是静态链接的程序,LD_PRELOAD不会生效(静态链接程序不会加载外部共享库)。可以用file ./test查看是否是动态链接。

5. 调试技巧:验证系统libc中的符号存在性

如果还是有问题,可以用nm命令查看系统libc中是否存在这些符号:

nm -D /lib/x86_64-linux-gnu/libc.so.6 | grep -E 'stat|lstat|fstat'

输出应该包含类似00000000000f2340 W stat的行,确认符号名和你在dlsym中使用的一致。


完整的Hook示例代码

下面是一个可运行的示例,包含了上述所有注意点:

#define _GNU_SOURCE
#include <dlfcn.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>

// 取消宏定义,避免函数名被替换
#undef stat
#undef lstat
#undef fstat

// 定义函数指针类型
typedef int (*stat_func)(const char *, struct stat *);
typedef int (*lstat_func)(const char *, struct stat *);
typedef int (*fstat_func)(int, struct stat *);

// 保存原始函数指针(静态变量仅初始化一次)
static stat_func original_stat = NULL;
static lstat_func original_lstat = NULL;
static fstat_func original_fstat = NULL;

// Hook stat函数
int stat(const char *pathname, struct stat *buf) {
    if (!original_stat) {
        original_stat = (stat_func)dlsym(RTLD_NEXT, "stat");
        if (!original_stat) {
            fprintf(stderr, "Failed to get original stat: %s\n", dlerror());
            exit(EXIT_FAILURE);
        }
    }
    // 插入你的Hook逻辑
    printf("[Hooked] stat called for path: %s\n", pathname);
    // 调用原始函数
    return original_stat(pathname, buf);
}

// Hook lstat函数
int lstat(const char *pathname, struct stat *buf) {
    if (!original_lstat) {
        original_lstat = (lstat_func)dlsym(RTLD_NEXT, "lstat");
        if (!original_lstat) {
            fprintf(stderr, "Failed to get original lstat: %s\n", dlerror());
            exit(EXIT_FAILURE);
        }
    }
    printf("[Hooked] lstat called for path: %s\n", pathname);
    return original_lstat(pathname, buf);
}

// Hook fstat函数
int fstat(int fd, struct stat *buf) {
    if (!original_fstat) {
        original_fstat = (fstat_func)dlsym(RTLD_NEXT, "fstat");
        if (!original_fstat) {
            fprintf(stderr, "Failed to get original fstat: %s\n", dlerror());
            exit(EXIT_FAILURE);
        }
    }
    printf("[Hooked] fstat called for fd: %d\n", fd);
    return original_fstat(fd, buf);
}

编译后用LD_PRELOAD=./fakestat.so ls测试,你应该能看到Hook的输出。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 10:22:35