Chinaunix首页 | 论坛 | 博客
  • 博客访问: 906595
  • 博文数量: 73
  • 博客积分: 2689
  • 博客等级: 少校
  • 技术积分: 897
  • 用 户 组: 普通用户
  • 注册时间: 2010-10-07 19:39
个人简介

一个有目标,为自己的未来努力奋斗的人

文章分类
文章存档

2015年(9)

2014年(2)

2013年(6)

2012年(11)

2011年(33)

2010年(12)

分类: LINUX

2011-04-27 02:29:45

众所周知,在Windows平台下可以使用挂钩(Hook)技术,将系统中的鼠标、键盘等事件拦截下来,以添加实现自己的功能。同样的,在Linux系统中也有类似的技术,都可以起到挂钩(Hook)拦截的作用。虽然可以实现拦截的功能,但是它们的实现原理是不同的(这点一定要注意)。

目前为止,笔者所知道的Linux系统下的一种挂钩技术,是通过libdl.so动态库中提供的一套函数dlopen(),dlsym(),dlerror(),dlclose()对动态共享链接库中的函数进行拦截的。这些函数的功能解析可以查看我的另一篇博文:http://blogold.chinaunix.net/u3/119372/showart_2534631.html。更详细的使用说明建议在unix/linux平台下使用man去了解。
 
拦截技术是现实时,它通过环境变量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;
}


阅读(8858) | 评论(11) | 转发(1) |
给主人留下些什么吧!~~

yzh071372015-04-07 15:49:53

你好,我在ubuntu 12.04.5下面试验了(内核版本是3.13.0-32-generic),输入sudo bash /mk.sh之后它提示这个错误
/bin/sh : symbol loopup error: /home/targetnull/Desktop/dlsym/dlsym.so: undefined symbol: dlopen
然后我用ldd查看了一下,发现依赖是这样的
./dlsym.so:
    linux-gate.so.1 => (0xb7700000)
    libc.so.6 => /lib/i386-linux/gnu/libc.so.6 (0xb7541000)
    /lib/ld-linux.so.2 (0xb7701000)
但是无论那我用ln软连接还是直接把.so复制过来,还是提示那个错误,请问是什么原因啊。
是因为内核版本的原因吗,还是我哪里遗漏了?