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


91

我想分解一下我拥有的可引导x86磁盘的MBR(前512个字节)。我已经使用以下方式将MBR复制到了文件中

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

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

Answers:


109

您可以使用objdump。根据本文的语法为:

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

您能解释一下您指定的选项吗?
霍肯,2012年

11
--target代替-b-D是“分解所有部分的内容”;-b bfdname--target=bfdname将强制读取为指定的目标代码格式(在本例中不是elf,而是原始二进制);或者 -m machine将指定要使用的架构(在我们的文件中没有带有arch信息的标头)。-M options是反汇编程序的选项;addr16,data16用于“指定默认地址尺寸和操作数大小”(治疗代码i8086在一个通用的x86 DISASM引擎)
osgx

29

GNU工具称为objdump,例如:

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

您还可以为体系结构和语法设置不同的选项。例如,-m i386-Mintel,x86-64i8086是旧的体系结构,将其用于现代代码可能会产生意外的结果。此外,由于许多机器都是64位的,因此指定x86-64to为当前-M可能是一个好主意。传递intel给,可以-M将语法更改为Intel样式,而不是您可能想要或不需要的默认AT&T样式。
GDP2

24

我喜欢ndisasm这个目的。它带有NASM汇编器,该汇编器是免费和开放源代码,并且包含在大多数Linux发行版的软件包存储库中。


我更喜欢这个答案。更易于使用,我可以在OS X上安装nasm-objdump不存在,并且我不想从源代码构建它。

22
ndisasm -b16 -o7c00h -a -s7c3eh mbr

解释 -来自ndisasm手册页

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

与简单的ndisasm相比,这有什么作用?您能解释一下这些选项吗?
Hawken

4
您能解释一下这些选择的含义和作用吗?了解答案比仅仅获得答案要好。
雪橇2012年

-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.
Janus Troelsen,

15

starbluehlovdal都具有典型的答案的一部分。如果要反汇编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的objconv非常好。它将标签放在分支目标上,使弄清楚代码的作用变得容易得多。它可以分解为NASM,YASM,MASM或AT&T(GNU)语法。”

多媒体迈克已经发现了有关--adjust-vma; 在ndisasm相当于是-o选项。

拆卸,比如说,sh4代码(我用Debian的自测试一个二进制),使用与GNU binutils的(几乎所有其他反汇编限于一个平台,例如x86与ndisasmobjconv):

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

-m是机器,并-EL意味着小端(对于sh4eb使用-EB代替),这是相关的存在于任一端序架构。


2
Agner Fog的objconv非常好。它将标签放在分支目标上,使弄清楚代码的作用变得容易得多。它可以分解为NASM,YASM,MASM或AT&T(GNU)语法。
彼得·科德斯

对我来说,它在GNU / Linux上开箱即用。但是,是的,它仅x86 / x86-64,与GNU binutils不同。但是,它具有很多很好的x86特定提示,可以将它们添加为注释,例如,操作数大小的前缀可能导致Intel CPU的解码器出现LCP停顿时。一定要在答案中提及它。评论的主要目的之一是帮助发布者改善其答案,而不仅仅是后来的观众也需要阅读这些内容。
彼得·科德斯

1
@PeterCordes是的,我有MirBSD作为主要操作系统;)
mirabilos 2015年

@PeterCordes,但似乎无法分解原始二进制文件,对吗?我只需要创建最少的ELF文件即可向其中输入一堆指令,但是也许我只是错过了一些选择?
Ruslan

1
@Ruslan:IDK,一个有趣的问题。我通常只使用objdump,或者如果我想要分支标签gcc -O3 -masm=intel -fverbose-asm -S -o- | less,因为我通常试图将C源代码调整为编译成良好的asm。
彼得·科德斯

9

试试这个命令:

sudo dd if=/dev/sda bs=512 count=1 | ndisasm -b16 -o7c00h -
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.