如何删除 PIN 中特定地址的 bbl 检测调用?

逆向工程 仪器仪表 小工具
2021-07-03 00:44:53

我创建了一个pintool,它在 json 文件中输出程序执行的所有基本块。问题是检测程序运行缓慢,所以我试图优化我的 pintool

我想我可以在调用一次后从块中删除对检测函数的调用,但我一直无法找到如何做到这一点。在官方 PIN 文档中,只有PIN_RemoveInstrumentation()似乎禁用所有仪器的功能。

谁能告诉我如何做到这一点,或者甚至可以使用 PIN 来做到这一点?

1个回答

PIN 不提供直接 API 来删除特定地址上的基本块检测调用。您可以做的是跟踪至少已执行一次的基本块。
您将只为那些以前未执行过的基本块插入检测调用。

这是基于官方文档的粗略示例

// The running count of instructions is kept here
// make it static to help the compiler optimize docount
static UINT64 icount = 0;

// Count the number of instructions in this basic block
VOID docount(UINT32 c) { icount += c; }

VOID Trace(TRACE trace, VOID *v)
{    
    for (BBL bbl = TRACE_BblHead(trace); BBL_Valid(bbl); bbl = BBL_Next(bbl))
    {   
        ADDRINT addr = BBL_Address(bbl);
        if (alreadyVistited(addr) == false) 
        {
            // Add instrumentation call for this basic block
            BBL_InsertCall(bbl, IPOINT_ANYWHERE, (AFUNPTR)docount, IARG_UINT32, BBL_NumIns(bbl), IARG_END);
        }
        else
        {
            addToVisitedList(addr);
        }
    }
}

int main(int argc, char * argv[])
{
...
TRACE_AddInstrumentFunction(Trace, 0);
...
}

这的开销完全取决于添加的检测代码的复杂性。
一般来说,要加快速度,您应该启用最大编译器优化。如果可能,您还可以使用更好的编译器,例如能够生成极快代码英特尔编译器


更新

如果您使用dynamoRIO而不是 PIN,您可以更轻松地实现您想做的事情。这是一个示例代码,它记录了程序在主模块中执行的所有基本块。

#define WINDOWS
#define X86_32
#define _CRT_SECURE_NO_DEPRECATE
#include "dr_api.h"
#pragma comment(lib, "dynamorio.lib")

static file_t logFile;
static LPBYTE mainModStartAddr, mainModEndAddr;

// This is called once for each basic block as it's discovered
static dr_emit_flags_t event_basic_block(void *drcontext, void *tag, instrlist_t *ilist, bool for_trace, bool translating)
{
    // The IP of the basoc block
    LPBYTE addr = dr_fragment_app_pc(tag);

    // Basic Block must be within the main module
    if (addr >= mainModStartAddr && addr <= mainModEndAddr) 
        dr_fprintf(logFile, "0x%08X", addr);
    return DR_EMIT_DEFAULT;
}


static void event_exit()
{
    dr_close_file(logFile);
}


DR_EXPORT void dr_init(client_id_t id)
{
    module_data_t *data  = dr_get_main_module();
    mainModStartAddr = data->start;
    mainModEndAddr = data->end;
    dr_free_module_data(data);

    logFile = dr_open_file("logfile.txt", DR_FILE_WRITE_OVERWRITE);

    dr_register_bb_event(event_basic_block);    
    dr_register_exit_event(event_exit);
}

请注意,根本不需要分析功能。event_basic_block每个基本块将调用一次检测函数它不会被多次调用,因为从第二次开始,代码将从代码缓存中执行。

dynamoRIO 和 PIN 的区别在于前者直接允许注册基本块生成的回调。另一方面,PIN 允许用于跟踪生成的回调。跟踪基本块的集合。此外,由于并非所有基本块都可以在跟踪中执行,因此在这种情况下使用 PIN 比较困难。