Galgame 汉化破解初级教程:以 BGI 为例,从解包到测试

管理提醒:
本帖被 乙津夢 执行加亮操作(2015-06-21)
囧,CK 这边的编辑器是 WindCode,也不能直接插入 HTML,只能大概排一下版了。对排版和格式有高要求的同学请看这里

  转载请注明出处。



Ever tried. 
Ever failed.
No matter. 
Try again.
Fail again. 
Fail better.


一直想写一篇面向新手的 Galgame 汉化教程,但一直苦于没有时间。现在终于考完了试,申请也告一段落,这才抽了点时间来写这篇文。还有,工口你认真学,今后杏爱会的程序就看你的了。

本教程假设你已经满足以下条件:

  • 玩过 Galgame,了解一般 Galgame 资源存储的方式
  • 会一门编程语言,VB6 和 JavaScript 等前端语言除外
  • 能看懂用其它编程语言写出的源代码,此处特指用 C++
  • 能看懂汇编,51 单片机的汇编语言就行
  • 懂数据结构
  • 知道什么是字符编码
  • 英语水平还说得过去
  • 懂一点儿日语

本教程中使用的名词:

  • 封包:指游戏的资源文件在游戏安装目录下的保存形式
  • 脚本:含有二进制控制符和纯文本的文件
  • 文本:从脚本中提取,人类能够读懂的文本文件

首先来看看破解都要干啥:

  • 解开游戏的封包文件
  • 从提取出的脚本中提取出文本
  • 从提取出的脚本中提取出图片
  • 把翻译好的文本写回到脚本里
  • 把新的图片和脚本放回到封包里
  • 修改游戏主程序,使之能正常读取中文

好,让我们开始吧。

1. 准备

我们以方糖社的《花色ヘプタグラム》为例进行实战。不过在开始之前,你需要准备几种工具:
  • 一款支持多语言编码的文本编辑器,例如 Notepad2
  • 一款十六进制编辑器,最好也能支持多语言编码,例如 010Editor
  • 一款反汇编工具,例如 OllyDbg
  • 你常用的 IDE,比如 Visual Studio
工具的用法在此不再赘述,请自行谷歌。
安装游戏后打开游戏的主目录,你会发现这些文件(已略去部分无用文件):
Copy code
2012/09/26  16:33               643 autoload.arc
2012/09/26  16:33         1,817,109 data01000.arc
2012/09/26  16:33       876,414,725 data02000.arc
2012/09/26  16:33       654,502,744 data02001.arc
2012/09/26  16:33     1,179,169,979 data02010.arc
2012/09/26  16:33        12,594,853 data02050.arc
2012/09/26  16:33       299,065,396 data02100.arc
2012/09/26  16:33        21,874,416 data02950.arc
2012/09/26  16:33        14,331,692 data03000.arc
2012/09/26  16:33       922,747,352 data04000.arc
2012/09/26  16:33        75,902,855 data05000.arc
2012/09/26  16:33           860,160 Heptagram.exe
2012/09/26  16:33        34,148,877 sysgrp.arc
2012/09/26  16:33           290,498 sysprg.arc
2012/09/26  16:33         3,702,778 syssnd.arc
2012/09/26  16:33             2,825 system.arc


很明显,Heptagram.exe 是游戏的主程序,*.arc是游戏的封包文件。接下来,我们开始正式的流程。

2. 破解

2.1. 运行破解


双击 Heptagram.exe 来测试一下,发现没有出现游戏主窗口;而用 AppLocate 工具加载后却能够正常运行。这说明开发商在游戏中进行了某种检查,以防止游戏在日本日外的国家运行(原因大家都知道,而且还有家中二公司把这点做到了极致)。

好,让我们想一想,如何得到当前操作系统的区域信息?



透露一下,BGI 引擎使用 GetSystemDefaultLangID 来确定当前操作系统的区域。
运行 OllyDbg,载入 Heptagram.exe,如图。



按下 CTRL + N,在打开的 API 列表中找到 GetSystemDefaultLangID,右键选择“在每个参考上设置断点”。如图。




