使用 Ghidra 分析 DOS MZ 与 COM¶
REA 可通过自带 Ghidra 适配器分析 DOS MZ 可执行文件和显式选择的 COM 映像。 Linux x64 与 macOS arm64 验证通道会通过 CLI 和 stdio MCP 执行实际的 16 位反汇编与反编译。Provider 准入接受 Ghidra 12.1.x 及该安装所声明的 JDK 范围。验证通道使用 Ghidra 12.1.4 和 JDK 21;无需 DOS 模拟器或交叉编译器。
打开并检查¶
rea inspect /absolute/path/to/legacy.exe --provider ghidra --json
rea search /absolute/path/to/legacy.exe entry --kind procedures --provider ghidra --json
rea instructions /absolute/path/to/legacy.exe entry --provider ghidra --json
rea function /absolute/path/to/legacy.exe entry --provider ghidra --json
rea inspect-native-load-image /absolute/path/to/legacy.exe --provider ghidra --json
rea read-bytes /absolute/path/to/legacy.exe 0x10000 --length 16 --provider ghidra --json
rea address-to-file-offset /absolute/path/to/legacy.exe 0x10000 --provider ghidra --json
当目标未将其入口函数命名为 entry 时,请使用发现过程中观察到的过程名或地址。MCP 使用 open_binary、list_procedures、procedure_info、read_function_instructions 和 analyze_function,并采用相同的准入目标与 provider 语义。
DOS MZ 解析器会使用可用的结构字节和实际文件长度来校验页计数、初始化模块长度、头部与重定位表边界、重定位目标以及初始化入口点。它将这些 DOS 事实与 Windows 头证据分开报告。已识别的 PE 签名仍保持为 PE;已识别的 NE、LE 和 LX 头被明确标记为不受支持。即使 DOS 结构校验通过,非零的 Windows 头指针若无已识别签名,通常仍是未解析候选;自动目标选择会失败关闭(fail closed)并同时报告这两种观察结果。当非空重定位表在完整 DOS 头内部结束时,剩余的头字节属于 DOS 填充;该处的非零 dword 不是 Windows 声明。在应用该填充规则之前,会请求读取当前探针之外尚未读取的签名。这样既避免从原始 DOS 填充中制造出 Windows 头,同时保留了对损坏 Windows 声明的拒绝。
Inventory 分类是一个有界前缀格式提示;对于未解析候选,或当其前缀无法确定格式时,返回 unknown。该结果不同于完整的 DOS 校验,也不决定目标准入。
Ghidra 使用 MzLoader、语言 x86:LE:16:Real Mode 和编译器规范 default 导入私有目标快照。这些设置、固定的 Ghidra 加载段 0x1000 以及线性地址约定都已提交到分析配置文件中。握手过程会拒绝语言或编译器偏差。关闭会话会删除临时项目和快照。
该配置文件还提交了 function_body_evidence: complete-inclusive-ranges-v1,因此来自旧版仅长度 Ghidra 结果的快照不满足当前配置文件。
无头 COM 映像¶
COM 没有标识头。请显式选择其解释方式;.com 后缀或任意无法识别的字节都不足以使其获得准入。
rea inspect /absolute/path/to/legacy.com --target-format dos-com --provider ghidra --json
rea function /absolute/path/to/legacy.com 0x10100 --target-format dos-com --provider ghidra --json
rea inspect-native-load-image /absolute/path/to/legacy.com --target-format dos-com --provider ghidra --json
{
"name": "open_binary",
"arguments": {
"path": "/absolute/path/to/legacy.com",
"format": "dos-com",
"provider_id": "ghidra"
}
}
调用者的解释适用于整个文件,即使其文件名暗示另一种格式。文件必须包含 1..65280 字节:即 64 KiB COM 段减去 256 字节 PSP 前缀。Ghidra 使用 BinaryLoader 和实模式语言,并将文件偏移零映射到 1000:0100(线性地址 0x10100)。打包的预分析脚本会植入入口函数以及 CS/DS/ES/SS 上下文 0x1000。这些设置和准备策略已提交到分析配置文件中;准备失败会阻止常驻 bridge 提供结果。
加载映像验证会检查所有原始和修改后的文件字节、完整的源映射/内存摘要、不存在重定位、入口以及测得的寄存器上下文。该上下文是为分析而施加的,并非从执行中观察得到。PSP 内存、初始栈内容/SP、DOS 中断和 PC-98 设备均未建模。COM 没有 MZ 头、重定位表或附加覆盖模型;所有选中的字节都属于其分析模块。原始文件保持不变。
地址与函数范围¶
返回的默认空间地址是线性字节坐标。Ghidra 的 segment:offset 地址的线性值为 segment * 16 + offset;多个段别名可以标识同一字节。REA 接受返回的线性地址用于后续查找,并将指令解码上下文保留在 Ghidra 中。这些坐标是分析加载地址,而非文件偏移或对运行中 DOS 系统的观察。
在读取或标注函数之前,那些会被 Ghidra 截断为不同地址的偏移将被拒绝。这也适用于显式或编码的地址空间名称;前导零保留数值偏移。
procedure_info 和函数档案包含 body 证据:
{
"available": true,
"provenance": "ghidra-function-body-address-set",
"ranges": [
{ "start": "0x10000", "end": "0x1000d" },
{ "start": "0x10060", "end": "0x10065" }
],
"total_bytes": 20,
"span_bytes": 102,
"non_contiguous": true,
"contains_entry": true
}
每个 end 都是包含式的。total_bytes 统计完整观察到的 AddressSet;span_bytes 测量其包围范围,跨地址空间时为 null。间隙和共享尾部不得被视为自有字节。这是 Ghidra 数据库的观察结果,并非原始源码所有权的证明,也不代表穷尽式代码发现。未报告完整范围的 provider 会返回 available: false 并附有明确原因。
已加载镜像的证据¶
inspect_native_load_image 独立地将不可变的会话快照与已加载的 Ghidra Program 进行核对。它测量完整的原始和修改后的 FileBytes 摘要、每个源映射及其内存摘要、重定位记录(包括多重性)以及外部入口点。它验证 MZ 头与模块分区、重定位修正和线性坐标,而不是仅依赖导入的可执行文件 SHA。
预期的 DOS 重定位记录保留每个修正项应用前的字节和已应用的值。它们的内存字节窗口来自最终重定位后的镜像,包括后续重叠修正项所做的更改。
结果为 verified、mismatch 或 unsupported。每项检查都保留其预期值和观测值。内存摘要不匹配会标识源范围的文件偏移和分析地址;它不会定位该范围内第一个不同的字节。映射端点是包含式的,不同于 list_segments 的排除式端点。追加的 overlay 保留在源文件标识中,并被排除在已初始化模块覆盖范围之外。未初始化的分配会被报告;其内容及 DOS 运行时语义不被验证。独立验证也涵盖显式的 raw-binary 导入;其他格式返回带实测观测值的 unsupported。
MZ 验证保留由头部页计数所描述的已初始化镜像,并将追加的 overlay 字节流式纳入完整的原始和修改后的源摘要。overlay 大小不会增加保留的镜像分配。
read_bytes 返回已初始化的 provider 内存,包括加载器修正;未映射或未初始化的字节会以显式返回长度和 complete: false 结束读取。address_to_file_offset 使用 provider 的源映射;未映射、未初始化及有歧义的映射会显式失败。即使源偏移已知,重定位后的字也可能与原始文件字不同。
覆盖边界¶
静态反编译不执行目标,也不模拟 BIOS、DOS 中断、设备端口或自修改代码。PC-98 硬件行为和恢复出的调用约定可能仍然不确定;provider 伪代码和诊断信息会保留以供分析师审查。
对于加壳的可执行文件,导入原始文件即可分析其解包存根。要检查原始程序恢复出的代码,请分析单独准备的脱壳副本。保留两个工件摘要和转换证据;REA 绝不会静默替换已接纳的目标。追加的 overlay 与已初始化的 MZ 模块是分开的。无头 COM 需要显式 COM 解释;REA 不会根据文件名或无法识别的字节进行猜测。未含已接纳 MZ 实模式入口的 DOS 扩展器仍处在此导入边界之外。
DOS MZ 可通过 Ghidra 获得,且不宣称支持 Hopper。它位于 Windows 原生 PE P0 边界之外。macOS x64 上的 DOS 验证仍未经验证。
真实验证¶
该验证通道会在运行时从源代码生成一个小型公共 fixture。它验证 16 位指令字节、近调用、段重定位远调用、实际反编译、不相交的函数范围、稳定的 CLI/MCP 观测值、未改变的输入字节,以及会话/进程清理。它不需要外部可执行 fixture、模拟器或现有分析数据库。
Provider 的 p-code 表示可能包含进程特定的地址空间选择器令牌。该验证通道保留这些报告值,并比较稳定的 dossier 观测值,而不是断言原始 p-code 的跨进程同一性。
函数注解¶
annotate_native_function 会在一个确切的本地函数入口处更改名称和/或注释,验证回读,并返回刷新后的 dossier。这在记录恢复出的 DOS 函数角色时很有用;它并不声称这些名称来自原始源代码。名称写入会保留现有命名空间;回读返回函数清单所使用的完全限定名称。普通注释映射到 Ghidra PRE 注释,行内注释映射到 EOL 注释。空文本清除注释;省略字段则保留注释。如果 setter、回读或分析失败,整个编辑会回滚。
{
"procedure": "0x10100",
"name": "entry",
"comment": "Recovered startup role",
"inline_comment": "Inspect segment setup"
}
rea annotate-native-function /local/program.com 0x10100 --target-format dos-com --provider ghidra --name entry --comment 'Recovered startup role' --json
CLI 在关闭其隔离会话之前返回更新后的分析。在 close_binary 之前,MCP 编辑对后续读取保持可见。原始字节保持不变,数据库编辑在关闭时被丢弃,不可变分析快照在编辑后失效。此操作不会保存 Ghidra 项目、更改 ABI/类型/函数体范围、修补指令,或模拟 DOS 运行时。Windows P0 不接纳此操作。
本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 rea2/rea