我正在编写具有以下功能的 Pin 工具:
- 它必须记录带有参数的指令。(效果很好)
- 它必须记录与指令相关的内存访问操作。(效果很好)
- 它必须记录正在调用的函数的名称(如果该名称可从外部库获得)。此功能基于 Intel Pin 提供的示例中的 calltrace.cpp。(部分运行良好)
- 它必须记录返回指令到达的位置(函数名称,或检测的可执行文件的主模块)。例如 funcA 被调用,然后从 funcA 调用 funcB,然后从 funcB 返回到 funcA。将 rets 记录到函数部分效果很好,但是我不知道如何记录返回到主模块。
在提供源代码之前,让我描述一下我得到的工具的输出有什么问题(我认为)。
- 录制以一组指令开始,以返回一个尚未调用的函数结束(或者至少我的 PinTool 没有录制它)。
[mov esp, esi]
[流行音乐]
电阻
[流行编辑]
电阻
[流行音乐]
电阻
[流行音乐]
电阻
[返回 0x10]
电阻
间接返回到[RtlAnsiCharToUnicodeChar]
- 有时它会记录没有相应调用指令的被调用函数的名称:
[推送0x77736e7c]
宽
[推送双字ptr [ebp-0x110]]
RW
[呼叫0x7779a490]
宽
[LdrGetProcedureAddress]
[LdrGetProcedureAddressForCaller]
[RtlAcquireSRWLock独家]
- rets 也类似。甚至有时它记录连续两次返回同一个函数(但它不应该)。
[呼叫0x777a8b60]
宽
[RtlRetrieveNtUserPfn]
间接返回到[RtlDeactivateActivationContextUnsafeFast]
////或者////
[mov ecx, dword ptr [edi]]
电阻
[呼叫0x7777e531]
宽
[RtlAddAccessAllowedAce]
[RtlAcquireSRWLock独家]
间接返回到[RtlAddAccessAllowedAce]
[RtlReleaseSRWLock独家]
间接返回到[RtlAddAccessAllowedAce]
间接返回到[RtlAddAccessAllowedAce]
[mov esi, eax]
我觉得我处理这些调用和 rets“解码”的方式存在根本性的错误。有人可以指出我到底错在哪里吗?还有两个次要问题。
1) 如何根据指令记录返回到可执行文件的主模块?
2) 有没有办法在 INS_InsertCall(或类似)函数之外获取 IARG_BRANCH_TARGET_ADDR 和 IARG_BRANCH_TAKEN 的值?
谢谢你。
源代码如下。
#include <stdio.h>
//#include <chrono>
#include "pin.H"
#include <string>
#include <exception>
FILE * ftrace;
long long icount=0;
long long ilimit=1000000;
BOOL print_args=false;
string invalid = "invalid_rtn";
const string *Target2String(ADDRINT target)
{
string name = RTN_FindNameByAddress(target);
if (name == "")
return &invalid;
else
return new string(name);
}
VOID do_call_args(const string *s, ADDRINT arg0)
{
fprintf(ftrace, "\n[%s]\n", (*s).c_str()); //(INS_Disassemble(ins)).c_str()
fflush(ftrace);
}
/* ===================================================================== */
VOID do_call_args_indirect(ADDRINT target, BOOL taken, ADDRINT arg0)
{
if (!taken) return;
const string *s = Target2String(target);
do_call_args(s, arg0);
if (s != &invalid)
delete s;
}
/* ===================================================================== */
VOID do_call(const string *s)
{
fprintf(ftrace, "\n[%s]\n", (*s).c_str()); //(INS_Disassemble(ins)).c_str()
fflush(ftrace);
}
VOID do_ret(const string *s)
{
fprintf(ftrace, "\nDirect RETURN to[%s]\n", (*s).c_str()); //(INS_Disassemble(ins)).c_str()
fflush(ftrace);
}
/* ===================================================================== */
VOID do_call_indirect(ADDRINT target, BOOL taken)
{
if (!taken) return;
const string *s = Target2String(target);
do_call(s);
if (s != &invalid)
delete s;
}
VOID do_ret_indirect(ADDRINT target, BOOL taken)
{
if (!taken) return;
const string *s = Target2String(target);
fprintf(ftrace, "\nInDirect RETURN to[%s]\n", (*s).c_str()); //(INS_Disassemble(ins)).c_str()
fflush(ftrace);
if (s != &invalid)
delete s;
}
VOID Instruction(INS ins, VOID *v)
{
//start = std::chrono::high_resolution_clock::now();
UINT32 memOperands = INS_MemoryOperandCount(ins);
fprintf(ftrace, "\n[%s]\n", (INS_Disassemble(ins)).c_str()); //(INS_Disassemble(ins)).c_str()
fflush(ftrace);
if (INS_IsCall(ins))
{
if (INS_IsDirectBranchOrCall(ins))
{
const ADDRINT target = INS_DirectBranchOrCallTargetAddress(ins);
INS_InsertPredicatedCall(ins, IPOINT_BEFORE, AFUNPTR(do_call_args),
IARG_PTR, Target2String(target), IARG_FUNCARG_CALLSITE_VALUE, 0, IARG_END);
}
else
{
INS_InsertCall(ins, IPOINT_BEFORE, AFUNPTR(do_call_indirect),
IARG_BRANCH_TARGET_ADDR, IARG_BRANCH_TAKEN, IARG_END);
}
}
else
{
if (INS_IsRet(ins))
{
if (INS_IsDirectBranchOrCall(ins))
{
const ADDRINT target = INS_DirectBranchOrCallTargetAddress(ins);
INS_InsertCall(ins, IPOINT_BEFORE, AFUNPTR(do_ret),
IARG_PTR, Target2String(target), IARG_FUNCARG_CALLSITE_VALUE, 0, IARG_END);
}
else
{
INS_InsertCall(ins, IPOINT_BEFORE, AFUNPTR(do_ret_indirect),
IARG_BRANCH_TARGET_ADDR, IARG_BRANCH_TAKEN, IARG_END);
}
}
else
{
// sometimes code is not in an image
RTN rtn = INS_Rtn(ins);
// also track stup jumps into share libraries
if (RTN_Valid(rtn) && !INS_IsDirectBranchOrCall(ins) && ".plt" == SEC_Name(RTN_Sec(rtn)))
{
if (print_args)
{
INS_InsertCall(ins, IPOINT_BEFORE, AFUNPTR(do_call_args_indirect),
IARG_BRANCH_TARGET_ADDR, IARG_BRANCH_TAKEN, IARG_FUNCARG_CALLSITE_VALUE, 0, IARG_END);
}
else
{
INS_InsertCall(ins, IPOINT_BEFORE, AFUNPTR(do_call_indirect),
IARG_BRANCH_TARGET_ADDR, IARG_BRANCH_TAKEN, IARG_END);
}
}
}
}
for (UINT32 memOp = 0; memOp < memOperands; memOp++)
{
if (INS_MemoryOperandIsRead(ins, memOp))
{
fprintf(ftrace, "R");
icount++;
}
if (INS_MemoryOperandIsWritten(ins, memOp))
{
fprintf(ftrace, "W");
icount++;
}
}
}
VOID Fini(INT32 code, VOID *v)
{ fprintf(ftrace, "\n");
fclose(ftrace);
}
INT32 Usage()
{
PIN_ERROR( "This Pintool prints a trace of memory addresses\n"
+ KNOB_BASE::StringKnobSummary() + "\n");
return -1;
}
KNOB<string> KnobOutputFile(KNOB_MODE_WRITEONCE, "pintool",
"o", "pinatrace2.out", "specify output file name");
KNOB<long long> KnobInsLimit(KNOB_MODE_WRITEONCE, "pintool",
"i", "1000", "specify instruction limit");
KNOB<BOOL> KnobPrintArgs(KNOB_MODE_WRITEONCE, "pintool", "a", "0", "print call arguments ");
int main(int argc, char *argv[])
{
PIN_InitSymbols();
if (PIN_Init(argc, argv)) return Usage();
ilimit=KnobInsLimit.Value();
ftrace = fopen(KnobOutputFile.Value().c_str(), "w");
print_args = KnobPrintArgs.Value();
INS_AddInstrumentFunction(Instruction, 0);
//TRACE_AddInstrumentFunction(Trace, 0);
PIN_AddFiniFunction(Fini, 0);
PIN_StartProgram();
return 0;
}