双击 Breakpoints 窗口中的项,来到 GetSystemDefaultLangID 的调用位置:
Copy code
00455CE0  /$  FF15 D0E04A00 call    dword ptr [<&KERNEL32.GetSystemD>; [GetSystemDefaultLangID
00455CE6  |.  8B5424 04     mov     edx, dword ptr [esp+4]
00455CEA  |.  25 FF030000   and     eax, 3FF
00455CEF  |.  33C9          xor     ecx, ecx
00455CF1  |.  3BC2          cmp     eax, edx
00455CF3  |.  0F94C1        sete    cl
00455CF6  |.  8BC1          mov     eax, ecx
00455CF8  \.  C3            retn

在简体中文环境下, GetSystemDefaultLangID 返回值是 0x804,而在日语环境下,返回值是 0x411。那么怎么改?很简单,直接把 0x411 写入返回值的寄存器就行了。这样,无论是什么语言的系统,都会被认为是日语系统。
双击 00455CE0 这一行,把汇编改为 mov eax, 411。改好后的这部分代码如下所示:
Copy code
00455CE0      B8 11040000   mov     eax, 411
00455CE5      90            nop                ;修改后的代码比原先的要短,所以剩余的部分会用 nop 补齐
00455CE6  |.  8B5424 04     mov     edx, dword ptr [esp+4]
00455CEA  |.  25 FF030000   and     eax, 3FF
00455CEF  |.  33C9          xor     ecx, ecx
00455CF1  |.  3BC2          cmp     eax, edx
00455CF3  |.  0F94C1        sete    cl
00455CF6  |.  8BC1          mov     eax, ecx
00455CF8  \.  C3            retn


改好之后,在 CPU 窗口右键,复制到可执行文件 -> 所有修改 -> 全部复制,再在弹出的窗口中右键,保存文件,命名为 Heptagram_NoCheck.exe,完成后退出 OllyDbg。

接下来找到刚保存的 Heptagram_NoCheck.exe,双击运行,游戏界面是不是出来了?

2.2. 游戏脚本

2.2.1. 解包

这一步可以说是整个汉化过程中最简单的了(当然,这是建立在前辈们的辛苦分析上的):用老毛子出品的 AnimED 即可(不推荐使用 Crass)。

从 BGI 汉化经验来看,脚本文件一般都保存在前几个封包中(本游戏的脚本就在 data01000.arc 中)。如果你找不到,你可以把封包逐一拖到 ExtractData 窗口中观察。单个脚本的大小一般不会超过 200KB。

使用 AnimED 解开 data01000.arc ,拿到脚本(同样,略去了部分文件):
Copy code
2013/01/13  16:31            64,740 a01
2013/01/13  16:31            72,838 a02
2013/01/13  16:31            76,598 a03
2013/01/13  16:31             6,433 b06_3
2013/01/13  16:31            47,365 b07_1
2013/01/13  16:31            71,012 b07_2
2013/01/13  16:31            92,156 c06_2
2013/01/13  16:31            77,374 d09
2013/01/13  16:31            79,352 d10_1
2013/01/13  16:31             1,712 main
2013/01/13  16:31             3,150 s_ci_02
2013/01/13  16:31           110,513 Yuzuriha
2013/01/13  16:31           128,763 _01
2013/01/13  16:31            93,819 _02
2013/01/13  16:31           154,264 _03
2013/01/13  16:31           100,339 _07
2013/01/13  16:31           268,696 _08
2013/01/13  16:31            28,475 _10_2

打开准备好的 Notepad2,载入其中的 _01 文件,然后按下 F8,选择 Japanese (Shift-JIS)。你会发现,这个文件就是游戏的第一章:



2.2.2. 二进制脚本分析

在打开的 _01 文件中,你可以看到不可读的二进制代码和可读的文本混在一起。接下来,打开你的十六进制编辑器,载入_01 文件。



如图所示,BGI 脚本分为四部分:

  • 头部 Magic:用于校验该文件的类型
  • 脚本头部:定义了该脚本所需的全局变量
  • 指令部分:控制游戏的流程
  • 文本列表:我们最感兴趣的东西


在游戏执行中,引擎不断地读取指令部分中的指令,形成了游戏的时间线。 可以看出,0x00000003 之后的四字节(DWORD)和下面文本列表中字符串 _01.txt (起始地址为 0x18D1C)有关:
Copy code
0x18D1C = 0x1C (MAGIC 长度) + 0x34 (头部长度) + 0x18CCC (0x00000003 之后的四字节)

如果你不放心,可以再找几句话计算看看。
那么,思路就确定下来了:
逐个读取所有的 0x00000003,把之后的四字节作为地址,修正后用来查找目标处的字符串。也就是
Copy code
String = GetStringAt(GetUnsignedIntAt(AddressOfAny(0x03) + 4) + LengthOf(magic) + LengthOf(header))


接下来,用你最擅长的编程语言写一个提取文本的工具吧。

2.3. 图片提取与转化

BGI 引擎的图片有两种格式:标准 BMP/PNG 和去掉文件头的 BMP。前者用于 CG 和立绘,后者用于系统图片(sysgrp.arc中的图片文件)。
注意:部分图片的像素排序是反转的,保存时也要保持反转排序(在 PS 的保存窗口中勾选翻转行序
注意2:如果图片含有 Alpha 通道,那么 Alpha 通道也要修!


2.3.1. 标准 BMP/PNG 文件

这些文件很好判断。对于 BMP 文件,文件头部总是 BM 两个字母;而对于 PNG 格式,文件头总是 {0x89, 0x50, 0x4E, 0x47}(写成中文的话就是 塒NG)。给解出来的文件添加相应后缀,用 Photoshop 打开即可。

2.3.2. 系统图片

让我们再次祭出十六进制编辑器。



如图,文件的钱六个字节分别是图片宽度,图片高度和色深。可以看出,sys_title_006 图片是一个 1280 * 720 的 32 位图片。
再次使用你最拿手的编程语言,写一个小程序来修复 BMP 文件头吧:请阅读 BeginBuildBMP 函数的代码

至此,资源破解结束。

3. 资源回封

3.1. 游戏脚本

脚本的回封很简单,照着提取工具写一个对应的逆运算就行了。注意,新文件中的汉字必须是 GBK 编码。

3.2. 图片

3.2.1. 标准图片

去掉后缀就行。

3.2.2. 系统图片

刚刚我们添加了 BMP Header,现在我们需要一个去掉 BMP Header 的工具:请阅读 BeginBuildResource 函数的代码

4. 测试运行

上面,我

  • “汉化”了一张 CG (ev_warn02 来自 data02010.arc):


  • 汉化了一张 系统图 (sys_title_006 来自 sysgrp.arc):

  • 汉化了 _01 脚本的前几句话:


把 ev_warn02 的后缀去掉,把 sys_title_006 的文件头去掉,把文本回写到 _01 中,生成新文件再重新命名为 _01。
完成后,把三个文件重命名为原本的名字,复制到游戏目录下。双击游戏,运行。





图片很正常,能用。可是脚本就没这么方便了:



出现了乱码。
这就不得不说字符编码和边界检查了。点击这里这里,仔细阅读肠姐姐的文章。
BGI 引擎中存在多处校验边界的代码,具体可以通过 OllyDbg 查找(CTRL+L)cmp al, 0A0 来定位(《花色ヘプタグラム》中只有两处)。
其它需要修改的地方:
  • CreateFontA 的 fdwCharSet 参数:改为 86 (其他游戏可能会有 CreateFontIndirectA 函数,后者要麻烦一些)
  • MultiByteToWideChar 的 Charset 参数:改为 3A8
  • cmp eax, 0EF40 ; 改为 0FE40
  • cmp ebx, 0EF40 ; 改为 0FE40
  • cmp ebx, 8140 ; 8140 是 Shift-JIS 编码中的全角空格,所以此处应改为 0A1A1 (GBK 的全角空格)

修改后保存主程序,再次运行,一切正常。




5. 后续工作

5.1. 字体

用十六进制编辑器打开刚刚运行成功的主程序,把所有MS 明朝(俵俽 柧挬),MS ゴシック(俵俽 僑僔僢僋),MS Mincho,MS Gothic 改为黑体,或 SimHei,别忘了把空余的字节全填上 0x00。

5.2. 窗口标题

从 system.arc 中得到 ipl._bp,用十六进制编辑器修改字符串。

5.3. (按需)人名乱码,下一句提示符乱码,方括号乱码

从 sysprg.arc 中提取相应的 ._bp 文件,用十六进制编辑器修改。下面的是完成品,补丁质量:





5.4. 补丁的注意事项

既然 BGI 不用封包就能读取汉化后的文件,那么在发补丁时怎么办?打补丁之后,游戏目录不得一下子多出几百个文件么?孩子,你需要 MoleBox

6. 接下来?

如果你觉得自己需要再次学习基本知识,请把这里所有回复大于 2 的主题帖读完。
如果你觉得自己能够挑战更高难度的破解,请点这里
如果你有任何疑问,请留言。
[ 此帖被amemiya在2014-05-15 23:49重新编辑 ]