跳转至

固件分析

REA 接受 Binwalk 3.1.x 用于区域检查,接受 Unblob 26.6.x 用于显式提取。报告解析器已通过 Binwalk 3.1.0 和 Unblob 26.6.4 验证。同一系列的其它构建也会被接受,实际观察到的版本会被报告,并记录一条限制说明解析器未针对该构建验证。这一首个固件里程碑已在 Linux x64 上验证。无需设备、root 权限、挂载、仿真或执行所提取的程序。任意固件字节不能通过本机可执行文件准入;请单独选择返回的 ELF 以进行受支持的 Ghidra 分析。

在 Linux 上,Binwalk 和 Unblob 作为 REA 拥有的进程运行,并且要求 REA 的 PATH 中存在兼容 procps 的 ps;请参阅共享的 Linux 进程前提条件。

调用方提供的工具

使用绝对可执行路径提供现有工具,并将其限定在你的 shell 环境中:

export REA_BINWALK_COMMAND=/absolute/path/to/binwalk
export REA_UNBLOB_COMMAND=/absolute/path/to/unblob

REA 不会安装这些工具、它们的依赖项或系统软件包。执行请求时,它会检查工具的 --version 版本横幅。Binwalk 必须打印 binwalk <version>,而 Unblob 必须只打印版本号。检查和提取有各自独立的前提条件;两者互不依赖。二者都要求 util-linux 的 prlimit,通常位于 /usr/bin/prlimit;如有需要,可用 REA_FIRMWARE_PRLIMIT_COMMAND 覆盖其绝对路径。rea doctor 目前不检查固件就绪状态。引擎选择/版本检查在固件操作被请求时运行;常规 doctor 检查通过并不代表固件工具或外部提取器可用。

REA 对每条命令最多保留 8 MiB 的 stdout 与 stderr 合并输出。超出该诊断预算将停止分析,并给出明确的截断输出错误;子进程限制不会约束父进程侧的管道保留。已完成的命令会在记录诊断信息之前排空其输出流。失败的 worker 清理会保留该 worker 和工作区,以便在下一次请求之前或关闭时重试。

Unblob 需要所选格式的外部提取器位于其继承的 PATH 上:例如,ext2/ext3/ext4 需要 debugfs。其默认的 Landlock 沙箱和跳过规则保持启用。沙箱启动失败仍然是可处理的错误;REA 不会使用 --no-sandbox 重试。有效分析报告中报告的缺失提取器会内联保留部分结果和依赖名称。

上游来源作为可选的固定子模块原样保留:

git submodule update --init third_party/binwalk third_party/unblob

常规 REA 构建和 npm 包不包含也不构建这些源码或引擎二进制文件。请参阅上游来源。

Windows 子模块检出

在 Windows 上,Unblob 检出会以 error: invalid path 停止。tests/integration/ 下的一些上游测试夹具名称包含 NTFS 不允许的字符、尾部点或尾部空格;REA 不使用这些夹具。保留克隆,排除该目录,然后在 PowerShell 中从仓库根目录重试:

git -C third_party/unblob config core.protectNTFS false
git -C third_party/unblob sparse-checkout set --no-cone '/*' '!/tests/integration/'
git submodule update third_party/unblob

两种设置都是必需的。当 core.protectNTFS 启用时,Git for Windows 还会拒绝稀疏模式排除的索引路径;该模式将无效名称排除在工作树之外。该设置仅适用于 Unblob 子模块。在 Git Bash 中,请在 sparse-checkout 命令前加上 MSYS_NO_PATHCONV=1;否则 !/tests/integration/ 会被重写为 Windows 路径。

提取目标必须不存在,且其父目录必须已存在且可写。REA 在启动引擎之前检查该选择,并在发布期间仍然以独占方式获取该目标。无效的源和目标会指明对应的调用方参数;已获取工作区内部的失败会保留其自身原因。已发布文件的 relative_path 保留生产者的拼写以用于溯源;path 使用写入者实际的规范化文件名。如果提取出的文件名无法无损地表示为 UTF-8,发布将显式失败,并以十六进制显示其原始名称字节,而不是静默省略该条目。

CLI 与 MCP

rea inspect-firmware-regions /path/to/firmware.bin
rea extract-firmware /path/to/firmware.bin /path/to/new-output
rea extract-firmware /path/to/firmware.bin /path/to/selected-output \
  --offset 64 --length 4096 --max-depth 3

对应的 MCP 工具接受相同的意图:

{
  "name": "inspect_firmware_regions",
  "arguments": { "path": "/path/to/firmware.bin" }
}
{
  "name": "extract_firmware",
  "arguments": {
    "path": "/path/to/firmware.bin",
    "output_directory": "/path/to/new-output",
    "range": { "offset": 64, "length": 4096 },
    "max_depth": 3
  }
}

