C++ 引脚从指令地址获取程序集操作码

C++ 引脚从指令地址获取程序集操作码,c++,c,assembly,x86,intel-pin,C++,C,Assembly,X86,Intel Pin,我使用PIN分析C程序的指令并执行必要的操作。我在Ubuntu上使用GCC编译了我的C程序,然后将生成的可执行文件作为输入传递给pintool。我有一个pintool,它调用指令插入例程,然后每次调用分析例程。这是我的C++中的Pintool -< /P> #include "pin.H" #include <fstream> #include <cstdint> UINT64 icount = 0; using namespace std; KNOB<str

我使用PIN分析C程序的指令并执行必要的操作。我在Ubuntu上使用GCC编译了我的C程序,然后将生成的可执行文件作为输入传递给pintool。我有一个pintool,它调用指令插入例程,然后每次调用分析例程。这是我的C++中的Pintool -< /P>
#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;
}
第一行是指令的字节大小,第二行是存储在每个字节中的操作码

我看到了这个特别的论坛-

他们提到Linux输出不一致,这是由于64位指令的32位反汇编程序造成的。我得到的输出与这里提到的Linux相同,而Windows是我期望的正确的x86_64操作码


你知道我怎样才能得到正确的操作码吗?如果我做了错误的分解,我怎样才能纠正它。我使用的是64位PC,所以不知道我是否在进行32位反汇编。

在32位模式下,
48
是一个1字节的
inc
dec
(我忘了是哪个)

在64位模式下,它是REX前缀(W=1,其他位未设置,选择64位操作数大小)。(AMD64将整个
0x40-f
inc/dec短编码范围重新用作REX前缀。)

48 89 e7
解码为3字节指令而不是
48
89 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指令的外观。有关特定编码的详细信息,请参阅英特尔第二卷手册。它有一些关于指令编码细节的介绍和附录部分。(手册的主体部分是说明集参考,其中详细介绍了每个说明的工作原理及其操作码。)请参阅,以及tag wiki中的其他链接。

Pin有一个用于反汇编的API,您应该使用它。请参见此问题,了解应如何进行:


pintool是否为64位代码提供了选项或单独的程序?永远不要使用它。那么我应该如何解释这里的指令?我应该忽略第一个字节,然后使用剩余的?
  400080:       48 89 e7                mov    rdi,rsp
  400083:       e8 78 0d 00 00          call rel32
  400088:       55                      push   rbp