众所周知,在Windows平台下可以使用挂钩(Hook)技术,将系统中的鼠标、键盘等事件拦截下来,以添加实现自己的功能。同样的,在Linux系统中也有类似的技术,都可以起到挂钩(Hook)拦截的作用。虽然可以实现拦截的功能,但是它们的实现原理是不同的(这点一定要注意)。
拦截技术是现实时,它通过环境变量LD_PRELOAD设置优先被加载器加载的动态库(以下简称拦截动态库),这里应该设置LD_PRELOAD=“xxx.so”,其中xxx.so是经过特殊功能封装的用于实现拦截功能的动态库。具体细节见下文。这样做的目的是为了在让那些使用了这些动态库的程序,在加载其中相应的函数时优先连接拦截动态库,之后根据需要来决定是否调用真正的目标函数。这些工作的实施其实都是在已经加载到内存的动态库中进行的。
用于劫持的动态链接库源文件:
/* Filename: dlsym.c */ #include <stdio.h> #include <stdlib.h> #include <dlfcn.h>
int (*realopen)(const char *pathname, int flags); int (*realclose)(int fd);
int open(const char *pathname, int flags) {
void *handle; char *error;
handle = dlopen("libc.so.6", RTLD_LAZY);//获得libc.so.6的句柄
if ((error = dlerror()) != NULL) { puts(error); exit(-1); }
realopen = dlsym(handle, "open");//返回open函数在libc.so.6中的加载时地址
if ((error = dlerror()) != NULL) { puts(error); exit(-1); }
fputs("you will open the file: ", stderr); puts(pathname);
return realopen(pathname, flags);//调用实际的open函数 }
int close(int fd) {
void *handle; char *error; handle = dlopen("libc.so.6", RTLD_LAZY);
if ((error = dlerror()) != NULL) { puts(error); exit(-1); }
realclose = dlsym(handle, "close");
if ((error = dlerror()) != NULL) { puts(error); exit(-1); }
printf("the file's fd you will close is: %d\n", fd); return realclose(fd); }
|
用于编译上述代码,并生成劫持库的脚本。
gcc -fpic -c -ldl dlsym.c #-fpic or -fPIC用于生成于位置无关的动态链接库
if [ -f dlsym.o ]; then gcc -shared -lc -o dlsym.so dlsym.o #-shared 用于指示生成共享库 fi
if [ -f dlsym.o ]; then rm dlsym.o fi
export LD_PRELOAD=`pwd`"/dlsym.so" #export LD_LIBRARY_PATH=`pwd` #export DT_RPATH=`pwd`
#export | grep LD #export | grep DT
ldconfig dlsym.so exit 0
|
用于测试的源码:
#include <stdio.h> #include <stdlib.h>
int main(int argc, char **argv) {
int fd = open("dlsym.c", 0);
if (fd != -1) close(fd);
return 0; }
|
阅读(8857) | 评论(11) | 转发(1) |