两者都返回 Evidence,包含原始路径和 SHA-256、生产者的原始报告、实际可执行文件路径/摘要、版本和限制。Binwalk 签名 UUID 和 Unblob blob ID 是生产者本地的标识;跨运行比较时应使用内容哈希和源范围。版本匹配并不能证明已安装构建的源码修订版本,因此该字段保持未知。

解读结果

  • 区域偏移量指向原始固件中的字节。reported_size 保留 Binwalk 的输出;size_basis=provider_reported_validation_unknown 反映了 Binwalk 在序列化之前可以用下一个签名或 EOF 替换未知长度。签名本身及其置信度字节都不能证明有效的分区、加密或运行时行为。
  • 提取返回常规文件路径、独立验证的 SHA-256 值、可用时的生产者哈希、块、诊断信息和任务派生关系。Unblob 的任务报告是无序的;REA 通过路径和 blob ID 解析关系。逻辑引用使用 $input、$output 或 $output/<relative-path>,因此名为 $input 的真实文件与原始输入保持区分。块偏移属于任务的输入文件。只有选定输入中的块才具有已知的 root_file_range,并根据所选偏移量进行调整。
  • 解压后的子项具有未知的原始字节范围和运行时地址。任务谱系不能建立通过解压的逐字节映射。
  • partial 标记未知/加密的块、所有已报告块区间之外的所选输入字节、已报告的提取问题、未发布的链接/特殊文件或达到深度限制的情况。complete 表示所选输入被已报告的块区间覆盖,且引擎在未出现上述报告条件的情况下完成了其配置的提取;默认跳过规则和格式覆盖仍然适用。它并不代表固件已完整重建。
  • extraction_gaps 使这些条件可恢复:一行标识一个未提取的区域或一个失败的任务/阶段。块保留其身份和字节范围,并且在属于所选输入时还保留其原始文件范围。unclassified-range 行标识没有已报告块的所选输入区间;其生产者身份和处理程序保持为 null。因此,空的块清单不能证明非空所选输入已被完整提取。多文件阶段保留其报告的身份和处理程序,但字节范围未知;独立任务失败时,不可用的阶段身份保持为 null。行保留生产者缺失依赖报告中确切的依赖名称;被接受但没有名称的报告仍然是失败,且依赖未知;不会推断任何可执行文件身份或具体安装步骤。每行的 continuation_id 引用 extraction_continuations 中的一条说明,因此多个区域可以共享恢复说明而不丢失任何区域身份。存在已配置能力时,说明会使用该能力。每次重新提取都需要一个全新的、不存在的 output_directory,从而保留先前的证据。Unblob 声明的 ERROR 严重级别构成提取失败,包括独立的 UnknownError 任务异常。警告和已解决的提取问题仍作为部分覆盖的诊断信息;它们不构成失败的提取器阶段。独立错误不会获得附近块的处理程序或字节范围。嵌套的未知块应针对实际发布的子项使用 inspect_firmware_regions,而不是以不变的处理程序重复相同的提取。检查需要单独配置 Binwalk(REA_BINWALK_COMMAND);没有它,检查步骤不可用,区域保持未检查状态。列出的缺口并不意味着目标已损坏,也不意味着保留的区域为空;REA 不会安装任何内容。
  • 目标必须不存在、必须是绝对路径,并且其父目录必须已存在。发布使用独占的、抗符号链接的写入和持久的摘要读回。现有目标绝不会被覆盖。这不是原子的目录重命名:文件写入期间新目录树可能可见。未提交的失败输出会被回滚。符号链接和特殊文件会被记录但不会发布;空目录、所有者和可执行权限位不会被重现。

为现有工具选择一个经过验证的原生子进程:

{
  "name": "open_binary",
  "arguments": {
    "path": "/path/from/extraction/usr/bin/program",
    "provider_id": "ghidra"
  }
}

然后使用 analyze_function、inspect_native_api 或其他原生原语。 原生架构与可执行文件验证仍然适用。通用 MIPS ELF 和 RISC-V ELF 通道是独立的文档,拥有各自的准入边界。 本里程碑不新增 PPC 反编译、原始闪存加载配置、引导加载程序/设备树语义、漏洞扫描、仿真或硬件运行时捕获。

