除了LD_PRELOAD技巧,以及用你提供的系统调用取代某个系统调用的Linux内核模块之外,是否有可能拦截一个系统调用(例如打开),以便在它到达实际打开之前首先通过你的函数?
为什么不能/不想使用LD_PRELOAD技巧?
这里的示例代码:
/* * File: soft_atimes.c * Author: D.J. Capelis * * Compile: * gcc -fPIC -c -o soft_atimes.o soft_atimes.c * gcc -shared -o soft_atimes.so soft_atimes.o -ldl * * Use: * LD_PRELOAD="./soft_atimes.so" command * * Copyright 2007 Regents of the University of California */ #define _GNU_SOURCE #include#define _FCNTL_H #include #include #include extern int errorno; int __thread (*_open)(const char * pathname, int flags, ...) = NULL; int __thread (*_open64)(const char * pathname, int flags, ...) = NULL; int open(const char * pathname, int flags, mode_t mode) { if (NULL == _open) { _open = (int (*)(const char * pathname, int flags, ...)) dlsym(RTLD_NEXT, "open"); } if(flags & O_CREAT) return _open(pathname, flags | O_NOATIME, mode); else return _open(pathname, flags | O_NOATIME, 0); } int open64(const char * pathname, int flags, mode_t mode) { if (NULL == _open64) { _open64 = (int (*)(const char * pathname, int flags, ...)) dlsym(RTLD_NEXT, "open64"); } if(flags & O_CREAT) return _open64(pathname, flags | O_NOATIME, mode); else return _open64(pathname, flags | O_NOATIME, 0); }
根据我的理解......它几乎是LD_PRELOAD技巧或内核模块.除非你想在一个模拟器下运行它,它可能会陷入你的函数或者在实际的二进制文件上重写代码来捕获你的函数,所以没有很多中间结构.
假设你不能修改程序而不能(或者不想)修改内核,LD_PRELOAD方法是最好的方法,假设你的应用程序是相当标准的,并且实际上并不是那个恶意试图过去的方法你的拦截.(在这种情况下,您将需要其他技术之一.)
Valgrind可用于拦截任何函数调用.如果您需要拦截成品中的系统调用,那么这将是没有用的.但是,如果您在开发期间尝试拦截,那么它可能非常有用.我经常使用这种技术来拦截散列函数,以便我可以控制返回的散列以进行测试.
如果您不知道,Valgrind主要用于查找内存泄漏和其他与内存相关的错误.但底层技术基本上是一个x86模拟器.它模拟你的程序并拦截对malloc/free等的调用.好的是,你不需要重新编译就可以使用它.
Valgrind有一个功能,他们称之为功能包装,用于控制功能的拦截.有关详细信息,请参见Valgrind手册的第3.2节.您可以为任何您喜欢的功能设置功能包装.拦截调用后,将调用您提供的替代函数.
有些应用程序可以欺骗strace/ptrace不运行,所以我唯一真正的选择就是使用systemtap
如果需要由于其通配符匹配,Systemtap可以拦截一堆系统调用.Systemtap不是C,而是一种单独的语言.在基本模式下,systemtap应该阻止你做愚蠢的事情,但它也可以在"专家模式"下运行,如果需要,可以回退到允许开发人员使用C.
它不需要你修补你的内核(或者至少不应该),并且一旦编译了一个模块,你就可以从测试/开发盒中复制它并在生产系统上插入它(通过insmod).
我还没有找到一个已经找到解决方法的linux应用程序/避免被systemtap捕获.