目标:将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
- 使用