如何按指令读取二进制可执行文件?

Top*_*ley 1 c assembly binaryfiles instructions

有没有办法以编程方式从x86架构上的二进制可执行文件中读取给定数量的指令?

如果我有一个简单的C程序的二进制文件hello.c:

#include <stdio.h>

int main(){
    printf("Hello world\n");
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

在使用编译后gcc,反汇编函数main如下所示:

000000000000063a <main>:
 63a:   55                      push   %rbp
 63b:   48 89 e5                mov    %rsp,%rbp
 63e:   48 8d 3d 9f 00 00 00    lea    0x9f(%rip),%rdi        # 6e4 <_IO_stdin_used+0x4>
 645:   e8 c6 fe ff ff          callq  510 <puts@plt>
 64a:   b8 00 00 00 00          mov    $0x0,%eax
 64f:   5d                      pop    %rbp
 650:   c3                      retq   
 651:   66 2e 0f 1f 84 00 00    nopw   %cs:0x0(%rax,%rax,1)
 658:   00 00 00 
 65b:   0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)
Run Code Online (Sandbox Code Playgroud)

有没有一种简单的方法在C中读取例如前三个指令(意思是字节55, 48, 89, e5, 48, 8d, 3d, 9f, 00, 00, 00)main?不能保证函数看起来像这样 - 第一条指令可能具有所有不同的操作码和大小.

Jea*_*bre 7

这将打印main函数的10个第一个字节,方法是获取函数的地址并转换为指针unsigned char,以十六进制打印.

这个小片段不计算说明.为此你需要一个指令大小表(不是很困难,只是单调乏味,除非你发现表已经完成,每个asm指令的大小是多少?)能够预测给定第一个字节的每个指令的大小.

(当然,除非你所针对的处理器有一个固定的指令大小,这使得这个问题很容易解决)

调试器也必须解码操作数,但在某些情况下,如步或跟踪,我怀疑他们有一个方便的表来计算下一个断点地址.

#include <stdio.h>

int main(){
    printf("Hello world\n");
    const unsigned char *start = (const char *)&main;
    int i;
    for (i=0;i<10;i++)
    {
       printf("%x\n",start[i]);
    }    
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出:

Hello world
55
89
e5
83
e4
f0
83
ec
20
e8
Run Code Online (Sandbox Code Playgroud)

似乎与拆卸相匹配:)

00401630 <_main>:
  401630:   55                      push   %ebp
  401631:   89 e5                   mov    %esp,%ebp
  401633:   83 e4 f0                and    $0xfffffff0,%esp
  401636:   83 ec 20                sub    $0x20,%esp
  401639:   e8 a2 01 00 00          call   4017e0 <___main>
Run Code Online (Sandbox Code Playgroud)

  • 为什么选择downvote?对于OP的问题,它看起来是正确的答案...... (4认同)