Pin是Intel公司提供的一个程序插装工具,支持IA-32,Intel(R) 64和IA64架构上的Linux和Windows可执行程序。
Pin允许一个工具在可执行程序的任何地方插入任意代码(用C或C++编写)。这些代码在程序运行的时候动态添加(修改内存映像)。这也使得可以将Pin附加到进程上。
插装粒度
指令级插桩(instruction instrumentatio),通过函数INS_AddInstrumentFunctio实现。
轨迹级插装(trace instrumentation),通过函数TRACE_AddInstrumentFunction实现。(貌似就是基本块插装)
镜像级插装(image instrumentation),使用IMG_AddInstrumentFunction函数,由于其依赖于符号信息去确定函数边界,因此必须在调用PIN_Init之前调用PIN_InitSymbols。
函数级的插装(routine instrumentation),使用RTN_AddInstrumentFunction函数。函数级插装比镜像级插装更有效,因为只有镜像中的一小部分函数被执行。
Pin与Pintool
Pin只是一个插装的平台或框架,执行具体的插装任务要通过定义Pintool来实现。目录source\tools\下定义了非常多的Pin工具,下面列举一些例子。
打开Visual Studio 命令行界面,进入目录source\tools\ManualExamples。
编译目录下的所有例子
$ cd source\tools\ManualExamples
$ ..\nmake tools
编译和运行一个具体例子(如inscount0)
$ cd source\tools\ManualExamples
$ ..\nmake inscount0.test
编译一个具体例子但不运行(如inscount0)
$ cd source\tools\ManualExamples
$ ..\nmake inscount0.dll
(注:这里的nmake指souce\tools\ nmake.bat,调用的是当前目录下的Nmakefile文件,即source\tools\ManualExamples\Nmakefile。打开Nmakefile文件,可以发现并不是每一个.cpp文件都有对应的.dll文件,可能要自己添加。)
简单指令计数(指令级插装)
源码:source/tools/ManualExamples/inscount0.cpp
功能:对应用程序执行的指令计数,展示怎么写分析函数
测试命令如下:
cd source\tools\ManualExamples
pin -t obj-ia32\inscount0.dll -- cmd /C dir
输出:
type inscount0.out
Count 4565876
Pin的用法为:pin [Pin Args] [-t <ToolDLL> [Tool Args]] -- <App EXE> [App args]
这里没有Pin Args,Tool DLL为obj-ia32\inscount0.dll,要计数的应用程序为cmd,cmd的参数为 /C dir,也可指定其他可执行程序,参数不是必须的。默认输出结果保存到inscount0.out,也可用-o filepath指定。
后面的Pintool不一定可以指定保存路径,只有实现了函数KnobOutputFile才可以,不过可以很容易添加。
指令地址追踪(指令级插装)
源码:source/tools/ManualExamples/itrace.cpp
功能:打印每条执行指令的地址,展示怎么向分析函数传递参数
测试命令如下:
pin -t obj-ia32\itrace.dll -- cmd /C dir
输出:itrace.out
内存引用追踪(指令级插装)
源码:source/tools/ManualExamples/pinatrace.cpp
功能:只追踪内存操作指令
测试命令如下:
pin -t obj-ia32\pinatrace.dll -- cmd /C dir
输出:pinatrace.out
检测镜像的加载和卸载(镜像级插装)
源码:source/tools/ManualExamples/imageload.cpp
功能:检测镜像文件的加载和卸载(Windows下主要为dll文件)
测试命令如下:
pin -t obj-ia32\imageload.dll -- cmd /C dir
输出:imageload.out
更有效的指令计数(Trace级插装)
源码:source/tools/ManualExamples/inscount1.cpp
功能:同inscount0,但不是在每一指令执行前插入调用,而是对每一基本块(BBL)
测试命令如下:
pin -t obj-ia32\inscount1.dll -- cmd /C dir
输出:inscount1.out
过程指令计数(函数级插装)
源码:source/tools/ManualExamples/proccount.cpp
功能:统计每一函数被调用的次数,及这一函数内执行的指令数
测试命令如下:
pin -t obj-ia32\proccount.dll -- cmd /C dir
输出:proccount.out
使用 PIN_SafeCopy()
源码:source/tools/ManualExamples/safecopy.cpp
功能:将指定数目字节从内存一个地址复制到另一地址(推荐用这个API来读写应用程序的内存)
测试命令如下:
pin -t obj-ia32\safecopy.dll -- ..\Tests\obj-ia32\cp-pin.exe Nmakefile obj-ia32\safecopy.dll.Nmakefile.copy
也可以在visual studio命令提示符窗口中切换到source/tools/ManualExamples/,然后输入:
..\nmake safecopy.test
输出:safecopy.out
指令顺序
源码:source/tools/ManualExamples/invocation.cpp
功能: 以3种不同的方式插装返回指令
测试命令如下:
pin -t obj-ia32\invocation.dll -- cmd /C dir
输出:invocation.out
发现函数参数的值
源码:source/tools/ManualExamples/malloctrace.cpp
功能: 打印函数malloc()和free()及malloc()返回值的输入参数
测试命令如下:
pin -t obj-ia32\ malloctrace.dll -- ..\Tests\obj-ia32\cp-pin.exe Nmakefile obj-ia32\ malloctrace.dll.Nmakefile.copy
输出:malloctrace.out
在Windows下通过名称查找函数
源码:source/tools/ManualExamples/w_malloctrace.cpp
功能: 通过符号表获得函数名为RtlAllocateHeap的地址,进一步获得其参数和返回值
测试命令如下:
pin -t obj-ia32\ w_malloctrace.dll -- ..\Tests\obj-ia32\cp-pin.exe Nmakefile obj-ia32\ w_malloctrace.dll.Nmakefile.copy
输出:w_malloctrace.out
对线程级应用插装
源码:source/tools/ManualExamples/malloc_mt.cpp
功能:展示对线程的插装
测试命令如下:
pin -t obj-ia32\malloc_mt.dll -- cmd /C dir
输出:malloc_mt.out
注:给的例子thread_lin不能在Windows编译,但是cmd /C dir貌似不是多线程的,不够典型。Windows下会有死锁的情况,解决的方法见buffer-win.cpp。
使用TLS
源码:source/tools/ManualExamples/inscount_tls.cpp
功能:展示使用线程本地存储(tls),创建特定于线程的数据
测试命令如下:
pin -t obj-ia32\inscount_tls.dll -- cmd /C dir
输出:inscount_tls.out
注:同样thread_lin不能在Windows编译,改用cmd /C dir。
使用Fast Buffering APIs
源码:source/tools/ManualExamples/buffer-lin_tls.cpp
功能:打印所有访问内存指令的PC(程序计数器)值和这个指令的有效访问地址
测试命令如下:
pin -t obj-ia32\buffer-lin_tls.dll -- cmd /C dir
输出:buffer-lin_tls.out
注:同样thread_lin不能在Windows编译,改用cmd /C dir。如果你的分析函数只是存储参数到缓冲区,可以用Fast Buffering APIs来代替。
发现镜像的静态特性
源码:source/tools/ManualExamples/staticcount.cpp
功能:不用插装发现镜像的静态特性,这里仍然是统计镜像文件的指令数(未运行)
测试命令如下:
pin -t obj-ia32\staticcount.dll -- cmd /C dir
输出:dos显示
从应用程序分离Pin
源码:source/tools/ManualExamples/detach.cpp
功能:从应用程序分离Pin,不再执行插装代码,使其以原始速度运行
测试命令如下:
pin -t obj-ia32\detach.dll -- cmd /C dir
输出:dos显示
在Probe Mode下替换函数
对子进程插装
在forks之前或之后插装