Garbro中的Formats.dat不完美解密构建

其它Garbro中的dat构建初稿Garbro
浏览数 - 305发布于 - 2026-02-28 - 21:55

重新编辑于 - 2026-03-04 - 13:10

1.frida逆向抓包获取key(为后续garbro编译做准备)

javascript
https://github.com/YuriSizuku/GalgameReverse/blob/master/project/krkr/src/krkr_hxv4_dumpkey.js

下载后放游戏目录

python安装步骤略自行查看b站教程

Python
pip install frida-tools

注意有些Steam的游戏存在DRM等,去除后使用,具体技术细节不在本文中赘述,请查看其他文章

游戏目录中运行以下命令

javascript
frida -l krkr_hxv4_dumpkey.js -f 游戏.exe > key_output.txt 2>&1

运行后等待一会命令窗口,然后游戏打开,关闭游戏

control_block.bin与key_output.txt将会在游戏目录中生成

Textile
hxpoint at 0x6c4cf0c3
cxpoint at 0x6c4c3c6d
* key : 724dc481e71024c53ed9ee2a1674f39caec40e0d55ffb11e60fe6e1f7dcc4128
* nonce : 522f20d0a8e442e85a1e8b4dead28da3
* verify : 481c32f156b99b6014ccbd2c479fce70422f58163d6c7ad344b05ca2955897c8
* filterkey : b9ac287fb5e05f0d
* mask : 0x1dc
* offset : 0x295
* randtype : 1
* order : 05 03 00 02 07 04 06 01 05 04 03 00 01 02 00 02 01
* PrologOrder (garbro) : 0, 2, 1
* OddBranchOrder (garbro) : 4, 1, 0, 3, 5, 2
* EvenBranchOrder (garbro) : 3, 4, 1, 2, 6, 0, 7, 5

删除了一些冗余信息,那么这些带"*"是我我们要重点关注的内容

2本地编译

尽可能用最新的.NET,最低要求是4.7.2的

下一个这个

https://strawberryperl.com/https://strawberryperl.com/

VSCodeStudio的一些开发包尽量下一下,或许未来用到

image.pngimage.png

如果进去了一堆报错正常缺少啥using的,点击生成,生成解决方案,清除生成的解决方案即可去除

image.png

没有就不用管

修改SchemeTool文件夹中的Program.cs

C#
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Remoting.Metadata.W3cXsd2001;

