如何指定一个代码区域以通过 pintool 对其进行检测?

Posted

技术标签:

【中文标题】如何指定一个代码区域以通过 pintool 对其进行检测?【英文标题】:How can i specify an area of code to instrument it by pintool? 【发布时间】:2015-11-08 16:15:33 【问题描述】:

Pin 有四个粒度级别:routine、instruction and image、trace。 我可以指定一个限制/区域来开始和停止插入检测代码吗? 可以通过类似指令(#start instrumentation,#end instrumentation) 或者类似的东西,

一个例子:for( int i=0; i< x; i++) #startInstrumentation for( ....;.....;.....) // some code // function call, conditions , loops, .... #endInstrumentation 有没有办法做到这一点?

【问题讨论】:

【参考方案1】:

您可以使用基于跟踪的检测来做您想做的事。在每个跟踪的开始,检查它的起始地址,如果它不在感兴趣的范围内,避免添加分析函数并立即从例程返回。

跟踪可能会在感兴趣区域之外开始但在其中结束,或者相反。如果发生这种情况,您将需要对要检测的内容执行更细粒度的选择。在投入努力之前,我会检查这是否是一个真正的问题。

如果您对检测特定例程或图像感兴趣,请考虑在套件中使用来自 InstLib 的 filter.cpp。使用示例可以在 InstLibExamples 中找到。

现在,至于如何定位这些感兴趣的区域,您有多种选择。如果您无法控制目标二进制文件,则可以在命令行参数中指定区域,作为感兴趣图像的一对偏移量。

如果您可以控制二进制文件,则可以插入两个符号,指定感兴趣区域的开始和结束,然后使用 SYM 接口迭代图像符号。

【讨论】:

但是我如何在二进制文件中指定感兴趣的范围(当然我可以在高级中指定,但是我如何在二进制文件中找到它),比如我怎样才能找到一个特定的循环(它是二进制文件中的开始和结束。 问题是在文件中定位感兴趣的区域还是将其指定为固定? 我想要两者,我想从 pin 中选择应用程序中的一个区域。 看看我添加的段落是否回答了你的问题【参考方案2】:

我的解决方案是:

1) 在代码中插入感兴趣区域 (ROI) 开始和结束函数

2) ROI begin 执行后设置标志,ROI end 执行前取消设置

3) 如果平面未设置,则立即从检测调用返回

这里有一个示例,我已将内存引用跟踪修改为仅跟踪 ROI。

#include <stdio.h>
#include "pin.H"
#include <string>

const CHAR * ROI_BEGIN = "__parsec_roi_begin";
const CHAR * ROI_END = "__parsec_roi_end";

FILE * trace;
bool isROI = false;

// Print a memory read record
VOID RecordMemRead(VOID * ip, VOID * addr, CHAR * rtn)

    // Return if not in ROI
    if(!isROI)
    
        return;
    

    // Log memory access in CSV
    fprintf(trace,"%p,R,%p,%s\n", ip, addr, rtn);


// Print a memory write record
VOID RecordMemWrite(VOID * ip, VOID * addr, CHAR * rtn)

    // Return if not in ROI
    if(!isROI)
    
        return;
    

    // Log memory access in CSV
    fprintf(trace,"%p,W,%p,%s\n", ip, addr, rtn);


// Set ROI flag
VOID StartROI()

    isROI = true;


// Set ROI flag
VOID StopROI()

    isROI = false;


// Is called for every instruction and instruments reads and writes
VOID Instruction(INS ins, VOID *v)

    // Instruments memory accesses using a predicated call, i.e.
    // the instrumentation is called iff the instruction will actually be executed.
    //
    // On the IA-32 and Intel(R) 64 architectures conditional moves and REP 
    // prefixed instructions appear as predicated instructions in Pin.
    UINT32 memOperands = INS_MemoryOperandCount(ins);

    // Iterate over each memory operand of the instruction.
    for (UINT32 memOp = 0; memOp < memOperands; memOp++)
    
        // Get routine name if valid
        const CHAR * name = "invalid";
        if(RTN_Valid(INS_Rtn(ins))) 
        
            name = RTN_Name(INS_Rtn(ins)).c_str();
        

        if (INS_MemoryOperandIsRead(ins, memOp))
        
            INS_InsertPredicatedCall(
                ins, IPOINT_BEFORE, (AFUNPTR)RecordMemRead,
                IARG_INST_PTR,
                IARG_MEMORYOP_EA, memOp,
                IARG_ADDRINT, name,
                IARG_END);
        
        // Note that in some architectures a single memory operand can be 
        // both read and written (for instance incl (%eax) on IA-32)
        // In that case we instrument it once for read and once for write.
        if (INS_MemoryOperandIsWritten(ins, memOp))
        
            INS_InsertPredicatedCall(
                ins, IPOINT_BEFORE, (AFUNPTR)RecordMemWrite,
                IARG_INST_PTR,
                IARG_MEMORYOP_EA, memOp,
                IARG_ADDRINT, name,
                IARG_END);
        
    


// Pin calls this function every time a new rtn is executed
VOID Routine(RTN rtn, VOID *v)

    // Get routine name
    const CHAR * name = RTN_Name(rtn).c_str();

    if(strcmp(name,ROI_BEGIN) == 0) 
        // Start tracing after ROI begin exec
        RTN_Open(rtn);
        RTN_InsertCall(rtn, IPOINT_AFTER, (AFUNPTR)StartROI, IARG_END);
        RTN_Close(rtn);
     else if (strcmp(name,ROI_END) == 0) 
        // Stop tracing before ROI end exec
        RTN_Open(rtn);
        RTN_InsertCall(rtn, IPOINT_BEFORE, (AFUNPTR)StopROI, IARG_END);
        RTN_Close(rtn);
    


// Pin calls this function at the end
VOID Fini(INT32 code, VOID *v)

    fclose(trace);


/* ===================================================================== */
/* Print Help Message                                                    */
/* ===================================================================== */

INT32 Usage()

    PIN_ERROR( "This Pintool prints a trace of memory addresses\n" 
              + KNOB_BASE::StringKnobSummary() + "\n");
    return -1;


/* ===================================================================== */
/* Main                                                                  */
/* ===================================================================== */

int main(int argc, char *argv[])

    // Initialize symbol table code, needed for rtn instrumentation
    PIN_InitSymbols();

    // Usage
    if (PIN_Init(argc, argv)) return Usage();

    // Open trace file and write header
    trace = fopen("roitrace.csv", "w");
    fprintf(trace,"pc,rw,addr,rtn\n");

    // Add instrument functions
    RTN_AddInstrumentFunction(Routine, 0);
    INS_AddInstrumentFunction(Instruction, 0);
    PIN_AddFiniFunction(Fini, 0);

    // Never returns
    PIN_StartProgram();

    return 0;

【讨论】:

以上是关于如何指定一个代码区域以通过 pintool 对其进行检测?的主要内容,如果未能解决你的问题,请参考以下文章

vue项目中使用bpmn-节点篇

如何将指令传递给 intel-pintool 中的回调?

如何以编程方式禁用解锁屏幕

PinTools学习笔记——安装和入门

八皇后

java源代码安全审计