gpt4 book ai didi

c - 如何覆盖 A C 系统调用?

转载 作者:太空宇宙 更新时间:2023-11-04 07:50:36 25 4
gpt4 key购买 nike

所以问题如下。项目需要拦截所有文件IO操作,如 open()close()。我试图在调用相应的 open()close() 之前添加 printf()。我不应该通过将 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);
}

最佳答案

是的,你想要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


更新:

I am not familiar with C and I got the following problems with gcc. "error: 'NULL' undeclared (first use in this function)",

这是由几个 #include 定义的文件,所以试试 #include <stdio.h> .如果你想调用printf,你将需要它.

"error: 'RTLD_NEXT' undeclared (first use in this function)",

这是通过执行 #include <dlfcn.h> 来定义的[如我的示例所示]

and "symbol lookup error: ./hack_stackoverflow.so: undefined symbol: 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;
}

关于c - 如何覆盖 A C 系统调用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54141254/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com