HsOjo’s Blog

📒 A powerless rookie's tree hole.

【汉化】11月的阿卡迪亚

2017-10-1800 分钟
type
status
date
slug
summary
tags
category
icon
password

前言

在数个月前我听到了这游戏的OP,感觉挺好听的。 然后找了一下这个游戏,发现并没有汉化版,甚至连开坑的消息都没有,个人开坑的不算,谁知道整到什么时候
于是乎,我花了2天时间来进行程序的分析及修改。(初版完成)
后来又花了4天时间,对乱码文本进行修复。(解析完善)
最后,加上写这篇文章的时间,便是一周了。

操作环境

系统:macOS+Windows
软件: AnimED, 010editor, LordPE, Python3.6, ollydbg, 易语言/C/C++/…(能编译windows动态链接库就行)
软件请自行下载/安装,纯windows亦可操作。

资源汉化

资源汉化过程:
  • 使用AnimED对游戏目录下arc文件解包。
  • 使用AnimED对解包后内容进行解析。(崩溃了)
  • 使用Python3对解包后内容进行解析。
  • 对资源进行汉化处理。
  • 使用AnimED对解包后内容重新打包。(也崩溃了)
  • 使用Python3对解包后内容重新打包。

BGI2_Archive解包

这是汉化文本的第一步,过程如图。
notion image
BGI2_Arc解包
解压出来的都是解密后的文件。
对此我曾尝试用Python来编写解包工具,arc文件解析出来了,能正常解包。
但是里面的文件都被DSC算法(可能是buriko的独家算法)加密了,由于我能力不足,对此没辙了。
虽然AnimED是开源的(delphi写的,pascal语言),我去看了下dsc算法的方法,试着用python抄了下来,可是解析失败,细节太多了,于是就放弃了。

BGI2_Script解析

这就是汉化文本的关键了。游戏的所有文本都存放在这个脚本里面。
看到AnimED里有个Script Tool,我天真的以为这玩意能解析脚本,结果一点,然后就没有然后了,TM的单纯是个按钮。

BGI2_Script结构

使用010editor进行分析。
notion image
BGI2_Script格式

BGI2_Script指令

还是使用010editor进行分析。
经过一番痛苦的猜测,测试,已知指令如下:
  • keycommand id
  • value[‘param’]参数数量

BGI2_Script数据

BGI2_Script主要包含指令数据以及文本数据(包含BSB)。

指令数据

首先按结构图的结构从开始读到Package List,读完List,取得当前位置为code_pos
读取Command Code - head,参数一为未知,参数二为code_foot_position
然后按照前面的指令字典,从当前位置一直读到code_foot_positioncode_body部分就解析完成了。
code_body部分解析完成时,当前stream的位置必须与code_foot_position相等,否则这个文件也许不是剧本的脚本。
然后开始读code_foot部分,方法和读code_body一样。
顺便读取BSB其实这个没用,重新封包加上)。

文本数据

然后根据之前读取到的command,筛选出command id为3的command(使用文本的命令)。
再在筛选出的内容里筛选出翻译的内容。
这buriko是真的操蛋,文件路径都在里面,否则就不用筛选了。
  • 角色谈话文本的下一位Command id一般为320(40 01 00 00)
  • 角色名称文本的Command在角色谈话文本之前。
  • 角色线路选项文本的下一位Command id一般为9(09 00 00 00),下两位为2(02 00 00 00)
  • 错误文本在code_foot里,下一位Command id一般为249(f9 00 00 00),下两位为244(f4 00 00 00)
符合以上条件的文本都需要翻译(translate)。
我筛选的方法如下:

BGI2_Archive封包

还是还是使用010editor进行分析。
Archive的结构是十分的简单,如下图所示。
notion image
BGI2_Script格式
由于过于简单,不做解释。

程序修改

绕过检测

由于原程序是japan only的,所以实际上我们并不能运行。

方法一

使用ollydbg对原程序进行修改。
按下ctrl+n,在弹出的api列表中寻找GetSystemDefaultLangID,然后按Enter查找调用位置。
notion image
OD修改语言区域_1
在简体中文环境下,GetSystemDefaultLangID 返回值是 0x804,而在日语环境下,返回值是 0x411。 按空格对代码进行修改,直接返回0x411
修改前:
notion image
OD修改语言区域_2
修改后:
notion image
OD修改语言区域_3
右键模块窗口,对修改进行保存:
notion image
OD修改语言区域_4

方法二

使用apihook对程序进行注入。
用易语言编写一个动态链接库,在启动时把KERNEL32GetSystemDefaultLangID给hook掉,修改返回值为1041(0x411)
当然,也可以用C/C++来写这个动态链接库,只是我不会而已
然后使用LordPE进行静态注入,即把该dll添加到程序的入口(随便做个方法就好,比如我这是test),这样程序运行时便会自动被dll把api hook掉。
notion image
LordPE注入

修改文本显示

虽然前面的资源汉化了,但是程序本身是日文环境的,读取汉化资源就会导致乱码,所以就要做以下的修改。

修改编码

由于我并不熟悉OD,所以只能以hook的方式来修改。
和之前的hook同理,这次hook的方法是以下两个:
  • GDI32CreateFontA,把fdwCharSet参数修改为134(0x86),同时可以在此处hook字体的参数,做个配置项,就可以随时更换字体了。
  • KERNEL32MultiByteToWideChar,把CharSet参数修改为936(0x3A8)
以上方法任一没有hook,都会导致乱码。

修改字符边界

编码修改了,但是程序还是乱码,这是由于字符边界的关系,把某些字符过滤掉了。
  • gbk字符边界: 0x80-0xFE
  • shift_jis字符边界:0x80-0xA0
这里需要使用OD对程序进行修改。
按下ctrl+f进行搜索,内容为cmp al,0xA0
然后把所有见到的cmp al,0xA0都修改成cmp al,0xFE
这样子程序就能正常加载gbk编码的资源了。

退出崩溃

由于进行了hook,程序退出的时候,hook找不到原来的地址发生了崩溃。
由于能力不足,没法从源头解决。所以我选择把这个问题堵掉。
还是hook,这次把USER32DestroyWindow hook掉,当destroy的句柄为游戏的窗口时,强制把自身的进程杀掉,于是关闭就不会崩溃了,嗯,完美

下一篇

使用"hexo+github pages"免费整个博客

Loading...