Linux C 中有一个很不错的特性,可以在不改变程序的前提下,修改动态库所调用的函数,也就是 Preload 功能。
这里简单介绍其使用方法。
最常见的使用场景是不修改程序,而直接修改动态库中函数的实现,例如重新实现 malloc() 和 free() 函数。
#include <stdio.h>
int main(void)
{
FILE *fd;
printf("Calling the fopen() function...\n");
fd = fopen("test.txt","r");
if (fd == NULL) {
printf("fopen() returned NULL\n");
return 1;
}
printf("fopen() succeeded\n");
return 0;
}然后可以通过如下方式编译、执行。
$ gcc foobar.c -o foobar
$ ./foobar
Calling the fopen() function...
fopen() succeeded接着我们生成自己定义 fopen() 函数。
#include <stdio.h>
FILE *fopen(const char *path, const char *mode)
{
printf("Always failing fopen\n");
return NULL;
}然后,编译生成动态库。
$ gcc -Wall -fPIC -shared -o libawrap.so awrap.c
$ LD_PRELOAD=./libawrap.so ./foobar
Calling the fopen() function...
Always failing fopen
fopen() returned NULL也可以通过如下命令查看符号的查找过程。
LD_DEBUG=symbols ./foobar以及其真正依赖的库。
$ ldd ./foobar
linux-vdso.so.1 => (0x00007fffaffe7000)
libc.so.6 => /lib64/libc.so.6 (0x00007f0c22128000)
/lib64/ld-linux-x86-64.so.2 (0x00007f0c224f5000)
$ LD_PRELOAD=./libawrap.so ldd ./foobar
linux-vdso.so.1 => (0x00007fff023fe000)
./libawrap.so (0x00007fbfa3e08000)
libc.so.6 => /lib64/libc.so.6 (0x00007fbfa3a3b000)
/lib64/ld-linux-x86-64.so.2 (0x00007fbfa400a000)假设我们仍然需要调用系统提供的函数,可以使用如下的方法。
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
FILE *fopen(const char *path, const char *mode)
{
FILE *(*oopen)(const char *, const char*);
printf("A wrapped fopen\n");
oopen = dlsym(RTLD_NEXT, "fopen");
if (oopen == NULL) {
fprintf(stderr, "Failed to find fopen\n");
return NULL;
}
return oopen(path, mode);
}也就是通过 dlsym() 查找下个 fopen() 符号。
详细可以参考 Dynamic linker tricks: Using LD_PRELOAD to cheat, inject features and investigate programs 或者 本地文档 。
如果喜欢这里的文章,而且又不差钱的话,欢迎打赏个早餐 ^_^
This Site was built by Rimond, generated with Jekyll, and hosted on GitHub Pages
©2013-2018 – Rimond