x86 是可变指令长度,这意味着很难反汇编。如果这是您的第一个反汇编程序,则不建议这样做。
说...我采取的方法是,您必须在二进制文件中识别作为操作码的第一个字节的字节,并将这些字节与操作码或数据中的第二个字节或其他字节分开。一旦您知道您可以从二进制文件的开头开始并反汇编操作码。
你如何从其他字节中找出操作码?您需要走所有可能的执行路径,这听起来像是一个递归问题,并且可能但不一定是。查看中断向量表和/或代码中的所有硬件入口点。这为您提供了一个简短的操作码字节列表。一种非递归方法是对二进制文件进行多次遍历,查看标记为操作码的每个字节,对其进行解码以了解它消耗了多少字节。您还需要知道它是否是无条件分支、条件分支、返回、调用等。如果它不是无条件分支或返回,您可以假设该指令之后的字节是下一条指令的第一个字节。每当您遇到某种分支或调用时,计算目标地址,将该字节添加到列表中。继续通过,直到您通过不向列表添加新字节的通过。您还需要确保如果说您找到一个 3 字节指令的字节,但它后面的字节被标记为指令,那么您就有问题了。诸如条件分支之类的东西之前是确保它们永远不会分支的东西。如果将高级代码编译为二进制文件,您根本看不到这么多,但是手写汇编程序的美好时光,或者想要保护他们的代码的人会做这样的事情。
不幸的是,如果您只有二进制文件,对于可变长度的指令集,您将无法获得完美的反汇编。一些分支目标是在运行时计算的,有时手动编码的程序集会在返回之前修改堆栈以更改接下来执行的代码,如果这是该代码的唯一路径,那么除非你走这么远,否则你可能不会以编程方式计算出来来模拟代码。即使使用模拟,您也不会涵盖所有执行路径。
例如,使用像 ARM 这样的固定长度指令集(只要它是 arm 而不是 arm 和 thumb 的混合),您可以简单地从二进制文件的开头开始并反汇编,直到用完单词。您可能会将数据字反汇编为有效或无效或不太可能使用的指令,但这很好。
如果在精灵的某个地方有一些东西表明二进制文件的哪些部分是可执行的,哪些部分是数据,我不会感到惊讶。甚至可能您不必走数据路径,我怀疑 objdump 执行的任务可能是它可能使用 elf 文件中的某些内容。
elf 文件格式在许多地方都有记录。有基本结构,供应商可以添加供应商记录的特定块类型。