混合 ARM/Thumb2 ELF 文件的反汇编

Disassembly of a mixed ARM/Thumb2 ELF file

我正在尝试反汇编一个 ELF 可执行文件,它是我使用 arm-linux-gnueabihf 编译的目标 thumb-2。但是,ARM 指令编码让我在调试反汇编程序时感到困惑。让我们考虑以下指令:

mov.w fp, #0

我使用 objdumphopper 作为 thumb-2 指令进行了反汇编。该指令在内存中显示为 4ff0000b,这意味着它实际上是 0b00f04f(小端)。因此,该指令的二进制编码为:

0000 1011 0000 0000 1111 0000 0100 1111

根据 ARM 体系结构手册,似乎所有 thumb-2 指令都应以 111[10|01|11] 开头。因此,上述编码不对应于任何 thumb-2 指令。此外,它与 A8.8.102 节(第 484 页)中的任何编码都不匹配。

我是不是漏掉了什么?

我认为您忽略了一个微妙的区别,即宽 Thumb-2 编码不像 ARM 编码那样是 32 位字,它们是一对 16 位半字(请注意 ARM ARM 编码图上方的位编号).因此,虽然半字本身是小字节序的,但它们仍然以相对于彼此的 'normal' 顺序存储。如果内存中的字节是4ff0000b,那么实际编码的指令是f04f 0b00.

thumb2 是 thumb 指令集的扩展,以前是未定义的指令,现在其中一些已定义。 arm 是一个完全不同的指令集。如果工具链没有给你留下关于什么代码是 thumb vs arm 的线索,那么弄清楚它的唯一方法是从一个入口点的假设开始,然后从那里按照执行顺序反汇编,即使在那里你也可能无法弄清楚一些的代码。

您无法仅通过位模式将 arm 指令与 thumb 或 thumb+thumb2 扩展区分开来。还记得 arm 指令在 4 字节边界上对齐,其中 thumb 是 2 字节,而 thumb 2 扩展不必与其父 thumb 位于相同的 4 字节边界,这使得这一切变得更加有趣。 (thumb+thumb2 是由 16 位值的倍数组成的可变长度指令集)

如果您的所有代码都是拇指的,并且其中没有 arm 指令,那么您仍然会遇到可变长度指令集会遇到的问题,并且要正确执行此操作,您必须按执行顺序遍历代码。例如,不难在 .text 中嵌入一个看起来像 thumb2 扩展名的前半部分的数据值,然后是一个真正的 thumb2 扩展名,导致反汇编程序脱离 rails。基本可变字长反汇编问题(以及打败简单反汇编程序的基本方法)。

16 位字 A、B、C、D

如果 C + D 是通过解码 C 获知的 thumb 2 指令,则 A 是 thumb 指令,B 是类似于 thumb2 扩展的前半部分的数据值,然后通过 ram A 进行线性解码是thumb 指令 B 和 C 被解码为 thumb2 扩展,而实际上是 thumb2 扩展的后半部分的 D 现在被解码为指令的前 16 位,关于它如何解码或它是否导致所有或下面很多指令被解码错误。

所以开始看看小精灵是否告诉你什么,如果没有,那么你必须按照执行顺序通过代码(你必须对入口点做出假设)跟随所有可能的分支和线性执行将 16 位部分标记为指令的第一个或附加块,未标记的块不一定确定为指令与数据,必须小心。

是的,可以玩其他游戏来打败反汇编程序,故意分支到 thumb2 指令的后半部分,该指令是手工制作的有效 thumb 指令或 thumb2 的开头。

固定长度的指令集,如 arm 和 mips,你可以线性解码,一些数据解码为奇怪或未定义的指令,但你的反汇编程序不会偏离 rails 并且无法完成它的工作。可变长度指令集,反汇编充其量只是一个猜测......真正解码的唯一方法是以与处理器相同的方式执行指令。