VdustR/game-save-android-halls-of-torment

GitHub: VdustR/game-save-android-halls-of-torment

针对 Godot 引擎开发的 Android 游戏「Halls of Torment」的存档解密、修改和重加密完整指南。

Stars: 0 | Forks: 0

# Halls of Torment — Android 存档数据 一份关于解密、修改和重新加密 [**Halls of Torment: Premium**](https://play.google.com/store/apps/details?id=com.halls.of.torment.paid.gp) (Android) 存档文件的详细指南。 已在版本 **1.0.1152** 及以下 DLC 上测试: - [Supporter Pack](https://store.steampowered.com/app/3386980/Halls_of_Torment__Supporter_Pack/) - [The Boglands](https://store.steampowered.com/app/3919420/Halls_of_Torment__The_Boglands/) (添加了 Alchemist, Crone 和 The Boglands 关卡) 预构建的存档文件可在 [Releases](https://github.com/VdustR/game-android-halls-of-torment-save-data/releases) 页面获取。 ## 目录 - [概述](#overview) - [前置条件](#prerequisites) - [环境设置](#environment-setup) - [存档文件位置](#save-file-location) - [存档文件格式](#save-file-format) - [解密](#decryption) - [存档文件结构](#save-file-structure) - [修改规则](#modification-rules) - [重新加密](#re-encryption) - [推回设备](#pushing-back-to-device) - [云同步注意事项](#cloud-sync-considerations) - [脚本](#script) ## 概述 Halls of Torment: Premium 基于 **Godot Engine 4.6** (`custom_build`) 构建。存档文件使用 Godot 内置的 `FileAccessEncrypted` 以及基于密码的加密 (`save_encrypted_pass`)。 关键信息: - **存档格式**:Godot GDEC (AES-256-CFB) - **加密密码**:作为 UUID 字符串常量存储在已编译的 GDScript 字节码 (`Global.gdc`) 中 - **存档内容**:JSON - **反篡改**:APK 使用 **pairip** 保护,阻止运行时检测(例如 Frida attach)。但这不影响静态分析或存档文件操作。 ## 前置条件 - **已 Root 的 Android 设备或模拟器**(访问 `/data/data/` 所需) - **ADB** 并具有 root shell 访问权限 - **Python 3** 并安装: - `cryptography` — AES 加密/解密 - `zstandard` — GDScript 字节码解压(仅在提取密钥时需要) ``` pip install cryptography zstandard ``` ## 环境设置 ### 使用带有 Magisk 的 Android 模拟器 如果您没有已 Root 的设备,请使用 Android Studio AVD: 1. **创建 AVD**,使用 `google_apis_playstore` 系统镜像(推荐 API 34): sdkmanager "system-images;android-34;google_apis_playstore;arm64-v8a" avdmanager create avd \ --name "Game_Research" \ --package "system-images;android-34;google_apis_playstore;arm64-v8a" \ --device "pixel_7" 2. **启动** 并启用可写系统: emulator -avd Game_Research -writable-system -no-snapshot-load 3. 使用 [rootAVD](https://gitlab.com/newbit/rootAVD) **通过 Magisk 获取 Root**: git clone https://gitlab.com/newbit/rootAVD.git cd rootAVD ./rootAVD.sh system-images/android-34/google_apis_playstore/arm64-v8a/ramdisk.img 4. 重启后,打开 Magisk 应用 → **超级用户** 标签页 → 为 `[SharedUID] Shell` 启用开关 5. 验证 root: adb shell "su -c 'id'" # uid=0(root) gid=0(root) ... ## 存档文件位置 ``` /data/data/com.halls.of.torment.paid.gp/files/HoT_progress_profile.dat ``` 其他相关文件: | 文件 | 描述 | |------|-------------| | `files/settings.json` | 游戏设置(音量、控制等)— **未加密** | | `files/HoT_progress_profile.dat` | 主存档文件 — **已加密** | ## 存档文件格式 存档文件使用 Godot 的 `GDEC` 格式 (Godot 4.4+): ``` Offset Size Description ------ ---- ----------- 0x00 4 Magic: "GDEC" (0x47 0x44 0x45 0x43) 0x04 16 MD5 hash of decrypted plaintext 0x14 8 Data length (uint64 LE) — original unpadded size 0x1C 16 IV (Initialization Vector) for AES-CFB 0x2C ... Encrypted data (AES-256-CFB, padded to 16-byte boundary) ``` ### 密钥派生(密码模式) Godot 的 `open_and_parse_password()` 按如下方式派生 AES 密钥: ``` password_string → MD5 hash → hex string (32 ASCII chars) → use ASCII bytes as 32-byte AES-256 key ``` 例如,如果密码是 `"hello"`: ``` MD5("hello") = "5d41402abc4b2a76b9719d911017c592" AES key = b"5d41402abc4b2a76b9719d911017c592" (32 bytes of ASCII) ``` 来源:[Godot Engine `file_access_encrypted.cpp`](https://github.com/godotengine/godot/blob/4.4-stable/core/io/file_access_encrypted.cpp#L107-L117)(游戏使用 v4.6 自定义构建;链接的 4.4 源码具有相同的加密逻辑) ### 加密密码 加密密码是嵌入在已编译 GDScript 字节码(APK 资源包内的 `Global.gdc`)中的 UUID 常量。 要自行提取: 1. 拉取包含资源的 APK 分包: adb shell "pm path com.halls.of.torment.paid.gp" # 查找 split_assetPackInstallTime.apk 2. 解压并解压 GDScript 字节码: import zstandard with open("Global.gdc", "rb") as f: data = f.read() zstd_pos = data.find(b'\x28\xb5\x2f\xfd') # zstd magic assert zstd_pos != -1, "No zstd data found in .gdc file" compressed = data[zstd_pos:] decompressed = zstandard.ZstdDecompressor().decompress( compressed, max_output_size=2*1024*1024 ) 3. 提取字符串并查找紧邻 `HoT_progress_profile.dat` 的 UUID 模式 (`xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`)。 版本 **1.0.1152** 的密码:**`e4422259-b391-43d3-9284-5f37189420ed`** ## 解密 ``` import struct, hashlib, json from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes PASSWORD = "e4422259-b391-43d3-9284-5f37189420ed" def decrypt_save(filepath): with open(filepath, "rb") as f: magic = f.read(4) assert magic == b"GDEC", f"Not a GDEC file: {magic}" md5_expected = f.read(16) data_len = struct.unpack("
标签:ADB, AES-256-CFB, Android游戏, DNS 反向解析, GDEC解密, GDScript字节码, Godot引擎, Halls of Torment, Homebrew安装, HTTP工具, Pairip保护, Python加密, Root权限, 云安全监控, 云资产清单, 存档修改, 存档编辑器, 密钥提取, 数据解密, 游戏修改, 逆向工具, 逆向工程, 静态分析