weiffun

由于基于探针的动态插桩,通常只能在函数边界插入代码,难以对程序的指令流进行很好的分析,所以平时用的比较少。以前使用微软研究院的detour的API觉得它很神奇,最近看了下它的原理还是很简单:基于简单动态重写函数的开始几个字节,然后跳转到特定函数。呵呵,但是要做好还是不容易的。闲来无事写了一个很粗糙的实现。

 

基本原理就是:(1)保存函数的入口的几个字节,并插入一天跳回函数的jmp指令(这一块代码称为trampaline)。这里的前几个字节不是个定数是有原因的,实际上我们只需要前5字节来保存一条JMP指令,但入口的5个字节可能并不是几条完整的指令,因此若只保存5个字节就会截断指令。如下面的代码所示,test函数入口的第5个字节包含于sub,保存前6个字节就可以避免截断sub指令。

(2)修改函数入口的5个字节为jmp xxx指令,其中的xxx就是探针函数到当前函数的偏移量。跳往探针函数并执行它。

(3)执行trampaline代码,执行原函数。

(3)恢复原函数的入口。

 

基本数据结构:

 

初始化

利用Linux LD_PRELOAD的特性,初始化整个库。其实在linux下利用LD_PRELAOD可以直接拦截库函数的执行,这里使用这个简化实现。

 

插入探针

偏移量计算一般是目标地址 - jmp的下一条指令的地址。在计算跳回员函数偏移量时,多加6个字节。因为6个字节的代码已经被执行了,同时这样做也避免了在探针和原函数间跳来跳去的死循环。这里作为了简单保存的6字节,因为测试的是本文开始的test函数。

 

 

 

删除探针

为了简单,只回复函数入口代码

dispatch函数

用来管理整个跳转和探针函数的执行。原函数有参数的话,需要进一步处理,这里简化了这一步。

 

探针的代码

  

 

fini函数:释放相应资源

 

测试程序:test.c

 

执行结果:

LD_PRELOAD=./libprobe.so ./test。可以看到hello函数在test之前执行了,删除探针后函数恢复正常执行。

分类:

技术点:

相关文章: