[Gal汉化入门教程]#1 基础知识部分
Dir-A
编辑于 2021年07月29日 16:09

#1 基础知识

说明:

都是我个人经验只谈,且都由我个人编写完成,有错误在所难免 不对本文的专业性负责,如有需要,可以自行检索相关知识点, 有错误可以指正,由于篇幅有限,很多东西都只作模糊解释。

建议电脑端阅读

一切的源头,我们都要从游戏的主程序入手,为什么?

游戏的主程序里面包括了封包的读取算法,对文本的编码控制,标题之类的

几乎我们就可以把Gal看成是游戏的主程序+封包里的资源文件


#0x0 从Kirikiri引擎聊脚本和可执行文件

很多游戏引擎会把游戏的脚本(包括剧本和控制画面的特效)放在封包中

游戏的主程序充当一个解释器的作用,用来解释脚本的命令。

相当于浏览器读取网页文件一样。

比如我们最熟悉的Kirikiri引擎

它就是由游戏的主程序去解释TJS和KS之类的脚本来组成游戏的

也就说,其实Kirikiri引擎的主程序是差不多的,不同游戏区别就在于脚本和资源文件

但是有些游戏也会自己外挂一些加密插件,或者特效之类的插件来实现自己想要的功能。

这也就是为什么,Kirikiri引擎的游戏能在手机上运行,

因为我们只要在安卓下构建TJS和KS之类的脚本文件的解释器,

就可以使得Kirikiri引擎的游戏在手机上运行了,kirikiroid2就是这个原理。

当然别的引擎也可以这样,不过不开源的引擎难度会很大。

有些Kirikiri引擎的游戏移植到手机上的kirikiroid2会丢失特效或一些功能

因为这些特效和功能是用C语言或其它语言编写的插件,并不是TJS或KS写的,

所以这些特效自然就没了。

kirikiroid2其实就是TJS和KS的解释器,

它运行的Kirikiri引擎的游戏的时候,就是解释TJS和KS

然后读取相关的资源就组成了游戏,游戏的exe和dll文件对于它来说压根没用,

因为那是基于Windows平台x86框架编写的,手机是安卓ARM平台的自然就用不了。

当然ARM也是可以模拟X86的,比如Windows10 ARM版也是可以运行x86程序的,

但是这个就不是那么一两句话能说清楚了,非常复杂。

所以从这我们也可以看出来,Kirikiri引擎的游戏主要不同就在于封包里的内容。

这里也就体现出了这种非针对一个特定硬件平台编译的游戏运行架构的好处,

只要我能搭建起游戏引擎脚本的解释器,那这个游戏就能直接跑。

最直观的例子就是,网页,什么手机/平板/电脑/游戏机 即使他们硬件/系统都不一样,

你依然能浏览同一个网页,

因为你网页是对HTML和JS脚本进行解释,只要我有支持解释HTML和JS的浏览器,

那就能把你网页内容显示出来。

这里我们可以举一个 TyranoScript 的例子,这个玩意就是基于web技术开发的游戏引擎,

所以你只要给他一个浏览器,就能跑。

需要注意的是,有些游戏的脚本文件,会进行编译,但是这种编译并不是针对硬件进行编译,而是依据内部构建的解释器进行编译,

也可以通俗的理解为对脚本进行加密,这种通常会和游戏内的剧本文件分离,

如果脚本被编译了,那这个修改起来就很麻烦了。

Kirikiri如果用TJS2的,就是对TJS脚本进行了编译,这样我们就很难去修改了,

不过kirikiroid2是支持TJS2的读取的。

当然这个主程序也不一定就是EXE文件,也有DLL文件,

有些游戏会调用DLL文件来解码音频之类的,或者一部分功能放在DLL里。

DLL其实我们就可以理解为EXE文件的一个拓展功能的插件,

里面封装好了一些功能,EXE文件去调用他们。

或者你可能只看到一个很大的EXE文件,别的什么都有,因为别的文件都捆绑进EXE文件了。

当然Kirikiri引擎的DLL文件可以改为tpm后缀,

相比于.dll后缀,游戏引擎会自动加载tpm后缀的文件

参考:https://krkrz.github.io/krkr2doc/kr2doc/contents/Plugins.html


#0x2 了解一下编码

其实编码这个问题,B站也有一些不错的视频,大家可以去看看

我这就讲我们汉化要用到的部分

通常日文的游戏基本用的是Shift-jis的编码,

