iamschmuck/MyTestStudentX-.MTF-Decoder

GitHub: iamschmuck/MyTestStudentX-.MTF-Decoder

通过逆向工程解密并解析 MyTestX 专有的加密 .mtf 测试文件,将其完整转换为包含题目与答案的 JSON。

Stars: 1 | Forks: 0

mytestx-decoder

用于解密 MyTestX (МойТестХ 10.x) 测试的解码器 — 格式为 .mtf
解密、解压并将整个测试提取为 JSON: 包含问题、选项以及正确答案。

Python Без зависимостей Лицензия MIT Reverse-engineered

🇨🇳 简体中文  ·  🇬🇧 English

## 📦 快速开始 ``` # 完整的解析 -> 包含问题、答案和正确标记的 JSON python mtf_parse.py тест.mtf out.json # 低级:打印格式版本 + 原始字符串 python mtf_decode.py тест.mtf ``` 输出结果示例 — [`sample_output.json`](sample_output.json): ``` { "name": "Демонстрационный тест", "author": "БАС", "count": 42, "questions": [ { "text": "Столица Франции?", "multiple": false, "answers": [ { "text": "Париж", "correct": true }, { "text": "Лион", "correct": false }, { "text": "Марсель","correct": false } ] } ] } ``` ## 🤔 为什么需要它 `.mtf` 文件经过了加密和压缩,因此只能在 Windows 程序中打开的测试, 无法在其他任何地方阅读或研究。这个解码器**无需 Windows 和** **MyTest** 即可读取它们 —— 非常适合将**您自己的**测试迁移到其他平台 (例如手机应用程序)。 ## 🧬 格式(完全逆向) ``` .mtf файл └─ XCrypt feedback stream cipher (расшифровка) ── универсальный ключ, см. ниже └─ "MyTestX" + версия + zlib-поток (78 da) └─ zlib inflate (распаковка) └─ UTF-16LE сериализация • строки с префиксом длины (u32 charCount + UTF-16) • текст вопроса/ответа — это RTF (\ansicpg1251) • бинарный «зазор» перед каждым блоком кодирует его роль: большой зазор → ВОПРОС средний зазор → ПРАВИЛЬНЫЙ ответ ~0 зазор → неправильный ответ ``` 完整的字节规范请见 [FORMAT.md](FORMAT.md)。 ## 🔑 密码 16位 feedback stream cipher (`MyTestStudent.exe` 中的 `FUN_0066523c`)。 对于没有密码的测试,密钥是固定的: ``` C1, C2, SEED = 0x6CA9, 0xCE1C, 0x0101 state = SEED for b in data: # b = байт шифротекста k = state & 0xFF out = b ^ k # байт открытого текста fb = (out + k) & 0xFF state = (fb*C1 + C2) & 0xFFFF ``` 密钥在 `FUN_00665498(a, b)` 中构建,公式为: `C1=|a|/|b|, C2=(|a|^|b|)&0xFFFF, SEED=(|a|&|b|)&0xFFFF`。 带有密码的测试会根据打开密码推导出 `a,b`。 ## 🧩 破解过程 简短的逆向工程分析 —— 因为这个案例非常有趣: 1. **分类与评估。** 所有 `.mtf` 文件都有相同的 14 字节前缀,且熵值约为 8.0 bit/字节 → 说明文件已加密。`MyTestStudent.exe` 是使用 Borland Delphi 编译的;在字符串中可以看到自定义的 `XCrypt` 模块 + zlib,但没有 AES/DCP。 2. **死胡同。** 尝试了 RC4 / XOR / 暴力破解 Borland-LCG —— 全部失败(而那个*似乎* 适用于约 13 KB 文件的 LCG 只是巧合)。静态追踪在 Delphi-gettext 和通过 VMT 的间接调用中宣告失败。 3. **反编译。** Ghidra(Delphi 模式)输出了 8071 个函数;唯一的 feedback stream cipher 是 `FUN_0066523c`。暴力破解其有效的 3 字节密钥依然 无果 —— 因为明文是 **UTF-16** 编码(每隔一个字节就是 `0x00`),而暴力破解中的“可打印”字符过滤器 排除了 `0x00`。🤦 4. **通过调试器发现真相。** 以 headless 模式启动 **IDA 7.7**,在 `FUN_0066523c` 的入口 和返回地址处设置断点,在实际测试中抓取了输入/密钥/输出。输出 以 `4D 00 79 00 54 00 65 00 73 00 74 00 58 00` = **"MyTestX"** + zlib 数据流 `78 da` 开头。大功告成 —— Python 的解密结果与运行中的程序**逐字节**吻合。 5. **格式。** Inflate 解压 → UTF-16 + RTF。事实证明,正确答案是通过 每个 RTF 块(问题 / 正确 / 错误)之前的**二进制间隙大小**进行编码的, 这已在一个真实的药理学测试中得到了验证(标记出的答案在医学上都是准确的)。 ## 📁 文件说明 | 文件 | 内容说明 | |---|---| | [`mtf_decode.py`](mtf_decode.py) | 解密 + inflate,低级别的字符串遍历 | | [`mtf_parse.py`](mtf_parse.py) | 完整解析器 → 问题 / 答案 / 正确答案 → JSON | | [`FORMAT.md`](FORMAT.md) | 格式的字节规范 | ## ⚠️ 状态与限制 - 支持未加密的 MyTestX 10.x `.mtf` 文件(单选和多选)。 已通过实际测试验证。 - 加密测试需要从密码推导出的密钥 (`a,b`) —— 暂未实现。 - 包含“手动输入”(填入数字/单词)的问题没有错误选项, 目前会被跳过。 ## 📜 许可证与免责声明 代码采用 [MIT](LICENSE) 许可协议。本项目旨在实现兼容性并读取**您自己的** 测试。MyTest 版权归其原作者 (mytest.klyaksa.net) 所有。本代码库中**不包含** MyTest 的二进制文件,也 没有任何受版权保护的测试内容。
标签:Aarch64, MyTestX, Python, 云资产清单, 数据提取, 数据解密, 文件解析, 无后门, 逆向工具, 逆向工程