Polypyus 通过学习从相似固件中提取已知函数,从而学会在原始二进制文件中定位函数。因此,它是一位固件史官。Polypyus 无需反汇编这些二进制文件即可工作,这对于难以反汇编且常用工具会遗漏函数的二进制文件来说是一个优势。此外,仅基于二进制的方法使其非常快速,只需几秒即可运行。然而,这种方法要求二进制文件具有相同的架构和相似的编译器选项。
Polypyus 可集成到现有工具(如 Ghidra、IDA、BinDiff 和 Diaphora)的工作流程中。例如,它可以导入之前注释过的函数并从中学到知识,还可以导出已找到的函数以便导入到 IDA 中。由于 Polypyus 使用相当严格的阈值,在我们的实验中它只找到了完全正确的匹配。虽然这导致结果数量少于现有工具,但它是一个很好的起点,可以将这些匹配加载到 IDA 中,以改进其自动分析结果,然后在此基础上运行 BinDiff。
在处理原始固件二进制文件时(特别是各种 Broadcom 和 Cypress 蓝牙固件版本),我们发现 IDA 的自动分析经常错误地识别函数起始位置。在 IDA Pro 6.8 中,自动分析略显激进,导致更多结果但也出现更多误报。总体而言,IDA Pro 7.2 更为保守,但错过了很多函数。这导致在我们的固件中,IDA Pro 6.8 只产生了很少的 BinDiff 匹配,而 IDA Pro 7.2 则根本没有有用匹配。
有趣的是,BinDiff 经常无法识别那些除了分支之外字节完全相同的函数。请注意,Polypyus 正是要寻找这些字节完全相同的函数。我们推测 BinDiff 在这些函数上失败,是因为由于缺失函数和误报而产生了不同的调用图。有时这些函数已经被 IDA 识别,但更多时候 IDA 要么没有将其识别为代码,要么没有标记为函数。注意,Diaphora 也有类似问题,因为它首先导出 IDA 识别出的函数,然后才进行后续处理。下图展示了在 CYW20735B1 蓝牙固件二进制文件上进行的基准测试,比较了各种反汇编器以及反汇编器的失败如何导致后续差异分析的问题。
此外,虽然我们发现 Amnesia 能发现许多函数,但它也发现了大量误报。然而,许多函数在开头都有相似的栈帧设置。因此,Polypyus 提供了一种选项,可以从已注释的输入二进制文件中学习常见的函数起始方式,并将其应用于其他二进制文件,以在不匹配函数名称的情况下识别函数。这个可选步骤仅应用于之前未找到函数的区域,这样常见函数起始方法与主函数查找方法就不会冲突。
由于这些匹配器基于原始二进制文件工作,因此不依赖于反汇编器。这也有一个重要缺点:如果使用了不同的编译器选项或不同的目标架构,Polypyus 将无法检测到相似函数。此外,虽然识别出的匹配非常可靠,但函数起始标识的可靠性稍低,因此请谨慎使用后者。下图中可以看到,Cypress 评估套件彼此之间非常相似,但 MacBook 固件则差异很大。
Polypyus 通过比较一批已注释固件二进制文件中的常见函数,创建模糊二进制匹配器。
目前支持以下注释格式:
patch.elf 文件,这是一种特殊的 ELF 文件,仅包含符号定义。.symdefs 文件,由大多数 ARM 编译器生成。.csv 文件,格式记录在 firmware 文件夹中。这些注释包含已知函数的地址、大小和名称。历史集合中输入的二进制文件共性越多,Polypyus 的性能和结果就越好。给定几个略有不同的函数,Polypyus 可以创建出非常好的匹配器。
Polypyus 需要 Python 3 >= 3.6。 建议使用 virtualenv 进行安装。克隆此仓库,然后在该文件夹中运行:
pip install .
安装后,可使用以下命令:
polypyus-guipolypyus-cliPolypyus 提供图形界面和命令行界面两种方式。
GUI(polypyus-gui)和 CLI(polypyus-cli)在调用时均可使用以下参数:
--verbose 设置详细级别。默认显示警告,-v 显示信息,-vv 显示调试信息。
--project 设置项目文件的路径。可以是文件路径或 ":memory:"。
--help 显示帮助信息。
项目选项使您可以针对不同上下文将工作存储在不同的文件中,并可重新打开它们。
一般的 GUI 工作流从左到右进行。首先,将二进制文件添加到历史中。然后,为历史中的条目添加符号注释。之后,可以添加目标二进制文件。对于匹配,点击 从历史创建匹配器。匹配器创建后,可以选择单个目标,也可以通过选择 批量匹配 来匹配所有目标。最后,可以将结果导出为 .csv 文件。
下面是一个演示视频,其中 Polypyus 仅需几秒就能从两个输入二进制文件学习、注释、创建匹配器,并将匹配应用到新二进制文件。
使用 CLI 的好处是可以实现自动化。目前,CLI 的输出格式可能会发生变化。以下是一个调用示例:
polypyus-cli --history firmware/history/20819-A1.bin --annotation firmware/history/20819-A1_patch.elf --history firmware/history/20735B1.bin --annotation firmware/history/20735B1_patch.elf --project test.sqlite
polypyus-cli --target firmware/history/20739B1.bin --project test.sqlite
第一个命令创建 test.sqlite 作为新的项目文件,并导入 20819-A1.bin 和 20735B1.bin 及其各自的 patch.elf 文件。第二个调用重用同一项目文件,并针对二进制文件 20739B1.bin 进行匹配。对于每个命令,--history 和 --annotation 的个数需要匹配。这两个命令也可以通过向第一个命令添加 --target 参数合并为一个。
一篇解释内部原理的论文发表于 2021年二进制分析研究研讨会 (BAR),标题为 Polypyus - The Firmware Historian。 更多细节也包含在 Jan 的硕士论文最终演示文稿 中,其中涵盖了在使用 ARM Thumb2 模式下的传统二进制差异分析时遇到的问题,以及替代的纯二进制方法的工作原理。
patch.elf 或 .symdefs 格式中泄露的符号仅包含函数和全局变量名称。但是,在 WICED Studio 6.2 和 6.4 中还有一些 .pdom Eclipse 项目文件。这些文件包含额外的类型信息。Eclipse 内部使用它们进行自动补全、函数搜索等,我们可以利用它们在逆向工程中添加类型信息。由于 .pdom 文件仅包含部分缓存信息,因此组合多个文件会很有帮助。
第一步,将 .pdom 类型信息导出到 SQLite 数据库。导出需要一些时间,但可以中止并在之后继续。导出方法如下:
java -jar pdom/export/export.jar -P BCM20739-B0.1462220149391.pdom
PDOM 导入会在 IDA 数据库中搜索函数名称,在 PDOM 中查找类型信息,然后将该类型信息应用到 IDA 数据库中。因此,IDA 数据库需要事先包含正确的函数名称。原则上,可以使用 Polypyus 的 import_export 脚本创建这些名称。然而,支持 PDOM 导入的更高级脚本也可以处理 patch.elf 段。按以下步骤运行导入器:
T=0x1 (Alt-g)。patch.elf 文件 (Select file)。20739mapb0.h 来命名硬件寄存器 (Import map.h)。该脚本已在 IDA Pro 7.4 和 7.5 上测试过。
经过一些内部测试,我们推荐以下使用 IDA Pro 和 Polypyus 的工作流程:
Alt-g, T=0x1)。0x0 开始,属性 rx;RAM 从 0x200000 开始,属性 rwx(至少对于蓝牙固件)。0x4 的 4 字节偏移 (o)。
在 CYW20735 固件上,它指向 0x3bc+1。返回一个字节,然后创建一个函数 (p)。...现在您的 IDA 数据库可能有些用处了 :) 尽管在 ARM Thumb2 中反汇编器仍有许多失败之处,但已经比 IDA 单独执行时好得多了。
firmware 文件夹包含各种带符号和不带符号的固件。
history 中的所有文件都包含符号,targets 中的所有文件都不包含符号。
对于三星系列,S8 还包括 Note 8 和 S8+ 等,S10/S20 也包括从 S10e 到 Note 20 5G 的所有型号。
Dump 质量可能有所不同,有些包含 RAM,有些只是 ROM。我们可以获取列表中大多数设备的 dump。如果您需要包含最新补丁级别且包括 RAM 的 dump,请随时联系我们。
论文中提到的一些设备未包含在此处,因为它们可能不是仅用于研究的设备等。还有几款 iPhone 和 MacBook 也未包含,因为我们是作为研究设备使用,但原始 dump 不是。这些设备将很快添加 :)
此仓库中有一个 .editorconfig 文件。它配置了缩进风格、字符集和行分隔符。贡献时请遵循此配置,使用 .editorconfig 的 IDE 插件可简化此操作。
要安装测试依赖,请执行:
pip install '.[test]'
这将安装仅用于执行测试用例所需的包。
开发依赖提供例如包类型的存根。要安装它们,请运行:
pip install '.[development]'
pytest 将运行所有测试。
项目使用 tox 在本地针对不同的 Python 版本运行测试。 Tox 配置为针对 3.6、3.7、3.8 和 3.9 版本进行测试。 要运行 tox,请安装测试依赖并安装上述四个 Python 版本。 我们推荐的安装和管理多个 Python 版本的方法是 pyenv。
步骤:
pyenv install 3.9.1
pyenv install 3.8.6
pyenv install 3.7.9
pyenv install 3.6.12
pyenv virtualenv 3.9.1 polypyus
penv local polypyus 3.8.6 3.7.9 3.6.12
pip install '.[test]'
pip install '.[development]'
toxPolypyus 使用 GitHub Actions 进行自动化测试运行和某些 lint 检查。您可以通过 pre-commit git 钩子在本地运行 lint 步骤。
每次创建新提交之前,这将触发 lint 检查并显示会阻止代码通过 GitHub Actions lint 步骤的问题。它还会使用 black 格式化更改的文件。
pip install '.[development]'
pre-commit install
感谢 Anna Stichling 创作了 Polypyus 标志。 感谢 Christian Blichmann 和 Joxean Koret 提供的反馈。
Polypyus 是开源的,遵循 GPLv3 许可。
| 芯片 | 设备 | 构建日期 | 符号 |
|---|
| BCM20703A2 | MacBook/iMac 2016-2017 | 2015年10月22日 | ✔ |
| CYW20719B1 | 评估板 | 2017年1月17日 | ✔ |
| CYW20735B1 | 评估板 | 2018年1月18日 | ✔ |
| CYW20819A1 | 评估板 | 2018年5月22日 | ✔ |
| 芯片 | 设备 | 构建日期 | 符号 |
|---|
| BCM2046A2 | iMac Late 2009 | 2007? | - |
| BCM2070B0 | MacBook 2011, Thinkpad T420 | 2008年7月9日 | - |
| BCM20702A1 | Asus USB Dongle | 2010年2月(?) | - |
| BCM4345B0 | iPhone 6 | 2013年7月15日 | - |
| BCM4335C0 | Google Nexus 5 | 2012年12月11日 | - |
| BCM4345B0 | Google Nexus 6P / Galaxy S6 | 2014年10月23日 | - |
| BCM43430A1 | Raspberry Pi 3 and Zero W | 2014年6月2日 | - |
| BCM4345C0 | Raspberry Pi 3+ and 4 | 2014年8月19日 | - |
| BCM4347B0 | Samsung Galaxy S8 series | 2016年6月3日 | - |
| BCM4375B1 | Samsung Galaxy S10/20 series | 2018年4月13日 | - |
| BCM4378B1 | iPhone 11/SE2 | 2018年10月25日 | 字符串 |