最近几年的一些游戏也可以采用Unicode编码

而我们中文的常见编码是GBK

那么什么是Shift-jis编码,什么是GBK编码,什么是Unicode编码、他们有什么区别呢?

“Shift-jis(CP932)编码是针对日文的一种编码方式 “GBK(CP936)编码是针对中文的一种编码方式 “Unicode编码是一种通用的编码,支持多国语言,和一些特殊符号

Shift-jis表示日文的假名和汉字都是用两个字节

82C9 82D9 82F1 82B2 906C 96AF 96D4 に    ほ   ん    ご   人   民    網

GBK表示中文字符都占用两个字节

D6D0 B9FA C8CB C3F1 CDF2 CBEA 中   国   人   民    万   岁

我们需要注意的是GBK和Shift-jis编码也有一定范围

GBK编码范围:

8140-FEFE

Shift-jis编码范围(两字节):

“第一位字节”使用0x81-0x9F、0xE0-0xEF(共47个) “第二位字节”使用0x40-0x7E、0x80-0xFC(共188个)

我们这里是随便写的,没有很准确,需要准确定义的可以去搜索引擎检索

因为这个编码范围问题,游戏用Shift-jis的会去限制范围,

以此来确保文本显示和游戏引擎不出问题。

所以会出现 你修改了编码,但是还是显示不全汉字甚至全是问号(也有可能是字体问题)

参考链接:

https://blog.csdn.net/madonghyu/article/details/103572482

https://www.52pojie.cn/thread-1200805-1-1.html

同时GBK和Shift-jis的英文和阿拉伯数字和一些符号表示对应的十六进制是一样的

所以英文和数字在GBK和Shift-jis下读取都是一样的

所以你会发现这两种编码非常相似

换句话说就是,即使我们改了程序读取方式为GBK编码,只要不去动脚本

游戏和Shift-jis编码时基本一样

只是游戏内的文本会不能正常显示日文

那么乱码是什么原理呢?

简单说就是游戏好好的拿着日文编码读取脚本,

结果你叫人家用中文的编码读取,这可不就乱了。

现在我们拿着 GBK去读取 日文的 

にほんご人民網 

的十六进制,也就是相当于用GBK去匹配 

82C9 82D9 82F1 82B2 906C 96AF 96D4 

这几个十六进制对应的中文,于是就变成了

偵傎傫偛恖柉栐

这就是大家喜闻乐见的乱码

这里需要注意一下的是,很多游戏默认里面的文本是不会乱码的,

因为人家写好了是用日文编码去读取

但是有些对话框或者标题是乱码的,这是为什么呢?

因为他这个程序是用日文的编码编写的。

有些字符串是直接写在exe文件里的,

读取的时候是按照系统的所设置的语言区域来决定读取的编码的。

有些游戏也会根据你这个系统所设置的语言区域去设置读取的编码,

导致内部的文本也是乱码的。

所以这个情况是不唯一的。

对于汉化我们只需要修改程序读取编码为GBK和编码校验范围

然后替换对应的日文十六进制数据

这个时候我们就不要去想什么编码不编码了

我们直接把脚本看成二进制的文件

我们不动这个二进制文件,那自然不会出问题,撑死只是显示文本不一样

比如原来日文对应的二进制(我们这写成十六进制)

82C982D982F182B2906C96AF96D4

正常日文编码是读取出来是

にほんご人民網

我们直接替换

82C982D982F182B2906C96AF96D4

D6D0B9FAC8CBC3F1CDF2CBEA0000

别的地方不动

然后修改程序读取编码为GBK,并修改编码校验范围

这个时候显示出来的就是

中国人民万岁

注意替换的那个十六进制后面还补了几个0,

是让这个替换后的长度保持一致,以免后面错位了

就和RNA合成蛋白质一样,中间少了个核糖核苷酸,

那往后那一排都错位了,合成出来的序列就和原来不一样了。

如果只是中间那个核糖核苷酸种类换了一下,

