c - Hook fopen() 函数抛出段错误

标签 c linux linux-kernel shared-libraries

我正在尝试通过 Hook fopen() 函数并使用 LD_PRELOAD 来记录对特定目录的访问。

  1. 我的第一个问题是: Hook fopen() 是否足以记录打开文件的操作?
  2. 我的代码抛出段错误。具体来说,代码是这样的(忽略错误检查): 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/

相关文章:

c 库定义了 int8_t

linux - 并行计算 : how to share computing resources among users?

c++ - 为什么 Xcode 6 在系统路径之前错误地包含用户路径?

c - 此版本的 C 程序内存不足。有人请告诉我为什么内存不足

php - 如何从 php 运行 linux 命令

使用 fork() 反增加子项和父项

c - GCC - Linux - 在返回之前将堆栈设置为零?

linux - 网络 block 设备 - 某些读取请求失败 - 内核 OOPS

linux - 为什么 HashiCorp 的 Vault 需要启用 ipc_lock 功能?

c - C语言有没有不用等待输入就可以检查用户是否输入的命令