c - 如何通过指令读取二进制可执行文件?

标签 c assembly binaryfiles instructions

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

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

#include <stdio.h>

int main(){
    printf("Hello world\n");
    return 0;
}

使用 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)

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

最佳答案

这通过获取函数的地址并转换为 unsigned char 的指针来打印 main 函数的前 10 个字节,以十六进制打印。

这个小片段不算指令。为此,您需要一个指令大小表(不是很困难,只是很乏味,除非您发现该表已经完成,What is the size of each asm instruction?)才能在给定第一个字节的情况下预测每条指令的大小。

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

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

#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;
}

输出:

Hello world
55
89
e5
83
e4
f0
83
ec
20
e8

似乎与反汇编相匹配:)

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>

关于c - 如何通过指令读取二进制可执行文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49153556/

相关文章:

nexus - Nexus 存储库是否重复在不同存储库中提供帮助并具有相同摘要的二进制文件?

iphone - 使用文本文件实时绘图

c - 通过 SPI 从微 Controller 发送命令以显示并接收结果

c++ - 使用 c(++) 扩展时的 @staticmethod

arrays - 内存中表示的未定义 vector 元素是什么?

java - 使用 Java 下载为二进制的文件已损坏

c - 反转整个数组的程序

assembly - 将 CISC 解释为 RISC

assembly - 什么是十六进制减法中的借位? (集会)

java - 为什么将 FileOutputStream 打开到二进制文件会损坏它?