用于分析二进制代码以检测 CPU 架构的工具或数据

逆向工程 二元分析
2021-06-14 01:50:06

假设我有一个带有未知 CPU 代码的二进制文件,我可以以某种方式检测 CPU 架构吗?我知道这主要取决于编译器,但我认为对于大多数 CPU 架构来说,它应该有很多 CALL/RETN/JMP/PUSH/POP 操作码(统计上比其他操作码多)。或者我应该在特定于 CPU 的代码中搜索一些模式(而不是操作码出现)?

4个回答

当你有锤子时,所有的问题看起来都像钉子……

前段时间我研究过一种叫做归一化压缩距离 - NCD 的东西,如果我遇到和你类似的问题,我会试一试。

  1. 我会制作一个示例数据库。对于您想了解的每个架构,需要 20 个程序,并保存它们。

  2. 当遇到一个我想知道它是哪种架构的程序时,我会根据我的所有示例计算它的 NCD。

  3. 我会选择最好的(较小的)NCD,然后验证它是否是真正的匹配(比如说,尝试在发现的架构上运行它)。

更新

当涉及到 NCD 时,我总是手工完成我是如何做到的:

  • 您有 20 个 SPARC 文件,您将它们命名为 A01、A02、A03 等。您的 x86 文件:B01、B02 等。

  • 您得到未知文件并将其命名为 XX。

  • 选择您喜欢的压缩工具(我使用 Gzip,但请参阅本答案末尾的备注)。

  • 计算第一对的 NCD:

NCD(XX,A01) = ( Z(XX+A01) - min(Z(XX), Z(A01) ) / max(Z(XX), Z(A01))

Z( something ) -> 表示你用 Gzip压缩某些东西并在压缩后获取文件大小。例如,8763 字节,所以 Z(something) = 8763。

XX + A01 -> 表示你连接事物。您将 A01 文件附加到 XX 文件的末尾。在 linux 中,您可以执行“cat XX A01 > XXA01”。

min() 和 max() -> 你计算 XX 和 A01 的压缩大小,并使用你得到的最小值和最大值。

因此,您将拥有一个 NCD 值:它将介于 0 和 1 之间,并使用尽可能多的小数位,因为有时差异在第 7 位或第 8 位。这就像将 0.999999887 与 0.999999524 进行比较。

您将对每个文件执行此操作,因此对于 SPARC,您将有 20 个 NCD 结果,对于 x86,您将有 20 个...

获得较小的 NCD。假设 B07 文件为您提供了较小的 NCD。因此,可能未知文件是 x86。

尖端:

  • 您的未知文件和您的测试文件必须具有相似的大小。当您将文件与更大或更小的文件进行比较时,NCD 不会发挥作用。所以,如果你要测试 5 到 10k 的文件,我会得到 2.5k、5k、7.5k、10k、12.5k 的测试文件......

  • 在我的硕士学位中,我总是使用较小的 NCD 值获得更好的结果。第二种最好的方法是进行一些投票:获得 5 个较小的 NCD 结果,然后看看哪个架构获得了更多的投票。例如:较小的 NCD 是 A03、A05、B02、B06、B07 -> B 投 3 票,所以我会说它是 x86...

  • 基于 Zip 结构的压缩器有 32kB 的限制:他们压缩事物的方式,他们当时只考虑 32kB。如果你的 XX + A01 比这个大,Gzip、Zip 等不会给你很好的结果。因此,对于大于 15 或 16kB 的文件,我会选择另一种压缩器:PPMD、Bzip ...

有一些工具可以扫描二进制文件以查找各种体系结构中的常见操作码。例如,Binwalk的 -A 选项就是这样做的(它扫描 ARM/MIPS/x86 和其他几种架构)。

通常,我首先尝试最常见的 CPU(ARM、PPC、MIPS 和 AVR),尝试查找是否有任何纯字符串说明了有关处理器等的信息……而且,当所有其他方法都失败时,我会尝试您要求的是:操作码的统计分析(如果我确定它既没有加密也没有压缩)。

我建议您阅读 Alexander Chernov 和 Katerina Troshina 的演讲“自定义虚拟机二进制程序的逆向工程”编写一个他们编写的工具一定非常困难(我猜)但是编写一个工具来尝试确定哪个 CPU 似乎是为使用该演示文稿中描述的技术而编译的并不那么难(只要您可以收集足够的多个不同架构的示例)。

我的懒人 hack:一个计算二元组和三元组计数的小型 Python 脚本。然后我在谷歌上搜索几个最常见的序列(引用十六进制)。我经常设法找到一些十六进制转储,并可以从上下文中计算出 CPU。如果 Google 可以按原始二进制值进行搜索,效果会更好……