Linux C 库打桩技术

10 篇文章 0 订阅

1.前言

库打桩技术,可以截获对共享库函数的调用。应用上可以如可以控制函数调用的输入输出值,以自己的逻辑替换函数调用等;
基本思想:创建一个与目标函数相同原型的包装函数,通过编译时函数实现的搜索机制、或链接时函数符号解析搜索的机制、或运行时动态链接库的加载机制,将自定义的包装函数替换目标函数。

2. 测试环境

系统环境:Ubuntu14.04
Gcc版本:gcc version 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04.4)

3.编译时打桩

3.1.相关文件

3.1.1.main.c

#include <stdio.h> 
#include <malloc.h>
int main()
{
	size_t len = 10;
	char * msg =  calloc(1,len);

	snprintf( msg,len,"%s","aloha");
	printf("msg:%s\n",msg);

	free(msg);
	msg = 0;

	return 0;
}

3.1.2.newcalloc.h

#define  calloc(nmemb,size) newcalloc(nmemb,size)
#define free(ptr)   newfree(ptr)

void *newcalloc(size_t nmemb, size_t size);
void newfree(void *ptr);

3.1.3.newcalloc.c

#include <stdio.h>
#include <malloc.h>

 void *newcalloc(size_t nmemb, size_t size)
 {

 	static int _newcalloc_calltime = 0;
 	++_newcalloc_calltime;
 	printf("calloc ptr(%d,%d) ,call times=%d\n",nmemb,size,_newcalloc_calltime);

 	void * ptr = calloc( nmemb,size);
 	printf("calloc return=%p\n",ptr);
 	return ptr;
 }


 void newfree(void *ptr)
 {
 	static int _newfree_calltime = 0;
 	++_newfree_calltime;
 	free(ptr);
 	printf("free(%p),call times =%d\n",ptr,_newfree_calltime);
 } 

3.2.编译命令

gcc -m32 -g -c newcalloc.c;
gcc -m32 -g -I. -o main main.c newcalloc.o;
./main
备注 :从测试情况看,这里不指定-I编译选项,也能按期望运行,即main.c中即使以尖括号方式include了,也是从当前目录先搜索。

3.3.运行情况和运行命令

calloc ptr(1,10) ,call times=1
calloc return=0x8734008
msg:aloha
free(0x8734008),call times =1
在这里插入图片描述

3.4.说明

1、编译时打桩,需要能访问源代码,本质上就是先定义自己的包装函数,在包装函数中进行调用标准的目标方法,并生成可重定位的文件。再定义一个通过宏定义方式转换的头文件(名称同需要打桩的函数所在的头文件),gcc编译时优先从本地搜索该同名头文件而调用了包装函数;
2、这里的一个注意点,对于包装文件newcalloc.c的编译需要单独编译,不能与宏定义转换的头文件放在同一个目录下进行编译,否则会变成循环嵌套递归调用,最终导致程序异常。

4.编译时打桩

4.1.相关文件

4.1.1.main.c

#include <stdio.h> 
#include <malloc.h>
int main()
{
	size_t len = 10;
	char * msg =  calloc(1,len);

	snprintf( msg,len,"%s","aloha");
	printf("msg:%s\n",msg);

	free(msg);
	msg = 0;

	return 0;
}

4.1.2.newcalloc.c

#include <stdio.h>
//#include <stdlib.h> 
 void * __real_calloc(size_t nmemb, size_t size);
 void __real_free(void *ptr);


 void * __wrap_calloc(size_t nmemb, size_t size)
 {

 	static int _newcalloc_calltime = 0;
 	++_newcalloc_calltime;
 	printf("calloc ptr(%d,%d) ,call times=%d\n",nmemb,size,_newcalloc_calltime);

 	void * ptr = __real_calloc( nmemb,size);
 	printf("calloc return=%p\n",ptr);
 	return ptr;
 }


 void __wrap_free(void *ptr)
 {
 	static int _newfree_calltime = 0;
 	++_newfree_calltime;
 	__real_free(ptr);
 	printf("free(%p),call times =%d\n",ptr,_newfree_calltime);
 } 

4.2.编译命令和运行命令

gcc -m32 -g -c newcalloc.c;
gcc -m32 -g -c main.c;
gcc -m32 -Wl,–wrap,calloc -Wl,–wrap,free -o main main.o newcalloc.o;
./main

4.3.运行情况

calloc ptr(1,10) ,call times=1
calloc return=0x840b008
msg:aloha
free(0x840b008),call times =1
在这里插入图片描述

4.4.说明

1、编译时打桩,需要能访问可重定位的目标文件;
2、静态链接器支持使用–wrap f选项进行打桩,即把对符号f的引用解析成__wrap_f,并对符号__real_f的引用解析成f。

5. 运行时打桩

5.1.相关文件

5.1.1.main.c

#include <stdio.h> 
#include <malloc.h>
int main()
{
	size_t len = 10;
	char * msg =  calloc(1,len);

	snprintf( msg,len,"%s","aloha");
	printf("msg:%s\n",msg);

	free(msg);
	msg = 0;

	return 0;
}

5.1.2.newcalloc.c

#include <stdio.h>
#include <stdlib.h>  

#define __USE_GNU
#include <dlfcn.h>

//#define _GNU_SOURCE
 void * calloc(size_t nmemb, size_t size)
 {

 	 void * (*callocp)(size_t nmemb, size_t size);
 	 char * error;
 	 callocp = dlsym(RTLD_NEXT,"calloc");
 	 if((error=dlerror())!=NULL)
 	 {
 	 	printf("dlsym calloc error,msg:%s\n",error);
 	 	exit(1);
 	 }
 	static int _newcalloc_calltime = 0;
 	++_newcalloc_calltime;
 	printf("calloc ptr(%d,%d) ,call times=%d\n",nmemb,size,_newcalloc_calltime);

 	void * ptr = callocp( nmemb,size);
 	printf("calloc return=%p\n",ptr);
 	return ptr;
 }


 void free(void *ptr)
 {
 	void (*freep)(void *ptr);
 	 char * error;
 	 freep = dlsym(RTLD_NEXT,"free");

 	static int _newfree_calltime = 0;
 	++_newfree_calltime;
 	freep(ptr);
 	printf("free(%p),call times =%d\n",ptr,_newfree_calltime);
 } 

5.2.编译命令和运行命令

gcc -m32 -g -shared -fpic -o newcalloc.so newcalloc.c -ldl;
gcc -m32 -g -o main main.c;
LD_PRELOAD="./newcalloc.so" ./main

5.3.运行情况

calloc ptr(1,10) ,call times=1
calloc return=0x8fb5008
msg:aloha
free(0x8fb5008),call times =1
在这里插入图片描述

5.4.说明

1、此机制基于动态链接器的LD_RELOAD环境变量。当加载和执行一个程序,需要解析未定义的引用时,动态链接器(LD-LINUX.SO)会先搜索LD_PRELOAD库,如果没有搜索到 ,则再搜索其他库。
2、中宏定义_GNU_SOURCE不能工作,查看dlfcn.h文件,需要使用__USE_GNU(#include <dlfcn.h>前面定义)
在这里插入图片描述

6. 参考资料

《深入理解计算机系统》中文版,[美]Randal E.Bryant等著,2019.3,机械工业出版社

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值