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 环境变量

查看更多

插桩

插桩

可以利用 clang/gcc 的 -finstrument-functions 编译参数,使得每个函数都会在出口和入口以此执行 __cyg_profile_func_enter 函数和 __cyg_profile_func_exit 函数。

使用 dladdr 将函数的地址转换成符号

hook.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <dlfcn.h>
#include <stdio.h>
#include <cxxabi.h>

inline const char* get_funcname(const char* src) {
int status = 99;
const char* f = abi::__cxa_demangle(src, nullptr, nullptr, &status);
return f == nullptr ? src : f;
}

extern "C" void __cyg_profile_func_enter(void* func, void* caller) {
Dl_info info1, info2;
if (dladdr(func, &info1) & dladdr(caller, &info2)) {
fprintf(stdout, "enter func: %s father: %s\n", get_funcname(info1.dli_sname), get_funcname(info2.dli_sname));
}
}

extern "C" void __cyg_profile_func_exit(void* func, void* caller) {
Dl_info info1, info2;
if (dladdr(func, &info1) & dladdr(caller, &info2)) {
fprintf(stdout, "exit func: %s father: %s\n", get_funcname(info1.dli_sname), get_funcname(info2.dli_sname));
}
}

查看更多

文件相关操作

一、判断文件是否存在

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
inline bool exists_test0 (const std::string& name) {
// 以 ifstream 打开文件流,成功则存在,失败则不存在
ifstream f(name.c_str());
return f.good();
}

inline bool exists_test1 (const std::string& name) {
// 以 fopen 读方式打开文件,成功则存在,失败则不存在
if (FILE *file = fopen(name.c_str(), "r")) {
fclose(file);
return true;
} else {
return false;
}
}

inline bool exists_test2 (const std::string& name) {
// 以 access 函数获取文件状态,成功则存在,失败则不存在
return ( access( name.c_str(), F_OK ) != -1 );
}

inline bool exists_test3 (const std::string& name) {
// 使用 stat 函数获取文件状态,成功则存在,失败则不存在
struct stat buffer;
return (stat (name.c_str(), &buffer) == 0);
}

性能测试对比结果:stat 函数的方式性能最好

1
2
3
4
5
6
# Results for total time to run the 100,000 calls averaged over 5 runs,

Method exists_test0 (ifstream): **0.485s**
Method exists_test1 (FILE fopen): **0.302s**
Method exists_test2 (posix access()): **0.202s**
Method exists_test3 (posix stat()): **0.134s**

查看更多