目标:将posix
函数hook
住
一个简单的例子
(连接mysql
服务),连接成功则打印success
mysql.c
#include <mysql/mysql.h> #include <stdio.h> int main(){ MYSQL* mysql = mysql_init(NULL); if(!mysql){ printf("mysql_init failed\n"); return 0; } if(!mysql_real_connect(mysql, "127.0.0.1", "root", "123456","mysql", 3306, NULL, 0)){ printf("mysql connect failed\n"); return 0; } printf("success!\n"); }
编译
gcc -o mysql mysql.c -lmysqlclient
运行
$ ./mysql success!
成功连接到mysql
服务
mysql
服务的连接少不了posix API
例如connect
,recv
,send
,其中mysql_real_connect
函数中一定调用了这些函数,我们就可以使用hook技术来将其hook住捕获原始posixAPI
目标:将posixAPI
捕获然后在其调用之前打印一定信息
main
函数的主要代码完全不用修改,底层hook
了后用户是无法感知的
操作步骤
一、定义要hook
的posixAPI
的函数指针
typedef int (*connect_t)(int sockfd, const struct sockaddr *addr, socklen_t addrlen); typedef ssize_t(*recv_t)(int sockfd, void *buf, size_t len, int flags); typedef ssize_t(*send_t)(int sockfd, const void *buf, size_t len, int flags); connect_t connect_f = NULL; recv_t recv_f = NULL; send_t send_f = NULL;
- 返回值和参数必须与原
posixAPI
相同
二、修改posixAPI
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen){ printf("CONNECT\n"); return connect_f(sockfd, addr, addrlen); } ssize_t recv(int sockfd, void *buf, size_t len, int flags){ printf("RECV\n"); return recv_f(sockfd, buf, len, flags); } ssize_t send(int sockfd, const void *buf, size_t len, int flags){ printf("SEND\n"); return send_f(sockfd, buf, len, flags); }
- 让
posixAPI
被触发之前能够触发打印
三、添加相关头文件并初始化hook
#define _GNU_SOURCE #include <dlfcn.h> #include <sys/types.h> #include <sys/socket.h> // ... void init_hook(void){ if(!connect_f) connect_f = dlsym(RTLD_NEXT, "connect"); if(!recv_f) recv_f = dlsym(RTLD_NEXT, "recv"); if(!send_f) send_f = dlsym(RTLD_NEXT, "send"); }
在上述mysql.c
中添加上述代码,并在程序开始前调用init_hook
函数
#define _GNU_SOURCE #include <dlfcn.h> #include <sys/types.h> #include <sys/socket.h> #include <mysql/mysql.h> #include <stdio.h> typedef int (*connect_t)(int sockfd, const struct sockaddr *addr, socklen_t addrlen); typedef ssize_t(*recv_t)(int sockfd, void *buf, size_t len, int flags); typedef ssize_t(*send_t)(int sockfd, const void *buf, size_t len, int flags); connect_t connect_f = NULL; recv_t recv_f = NULL; send_t send_f = NULL; int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen){ printf("CONNECT\n"); return connect_f(sockfd, addr, addrlen); } ssize_t recv(int sockfd, void *buf, size_t len, int flags){ printf("RECV\n"); return recv_f(sockfd, buf, len, flags); } ssize_t send(int sockfd, const void *buf, size_t len, int flags){ printf("SEND\n"); return send_f(sockfd, buf, len, flags); } void init_hook(void){ if(!connect_f) connect_f = dlsym(RTLD_NEXT, "connect"); if(!recv_f) recv_f = dlsym(RTLD_NEXT, "recv"); if(!send_f) send_f = dlsym(RTLD_NEXT, "send"); } int main(){ init_hook(); MYSQL* mysql = mysql_init(NULL); if(!mysql){ printf("mysql_init failed\n"); return 0; } if(!mysql_real_connect(mysql, "127.0.0.1", "root", "123456","mysql", 3306, NULL, 0)){ printf("mysql connect failed\n"); return 0; } printf("success!\n"); }
编译
gcc -o mysql mysql.c -lmysqlclient -ldl
运行
$ ./mysql CONNECT RECV SEND success!
可以发现mysql_real_connect
中的posixAPI
被捕获了
总结
按照以下步骤,就可以自定义其他的hook
- 定义想要
hook
的函数的指针(别名),并初始化NULL
- 自定义原函数的操作并在最后返回
hook
后的函数调用体 - 初始化hook
- 使用
dlysm