namespace SchemeTool
{
    class Program
    {
        static void Main(string[] args)
        {
            // ================================
            // 基本信息(根据游戏修改这里)
            // ================================
            string gameTitle = "TenShiSouZou";     // Scheme 名称(自定义)
            string exeName = "tenshi_sz.exe";      // 游戏主程序名

            string formatPath = @".\GameData\Formats.dat"; // GARbro 数据库
            string controlBlockFile = "Tenshi.bin";        // 控制块文件
            string namesFile = "HxNames-Tenshi.lst";       // 名称表文件

            // ================================
            // 1. 读取原有 Formats.dat
            // ================================
            using (Stream stream = File.OpenRead(formatPath))
            {
                GameRes.FormatCatalog.Instance.DeserializeScheme(stream);
            }

            // ================================
            // 2. 获取 XP3 解包器
            // ================================
            var format = GameRes.FormatCatalog.Instance.ArcFormats
                .FirstOrDefault(a => a is GameRes.Formats.KiriKiri.Xp3Opener)
                as GameRes.Formats.KiriKiri.Xp3Opener;

            if (format == null)
            {
                Console.WriteLine("未找到 Xp3Opener");
                return;
            }

            var scheme = format.Scheme as GameRes.Formats.KiriKiri.Xp3Scheme;
            if (scheme == null)
            {
                Console.WriteLine("未找到 Xp3Scheme");
                return;
            }

            // ================================
            // 3. 读取 ControlBlock(二进制控制块)
            // ================================
            if (!File.Exists(controlBlockFile))
            {
                Console.WriteLine("未找到 Tenshi.bin");
                return;
            }

            byte[] cb = File.ReadAllBytes(controlBlockFile);

            // ControlBlock 必须是 4 字节对齐
            if (cb.Length % 4 != 0)
            {
                Console.WriteLine("ControlBlock 大小错误");
                return;
            }

            // 转换为 uint 数组
            uint[] controlBlock = new uint[cb.Length / 4];
            Buffer.BlockCopy(cb, 0, controlBlock, 0, cb.Length);

            // ⚠ 不需要 ~ 取反(本游戏已验证)

            // ================================
            // 4. 构造 CxScheme(来自 Frida 抓到的参数)
            // ================================
            var cs = new GameRes.Formats.KiriKiri.CxScheme
            {
                Mask = 0x1dc,      // Frida 抓到
                Offset = 0x295,    // Frida 抓到

                // 分支顺序(非常重要)
                PrologOrder = new byte[] { 0, 2, 1 },
                OddBranchOrder = new byte[] { 4, 1, 0, 3, 5, 2 },
                EvenBranchOrder = new byte[] { 3, 4, 1, 2, 6, 0, 7, 5 },

                ControlBlock = controlBlock
            };

            // ================================
            // 5. 构造 HxCrypt
            // ================================
            var crypt = new GameRes.Formats.KiriKiri.HxCrypt(cs)
            {
                RandomType = 1,                      // Frida 抓到
                FilterKey = 0xb9ac287fb5e05f0d,       // Frida 抓到
                NamesFile = namesFile                // 文件名表
            };

            // ================================
            // 6. 设置 IndexKey(key + nonce)
            // ================================

            // 这是 32 字节 key
            byte[] key = SoapHexBinary.Parse(
                "724dc481e71024c53ed9ee2a1674f39caec40e0d55ffb11e60fe6e1f7dcc4128"
            ).Value;

            // 这是 16 字节 nonce
            byte[] nonce = SoapHexBinary.Parse(
                "522f20d0a8e442e85a1e8b4dead28da3"
            ).Value;

            // 绑定到 data.xp3
            crypt.IndexKeyDict = new Dictionary<string, GameRes.Formats.KiriKiri.HxIndexKey>()
            {
                {
                    "data.xp3",
                    new GameRes.Formats.KiriKiri.HxIndexKey
                    {
                        Key1 = key,
                        Key2 = nonce
                    }
                }
            };

            // ================================
            // 7. 注册到 KnownSchemes
            // ================================
            scheme.KnownSchemes[gameTitle] = crypt;

            // ================================
            // 8. 绑定 exe → Scheme
            // ================================
            var gameMapField = typeof(GameRes.FormatCatalog)
                .GetField("m_game_map", BindingFlags.Instance | BindingFlags.NonPublic);

            var gameMap = gameMapField.GetValue(GameRes.FormatCatalog.Instance)
                as Dictionary<string, string>;

            if (gameMap != null)
                gameMap[exeName] = gameTitle;

            // ================================
            // 9. 保存回 Formats.dat
            // ================================
            using (Stream stream = File.Create(formatPath))
            {
                GameRes.FormatCatalog.Instance.SerializeScheme(stream);
            }

            Console.WriteLine("TenShiSouZou 加密方案添加成功!");
        }
    }
}

ctrl+shift+B,再生成一次image.png

右键ScchemeTool,点击生成

image.pngimage.png.bin放入

在GARbro-Mod-master\GARbro-Mod-master\bin\Debug存在SchemeTool.exe

cmd运行SchemeTool.exe,直接把exe拖到cmd窗口上回车就是了

成功了会有提示

image.png

虽然吧无法直接解析查看文件,但可以提取出来当参考目录,配合CXDECExtractorV2这个项目可以快速写个快速恢复脚本

3.Garbro2可视化SchemeTool也可以可视化编辑,同样的只可以看到结构无法查看问渐文件详细

本文版权遵循 CC BY-NC 协议 本站版权政策

(。>︿<。) 已经一滴回复都不剩了哦~