undefined

zookeeper 的应用场景

zookeeper 是一个开源的分布式协调服务框架,为分布式系统提供一致性服务

一、数据发布/订阅

当某些数据由几个机器共享,且这些信息经常变化、数据量小的时候,这些数据就适合存储在 zookeeper 中

  • 数据存储:将数据存储到 Zookeeper 上的一个数据节点
  • 数据获取:应用在启动初始化时,从 Zookeeper 数据节点读取数据,并在该节点上注册一个 Watcher 用来监听数据变更
查看更多

实现一个 hook 库

实现一个 hook 库

一、背景

在日常开发中,我们经常可能会对动态库中的函数调用做 hook(替换、拦截、监听等等),实现业务目的,比如对于 hook malloc、free 等,我们能够统计出分配了多少内存、那些内存一直被占用而没有被释放等等。

鉴于此,我们实现一个 hook 库,提供接口帮助业务进行 hook 相关函数调用。本文主要分享一个通过 got 方式进行 hook 的方式

二、基础知识

1. LD_PRELOAD 预加载方式

一般情况下,在 linux 下,动态链接库的加载顺序如下:

  • LD_PRELOAD
查看更多

如何 hook calloc

一、如何 hook calloc

dlsym 内部可能使用 calloc 分配内存。如果 hook calloc 的时候,使用 dlsym 可能会导致出现死循环。

如下是一种解决方案:

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/**
* 对于 hook calloc 的几点说明
* 问题点:dlsym 底层实现调用了 calloc 进行内存分配。因此 hook calloc 时需要注意不能出现死循环
*
* 当前解决方案如下:
* 1. 在全局开辟一块内存空间,用来做为 dlsym 内部需要 calloc 的空间
* 2. 设置 my_init_calloc_hook 函数的属性为 constructor,使其自动调用,且在 main 函数之前调用,实现初始化
* 并且设置 constructor 构造函数的优先级为 1。constructor 的优先级,数值越小,越先调用;destructor 的优先级,数值越大,越先调用
* 这个优先级 [1, 100] 范围是保留的,最小只能使用 101
* 因此 my_init_calloc_hook 函数“尽可能”保证了当前代码是当前进程第一个调用 calloc 的位置
* 当 dlsym 内部调用 calloc 时,此时 real_calloc 为空,则使用全局提前开辟好的空间,8192 字节大小够用
* 3. 当 dlsym 寻找 calloc 符号找不到时,出错情况下,为了保证 calloc 函数的逻辑。
* 使用全局变量 is_gather_calloc_ptr_error 做为判断。使业务调用 calloc 直接返回 null,而不是 calloc_ptr_buffer
* 4. 对于在 my_init_calloc_hook 执行前,有调用 calloc 的行为,我们一般默认返回 nullptr。如何实现呢?
* 使用全局变量 is_init_calloc,只有在进入 my_init_calloc_hook 后才将其置为 true
* 保证了在 my_init_hook 之前调用 calloc 的场景都返回 nullptr
*
* 存在问题:
* 此解决方案在 my_init_calloc_hook 执行后,calloc 才可用
*/
static unsigned char calloc_ptr_buffer[8192] = {0};
static calloc_type real_calloc = nullptr;
static bool is_gather_calloc_ptr_error = false;
static bool is_init_calloc = false;

__attribute__((constructor(101))) static void my_init_calloc_hook(void) {
is_init_calloc = true;
static calloc_type tmp_calloc_ptr = reinterpret_cast<calloc_type>(dlsym(RTLD_NEXT, "calloc"));
if (tmp_calloc_ptr != nullptr) {
real_calloc = tmp_calloc_ptr;
} else {
// dlsym 出错的情况
is_gather_calloc_ptr_error = true;
}
}

void* calloc(size_t nmemb, size_t size) __THROW {
if (real_calloc == nullptr) {
if (is_gather_calloc_ptr_error) return nullptr;
if (is_init_calloc) return calloc_ptr_buffer;
return nullptr;
}
void* point = real_calloc(nmemb, size);
if (point) {
default_malloc_size_func(_msize(point), true);
}
return point;
}

undefined

hook 库

1
2
3
4
5
6
7
8
x86/64 hook库: 
git地址:https://github.com/stevemk14ebr/PolyHook
文档:https://www.codeproject.com/articles/1100579/polyhook-the-cplusplus-x-x-hooking-library

pltgot x86/64 hook库:https://github.com/hMihaiDavid/pltgot_hook_demo
xhook: https://github.com/iqiyi/xHook/blob/master/README.zh-CN.md
hookso: https://github.com/esrrhs/hookso

微信的 IO hook 的文章:https://github.com/Tencent/matrix/wiki/Matrix-Android-IOCanary

ELF PLT hook 原理简述:https://juejin.cn/post/6914466700159090701

查看更多