[英]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字节的inc
或dec
(我忘记了)。
在64位模式下,它是REX前缀(W = 1,未设置其他位,选择64位操作数大小)。 (AMD 64将inc / dec短编码的整个0x40-f
范围重新用作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指令的外观。 有关特定的编码详细信息,请参阅Intel的vol.2手册。 它有一些关于指令编码细节的简介和附录部分。 (手册的主体是指令集参考,其中包含每条指令的工作方式及其操作码的详细信息。)请参阅https://software.intel.com/zh-cn/articles/intel-sdm#three- volume和x86标签wiki中的其他链接。
Pin有一个可拆卸的API,您应该使用它。 请参阅以下有关应如何处理的问题:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.