解密工具的可靠性从何而来?RPGMakerDecrypter基于NUnit的加密存档测试实践
【免费下载链接】RPGMakerDecrypterTool for decrypting and extracting RPG Maker XP, VX and VX Ace encrypted archives and MV and MZ encrypted files.项目地址: https://gitcode.com/gh_mirrors/rp/RPGMakerDecrypter
做解密工具最怕什么?没有文档、没有官方规范,解析错了可能到最后一刻才暴露。RPGMakerDecrypter 是一款开源的 RPG Maker 解密工具,负责解开 RPG Maker XP、VX、VX Ace 加密的 RGSSAD 存档以及 MV/MZ 加密文件。它的可靠性,正是来自一套基于 NUnit 的加密存档测试实践:用真实的加密存档做"黄金样本",把文件数量、文件名、偏移量、大小、解密密钥五个维度逐项验证。
上图:解密工具 GUI 打开Game.rgssad后,16 个 Data 文件全部正确列出——测试断言的正是这份"正确清单"。
解密工具为什么需要专门的测试?
解密工具处理的是无文档的二进制格式,它的正确性无法靠"看起来对"来判断:
- 文件名是异或加密的,偏移量算错 1 字节,整个文件就会错位;
- 密钥滚动算法(v1 版是
key*7+3,v3 版是key*9+3)任何一步写错,解出的就是乱码; - 存档损坏时,工具必须优雅地抛出异常,而不是崩溃。
这些细节靠肉眼检查输出文件几乎不可能发现。RPGMakerDecrypter 的解法很朴素:拿三份真实的加密存档,把"应该读出的元数据"硬编码为断言,任何回归一跑测试就会红。
测试工程一览:依赖与结构
测试集中在独立的 RPGMakerDecrypter.Tests 项目中,只引用一个核心模块 RPGMakerDecrypter.Decrypter,边界清晰。
NUnit 相关依赖声明在 RPGMakerDecrypter.Tests.csproj 中:
| 包 | 版本 | 作用 |
|---|---|---|
| NUnit | 3.13.3 | 测试框架核心,[Test]与Assert.That |
| NUnit3TestAdapter | 4.2.1 | 让 VS /dotnet test发现并执行 NUnit 用例 |
| NUnit.Analyzers | 3.3.0 | 编码时的静态分析提示,防误用 API |
| Microsoft.NET.Test.Sdk | 17.1.0 | .NET 测试宿主与发现基础设施 |
| coverlet.collector | 3.1.2 | 代码覆盖率采集 |
三个测试类各司其职:
- RGSSADv1Tests.cs:覆盖 XP(
Game.rgssad)与 VX(Game.rgss2a)的 v1 格式; - RGSSADv3Tests.cs:覆盖 VX Ace(
Game.rgss3a)的 v3 格式; - BinaryUtilsTests.cs:覆盖文件头识别与版本号判定。
黄金样本:三份真实加密存档
测试的数据基础是 EncryptedArchives/ 目录下的三份真实游戏加密存档:
| 存档 | 对应引擎 | 格式版本 |
|---|---|---|
| Game.rgssad | RPG Maker XP | RGSSAD v1 |
| Game.rgss2a | RPG Maker VX | RGSSAD v1 |
| Game.rgss3a | RPG Maker VX Ace | RGSSAD v3 |
csproj 中用CopyToOutputDirectory=PreserveNewest保证每次构建后样本都被拷贝到输出目录,测试永远不会"找不到文件"。文件名与版本的对应关系统一收口在 Constants.cs 中,避免魔法字符串散落各处。
五维断言:把"读对了"变成可执行的检查
打开 RGSSADv1Tests.cs 可以看到,每个存档都从五个维度验证解析结果,以 XP 存档为例:
- 文件数量:
ArchivedFiles.Count必须等于 16; - 文件名:前三个必须是
Data\Actors.rxdata、Data\Animations.rxdata、Data\Armors.rxdata; - 偏移量:分别等于 34、11045、147314;
- 文件大小:分别等于 10981、136243、4285 字节;
- 解密密钥:分别为
0x7B7448AE、0x366D564E、0x222699FE。
为什么五个维度缺一不可?以 RGSSADv1 的解析流程为例:读文件名长度 → 读文件名 → 读大小 → 记录当前位置作为偏移 → 记录当前密钥 → 跳到下一个文件。任何一步的字节序、密钥滚动(key*7+3)或跳过逻辑出错,都会让某一个维度先变脸——偏移错一个字节,尺寸必然跟着错。五维交叉验证,等于给整个状态机上了五道锁。
v3 格式(RGSSADv3)的测试结构完全一致,只是期望值不同:VX Ace 存档前 4 字节直接藏着初始密钥(0x00000029),密钥按key*9+3滚动,这些差异都由断言值天然覆盖。
期望值从哪来?交叉验证的"锚点"
测试代码中反复出现这行注释:
// Verified with Falos RPG Maker Decrypter期望值不是凭空捏造的,而是先用另一款成熟工具(Falos RPG Maker Decrypter)解密同一份存档,把它产出的文件名、偏移、大小、密钥作为"标准答案"回填进断言。这种跨工具交叉验证是逆向工程领域建立信任的经典做法:两份独立实现读同一二进制,结论一致,才有资格当回归测试的基准。
而 BinaryUtilsTests.cs 则守护着最外层的第一道门:三个存档的文件头都必须是RGSSAD(由 BinaryUtils.ReadCString 读取),版本字节 XP/VX 为 1、VX Ace 为 3。这正好对应 RGSSAD.GetVersion 的判定逻辑——头不对就抛InvalidArchiveException,版本不在 {1, 3} 内就返回 -1,防止拿Game.rgssad当 v3 硬解。
测试隔离:临时目录的"用完即焚"
解密过程要 seek 文件流,若直接操作原始样本,中途失败可能留下脏状态。FileHelpers.cs 提供了极简的隔离方案:
CopyArchives():清掉Temp目录,把三份存档复制进来,每个测试都在纯净副本上运行;Cleanup():测完删除副本、移除目录,保证测试之间零干扰、仓库零污染。
每个测试方法都是同一个三段式:CopyArchives() → 断言 → Cleanup()。没有复杂的 fixture,新手打开任何一个[Test]方法都能 30 秒读懂全貌——这本身就是可维护性的胜利。
如何运行这套测试
整个仓库基于 .NET 6.0 SDK 构建,运行测试只需两步:
- 安装 .NET 6.0 SDK;
- 在仓库根目录执行:
dotnet testdotnet test会自动发现 NUnit3TestAdapter 中的所有用例。看到全绿,意味着三个版本的格式解析、文件头识别、密钥推导都与黄金样本完全一致。
小结:解密工具可靠性的三个支点
回看开篇的问题——可靠性从何而来?RPGMakerDecrypter 给出了一个可以复制的答案:
- 🎯黄金样本真实:用真机产出的加密存档做基准,而非自己造的数据;
- 🧭断言多维交叉:数量、名字、偏移、大小、密钥五个维度互相咬合,错误无处遁形;
- 🔁跨工具锚定 + 隔离执行:期望值来自独立实现的交叉验证,测试环境用完即焚。
对任何做二进制格式解析、逆向解密的朋友来说,这套实践的成本极低:三份样本文件 + 一个 NUnit 项目,换来的是"每次改动都不敢悄悄改坏"的安全感。🚀
【免费下载链接】RPGMakerDecrypterTool for decrypting and extracting RPG Maker XP, VX and VX Ace encrypted archives and MV and MZ encrypted files.项目地址: https://gitcode.com/gh_mirrors/rp/RPGMakerDecrypter
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考