GARbro的功能十分强大,并自带了多种解密算法;但即使是再强大的引擎也无法囊括所有游戏,何况作者已经好久不更新了(虽然最近不知为何诈尸),更何况GARbro的作者在某个pull request里说了该工程的目标不包括囊括尽可能多的游戏。因此,当我们由于各种目的想要拆包某个游戏的资源文件时,就很大程度上要自食其力了。
前一阵子由于软工做了个机器人,心血来潮想去拆某个frontwing+makura的杀手机器人作品的语音塞到机器人里;在网上随便搜了搜就看到了某位大佬的解密教学,但在跟着流程拿到了加密参数之后,教程的最后一句令不懂C#的我抓耳挠腮:
在GARbro里随便找个地方塞进去,……
上网搜了也搜不到(怎么可能会有),下了源码自己琢磨了半天也不知道塞到哪里去,结果这一卡就是两个月;于是这一篇博客就是来记录如何在GARbro中加入自定义的压缩包加密参数的。
首先从github上clone下来GARbro的整个工程,使用Visual Studio打开。
在打开的时候,VS很有可能提示.Net版本与当前机器上的版本不符;从最终结果来看除了Net20工程是必须需要.Net 2.0(可以在“启用或关闭Windows功能”里配置)的,其他工程好像都可以直接更新到最新版.Net;不过我是老老实实的去下载了对应版本的.Net。
在这之后,VS很有可能又开始提示你缺少Nuget包;在确认没有乱动什么配置的前提下,可以去手动删除报错工程的.csproj中"<Target Name="EnsureNuGetPackageBuildImports" ..."这一个Target节点,来解决这一个报错。
在这之后VS可能又会报错说缺少一些C#文件;我的情况是缺少Nanami社的某个加密算法文件大概,所以可以直接将该文件从编译路径里删除,并不会影响最后的结果。
在这些步骤之后,你应该可以成功生成GARbro解决方案,并运行GARbro.GUI;如果不行,请向C++和C祈祷,然后去百度或谷歌。
在刚克隆源代码的时候,我本以为很快就能够找到下面这个窗口对应的逻辑;里面明显有字符串元素,只要全局搜索字符串,再反向查找应该就可以了。事实证明我还是太甜了。
如图所示,这里的选项很明显在工程中需要一个字符串来表示;但在工程里全局搜索,甚至用IDA打开文件进行反汇编搜索,都搜不到这个字符串。这使得我一度怀疑GARbro是否真的能从源代码build起来。
在这之后,我去阅读了GUI工程里的大部分逻辑;但是几乎完全没有看到与这个对话框相关的逻辑。直到我在VS上成功build了这个工程,才终于找到了其具体逻辑。
首先,这个对话框实际上并没有写在GUI工程中,而是被放在了ArcFormats/Kirikiri/WidgetXP3.xaml中。这时我才意识到GARbro会自动识别xp3的文件后缀,然后去找Kirikiri引擎的相关加密方式。
在找到这个对话框之后,剩下的就变得简单了。顺着该xaml生成的.cs文件向上摸瓜,可以在App.xaml.cs的第82行找到从文件中读取所有Scheme(加密模式?)的函数调用;跟进追踪该函数,在FormatCatalog.cs的DeserializeScheme函数中可以找到其具体过程(如下图所示)。
静态+动态分析代码可以发现,该函数会读取ArcFormats/Resouces下的Formats.dat,使用zlib库对其进行Deflate解压缩,再将该二进制串转化为SchemeDataBase对象。
既然获得参数的方式已经确定,那么写入参数的方式也自然而然确定了:反过来。
注意:本方案不是最佳方案,是在对代码与静态文件进行测试时产生的缝合怪。如果你读懂了代码,建议自己写一个函数来加入自定义参数。
注意:截至2022年5月底,博主不会写C#的Hello World。
首先修改FormatCatalog.cs,构造你自己的scheme,并将其加入db,再将db序列化;
public void DeserializeScheme (Stream input) { int version = GetSerializedSchemeVersion (input); if (version <= CurrentSchemeVersion) return; using (var zs = new ZLibStream (input, CompressionMode.Decompress, true)) { ...... /* construct your own scheme and add it into db here*/ var bin2 = new BinaryFormatter(); var tempOut = File.OpenWrite("path\\to\\GARbro\\ArcFormats\\Resources\\FormatsGenerated.raw"); bin2.Serialize(tempOut, db); } }
然后用python的zlib库将序列化后的文件进行Deflate压缩;当然用C#更好,但我直接复用了检验测试文档是否为zlib格式环节时写的py脚本:
import zlib def com(): header = b'GARbroDB\x94\x00\x00\x00' with open('FormatsGenerated.raw', 'rb') as f: data = f.read() com_data = zlib.compress(data) with open('FormatsGenerated.dat', 'wb') as fw: fw.write(header) fw.write(com_data) if __name__ == "__main__": com()
注意,原Formats.dat中头部有几个特殊的字节;但直接调用zlib并不会生成这些字节,因此我们这里给它补上。
在对原来的.dat文件进行备份后,我们便可以使用生成的.dat文件替换掉原来的.dat文件,来让GARbro读入你所指定的加密引擎参数。应该是可以跑的。跑不了的话,请自行debug。
由于各种原因我并没有对GARbro的源码进行深入的阅读;如果你详细的阅读的话,说不定会找到作者写好的导出db的函数,或者其他helper参数。
不过如果你只想跑起来加入了自己参数的GARbro的话,这篇文章的内容或许已经足够了。