我正在尝试使用我可以通过openat()
加载的自定义共享库拦截Linux上的LD_PRELOAD
系统调用。示例intercept-openat.c
包含以下内容:
#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <dlfcn.h>
int (*_original_openat)(int dirfd, const char *pathname, int flags, mode_t mode);
void init(void) __attribute__((constructor));
int openat(int dirfd, const char *pathname, int flags, mode_t mode);
void init(void)
{
_original_openat = (int (*)(int, const char *, int, mode_t))
dlsym(RTLD_NEXT, "openat");
}
int openat(int dirfd, const char *pathname, int flags, mode_t mode)
{
fprintf(stderr, "intercepting openat()...\n");
return _original_openat(dirfd, pathname, flags, mode);
}
我通过gcc -fPIC -Wall -shared -o intercept-openat.so intercept-openat.c -ldl
进行编译。然后,当我运行这个小例子程序时:
int main(int argc, char *argv[])
{
int fd;
fd = openat(AT_FDCWD, "/home/feh/.vimrc", O_RDONLY);
if(fd == -1)
return -1;
close(fd);
return 0;
}
openat()
调用通过库重写:
$ LD_PRELOAD=./intercept-openat.so ./openat
intercepting openat()...
但是,GNU tar也不会发生同样的情况,即使它使用相同的系统调用:
$ strace -e openat tar cf /tmp/t.tgz .vimrc
openat(AT_FDCWD, ".vimrc", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW|O_CLOEXEC) = 4
$ LD_PRELOAD=./intercept-openat.so tar cf /tmp/t.tgz .vimrc
因此,openat()
中的自定义intercept-openat.so
未被调用。那是为什么?
答案 0 :(得分:2)
它使用相同的系统调用,但显然它不会通过相同的C函数调用它。或者,也可能是这样,但它是静态链接的。
无论哪种方式,我认为你已经证明它永远不会动态链接函数名称“openat”。如果您仍想继续使用此选项,您可能希望查看它是否链接到该功能的特定版本,但这是一个很长的镜头。
您仍然可以通过编写程序来使用ptrace
拦截系统调用。这与strace和gdb使用的接口相同。但它会有更高的性能损失。