我试图通过挂钩fopen()函数并使用LD_PRELOAD来记录对特定目录的访问。
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);
*(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()
,但没有帮助。
答案 0 :(得分:4)
您的代码中存在一些问题,这些问题已在下面的示例中修复(我还添加了相关标题并提供了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
指针的ffunction指针,您需要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
,{{1 }},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
}。
现在,这一切都非常好,但是,即使一旦你开始工作,你也必须截取几个不同的电话,以确保你能抓住所有的变化。
这将花费您很长时间才能完成,正如Chris Stratton在评论中指出的那样,Linux内核已经具有报告文件系统更改的能力你。
如果您的目标是仅跟踪文件系统更改而不是自行了解如何完成更改,请查看inotify以了解如何执行此操作,无需发明轮子。