1. hook 原理
hook机制本质上是一种函数的劫持技术,比如我们通常需要调用malloc函数来进行内存分配,那么能不能我们自己封装一个同名、同入参和同返回值的malloc函数来替代系统的malloc函数,在我们自己封装的malloc函数中实现一些特定的功能,而且也能回调系统的malloc,这就是hook机制。
系统提供给我们的dlopen、dlsym族函数可以用来操作动态链接库,比如我们要hook系统调用函数read,我们可以使用dlsym族函数获取hook前函数的地址,这样就可以在自己实现的read中回调原函数,并加上一些额外的逻辑,并且在运行是会调用我们的版本了。
通过hook机制,libco可以达到用户无感的情况下把同步的代码替换为异步,这也是腾讯工程师写出libco的目的。libco库里面提供了socket族函数的hook,使得后台逻辑服务几乎不用修改逻辑代码就可以完成异步化改造,号称单机可以达到千万连接。
1.1 函数解析
#include <dlfcn.h>
void * dlopen( const char * pathname, int mode );
函数描述:
在dlopen的()函数以指定模式打开指定的动态连接库文件,并返回一个句柄给调用进程。使用dlclose()来卸载打开的库。
mode:分为这两种
RTLD_LAZY 暂缓决定,等有需要时再解出符号
RTLD_NOW 立即决定,返回前解除所有未决定的符号。
RTLD_LOCAL
RTLD_GLOBAL 允许导出符号
RTLD_GROUP
RTLD_WORLD
返回值:
打开错误返回NULL
成功,返回库引用
编译时候要加入 -ldl (指定dl库)
根据动态链接库操作句柄与符号,返回符号对应的地址。
包含头文件:
#include <dlfcn.h>
函数定义:
void*dlsym(void* handle,const char* symbol)
函数描述:
dlsym根据动态链接库操作句柄(handle)与符号(symbol),返回符号对应的地址。使用这个函数不但可以获取函数地址,也可以获取变量地址。
handle是由 dlopen打开 动态链接库后返回的 指针,symbol就是要求获取的函数或 全局变量的名称。
dlsym主要针对系统库的调用,dlopen主要针对第三方的库。且两者使用都需要包含头文件#include <dlfcn.h>。
2. hook实现
hook的实现有两种方法,第一种是使用环境变量LD_PRELOAD,第二种是直接代码入侵。
2.1 使用环境变量LD_PRELOAD
系统为我们提供了 dlopen,dlsym工具,用于运行时加载动态库。可执行文件在运行时可以加载不同的动态库,这就为hook系统函数提供了基础。下面用一个小小的例子来说明如何利用dlsym工具hook系统函数。假设现在我们需要统计程序中malloc的调用次数,但是不能修改原有程序。最简单的思路类似于Java中动态代理Proxy的做法,先找到系统的malloc函数,然后将其替换为自定义的函数,在自定义函数中增加调用次数,并回调系统的原有malloc函数。例如我们要统计以下main.c中调用malloc的次数:
// main.c
#include <stdio.h>
#include <stdlib.h>
int main() {
int index;
for (index=0; index < 10; index++) {
char* p = (char*)malloc(4);
printf("index:%d, p[0]=%d\n", index, *p);
free(p);
}
printf("hello world\n");
return 0;
}
为了能让自己的malloc函数回调系统的malloc函数,我们需要利用dlsym获取系统的malloc函数。
// myhook.c
#include <stdlib.h>
#include <dlfcn.h>
#include <stdio.h>
int count = 0;
void *malloc(size_t size) {
void *(*myMalloc)(size_t) = dlsym(RTLD_NEXT, "malloc");

本文介绍了hook机制的基本原理,包括函数劫持和动态链接库操作,展示了如何通过环境变量LD_PRELOAD实现hook系统函数(如malloc和read),以及通过源码入侵(如libco库)进行hook的方法。实例演示了如何统计malloc调用次数和hook读函数。
最低0.47元/天 解锁文章
562

被折叠的 条评论
为什么被折叠?



