概述
相关:pin是什么 pin可以做什么 pin examples
此次使用pin目的,是为了能够应用pin在函数分析方面的功能,以及XXXInsertCall的功能
由于此前对pin了解不够深入,以为可以实现相应功能,哪知撞了南墙才知道pin也有些许局限。
下面将我对了解到的pin可以实现以及不能实现的各种坑写作笔记。
函数分析
RTN
1 | PIN_CALLBACK LEVEL_PINCLIENT::RTN_AddInstrumentFunction (RTN_INSTRUMENT_CALLBACK fun, VOID *val) |
使用RTN_AddInstrumentFunction
即可对分析目标添加函数级插桩,在设置的回调中可以获取函数的各种信息。
1 | typedef VOID(*) LEVEL_PINCLIENT::RTN_INSTRUMENT_CALLBACK(RTN rtn, VOID *v) |
回调函数中rtn就表示被插桩的该函数,通过RTN_XXX相关函数可以获取函数的名字、地址、大小、范围等等
1 | const string & LEVEL_PINCLIENT::RTN_Name (RTN x) |
不得不提一个函数,RTN_FindByName
类似于GetProcAddress,可以获取img(模块对象)中指定名字的rtn对象。
1 | RTN LEVEL_PINCLIENT::RTN_FindByName (IMG img, const CHAR *name) |
也可以通过地址来获取对应的rtn对象,但是如果对应函数没有符号信息,获取到的rtn是不对的,会找到最小范围内满足的rtn对象
1 | RTN LEVEL_PINCLIENT::RTN_FindByAddress (ADDRINT address) |
函数
初以为RTN表示所有函数对象,像IDA一样能将基本所有函数分析出来,哪知吃了不看文档的亏(虽然知道使用RTN之前需要调用符号相关初始化)。
A RTN represents the functions/routines/procedures typically produced by a compiler for a procedural programming language such as C. Pin finds routines by using the symbol table information. You must call PIN_InitSymbols() so that symbol table information will be available. Can be accessed at instrumentation time and analysis time.
也就是说pin是根据符号信息来分析函数,生成RTN对象。那么没有符号信息的函数,像IDA中的是那么sub_xxxx
也就没有可能这么方便的使用了。
当然,如果需求是对有符号信息的函数,比如对系统函数的分析,那么RTN还是能够提供相当nb的功能的。记得调用PIN_InitSymbols()
初始化符号信息。
maybe hook
pin可以实现类似于对函数hook的功能,有两类,第一类用在JIT模式下,另一类用在Probe模式下。
先说JIT模式下使用的RTN_InsertCall
。
1 | VOID LEVEL_PINCLIENT::RTN_InsertCall ( RTN rtn, |
Insert call relative to a rtn.
使用这个函数注册一个回调函数,该回调函数可以在rtn调用前(IPOINT_BEFORE)或者调用后(IPOINT_AFTER)被调用。可以给回调函数传递各种信息,使用第三个参数之后的内容传递。
pin中各种XXX_InsertCall传递参数有一个统一的类型IARG_TYPE
。这里简单说一下传递方法,具体要根据IARG_TYPE
说明来使用,大致分为两种:
- 只需要指定IARG_XXX类型,pin自己传递具体值给回调函数
- 指定IARG_XXX类型,开发者传递类型对应的具体值
必须以IARG_END表示参数结束。
1 | //pin传递值,只需要指定类型即可 |
举个例子:1
2
3
4
5
6
7
8
9
10
11
12
13
14char* p = "this is log info.";
BOOL log_falg = TRUE;
ADDRINT addr = RTN_Address(rtn);
RTN_InsertCall(rtn, IPOINT_BEFORE, RtnClk,
IARG_ORIG_FUNCPTR,
IARG_RETURN_IP,
IARG_ADDRINT, addr,
IARG_PTR, p,
IARG_BOOL, log_falg,
IARG_END);
VOID RtnClk(ADDRINT OrigFunc, ADDRINT retIp, ADDRINT addr, void* log, BOOL log_falg)
{
}
Probe模式下使用下面两个函数,其实没有弄明白这两个函数和JIT模式下RTN_InserCall的区别,暂时就不做深入了。
1 | VOID LEVEL_PINCLIENT::RTN_InsertCallProbed (RTN orgRtn, IPOINT action, AFUNPTR funptr,...) |
Insert a call to an analysis routine relative to a RTN.
其他1
2RTN_ReplaceProbed
RTN_ReplaceProbedEx
下面一个示例,可能更符合对函数hook的理解,这里使用到的是RTN_ReplaceSignatureProbed
这种方式需要向函数hook一样指定函数原型,也就是需要知道函数需要哪些参数,调用方式等等。
1 | typedef VOID * ( *FP_MALLOC )( size_t ); |
can be hook
另外pin还提供对任意地址做hook的函数,也就是PIN_InsertCallProbed。
显然这也是用于Probe模式下的函数,顺便就说一下Probe模式下需要注意,调用PIN_StartProgramProbed()启动目标进程,这样子之后,JIT模式的很多函数就不能使用了。正是因为这个,如RTN、INS、Trace插桩函数不能使用,只能通过IMG插桩,在回调中进行函数的分析,想下面的实例代码中一样。
这样就给我要实现的功能带来了麻烦,无法通过INS插桩分析call xxx的目标地址,更别说后续的使用PIN_InsertCallProbed来对函数hook了,这样子PIN_InsertCallProbed对我来说显得很鸡肋。
PIN_StartProgramProbed() must be used when using this API.
Use RTN_IsSafeForProbedInsertion() to determine if a function is a suitable candidate for probed function insertion.
不过,我觉得这种模式更类似于函数hook,不会像上面指定IPOINT_BEFORE,它更像hook一样只是对函数进行inline hook(或者其他方式)。
使用示例(代码来自于pin例子源码source\tools\Probes\insert_call_probed.cpp
):
1 | void Notification(ADDRINT val) |
INS
INS表示某地址对应的指令对象,通过INS_XXX函数可以获取指令对应汇编代码,可以判断指令时什么类型,也可以对INS进行插桩。
An INS represents an instruction. Can only be accessed at instrumentation time.
下面列出一部分函数,看名字就知道干什么的。
1 | string LEVEL_CORE::INS_Disassemble (INS ins) |
下面主要对用到的几个函数,对其理解做一下笔记。
call/branch
上面提到我要对call xxx中xxx的信息进行获取,就需要用到对INS的分析,进而通过插桩来获取地址。
用到了下面几个函数对指令进行判断,是否是call。
1 | BOOL LEVEL_CORE::INS_IsCall (INS ins) |
目标地址
如果INS满足INS_IsDirectBranchOrCall,可以直接通过INS_DirectBranchOrCallTargetAddress
获取到目标地址。
如果INS是INS_IsIndirectBranchOrCall
,那么只有通过插桩来获取目标地址。插桩是必须使用IPOINT_TAKEN_BRANCH
类型的action,然后再回调函数中可以通过寄存器来获取目标地址。
如下所示代码:
1 | INS_InsertCall(ins, IPOINT_TAKEN_BRANCH, (AFUNPTR)RttiCall, IARG_CONTEXT, IARG_INST_PTR, IARG_END); |
总结
通过上面对RNT,INS使用的相关总结,已经可以拿到call xxx的目标地址,也可以对任意地址进行插桩(hook),但是就在JIT\Probe两个模式中找不到可以以结合的地方。
- JIT模式下,可以通过INS拿到目标地址,但是不能对目标地址进行插桩
- Probe模式下,可以对目标地址插桩,但是拿不到目标地址
不知道pin是否可以满足这种需求,但在我目前看到的东西里,是没法实现了。
如果有过路的高人,想可以指点一二,不甚感激。
另外总结一下pin中各对象的关系:1
IMG->SEC->BBL->RTN->INS
完结。