那撑死就那个中间部分的一个蛋白质出错,后面还是一样(别杠起始密码子

很多游戏的脚本修改就是这样的,我们只是把这个脚本文件,

日文编码对应文本那一块二进制扣掉,换成中文的二进制

其余部分和原来是一模一样的,

因为有些部分的脚本游戏运行会依据这些脚本加载立绘,音频,背景图片之类的

程序只认二进制的数据,管你GBK还是什么编码,

他读到 000101010 的时候就是加载立绘A,如果你这个时候把脚本

当成Shift-jis编码全部转换成GBK了,

那这个二进制是不是就变了,那程序加载立绘就出问题了。

至于Unicode比较复杂,

我们只要知道Unicode和GBK/Shift-jis是很不一样的就行了

我们这就不多说了。

遇到Unicode,直接写中文就ok,没必要修改什么编码,因为人家本来就支持中文。


#0x3 编码的应用

修改前我们需要了解一个基础的概念

“所谓游戏引擎的编码,主要还是对游戏的剧本和脚本起作用 如果编码的读取不正常,轻则游戏内文本乱码,重则游戏无法运行”

我们可以继续举例Kirikiri的例子,

我们知道Kirikiri运行的时候要去读取TJS和KS之类的文件

这些文件里面写的就是一些代码,

这些代码控制封包里资源的读取,界面的UI设计,游戏的内文本

如果这些脚本文件的编码读取不正确就会造成乱码,或者游戏无法运行

比如有些时候你在中文系统下运行Kirikiri2的游戏,你会发现标题乱码了,

其实这个标题是写在TJS里的

而这个TJS是Shift-jis编码的,中文系统下用GBK读取,这就造成了乱码

有些Kirikiri2的游戏你运行直接出错,为什么呢?

很大原因是关键的代码用了日文,然后你在中文系统下运行

导致编码读取错误,造成了整个游戏脚本无法正常运行。

不过一般的游戏引擎其脚本基本都是全英文,这时候Shift-jis和GBK都是正常的

文本是日文,所以游戏里的文本就乱了,这个时候我们直接修改脚本,

把原来乱码的日文字符串部分替换为中文就可以了。

所以从这里我们就知道编码的读取正确性,对游戏的正常运行很重要。

由于Kirikiri2/Z引擎都支持Unicode编码,

所以我们并不需要对引擎编码读取上进行什么修改

但是有部分游戏天生就不支持Unicode,只支持Shift-jis编码,

因为我们知道Shift-jis这个编码是不能表示所有中文的

所以我们就要来修改程序的编码控制使其支持GBK。

切记不要试图在不支持Unicode的游戏引擎下把Shift-jis的编码修改成Unicode的

这会导致很多问题,我们通常的做法是游戏如果采用Shift-jis并且不支持Unicode编码,

那么我们就换用GBK编码

如果游戏支持Unicode编码,那么我们就采用Unicode编码来汉化游戏。


#0x4 调试器的基本原理

我们通常使用x64dbg和Ollydbg来修改程序

如果需要修改程序,我们还需要了解一些很基础的概念

一个程序采用C语言编写,然后编译,最终变成我们的可执行文件

这其中编译后的程序是针对我们的CPU架构和系统编译的

CPU并不认识所谓的C语言,它只认识机器码,而机器码一大串010101010太复杂了

我们又发明出汇编,汇编就是用一段简单的指令来表示这些机器码

比如

 89C8          MOV     AX,CX

对应机器码 

1000 1001 1100 1000

他本质并没有改变机器码,只是换了一个表达方式

就和你们班里有(张三、李四、王五、xxxx)这些人我们统一用一个"你班同学&#​34;来指代一样

免得我说你们班同学的时候,要一个个把他们名字念出来。

系统这方面呢,不同系统有不同的API调用,

编译器不同编译的程序从汇编/机器码的角度看也会有不一样

而且编译的程序需要让系统执行,也需要一些而外的配置,

比如Windows下EXE文件有PE结构

不过这些是后话了,

我们主要关心的还是程序实现功能的部分,这些辅助程序运行的之后再聊。

参考链接:网页链接​

现在我们知道,要运行这个程序,你必须得符合x86架构下的汇编才行,

不然CPU是不认的

所以不管你程序怎么写,最终都是一堆汇编在跑。

那么我们就可以去解析编译出来的EXE文件,当成一堆二进制数据,依据PE结构,

去掉那些辅助程序运行的部分,来到程序的主体结构,

依据汇编指令的原则,进行解析这些二进制数据,变成一堆汇编指令

这样就变成了我们x64dbg和OllyDBG打开后那一堆mov call jmp push指令了

现在我们已经解析成了这些汇编指令,但是汇编指令毕竟太复杂,

我们很难从中看出什么名堂

不过Windows的Api调用都是有一定结构的

很多程序,想要读取文件,弹出窗口提示,这些都是调用系统内置的帮你写好的代码完成的

所以这也就方便我们快速定位需要修改部分的位置

这个Call就是调用系统的API

在调用前,我们一般需要给这API一些原料

比如系统内置了一个加法运算的函数,那么我们调用这个函数之前呢

需要给他几个数字,不然这个算加法的函数拿什么来加

看下面这个<&GDI32.BitBlt>

它调用前就会push一堆参数进去

代码块
C++
自动换行
复制代码
68 2000CC00   push 0xCC0020                            ; /ROP = SRCCOPY
6A 00         push 0x0                                 ; |YSrc = 0x0
6A 00         push 0x0                                 ; |XSrc = 0x0
57            push edi                                 ; |hSrcDC = 011F075F
FF75 F8       push [local.2]                           ; |Height = 5BE7000
FF75 F4       push [local.3]                           ; |Width = 7703FE09
6A 00         push 0x0                                 ; |YDest = 0x0
6A 00         push 0x0                                 ; |XDest = 0x0
53            push ebx                                 ; |hDestDC = 05BE7000
FF15 78604801 call dword ptr ds:[<&GDI32.BitBlt>]      ; \BitBlt
FF75 A0       push [local.24]                          ; /hObject = NULL
57            push edi                                 ; |hDC = 011F075F
FF15 98604801 call dword ptr ds:[<&GDI32.SelectObject>>; \SelectObject
57            push edi                                 ; /hDC = 011F075F
FF15 94604801 call dword ptr ds:[<&GDI32.DeleteDC>]    ; \DeleteDC
FF75 A4       push [local.23]
E9 EAFEFFFF   jmp SiglusEn.010E6B11
复制成功

最左边那一排就是汇编指令对应的机器码,用的是十六进制表示,毕竟二进制太长了。

这些函数的参数可以去看MSDN文档,参数是倒着看的,也就是

push

push

push

call

从Call往上数的

不理解也没关系,反正我们就改一改编码和编码校验范围,

而且改的时候由于编译器和写的代码的不同的缘故

也不一定在call上面几个,我们还需要跟踪字符串的读取,

或可以直接记住一些引擎编码修改的位置。

参考链接:https://www.52pojie.cn/thread-1200805-1-1.html


#0x5 谈谈程序加壳

上面理解了我们程序的一些基本原理之后呢

我们来简单聊一下加壳的事情

我们知道这个程序编译好之后呢,就是那么一堆汇编,非常容易就让别人给修改掉了

程序加壳也就是保护程序,当然有些壳是压缩壳,重在减小体积

有些加密壳,会把原来那些汇编代码给吞掉,或者塞一些乱七八糟的数据

让一些工具和人都很难分析

有些还会吞了代码,一边运行一边吐出来

这些都是在保护代码不会轻易被修改

除了吞代码,有些壳还会把程序用到的一些系统的导出/导入表给你吞了

只留下几个壳需要用到的表

其它都通过壳内部映射,这样使修改的人很难定位到需要的代码

其实这些对我们来说都不重要,重要的是我们怎么知道有没壳?

毕竟对于没什么基础的人来说,脱壳是比较麻烦的

通常我们可以借助一些查壳软件

比如

Detect It Easy(DiE)  https://github.com/horsicq/Detect-It-Easy

Exeinfo PE

至于这两个软件的用法大家可以自行去百度

我们用另一种方法来间接判断是否有壳

1.如果你把exe文件拖入Ollydbg,提示你代码被压缩或者加密。基本可以说exe加壳了

2.看导入表,如果你发现这个程序导入表都被干没了只剩下几个。基本可以确定exe加壳了

两个结合起来判断基本就八九不离十了,都不着查壳软件

知道有壳之后怎么办呢?直接放弃修改,因为壳的代码都是变化过的,你直接修改是不行的

有些壳是一边运行一边吐代码

现在要么脱壳

要么找到位置后打内存补丁

这些内容就比较难讲了

所以我建议大家暂时先放弃有壳的游戏,或者找的没壳的exe或找到脱壳的版本。


好了最后我还是推荐大家看看下面这几个链接的文章。

https://www.52pojie.cn/thread-1200805-1-1.html

https://blog.csdn.net/madonghyu/article/details/90029001

https://blog.csdn.net/madonghyu/article/details/103572482

然后下节我们需要讲一些调试器的操作,大家有兴趣可以去看看这篇教程

https://www.52pojie.cn/thread-1359142-1-1.html

https://www.52pojie.cn/thread-1361926-1-1.html