我正在尝试通过 Hook fopen() 函数并使用 LD_PRELOAD 来记录对特定目录的访问。
- 我的第一个问题是: Hook fopen() 是否足以记录打开文件的操作?
- 我的代码抛出段错误。具体来说,代码是这样的(忽略错误检查):
FILE* (<em>my_fopen)(const char</em> filename, const char* mode); void* libc_handle;<br/> void __attribute__ ((constructor)) init(void){ libc_handle = dlopen("libc.so.6", RTLD_LAZY); *(void**)(&my_fopen) = dlsym(libc_handle,"fopen"); } FILE* fopen(const char* filename, const char* mode){ printf("Hello world\n"); return my_fopen(filename, mode); }
在 LD_PRELOAD 中编译并指定新库后,我运行了
ls
它会抛出 Segmenation Fault。知道为什么会这样吗?我什至试图删除 printf()
,但没有帮助。
最佳答案
您的代码中存在一些问题,这些问题已在下面的示例中修复(我还添加了相关的 header 并提供了一个 main
以提供一个完整的程序):
#include <stdio.h>
#include <dlfcn.h>
FILE* (*my_fopen)(const char *filename, const char* mode);
void* libc_handle;
void __attribute__ ((constructor)) init(void){
libc_handle = dlopen("libc.so.6", RTLD_LAZY);
my_fopen = dlsym(libc_handle,"fopen");
}
FILE* fopen(const char* filename, const char* mode){
printf("Hello, Pax\n");
return my_fopen(filename, mode);
}
int main (void) {
FILE *fout = fopen ("xyzzy.txt","w");
fclose (fout);
return 0;
}
根据您提供的更改如下:
my_fopen
函数指针应该就是一个指针。我怀疑您可能已经想到了FILE*
做到了,但这实际上并不正确。指定返回FILE
的函数指针指针,你需要FILE * (*fn)(blah, blah)
.同样,该函数的第一个参数必须是
const char *
,换句话说,一个指针。你把它当作简单的const char
.您实际上不需要那个复杂的表达式来设置
my_fopen
指针(转换、获取地址、解除引用)。您可以使用更简单的my_fopen = ...
.事实上,我认为类型转换可能实际上是阻止的原因gcc
在这种情况下不会报告错误,因为如果您转换,它假设您知道自己在做什么。您可能还应该检查
dlopen
的返回值.我没有在这段代码中这样做,但是,如果您出于某种原因没有找到(或无法加载)该库,那之后的行可能会让您感到悲伤。
当我在 Red Hat Enterprise Linux Workstation release 6.4 (Santiago)
上编译并运行这个程序时,我得到 Hello, Pax
的输出和文件xyzzy.txt
已创建。
另外,还有其他函数可用于访问文件系统,例如open
。 , opendir
, freopen
, creat
, mkfifo
(我认为)。
根据您的需要,您可能需要做一些额外的工作。
您可能要考虑的一件事是 ls
甚至可能使用 fopen
.它实际上可以用 opendir/readdir
构建和 stat
.
那么,让我们使用一个我们知道调用的程序fopen
.输入以下程序 qqtest.c
:
#include <stdio.h>
int main (void) {
FILE *fh = fopen ("xyzzy.txt", "w");
fclose (fh);
return 0;
}
并用gcc -o qqtest qqtest.c
编译它,然后运行它。你应该看不到输出,但文件 xyzzy.txt
应该创建。确认后,删除 xyzzy.txt
文件,然后输入以下程序 qq.c
:
#include <stdio.h>
#include <dlfcn.h>
FILE* (*my_fopen)(const char *filename, const char* mode);
void* libc_handle;
void __attribute__ ((constructor)) init(void){
libc_handle = dlopen("libc.so.6", RTLD_LAZY);
my_fopen = dlsym(libc_handle,"fopen");
}
FILE* fopen(const char* filename, const char* mode){
printf("Hello, Pax\n");
return my_fopen(filename, mode);
}
用 gcc -shared -o qq.so qq.c -ldl
编译它然后运行你的 qqtest
程序(当然要将共享对象路径更改为您自己的目录):
LD_PRELOAD=/home/pax/qq.so ./qqtest
这一次,您应该看到 Hello, Pax
xyzzy.txt
之前的字符串输出文件已创建,证明它正在调用您的包装函数,该函数又调用原始 fopen
.
现在,这一切都很好,但是,即使您使这部分工作正常,您也必须拦截相当多的不同调用以确保捕获所有更改。
这将花费您相当长的时间才能完成,正如 Chris Stratton 在评论中指出的那样,Linux 内核已经能够向您报告文件系统更改。 p>
如果您的目标只是跟踪文件系统更改而不是自学如何完成,请查看 inotify了解如何无需重新发明轮子即可做到这一点。
关于c - Hook fopen() 函数抛出段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24947571/