Intel Pin-JIT模式和Probe模式下库函数的替换
来源:互联网 发布:苹果便签软件 编辑:程序博客网 时间:2024/05/05 21:48
这篇文章主要介绍一下Intel Pin在JIT模式和Probe模式下对库换数的替换,以及实现中有哪写需要注意的地方。
JIT模式就是对插桩的代码进行即时编译,然后缓存起来使用
Probe模式就是在要插桩的函数入口前面插入一条跳转指令,跳转到新的替换函数处执行,不在原来执行代码上进行修改
具体的大家可以参考Pin官方手册
https://software.intel.com/sites/landingpage/pintool/docs/65163/Pin/html/index.html
下面进入正文
在编写程序过程中,我们有时候需要需要关注一下某些库函数的调用,方便我们我们监测。比如我们想关注应用程序中共享变量的情况,共享变量主要就是静态变量,全局变量,以及堆变量(new或是malloc或是realloc或是calloc),以堆变量为例,我们就必须要监测malloc等函数,GCC中提供了LD_PRELOAD预加载库技术,通过这种技术,我们可以对一些库函数进行重写,然后在链接的时候首先加载我们自己写的动态链接库,后面加载正常的库函数时候由于符号表中已经有了我们重写的函数,那么就不会重定位到真正的库函数的位置。这篇文章主要使用Intel的Pin 二进制动态插桩框架来达到同样的效果,如果对Pin不了解的同学建议去看一下上面给出的手册链接。
使用JIT进行的malloc函数替换,根据代码解释
#include "pin.H"#include <string.h>#include <iostream>using namespace std;void * MallocWrapper( CONTEXT * ctxt, AFUNPTR pf_malloc, size_t size){ // Simulate out-of-memory every so often void * res; cout<<"=====Enter the MallocWrapper=======\n"; cout<<"Malloc Size:"<<size<<endl; PIN_CallApplicationFunction(ctxt, PIN_ThreadId(), CALLINGSTD_DEFAULT, pf_malloc, PIN_PARG(void *), &res, PIN_PARG(size_t), size, PIN_PARG_END()); return res; } VOID ImageLoad(IMG img, VOID *v) { // Pin callback. Registered by IMG_AddInstrumentFunction if (strstr(IMG_Name(img).c_str(), "libc.so") || strstr(IMG_Name(img).c_str(), "MSVCR80") || strstr(IMG_Name(img).c_str(), "MSVCR90")) { RTN mallocRtn = RTN_FindByName(img, "malloc"); //build a function proto PROTO protoMalloc = PROTO_Allocate( PIN_PARG(void *), CALLINGSTD_DEFAULT, "malloc", PIN_PARG(size_t), PIN_PARG_END() ); //replace the application function RTN_ReplaceSignature(mallocRtn, AFUNPTR(MallocWrapper), IARG_PROTOTYPE, protoMalloc,IARG_CONST_CONTEXT, IARG_ORIG_FUNCPTR,IARG_FUNCARG_ENTRYPOINT_VALUE, 0, IARG_END); } }int main(int argc, CHAR *argv[]) { PIN_InitSymbols(); PIN_Init(argc,argv); IMG_AddInstrumentFunction(ImageLoad, 0); PIN_StartProgram(); }对于ImageLoad函数
首先根据malloc函数名找到malloc函数所在的库以及对应的Routine,RTN_FindByName主要干的就是这个
其次,对插桩的函数重新生成原型,替换原有的malloc函数原型
PROTO_Allocate就是生成一个原始函数原型,PIN_PARG(void *)表示的是返回类型,malloc函数的返回类型为void *,CALLINGSTD_DEFAULT表示编译这个函数的调用标准(一般不用改变),PIN_PARG(size_t)表示就是malloc中的传递的参数,这里参数传递的是类型就是size_t,最后必须加上IARG_END表示截止,这样返回的就是一个指向函数原型的指针。
RTN_ReplaceSignature表示就是在JIT模式对函数进行替换,mallocRtn表示就是malloc函数的Routine,AFUNPTR(MallocWrapper)表示就是替换函数的指针,IARG_PROTOTYPE允许你定义原始函数原型,因此后面加上我们之前定义好的原始函数原型protoMalloc,IARG_CONST_CONTEXT就是我们包装函数需要传递的第一个参数,IARG_ORIG_FUNCPTR表示原始函数指针(可以通过这个调用原始函数),最后一个参数是我们传递给原始malloc函数的,因此使用IARG_FUNCARG_ENTRYPOINT_VALUE,0表示传递给原始malloc的第一个参数,IARG_END表示截止。
再来看一下我们的包装函数MallocWrapper
我们首先打印一些信息,然后通过PIN_CallApplicationFunction调用我们原始函数,参数中需要注意的就是pf_malloc就是我们要调用的原始函数指针, PIN_PARG(void *), &res,表示原始函数返回类型和值,PIN_PARG(size_t), size表示原始函数的参数类型和值,这样的话我们就能够调用原始函数了。
大家编译成Pin Tool后,可以用小程序测试(也可从这里参考我的代码)
结果类似如下:
=====Enter the MallocWrapper=======
Malloc Size:5
=====Enter the MallocWrapper=======
Malloc Size:5
=====Enter the MallocWrapper=======
Malloc Size:120
=====Enter the MallocWrapper=======
Malloc Size:12
=====Enter the MallocWrapper=======
Malloc Size:784
使用Probe进行malloc函数替换,代码如下:
typedef VOID * ( *PF_MALLOC )( size_t );void * MallocWrapper(PF_MALLOC pf_malloc,size_t size){ // Simulate out-of-memory every so often cout<<"=====Enter the MallocWrapper=======\n"; cout<<"Malloc Size:"<<size<<endl; return pf_malloc(size);} // Pin calls this function every time a new img is loaded.// It is best to do probe replacement when the image is loaded,// because only one thread knows about the image at this time.VOID ImageLoad( IMG img, VOID *v ){ // See if malloc() is present in the image. If so, replace it. RTN rtn = RTN_FindByName( img, "malloc" ); if (RTN_Valid(rtn)) { // Define a function prototype of the orig func PROTO proto_malloc = PROTO_Allocate( PIN_PARG(void *), CALLINGSTD_DEFAULT, "malloc", PIN_PARG(int), PIN_PARG_END() ); // Replace the application routine with the replacement function. RTN_ReplaceSignatureProbed(rtn, AFUNPTR(MallocWrapper), IARG_PROTOTYPE, proto_malloc, IARG_ORIG_FUNCPTR, IARG_FUNCARG_ENTRYPOINT_VALUE, 0, IARG_END); // Free the function prototype. PROTO_Free( proto_malloc ); }} int main(int argc, CHAR *argv[]) { PIN_InitSymbols(); PIN_Init(argc,argv); IMG_AddInstrumentFunction(ImageLoad, 0); PIN_StartProgramProbed(); }
和之前的JIT模式很类似,只是这里的话,我们可以直接通过原始函数指针来调用(因为在Probe模式中不支持CONTEXT),还有就是替换函数变成了RTN_ReplaceSignatureProbed,程序启动函数变成了PIN_StartProgramProbed。
同时还需要注意的是,如果以Probe方式启动的话,那么系统需要支持特定的库,具体参考这里。
以Probe方式运行效率更高,但是有很多Pin的一些功能支持Probe,如果不是特别在意效率的话,建议大家就是用JIT模式,使用简单并且功能齐全。
- Intel Pin-JIT模式和Probe模式下库函数的替换
- vi模式下的替换
- Motorola 6800模式和Intel 8080模式的区别
- 安装和使用 Intel PIn
- vi模式下字符串的替换
- vi模式下的文本替换
- Intel 80386的保护模式
- Intel CPU的保护模式
- Intel CPU的保护模式
- PWM模式的库函数介绍
- Intel CPU的保护模式和段式内存管理简介
- Intel处理器的保护模式-分段和分页
- .Net下的CIL和JIT
- JIT与JVM的三种执行模式:解释模式、编译模式、混合模式
- JIT与JVM的三种执行模式:解释模式、编译模式、混合模式
- JIT与JVM的三种执行模式:解释模式、编译模式、混合模式
- JIT与JVM的三种执行模式:解释模式、编译模式、混合模式
- linux基础命令之:vi模式下查找和替换
- 第三章习题
- JAVA关键字—final修饰符
- Linux常用命令-文件处理命令-目录处理命令
- CentOS 7安装过程中遇到的问题总结
- 编程之美2015资格赛 - 题目3 : 基站选址(三分)
- Intel Pin-JIT模式和Probe模式下库函数的替换
- 第47课时,简单银行系统的初步框架(加强版)
- 马的遍历问题
- spring aop、IOC专题
- DPDK初识
- android apk 防止反编译技术第四篇-对抗JD-GUI
- mjpg-streamer移植
- UnixC内存管理那些事儿(上)
- word写论文,插入图片后图片不清楚的问题