有没有一种方法可以“猜测”裸机固件二进制文件中未知区域的地址?

逆向工程 拆卸 固件
2021-06-25 00:43:03

想象一下:

你有一个 ARM 固件的二进制文件。您几乎 100% 是 ARM,并且它在裸机上运行。您从制造商更新页面获得了此固件。

但是,您不确定二进制文件适用的确切芯片型号。您无法找到该芯片的开发人员指南或规格表。

该二进制文件没有已知的标头,研究表明它没有被压缩或加密。二进制文件底部的大部分字符串表明它是一个单一的平面二进制文件,而不是几个压缩在一起的记录。没有文件系统的迹象。

您应该能够合理地反汇编代码,但缺少一些因素来阻止您检索控制流并创建合理的反汇编。

1) 你不知道初始入口点在哪里。2) 您不知道是否有 ram 部分,以及它可能开始和结束的地址。3) 您不知道是否有 rom 部分,以及它可能开始和结束的地址。

鉴于这些或类似的情况,逆向工程师如何推断初始入口点以及 ROM 等区域的位置/大小?

我想从某种内存映射芯片中检测读取和写入可以从有效的反汇编中推断出来,只需突出显示经常引用的公共内存区域,并将它们分类为部分。我希望有人为这种分析提出了一种自动化的方法。

例如

“范围0x7-0x9经常被引用。它可能是ROM。最高地址是0x7998,该区域似乎占用了8 Mbs。”

到目前为止,确定入口点的另一个区域让我感到难堪。如果没有芯片的文档,是否可以推断出代码的初始入口点?这在引导加载程序似乎存储在与主固件分开的 ROM 中的芯片上尤其令人沮丧。

如果没有开发人员文档,是否可以暗示这种固件映像的结构?

2个回答

我通常做什么:

  • 以不太小的基地址加载二进制文件,例如0x10000000.
  • 标识尽可能多的函数和字符串。
    • 您可能会很幸运,只从字符串开始,这通常会减少工作量。
  • 创建所有常量值、立即数和双字(假设为 32 位二进制)值的列表。
  • 现在对函数和字符串地址列表进行排序,并计算每个连续地址之间的差异。
  • 对常量值列表执行相同的操作。

现在您有两个地址差异列表,如果您在两个列表中找到一系列连续差异,您就找到了基地址。

这在大多数情况下都有效,但您可能会遇到两个列表可能都不完整的问题。例如地址列表不会有每个函数的绝对指针,或者你可能错误地反汇编了一些函数。也许专注于字符串地址会有更好的运气。

我通常vim使用正则表达式搜索手动执行此列表匹配在某些情况下,我编写了一些小脚本来帮助查找匹配项。...但我现在找不到那些,如果我再次找到它们,我会更新我的帖子。


聊天总结

正在讨论的固件文件:来自dvdo 的DVDO Matrix6 Firmware 01.01

我查看了来自同一站点的其他二进制文件,并找到了对LPC1758- 基于 ARM 的芯片的引用

事实上,IDA 不会立即识别二进制文件。原因是这个二进制文件只有 Thumb 指令。IDA 期望 arm 二进制文件以 ARM32 代码开头。Thumb 代码可以从十六进制转储中通过字节序列70 47(BX LR)、00 bf(NOP)、*0 b5(PUSH {...}

因此,在将段类型更改T1using 之后Alt-G我可以反汇编文件。

查找偏移量:

这两个命令将生成文件中出现的双字列表和文件中出现的字符串列表:

od -Ax -t x4 Matrix6_Version_01/M6FW0101.BIN | perl -pe 's/^\w+\s+//' | tr " " "\n" | sort|uniq  > dwordlist.txt
strings -10 -o -t x "Matrix6_Version_01/M6FW0101.BIN" > stringlist.txt

现在查看字符串列表中的第一个真实文本:

28eaa pGSAC Initiation task finished
28eca SAC Audio Format Discovery task finished
28ef4 SAC volume has changed
28f0c Audio System Logical Address not assigned
28f37 CBUS MUTE received
28f4b CBUS UN-MUTE received
28f62 CBUS VOL UP received
28f78 CBUS VOL DOWN received

您可能会注意到第一个字符串的前 2 个字符pG实际上是一个70 47orBX LR指令。

现在我将加载两个文件Vim,并在两者中运行这个 vim-perl 脚本:

:perldo s/^\w+/($x,$p)=(hex($&),$x); sprintf("%s(%8x)", $&, $x-$p)/e

这将导致字符串列表部分如下所示:

28eaa(    25dd) pGSAC Initiation task finished
28eca(      20) SAC Audio Format Discovery task finished
28ef4(      2a) SAC volume has changed
28f0c(      18) Audio System Logical Address not assigned
28f37(      2b) CBUS MUTE received
28f4b(      14) CBUS UN-MUTE received
28f62(      17) CBUS VOL UP received
28f78(      16) CBUS VOL DOWN received

现在,跳过前两个,因为不正确的pG开始,我使用这个正则表达式搜索dwordlist.txt,分别搜索连续的2a182b 行

/ 2a)\n.* 18)\n.* 2b)

这导致我在两个文件中匹配以下行:

0002ebc3(      80)
0002eeac(     2e9)       28eaa(    25dd) pGSAC Initiation task finished
0002eeca(      1e)       28eca(      20) SAC Audio Format Discovery task finished
0002eef4(      2a)       28ef4(      2a) SAC volume has changed
0002ef0c(      18)       28f0c(      18) Audio System Logical Address not assigned
0002ef37(      2b)       28f37(      2b) CBUS MUTE received
0002ef4b(      14)       28f4b(      14) CBUS UN-MUTE received
0002ef62(      17)       28f62(      17) CBUS VOL UP received
0002ef78(      16)       28f78(      16) CBUS VOL DOWN received
0002ef8c(      14)

从 0x2eeac 中减去 0x28eaa 导致偏移量为0x6000.

我在我的Recon 2010 演示文稿中介绍了其中的一些内容(从第 48 页开始)。

总结这些方法:

  • 自重定位代码将自身复制到预期位置

  • 包含对预期运行时地址的引用的初始化代码

  • 具有绝对地址的跳转表

  • 字符串表(地址表)与二进制文件中的实际字符串匹配。

  • 符号表(如果幸运的话)