资源与生命周期策略

  • 非空常规固件输入:最多 128 MiB,在分析前复制并哈希到私有工作区。复制期间超出该限额的增长将收到与已超限文件相同的类型化输入拒绝。请在限额内提供稳定副本。不进行原位源修改。
  • 每个提供商实例仅允许一个排队中的重型操作;Binwalk 使用单线程,Unblob 使用单工作进程。不提供自动并行提取引擎。
  • 分析默认时限为 120 秒,涵盖从工具解析与输入快照开始,到检查及最终私有工作区清理,或从提取到报告消费与清单盘点,不包括排队等待与保留清理准入。检查阶段没有发布阶段。若需更慢的分析,可在任一 MCP 操作中选择 analysis_timeout_ms,或在任一 CLI 命令中选择 --analysis-timeout-ms。当前结果保留实际预算;历史值缺失表示未知。提取发布及其最终清理启动独立的 120 秒 预算;若目标较慢,可在 MCP 中选择 publication_timeout_ms,或在 CLI 中选择 --publication-timeout-ms。有效预算为 1 到 2,147,483,647 毫秒(计时器表示上限)之间的整数。发布超时标识其所处阶段与已验证文件进度;原子提交前的已验证写入并不代表回滚后输出仍保持发布状态。调用方取消同时适用于两个阶段及最终清理。阶段交接、发布提交与最终完成也会检查单调流逝时间,因此延迟的计时器回调无法复活已过期的预算。
  • 分析超时恢复会指明所选的预算与分析控制项,而非后续的发布控制项。客户端调用超时需高于分析、发布与清理的余量;输入/范围/问题保持不变。重试前需解决任何已报告的不完整清理。提高墙钟时间并不会提高固定的 CPU、内存、报告、诊断或输入限制。
  • 通过 prlimit 继承 每进程 1 GiB 地址空间 限制、120 CPU 秒以及零核心转储配额。
  • JSON 报告:最多 8 MiB 且为有效 UTF-8;编码格式错误或超限的报告将失败,且不会修复或截断生产方数据。退出状态 0 并不表示结果为空:缺失、为空、格式错误或超限的报告会以 unreadable_output、其 report_state、命令、退出状态及捕获输出失败。REA 不会自动重试。诊断输出有界,并带有精确的捕获字节计数。
  • 默认暂存预算:256 MiB 与 10,000 项,可通过 max_output_bytes / max_output_files(CLI --max-output-bytes / --max-output-files)配置。超出任一所选暂存预算将返回一个不可重试的资源约束,并指明所选的限制。深度默认为 3,允许范围为 1–10。

暂存预算会在退出后轮询并重新检查;短暂的超限是可能的。每文件进程限制取所选负载预算与固定报告/诊断文件配额中的较大者,因此较小的负载选择仍允许生成强制报告。更严格的继承宿主限制仍然适用。继承的文件大小限制约束的是每个文件,而非总存储;地址空间限制按进程计,而非聚合内存配额。工作进程数量并非针对每个外部提取器的 CPU 亲和性。这些限制并不声称提供 cgroup/容器隔离。取消操作会在移除工作区之前清理所属进程组;不确定的清理会保留资源,并阻止该提供商实例中的后续操作。

验证

生成小型公开的、源自源码的测试夹具到被忽略的 _reference/ 目录:

npm run fixtures:firmware
npm run verify:firmware

夹具生成需要已有的 Python 3 和宿主 C 编译器(cc);可通过 REA_FIRMWARE_PYTHON / REA_FIRMWARE_CC 覆盖。独立预言机记录 gzip 偏移/长度以及提取出的文件哈希。真实验证检查 CLI/MCP、全文件与选定范围提取、未知块、深度限制、内容一致性以及源字节未变更。不提交任何二进制夹具。

可选的缺失提取器通道会在 extraction_gaps 中断言依赖名称与所属处理程序。这些断言必须针对固定的 Unblob 版本运行,以建立真实提供商的覆盖;仅凭合成生产方夹具无法验证 Unblob 的报告嵌套或阶段标识。在该通道运行之前,缺口归属声明仍未针对真实 Unblob 得到验证。

附加通道是显式启用的,因此基础通道保持精简:

# Existing mke2fs and debugfs required; put debugfs on the scoped PATH.
REA_FIRMWARE_VERIFY_EXT4=1 npm run fixtures:firmware
REA_FIRMWARE_VERIFY_EXT4=1 npm run verify:firmware

# Existing Ghidra 12.1.x and its declared JDK required.
REA_FIRMWARE_VERIFY_GHIDRA=1 npm run verify:firmware

REA_FIRMWARE_MKE2FS_COMMAND 选择可选的 ext4 夹具生成器。REA_FIRMWARE_FIXTURE_ROOT 选择生成数据的存储位置。REA_FIRMWARE_TEST_ENTRYPOINT 可以选择隔离安装的 npm 包中的 scripts/rea.mjs,以验证打包后的 CLI/MCP 工作流。此处的真实覆盖为使用 Linux x64 ELF 子文件生成的 gzip/USTAR/ext4;SquashFS、UBIFS、专有固件、其他宿主与架构仍未得到验证。

检查提取的设备树

对提取的 DTB 使用 inspect_devicetree / rea inspect-devicetree,以获取其节点/属性树、保留项、硬件摘要以及选定的 phandle 关系。FDT v16/v17 检查是可移植的,无需外部工具或反汇编器。

本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 rea2/rea