如何在Linux中检测文件访问? [英] How can I detect file accesses in Linux?
问题描述
我有一堆流和数据处理应用程序,我偶尔需要窥探,这意味着我需要知道他们阅读什么文件。这主要是帮助包装测试用例,但也可以在调试时使用。
有没有办法以这种方式运行可执行文件,生成这样的列表?
我有两个想法:
- 可以调用,该命令调用我的应用程序。沿着GDB的线。我调用GDB,给它一个路径的可执行文件和一些参数和GDB调用它为我。也许有类似的东西类似告诉我如何使用系统资源。
- 也许更有趣(但不必要的边路径)解决方案。
- 更改LD_LIBRARY_PATH以指向新库 >
- 在编辑器中创建真实libc.so的副本并重命名fopen(nepof,可能)
- 我的库加载副本并调用重命名的函数必须提供fopen功能。
- 调用应用程序,然后调用我的代理fopen。
替代#1肯定会是最好的,但是对于如何更容易地做#2的评论也很受欢迎。
一个选项是使用strace:
strace -o logfile -eopen yourapp
这将记录所有打开文件的事件,但它会强加性能惩罚。它具有易于使用的优点。
另一个选择是使用LD_PRELOAD。这对应于您的选项#2。其基本思路是做这样的事情:
的#define _GNU_SOURCE
&#包括LT; stdio.h中>
#include< dlfcn.h>
int open(const char * fn,int flags){
static int(* real_open)(const char * fn,int flags);
if(!real_open){
real_open = dlsym(RTLD_NEXT,open);
}
fprintf(stderr,打开的文件'%s'\ n,fn);
return real_open(fn,flags);
}
然后建立:
gcc -fPIC -shared -ldl -o preload-example.so preload-example.c
运行程序,例如:
$ LD_PRELOAD = $ PWD / preload-example .so cat / dev / null
打开文件'/ dev / null'
。少得多的开销
请注意,但是,还有其他入口点的打开文件 - 例如,fopen()函数,openat(),或许多遗留的兼容性之一入口点:
00000000000747d0摹DF的.text 000000000000071c GLIBC_2.2.5 _IO_file_fopen
0000000000068850克DF的.text 000000000000000a GLIBC_2.2.5 FOPEN
000000000006fe60摹DF的.text 00000000000000e2 GLIBC_2.4 open_wmemstream
00000000001209c0W¯¯DF .text区段00000000000000ec GLIBC_2.2.5 posix_openpt
0000000000069e50摹DF的.text 00000000000003fb GLIBC_2.2.5 _IO_proc_open
00000000000dcf70摹DF的.text 0000000000000021 GLIBC_2.7 __open64_2
0000000000068a10摹DF的.text 00000000000000f5 GLIBC_2.2.5 fopencookie的
000000000006a250摹DF的.text 000000000000009b GLIBC_2.2.5的popen
00000000000d7b10W¯¯DF .text区段0000000000000080 GLIBC_2.2.5 __open64
0000000000068850克DF的.text 000000000000000a GLIBC_2.2.5 _IO_fopen
00000000000d7e70W¯¯DF .text区段0000000000000020 GLIBC_2.7 __openat64_2
00000000000e1ef0摹DF的.text 000000000000005b GLIBC_2.2.5 openlog
00000000000d7b10W¯¯DF的.text 0000000000000080 GLIBC_2.2.5 open64
0000000000370c10 g执行的.bss 0000000000000008 GLIBC_PRIVATE _dl_open_hook
0000000000031680克DF的.text 0000000000000240 GLIBC_2.2.5的catopen
000000000006a250摹DF的.text 000000000000009b GLIBC_2.2.5 _IO_popen
0000000000071af0摹DF的.text 000000000000026a GLIBC_2.2.5 freopen64
00000000000723a0摹DF的.text 0000000000000183 GLIBC_2.2.5 fmemopen
00000000000a44f0W¯¯DF .text区段0000000000000088 GLIBC_2.4 fdopendir
00000000000d7e70摹DF的.text 0000000000000020 GLIBC_2.7 __openat_2
00000000000a3d00W¯¯DF .text区段0000000000000095 GLIBC_2.2.5执行opendir
00000000000dcf40摹DF的.text 0000000000000021 GLIBC_2.7 __open_2
00000000000d7b10W¯¯DF .text区段0000000000000080 GLIBC_2.2.5 __open
0000000000074370克DF的.text 00000000000000d7 GLIBC_2.2.5 _IO_file_open
0000000000070b40摹DF的.text 00000000000000d2 GLIBC_2.2.5 open_memstream
0000000000070450克DF的.text 0000000000000272 GLIBC_2.2.5 freopen函数
00000000000318c0摹DF的.text 00000000000008c4 GLIBC_PRIVATE __open_catalog
00000000000d7b10W¯¯DF .text区段0000000000000080 GLIBC_2.2.5开放
0000000000067e80摹DF的.text 0000000000000332 GLIBC_2.2.5 fdopen
000000000001e9b0摹DF的.text 00000000000003f5 GLIBC_2.2.5 iconv_open子
00000000000daca0摹DF的.text 000000000000067b GLIBC_2 .2.5 fts_open
00000000000d7d60W¯¯DF .text区段0000000000000109 GLIBC_2.4 openat
0000000000068850瓦特DF的.text 000000000000000a GLIBC_2.2.5 fopen64
00000000000d7d60W¯¯DF .text区段0000000000000109 GLIBC_2.4 openat64
00000000000d6490摹DF .text区段00000000000000b6 GLIBC_2.2.5 posix_spawn_file_actions_addopen
0000000000121b80摹DF的.text 000000000000008a GLIBC_PRIVATE __libc_dlopen_mode
0000000000067e80摹DF的.text 0000000000000332 GLIBC_2.2.5 _IO_fdopen
您可能需要连接所有这些设备的完整性 - 最起码,不是_应迷上前缀的人。尤其是,一定要挂钩的fopen单独的,从fopen()函数打开()不是由LD_PRELOAD库大呼过瘾。
$ B $ libc中内部通话b
一个类似的警告适用于与strace - 还有就是'openat'系统调用为好,并根据您的架构有可能是其他传统的系统调用为好。但没有LD_PRELOAD挂钩那么多,所以如果你不介意性能影响,它可能是一个更容易的选择。
I have a bunch of flows and data processing applications that I occasionally need to spy on, meaning I need to know what files they read. This is mostly to aid in packaging testcases, but can also be useful when debugging.
Is there a way to run the executables in such a way that produces such a list?
I have two thoughts on this:
- There is a command that I can invoke and that command invokes my apps. Something along the lines of GDB. I call GDB, give it a path to the executable and some arguments and GDB calls it for me. Perhaps there's something similar to telling me how system resources are used.
- Maybe the more interesting (but unnecessary side path) solution.
- create library called libc.so which implements fopen (and some others)
- change LD_LIBRARY_PATH to point at the new library
- make a copy of the real libc.so and rename fopen (nepof, perhaps) in an editor
- my library loads the copy and calls the renamed function as necessary to provide fopen functionality.
- call the app which then calls my proxy fopen.
Alternative #1 would certainly be the preferable one but comments on how to do #2 more easily are welcome too.
One option is to use strace:
strace -o logfile -eopen yourapp
This will log all file-open events, but it will impose a performance penalty that may be significant. It has the advantage of being easy to use however.
Another option is to use LD_PRELOAD. This corresponds to your option #2. The basic idea is to do something like this:
#define _GNU_SOURCE
#include <stdio.h>
#include <dlfcn.h>
int open(const char *fn, int flags) {
static int (*real_open)(const char *fn, int flags);
if (!real_open) {
real_open = dlsym(RTLD_NEXT, "open");
}
fprintf(stderr, "opened file '%s'\n", fn);
return real_open(fn, flags);
}
Then build with:
gcc -fPIC -shared -ldl -o preload-example.so preload-example.c
And run your program with eg:
$ LD_PRELOAD=$PWD/preload-example.so cat /dev/null
opened file '/dev/null'
This has much less overhead.
Note, however, that there are other entry points for opening files - eg, fopen(), openat(), or one of the many legacy compatibility entry points:
00000000000747d0 g DF .text 000000000000071c GLIBC_2.2.5 _IO_file_fopen
0000000000068850 g DF .text 000000000000000a GLIBC_2.2.5 fopen
000000000006fe60 g DF .text 00000000000000e2 GLIBC_2.4 open_wmemstream
00000000001209c0 w DF .text 00000000000000ec GLIBC_2.2.5 posix_openpt
0000000000069e50 g DF .text 00000000000003fb GLIBC_2.2.5 _IO_proc_open
00000000000dcf70 g DF .text 0000000000000021 GLIBC_2.7 __open64_2
0000000000068a10 g DF .text 00000000000000f5 GLIBC_2.2.5 fopencookie
000000000006a250 g DF .text 000000000000009b GLIBC_2.2.5 popen
00000000000d7b10 w DF .text 0000000000000080 GLIBC_2.2.5 __open64
0000000000068850 g DF .text 000000000000000a GLIBC_2.2.5 _IO_fopen
00000000000d7e70 w DF .text 0000000000000020 GLIBC_2.7 __openat64_2
00000000000e1ef0 g DF .text 000000000000005b GLIBC_2.2.5 openlog
00000000000d7b10 w DF .text 0000000000000080 GLIBC_2.2.5 open64
0000000000370c10 g DO .bss 0000000000000008 GLIBC_PRIVATE _dl_open_hook
0000000000031680 g DF .text 0000000000000240 GLIBC_2.2.5 catopen
000000000006a250 g DF .text 000000000000009b GLIBC_2.2.5 _IO_popen
0000000000071af0 g DF .text 000000000000026a GLIBC_2.2.5 freopen64
00000000000723a0 g DF .text 0000000000000183 GLIBC_2.2.5 fmemopen
00000000000a44f0 w DF .text 0000000000000088 GLIBC_2.4 fdopendir
00000000000d7e70 g DF .text 0000000000000020 GLIBC_2.7 __openat_2
00000000000a3d00 w DF .text 0000000000000095 GLIBC_2.2.5 opendir
00000000000dcf40 g DF .text 0000000000000021 GLIBC_2.7 __open_2
00000000000d7b10 w DF .text 0000000000000080 GLIBC_2.2.5 __open
0000000000074370 g DF .text 00000000000000d7 GLIBC_2.2.5 _IO_file_open
0000000000070b40 g DF .text 00000000000000d2 GLIBC_2.2.5 open_memstream
0000000000070450 g DF .text 0000000000000272 GLIBC_2.2.5 freopen
00000000000318c0 g DF .text 00000000000008c4 GLIBC_PRIVATE __open_catalog
00000000000d7b10 w DF .text 0000000000000080 GLIBC_2.2.5 open
0000000000067e80 g DF .text 0000000000000332 GLIBC_2.2.5 fdopen
000000000001e9b0 g DF .text 00000000000003f5 GLIBC_2.2.5 iconv_open
00000000000daca0 g DF .text 000000000000067b GLIBC_2.2.5 fts_open
00000000000d7d60 w DF .text 0000000000000109 GLIBC_2.4 openat
0000000000068850 w DF .text 000000000000000a GLIBC_2.2.5 fopen64
00000000000d7d60 w DF .text 0000000000000109 GLIBC_2.4 openat64
00000000000d6490 g DF .text 00000000000000b6 GLIBC_2.2.5 posix_spawn_file_actions_addopen
0000000000121b80 g DF .text 000000000000008a GLIBC_PRIVATE __libc_dlopen_mode
0000000000067e80 g DF .text 0000000000000332 GLIBC_2.2.5 _IO_fdopen
You may need to hook all of these for completeness - at the very least, the ones not prefixed with _ should be hooked. In particular, be sure to hook fopen seperately, as the libc-internal call from fopen() to open() is not hooked by a LD_PRELOAD library.
A similar caveat applies to strace - there is the 'openat' syscall as well, and depending on your architecture there may be other legacy syscalls as well. But not as many as with LD_PRELOAD hooks, so if you don't mind the performance hit, it may be an easier option.
这篇关于如何在Linux中检测文件访问?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!