繁体   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