修改 PIN 中的应用指令

Posted

技术标签:

【中文标题】修改 PIN 中的应用指令【英文标题】:Modify application instruction in PIN 【发布时间】:2018-03-20 07:03:58 【问题描述】:

我正在使用英特尔 PIN 修改我的应用程序中的指令。我使用此链接中的 Safecopy() 示例作为参考:

https://software.intel.com/sites/landingpage/pintool/docs/81205/Pin/html/index.html#SafeCopy

我有以下示例 C 程序:

int main()

    asm(".byte 0x16");
    return 0;

0x16 在 x86_64 中是非法的,当我运行可执行文件时,它会按预期显示以下错误:

Illegal instruction (core dumped)

我有一个 pintool,它将上述可执行文件作为输入并修改非法指令 0x16 以执行其他操作。

我的 Pintool 如下:

#include "pin.H"
#include <iostream>
#include <fstream>

using namespace std;

KNOB<string> KnobOutputFile(KNOB_MODE_WRITEONCE, "pintool", "o", "test.out","This pin tool simulates ULI");

FILE * op;

//====================================================================
// Analysis Routines
//====================================================================

VOID analysis_routine(VOID *ip, UINT32 size) 
 

    fprintf(op,"16 came to analysis routine\n\n");



//====================================================================
// Instrumentation Routines
//====================================================================

VOID Instruction(INS ins, void *v) 


    UINT8 opcodeBytes[15];

    UINT64 fetched = PIN_SafeCopy(&opcodeBytes[0],(void *)INS_Address(ins),INS_Size(ins));

    if (fetched != INS_Size(ins))
        fprintf(op,"\nBad\n");

    else 
    
        if(opcodeBytes[0]==0x16)
        

            fprintf(op,"\n16 came to instrumentation routine\n");

            INS_InsertCall( ins, IPOINT_BEFORE, (AFUNPTR)analysis_routine, IARG_INST_PTR, IARG_UINT64, INS_Size(ins) , IARG_END);
            INS_Delete(ins);
        
    


VOID Fini(INT32 code, VOID *v) 



INT32 Usage() 
    PIN_ERROR("This Pintool failed\n" + KNOB_BASE::StringKnobSummary() + "\n");
    return -1;


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


    op = fopen("test.out", "w");

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

    PIN_InitSymbols();
    INS_AddInstrumentFunction(Instruction, 0);
    PIN_AddFiniFunction(Fini, 0);
    PIN_StartProgram();
    return 0;

根据我的理解,每次遇到新指令时都会执行检测例程指令,并且根据我的代码,在执行指令之前调用分析例程,因为我在检测函数中使用 IPOINT_BEFORE 参数来调用分析常规。因此,我正在检查我的操作码,如果它是 0x16,那么我正在调用我的分析例程并删除我的原始指令。由于该指令是非法的并且已被删除,因此我的跟踪应该继续进行,没有任何问题。

但是,即使使用此逻辑,似乎我的非法指令正在执行,我的程序崩溃并给出相同的非法指令错误。我无法理解这个问题,因为我似乎在执行指令之前删除了指令,并且我使用的是 Pin 教程中的相同示例。

如果我调用任何错误的任何想法?如果我在上面的任何地方错了,也请纠正我。根据我的理解,检测例程在指令执行之前被调用,因此我也可以在那个时候修改指令。如果我错了,请纠正我。

【问题讨论】:

您是否成功替换了正确地址的正确字节?你确定你只是替换给你带来麻烦的一个字节吗?您是否仅替换该单个字节而不替换其他字节模式? 0x16 本身可能不是合法指令,但您如何确保它不会被解释为更大指令的一部分? 【参考方案1】:

我不知道这里出了什么问题,但这就是我要做的:我将首先打印有关检测例程中指令的更多信息。

多长时间? 这条指令的地址是什么?打印测试程序中main()的地址,看看两者是否接近。 其他指令字节是什么?它们是否恰好是与非法字节后面的指令匹配的字节?

另外:

确保在每次打印后刷新输出文件,以确保不会发生非法指令失败来掩盖您的调试打印 我建议捕获您的程序可能收到的 SIGILL 信号,并确保它在有或没有 Pin 的情况下发生在同一个地方。

【讨论】:

我使用 INS_Size(ins) 获得指令大小。我使用 INS_Address(ins) 获取地址。当我从指令地址处的指针复制 INS_Size(ins) 字节时,我得到了所有指令字节。它们与我通过指令跟踪的反汇编检查过的匹配。 我建议您进行其他检查【参考方案2】:

您需要意识到 INS_Delete() 是在检测时调用的,即在实际执行指令之前,而且在调用检测例程之前。事件发生的顺序如下:

INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)analysis_routine, ...);
INS_Delete(ins);
analysis_routine(); /* <= BOOM ! ins had been deleted just before... */

当调用 INS_Delete(ins) 时,您需要删除所有附带的工具,否则您的工具将不连贯。假设检测仍然存在,与检测例程关联的指令将不是预期的指令,因此会崩溃。

为了更好地理解这一点(第一次不容易理解),您可能需要再次阅读pin works。

编辑:根据该工具附带的一些官方 pintools(参见下面的 cmets),instrument then delete 模式是 PIN 的常规模式。

【讨论】:

我根本没用过 PIN,但我很好奇。为什么在使用INS_Delete() 之后调用analysis_routine() 会出现问题? INS_Delete() 究竟是做什么的?假设阅读答案的人不了解如何正确使用 PIN,否则他们不会遇到这个问题。至少链接到解释它的文档部分,并指出究竟是什么错误。 谢谢彼得。我相应地更新了答案,希望对您有所帮助。 我从未这样做过,但我相信应该使用以下 API(仅供专家使用):software.intel.com/sites/landingpage/pintool/docs/97438/Pin/… @Heyji 我不确定你的想法是什么,你不能将分析函数插入到已删除的指令中——这种方法在 Pin 套件提供的示例中非常常用。参见例如source\tools\Tests\emu.cpp 可能不会针对该特定指令再次调用检测例程(它可能会发生,但在给定场景中不太可能发生)

以上是关于修改 PIN 中的应用指令的主要内容,如果未能解决你的问题,请参考以下文章

如何获取 Pin 中存储指令写入的值?

如何使用 pin 工具跟踪二进制仪器中的特定循环?

使用 Intel Pin 时跟踪不匹配的 CALL 和 RET 指令数

Intel Pin 3.0 不识别 MPX 指令?

目标代码重定位和 Intel Pin 交互

如何使用intel pin工具来计算在linux上执行的指令?