簡體   English   中英

PIN從指令地址獲取匯編操作碼

[英]PIN get assembly opcodes from instruction address

我正在使用PIN分析C程序的指令並執行必要的操作。 我已經在Ubuntu上使用GCC編譯了C程序,然后將生成的可執行文件作為輸入傳遞給pintool。 我有一個pintool,它會調用一個指令檢測例程,然后每次都調用一個分析例程。 這是我在C ++中的Pintool-

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

UINT64 icount = 0;

using namespace std;

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

FILE * trace;

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

VOID dump(VOID *ip, UINT32 size) { 
    unsigned int i;
    UINT8 opcodeBytes[15];

    UINT32 fetched = PIN_SafeCopy(&opcodeBytes[0], ip, size);

    if (fetched != size) {
        fprintf(trace, "*** error fetching instruction at address 0x%lx",(unsigned long)ip);
        return;
    }

    fprintf(trace, "\n");
    fprintf(trace, "\n%d\n",size);

    for (i=0; i<size; i++)
        fprintf(trace, " %02x", opcodeBytes[i]); //print the opcode bytes
    fflush(trace);
}

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

VOID Instruction(INS ins, void *v) {
      INS_InsertCall( ins, IPOINT_BEFORE, (AFUNPTR)dump, IARG_INST_PTR, IARG_UINT32, INS_Size(ins) , IARG_END);
}

VOID Fini(INT32 code, VOID *v) {
    printf("count = %ld\n",(long)icount);
}

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

int main(int argc, char *argv[])
{
    trace = fopen("test.out", "w");

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

    PIN_InitSymbols();
    PIN_AddInternalExceptionHandler(ExceptionHandler,NULL);
    INS_AddInstrumentFunction(Instruction, 0);
    PIN_AddFiniFunction(Fini, 0);

    // Never returns
    PIN_StartProgram();

    return 0;
}

當我檢查輸出跟蹤時,我看到我得到了這樣的輸出-

3
 48 89 e7

5
 e8 78 0d 00 00

1
 55

第一行是指令的字節大小,第二行是每個字節中存儲的操作碼。

我看到了這個特殊的論壇-https : //groups.yahoo.com/neo/groups/pinheads/conversations/topics/4405#

他們提到Linux輸出不一致,這是由於32位反匯編程序可用於64位指令。 我得到的輸出與此處提到的Linux相同,而Windows則是我期望的正確x86_64操作碼。

知道如何獲取正確的操作碼,以及如果我做錯了反匯編,該如何解決。 我使用的是64位PC,所以不知道我是否在進行32位反匯編。

在32位模式下, 48是1字節的incdec (我忘記了)。

在64位模式下,它是REX前綴(W = 1,未設置其他位,選擇64位操作數大小)。 (AMD 64將inc / dec短編碼的整個0x40-f范圍重新用作REX前綴。)

48 89 e7解碼為3字節指令而不是4889 e7絕對證明了它在64位模式下會反匯編。

那么我應該如何解釋這里的說明?

如x86-64指令所示。

對於您的情況,我將那些十六進制字節提供給反匯編程序:

db 0x48, 0x89, 0xe7
db 0xe8, 0x78, 0x0d, 0x00, 0x00
db 0x55

nasm -f elf64 foo.asm && objdump -drwC -Mintel foo.o

  400080:       48 89 e7                mov    rdi,rsp
  400083:       e8 78 0d 00 00          call rel32
  400088:       55                      push   rbp

objdump -d發現相同的指令中斷,因為PIN正確地對其進行了解碼。

push大概是在被調用函數的開始處。 將它們放在一起可以使跟蹤變平,這不是制作可運行版本的方法,只是為了分解字節。

我應該簡單地忽略第一個字節,然后使用剩余的嗎?

不,當然不。 REX前綴是指令的一部分。 如果沒有0x48,則第一條指令將解碼為mov edi,esp ,這是另一條指令。

嘗試查看一些反匯編輸出以獲取一些現有代碼,以習慣x86-64指令的外觀。 有關特定的編碼詳細信息,請參閱Intel的vol.2手冊。 它有一些關於指令編碼細節的簡介和附錄部分。 (手冊的主體是指令集參考,其中包含每條指令的工作方式及其操作碼的詳細信息。)請參閱https://software.intel.com/zh-cn/articles/intel-sdm#three- volume標簽wiki中的其他鏈接。

Pin有一個可拆卸的API,您應該使用它。 請參閱以下有關應如何處理的問題:

https://reverseengineering.stackexchange.com/questions/12404/intel-pin-how-to-access-the-ins-object-from-inside-an-analysis-function

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM