所以问题出在下面。项目需要拦截所有文件IO
操作,例如open()
和close()
。我试图在调用相应的printf()
或open()
之前添加close()
。我不应该通过将open()
或close()
更改为myOpen()
或myClose()
来重写源代码。我一直在尝试使用LD_PRELOAD
环境变量。但是出现了无限循环问题。我的问题是这样的one。
int open(char * path,int flags,int mode)
{
// print file name
printf("open :%s\n",path);
return __open(path,flags,mode);
}
答案 0 :(得分:2)
是的,您想要LD_PRELOAD
。
您需要创建一个共享库(.so
),其中包含要拦截的所有功能的代码。而且,您想要设置LD_PRELOAD
以使用该共享库
以下是open
函数的一些示例代码。您需要为要拦截的每个函数做类似的事情:
#define _GNU_SOURCE
#include <dlfcn.h>
int
open(const char *file,int flags,int mode)
{
static int (*real_open)(const char *file,int flags,int mode) = NULL;
int fd;
if (real_open == NULL)
real_open = dlsym(RTLD_NEXT,"open");
// do whatever special stuff ...
fd = real_open(file,flags,mode);
// do whatever special stuff ...
return fd;
}
我相信RTLD_NEXT
最简单,可能就足够了。否则,您可以添加一个对dlopen
libc
的构造函数
更新:
我不熟悉C,并且gcc遇到以下问题。 “错误:未声明'NULL'(此功能首次使用)”,
这是由几个#include
文件定义的,因此请尝试#include <stdio.h>
。如果您要致电printf
,则需要使用此电话。
“错误:未声明'RTLD_NEXT'(此功能首次使用)”,
这是通过执行#include <dlfcn.h>
来定义的(如我的示例所示)
和“符号查找错误:./hack_stackoverflow.so:未定义的符号:dlsym”。
在man dlsym
中说:与-ldl
链接因此,将-ldl
添加到构建.so
的行中。
此外,如果“特殊内容”所做的事情会在您的拦截函数上循环返回,则必须小心以防止无限递归。
值得注意的是,您想致电printf
。如果您拦截write
系统调用,则可能会发生不良情况。
因此,您需要跟踪何时已进入某个拦截函数,并且不(如果已存在)进行一些特殊操作。请参见in_self
变量。
#define _GNU_SOURCE
#include <stdio.h>
#include <dlfcn.h>
ssize_t
write(int fd,const void *buf,size_t len)
{
static ssize_t (*real_write)(int fd,const void *buf,size_t len) = NULL;
static int in_self = 0;
ssize_t err;
if (real_write == NULL)
real_write = dlsym(RTLD_NEXT,"write");
++in_self;
if (in_self == 1)
printf("mywrite: fd=%d buf=%p len=%ld\n",fd,buf,len);
err = real_write(fd,buf,len);
if (in_self == 1)
printf("mywrite: fd=%d buf=%p err=%ld\n",fd,buf,err);
--in_self;
return err;
}
上面的方法对于单线程程序/环境来说还可以,但是如果您拦截任意一个程序,则它可能是多线程。
因此,我们必须在构造函数中初始化所有real_*
指针。这是一个具有特殊属性的函数,它告诉动态加载程序自动调用该函数。
而且,我们必须将in_self
放入线程本地存储。为此,我们添加了__thread
属性。
对于多线程版本,您可能需要链接-lpthread
和-ldl
。
编辑:我们还必须保留正确的errno
值
将它们放在一起:
#define _GNU_SOURCE
#include <stdio.h>
#include <dlfcn.h>
#include <errno.h>
static int (*real_open)(const char *file,int flags,int mode) = NULL;
static ssize_t (*real_write)(int fd,const void *buf,size_t len) = NULL;
__attribute__((constructor))
void
my_lib_init(void)
{
real_open = dlsym(RTLD_NEXT,"open");
real_write = dlsym(RTLD_NEXT,"write");
}
int
open(const char *file,int flags,int mode)
{
int fd;
// do whatever special stuff ...
fd = real_open(file,flags,mode);
// do whatever special stuff ...
return fd;
}
ssize_t
write(int fd,const void *buf,size_t len)
{
static int __thread in_self = 0;
int sverr;
ssize_t ret;
++in_self;
if (in_self == 1)
printf("mywrite: fd=%d buf=%p len=%ld\n",fd,buf,len);
ret = real_write(fd,buf,len);
// preserve errno value for actual syscall -- otherwise, errno may
// be set by the following printf and _caller_ will get the _wrong_
// errno value
sverr = errno;
if (in_self == 1)
printf("mywrite: fd=%d buf=%p ret=%ld\n",fd,buf,ret);
--in_self;
// restore correct errno value for write syscall
errno = sverr;
return ret;
}