如何反汇编原始 16 位 x86 机器代码?

Posted

技术标签:

【中文标题】如何反汇编原始 16 位 x86 机器代码?【英文标题】:How do I disassemble raw 16-bit x86 machine code? 【发布时间】:2010-12-16 18:19:52 【问题描述】:

我想反汇编我拥有的可引导 x86 磁盘的 MBR(前 512 个字节)。我已将 MBR 复制到一个文件中使用

dd if=/dev/my-device of=mbr bs=512 count=1

对可以反汇编文件mbr的Linux实用程序有什么建议吗?

【问题讨论】:

【参考方案1】:

您可以使用 objdump。根据this article,语法是:

objdump -D -b binary -mi386 -Maddr16,data16 mbr

【讨论】:

你能解释一下你指定的选项是做什么的吗? --target 而不是 -b-D是“反汇编所有节的内容”; -b bfdname--target=bfdname 将强制读取为指定的目标代码格式(在我们的例子中不是精灵,而是原始二进制文件); -m machine 将指定要使用的架构(在我们的文件中,没有包含拱信息的标题)。 -M options 是反汇编器的选项; addr16,data16 用于“指定默认地址大小和操作数大小”(在通用 x86 disasm 引擎中将代码视为 i8086 之一)【参考方案2】:

GNU 工具名为objdump,例如:

objdump -D -b binary -m i8086 <file>

【讨论】:

您还可以为架构和语法设置不同的选项。例如,-m i386-Mintel,x86-64i8086 是一种旧架构,将其用于现代代码可能会产生意想不到的结果。此外,现在将x86-64 指定为-M 可能是一个好主意,因为许多机器都是64 位的。将 intel 传递给 -M 会将语法更改为 Intel 样式,而不是您可能想要也可能不想要的默认 AT&T 样式。【参考方案3】:

为此,我喜欢ndisasm。它带有 NASM 汇编器,它是免费和开源的,并且包含在大多数 linux 发行版的软件包存储库中。

【讨论】:

我更喜欢这个答案。更易于使用,我可以在 OS X 上安装 nasm - objdump 不存在,我不想从源代码构建它。【参考方案4】:
ndisasm -b16 -o7c00h -a -s7c3eh mbr

解释 - 来自 ndisasm 手册页

-b = 指定 16、32 或 64 位模式。默认为 16 位模式。 -o = 指定文件的名义加载地址。此选项使 ndisasm 获取它在左边距下列出的地址,以及与 PC 相关的跳转和调用的目标地址,右边。 -a = 启用自动(或智能)同步模式,在这种模式下,ndisasm 将通过检查相对跳转的目标地址并调用它反汇编来尝试猜测应该在哪里执行同步。 -s = 手动指定同步地址,这样 ndisasm 将不会输出包含地址两侧字节的任何机器指令。因此,从该地址开始的指令将被正确反汇编。 mbr = 要反汇编的文件。

【讨论】:

与简单的 ndisasm 相比,这有什么作用?你能解释一下选项吗 您能解释一下这些选项的含义和作用吗?理解答案总比得到答案要好。 -b specifies 16-, 32- or 64-bit mode. The default is 16-bit mode. -o is the notional load address for the file. This option causes ndisasm to get the addresses it lists down the left hand margin, and the target addresses of PC-relative jumps and calls, right. -s specifies a synchronisation address, such that ndisasm will not output any machine instruction which encompasses bytes on both sides of the address. Hence the instruction which starts at that address will be correctly disassembled.【参考方案5】:

starblue 和 hlovdal 都有部分规范答案。如果你想反汇编原始 i8086 代码,你通常需要 Intel 语法,而不是 AT&T 语法,所以使用:

objdump -D -Mintel,i8086 -b binary -m i386 mbr.bin
objdump -D -Mintel,i386 -b binary -m i386 foo.bin    # for 32-bit code
objdump -D -Mintel,x86-64 -b binary -m i386 foo.bin  # for 64-bit code

如果您的代码是 ELF(或 a.out(或 (E)COFF)),则可以使用简写形式:

objdump -D -Mintel,i8086 a.out  # disassembles the entire file
objdump -d -Mintel,i8086 a.out  # disassembles only code sections

对于 32 位或 64 位代码,省略 ,8086; ELF 标头已包含此信息。

ndisasm,正如jameslin 所建议的,也是一个不错的选择,但objdump 通常是操作系统自带的,可以处理GNU binutils 支持的所有架构(GCC 支持的超集),以及它的输出通常可以输入到 GNU as(当然,ndisasm 通常可以输入到nasm)。

Peter Cordes 建议“Agner Fog's objconv 非常好。它将标签放在分支目标上,从而更容易弄清楚代码的作用。它可以反汇编成 NASM、YASM、MASM 或 AT&T (GNU) 语法。”

Multimedia Mike 已经发现了--adjust-vmandisasm 等效项是 -o 选项。

要反汇编,比如说,sh4 代码(我使用 Debian 的一个二进制文件进行测试),将其与 GNU binutils 一起使用(几乎所有其他反汇编程序都仅限于一个平台,例如 x86 与 ndisasmobjconv ):

objdump -D -b binary -m sh -EL x

-m 是机器,-EL 表示 Little Endian(sh4eb 使用 -EB 代替),这与存在于任一字节序中的架构相关。

【讨论】:

Agner Fog's objconv 非常好。它将标签放在分支 targets 上,从而更容易弄清楚代码的作用。它可以反汇编成 NASM、YASM、MASM 或 AT&T (GNU) 语法。 它在 GNU/Linux 上开箱即用,对我来说构建得很好。但是,是的,它只是 x86 / x86-64,不像 GNU binutils。但是,它有很多很好的 x86 特定提示,它作为 cmets 添加,例如当操作数大小前缀可能导致 Intel CPU 的解码器中的 LCP-stall 时。无论如何,请在您的答案中提及它。 cmets 的主要目的之一是帮助发布者改进他们的答案,而不仅仅是后来的观众也需要阅读。 @PeterCordes 是的,我将 MirBSD 作为主要操作系统 ;) @PeterCordes 但它似乎无法反汇编原始二进制文件,可以吗?我必须创建最小的 ELF 文件才能向其中输入一堆指令,但也许我只是错过了一些选项? @Ruslan:IDK,有趣的问题。我通常只使用 objdump,或者如果我想要分支标签,gcc -O3 -masm=intel -fverbose-asm -S -o- | less,因为我通常会尝试将 C 源代码调整为编译为好的 asm。【参考方案6】:

试试这个命令:

sudo dd if=/dev/sda bs=512 count=1 | ndisasm -b16 -o7c00h -

【讨论】:

以上是关于如何反汇编原始 16 位 x86 机器代码?的主要内容,如果未能解决你的问题,请参考以下文章

Android 逆向使用 Python 解析 ELF 文件 ( Capstone 反汇编 ELF 文件中的机器码数据 | 创建反汇编解析器实例对象 | 设置汇编解析器显示细节 )(代码片段

ida pro静态分析

第4章 x86反汇编速成班

什么是反汇编?

x86 反汇编,涉及模块化散列

C++软件异常分析与排查的学习历程