网上已经有不少相关文章,具体可参考:
通过getuid、printf等函数讲解了基本的加钩子的方法:
http://blog.chinaunix.net/u/9577/showart_1195703.html
如果你希望的不仅仅是替换掉原有库函数,而且还希望最终将函数逻辑传递到原有系统函数,那么你可能需要用到RTLD_NEXT。系统可能提示RTLD_NEXT未定义,这里给出了解决方案:
http://xueruini.spaces.live.com/blog/cns!DF086AB717BC7F6F!517.entry
使用dlsym时候可能遇到链接错误,提示找不到dlsym。解决方法是编译的时候加上-ldl编译选项:
http://blog.tianya.cn/blogger/post_show.asp?BlogID=78856&PostID=13635493
我的过程记录
fork.c,最后编译成fork.so
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <dlfcn.h>
/* 即使按照参考文献中的方法,定义__USE_GNU
* 还是被提示RTLD_NEXT未定义
* 只能用这种猥琐的,不可移植的方法了
* 实验目的,无伤大雅。
*/
# define RTLD_NEXT ((void *) -1l)
static pid_t (*real_fork)(void);
pid_t fork(void)
{
printf("Fork is called/n");
if (real_fork == NULL)
{
real_fork = (pid_t (*)(void))dlsym( RTLD_NEXT, "fork" );
}
return real_fork();
}
strlen.c,最后编译成strlen.so 。 需要说明的是,最后这个so没有用到,因为我遇到了一个诡异的事情,详细见后文。
#include <stdio.h>
size_t strlen(const char *s)
{
size_t i = 0;
printf("strlen is called, return x/n");
while(*s)
{
i++;
s++;
}
return i;
}
测试代码。测试了strlen和fork。
但是,我并没有为strlen加钩子,因为,我发现,无论是否挂钩strlen,这个测试函数总是没有反应,根本没有进入到strlen.c的代码中。不过呢,当我用export LD_PRELOAD="./strlen.so"后,vi、ls等应用程序都能够进入到strlen.c中,唯独我的./hello不能进入strlen.c。诡异!
fork函数测试有效。
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc,char** argv)
{
pid_t m;
if(argc < 2)
exit(0);
const char* hello = argv[1];
printf("%s length is %d/n",hello, strlen(hello));
m = fork();
printf("pid=%d/n", (pid_t)m);
return 0;
}
编译过程(只涉及到 fork.c 和 hello.c )
gcc -fPIC -shared -ldl -o fork.so fork.c
; note: 如果没有家ldl,则提示找不到符号dlsym,没有家-fPIC,则编译器会提示添加此选项。跟网上的一些资料有点出入。
gcc -o hello hello.c
export LD_PRELOAD="./fork.so"
./hello abcd
abcd length is 4
Fork is called
pid=0
pid=12828
export LD_PRELOAD=""
; clear preload path
上面使用LD_PRELOAD的方法有个问题,它是一个持久的全局设置,可能会影响到./hello之外的程序的正常行为。一个更好的使用方法是直接执行:
LD_PRELOAD="./fork.so" ./hello abcd
后记:
关于dlsym
#include <dlfcn.h>
void *dlopen(const char *filename, int flag);
char *dlerror(void);
void *dlsym(void *handle, const char *symbol);
int dlclose(void *handle);
LD_PRELOAD能够很方便地实现应用层的二进制兼容,值得推广。同时谨记LD_PRELOAD不可滥用,否则会干扰正常系统的功能。一般,用完后需要将LD_PRELOAD的内容清空。
标签:PRELOAD,fork,LD,void,include,strlen,hello,库函数 From: https://blog.51cto.com/u_16162111/6493131