一个用于执行、逆向工程和逐步重写无源码实模式 DOS 程序的 .NET 跨平台 PC 模拟器,支持 Ghidra 联动与 GDB 动态调试。
Stars: 617 | Forks: 37
# Spice86 - 用于实模式逆向工程的 PC 模拟器



[](https://github.com/OpenRakis/Spice86/actions/workflows/prerelease.yml)
[](https://www.nuget.org/packages/Spice86)

[](https://www.nuget.org/packages/Spice86)
Spice86 是一个用于执行、逆向工程和重写无源代码实模式 DOS 程序的工具。
发布版本可在 [Nuget](https://www.nuget.org/packages/Spice86/) 上获取。
预发布版本也可在 [发布页面](https://github.com/OpenRakis/Spice86/releases/tag/latest) 获取
注意:这是[原始 Java Spice86](https://github.com/kevinferrare/spice86) 的移植和延续版本。
它需要 [.NET 10](https://dotnet.microsoft.com/en-us/download/dotnet/10.0) 并可在 Windows、macOS 和 Linux 上运行。
## 方法
仅从二进制文件重写程序是一项艰巨的任务。
Spice86 是一个通过系统化的分而治之方法来帮助您完成此任务的工具。
一般流程:
- 您首先在 Spice86 模拟器中模拟程序。
- 每次运行结束时,模拟器会转储一些运行时数据(内存转储和执行流)
- 您可以通过 [spice86-ghidra-plugin](https://github.com/OpenRakis/spice86-ghidra-plugin) 将这些数据加载到 [ghidra](https://github.com/NationalSecurityAgency/ghidra) 中
- 该插件将内存转储中的汇编指令转换为 C#,这些 C# 代码可以加载到 spice86 中,并部分或完全替代汇编代码。
- 这允许您逐步用 C# 方法重新实现汇编代码
- 这很有帮助,因为:
- 小段的汇编代码可以进行静态分析,通常很容易翻译成高级语言。
- 您始终使用程序的完整工作版本,因此相对容易及早发现错误。
- 逐个函数地重写代码使您能够发现作者的意图。
## 运行您的 exe
| 命令 | 描述 |
|---------|-------------|
| `Spice86 -e file.exe` | 运行指定的可执行文件 |
| `Spice86 -e file.com` | 运行 COM 文件 |
| `Spice86 -e file.bin` | 运行 BIOS 文件 |
## 转储数据
| 设置 | 描述 |
|---------|-------------|
| 环境变量 | `SPICE86_DUMPS_FOLDER` - 设置此项以控制数据转储的基本目录 |
| 命令行 | 使用 `--RecordedDataDirectory` 指定基本转储位置 |
| 默认位置 | 如果未指定上述任何一项,则为当前目录 |
**注意:** 无论基本目录设置如何,转储始终放置在以程序 SHA-256 哈希命名的子目录中。这确保同一游戏的多个可执行文件(例如 SETUP.EXE、GAME.EXE)拥有独立的转储文件夹。
模拟器转储以下文件:
- **spice86dumpMemoryDump.bin**:实模式地址空间的快照
- **spice86dumpExecutionFlow.json**:包含函数地址、标签和已执行的指令
当指定位置已有数据时,模拟器将首先加载并补充它。
### CPU 高负载日志
为了进行详细调试,您可以启用 CPU 高负载日志,该功能会将每条执行的指令记录到文件中。
**⚠️ 警告:** 此功能会显著影响性能,仅应用于调试目的。
| 设置 | 描述 |
|---------|-------------|
| `--CpuHeavyLog` | 启用 CPU 高负载日志(默认值:false) |
| `--CpuHeavyLogDumpFile` | 日志文件的自定义路径(可选)。如果设置,也会启用 CpuHeavyLog。默认位置:`{DumpDirectory}/cpu_heavy.log` |
**日志格式:** 每行包含:`SegmentedAddress InstructionString`
**示例:**
```
017D:0000 mov AX,0xDD1D
017D:0003 call near 0xE4AD
017D:E4AD mov SI,0x0080
```
**用法:**
```
# 使用默认位置启用
Spice86 -e program.exe --CpuHeavyLog
# 使用自定义 log file 路径
Spice86 -e program.exe --CpuHeavyLog --CpuHeavyLogDumpFile "C:\logs\cpu.log"
```
## 命令行选项
```
--Debug (Default: false) Starts the program paused and pauses once again when stopping.
--Cycles (Default: null) Target CPU cycles per ms, for the rare speed sensitive game. 3000 by default. Overrides Instructions per second option below if used.
--Xms (Default: true) Enables 15 MB of XMS memory.
--Ems (Default: true) Enables EMS memory. EMS adds 8 MB of memory accessible to DOS programs through the EMM Page Frame.
--A20Gate (Default: false) Disables the 20th address line to support programs relying on the rollover of memory addresses above the HMA (slightly above 1 MB).
-m, --Mt32RomsPath Zip file or directory containing the MT-32 ROM files
-c, --CDrive Path to C drive, default is exe parent
-r, --RecordedDataDirectory Directory to dump data to when not specified otherwise. If blank dumps to SPICE86_DUMPS_FOLDER, and if not defined dumps to a sub directory named with the program SHA 256 signature
-e, --Exe Required. Path to executable
-a, --ExeArgs List of parameters to give to the emulated program
-x, --ExpectedChecksum Hexadecimal string representing the expected SHA256 checksum of the emulated program
-f, --FailOnUnhandledPort (Default: false) If true, will fail when encountering an unhandled IO port. Useful to check for unimplemented hardware. false by default.
-g, --GdbPort GDB port. If 0, GDB server will be disabled. Default is 10000.
-o, --OverrideSupplierClassName Name of a class that will generate the initial function information. See documentation for more information.
-p, --ProgramEntryPointSegment (Default: 4096) Segment where to load the program. DOS PSP and MCB will be created before it.
-u, --UseCodeOverride (Default: true) if false it will use the names provided by overrideSupplierClassName but not the code
-i, --InstructionsPerSecond if blank will use time based timer.
-t, --TimeMultiplier (Default: 1)