perload失效

一、preload 失效原因

1. RTLD_DEEPBIND 的使用

来自于:http://linux.die.net/man/3/dlopen

RTLD_DEEPBIND(自 glibc 2.3.4 起)将此库中符号的查找范围置于全局范围之前。这意味着自包含库将优先使用其自己的符号,而不是已加载库中包含的具有相同名称的全局符号。该标志未在 POSIX.1-2001 中指定。

可以使用 LD_DEBUG=all 查看链接的过程

2. 通过静态链接的方式

使用 gcc -static 参数可以把 libc.so 静态链接进执行程序中。但这也就意味着程序不再支持动态链接。

3. 设置执行文件的 setgid/setuid 权限

在有 SUID 权限的执行文件,系统会忽略 LD_PRELOAD 环境变量

4. 内联方式

编译器可能会某些函数进行了内联优化,并不会调用 so 库中的函数,因而通过优先加载自定义动态库的方式不可行。比如:strcmp 函数

一种解决方案:可以在编译测试程序时,添加 -fno-builtin-strcmp 关闭 strcmp 函数的优化

5. 链接库的顺序

当使用 dlsym 的 RTLD_NEXT 时,需要注意链接库的顺序。ld-linux 链接器也有 malloc、free 的实现,可能会存在 dlsym 查看到 ld-linux 内部实现的符号。

1
2
3
4
5
6
7
8
void* func = dlsym(RTLD_NEXT, "malloc");
Dl_info dl_info;
if (!dladdr(func, &dl_info)) {
// dladdr() failed
}
if (strstr(dl_info.dli_fname, "ld-linux")) {
// 'malloc' is inside linker/loader
}

如果我们发现一个函数在 ld-linux 中,这时,没有直接的办法可以继续在所有其他库中搜索相同的函数名称。但是,如果您知道函数所在的特定库的名称,比如 libc.so 。则可以使用 dlopen 和 dlsym 来获取所需的指针。

1
2
3
4
5
6
7
8
void* handle = dlopen("libc.so.6", RTLD_LAZY);
if (!handle) {
// dlopen() failed
}
void* func = dlsym(handle, "free");
if (!func) {
// Bad! 'free' was not found inside libc
}