最近遇到一些游戏使用yu-ris引擎制作,估计不少同学和我一样在拆包汉化的过程中遇到了严重的问题如:
提取出的ybn文件都是乱码
解密后的ybn文件依然是一堆乱码
客户端显示的中文都是乱码
接下来我们一条一条来解决,为了避免图片失效,我尽量只使用文字
一、提取出的ybn文件都是乱码
大家应该都知道ybn是加密文件,而加密方法其实很简单就是拿加密表进行异或计算,算法也不难,首先我们要了解ybn文件的结构(以下所有单位均为字节),我们这里使用473版本的ybn文件,其他版本大同小异,可以使用010Editor查看
索引头固定32Byte,应该所有版本都一样:
0-4:固定为ystb,只要处理形如:yst0000x.ybn的文件,除此之外别动
4-8:文件版本
8-12: 函数数量
12-16:函数区字节数,每个函数4字节[byte,byte,byte,byte]->[未知,参数个数,0,0]
16-20:参数区字节数,每个参数12字节[long,long,long]->[未知,字符串长度,偏移地址]
20-24:字符串区字节数,没有固定长度
24-28:未知数据区大小
28-32:全零
函数区大小:函数数量*4
参数区大小:参数数量*12,参数数量并没有直接给出,可以自己算一下
未知区大小:我们不用管他
接下来就是对每个区域的数据分别进行异或操作,而常用的异或表有3种
BYTE dec_tbl0[4] = { 0x80, 0x80, 0x80, 0x80 };
BYTE dec_tbl1[4] = { 0x07, 0xb4, 0x02, 0x4a };
BYTE dec_tbl2[4] = { 0xd3, 0x6f, 0xac, 0x96 };
这些是我从crass源代码摘出来的,基本上最后一个是目前最常使用的版本
具体算法可以参考:损疾 给的教程,为了方便大家调试我用python3写了一个版本:
def create_head_ystb(data:bytes):
header = {
'magic_8*4':data[:4].decode(),
'version_32':0,
'data1_length_div_4_32':0,
'data1_length_32':0,
'data2_length_32':0,
'data3_length_32':0,
'data4_length_32':0,
'reserved_32':0
}
if header['magic_8*4'] != 'YSTB':
return None
cnt = 1
for key in header:
if key == 'magic_8*4':
continue
header[key] = int.from_bytes(data[cnt*4:cnt*4+4],byteorder='little')
cnt += 1
return header
def decode_473(file_name):
dec_tbl2 = [ 0xd3, 0x6f, 0xac, 0x96 ]
with open(file_name, 'rb') as f:
data = f.read()
header = create_head_ystb(data)
print(header)
if not header or header['magic_8*4'] != 'YSTB':
print('未知文件:', file_name)
return None
header_byte = data[:32]
data = list(data)
data1_pointer = 32
for i in range(header['data1_length_32']):
ch = data[data1_pointer+i]
ch ^= dec_tbl2[i&3]
data[data1_pointer+i] = ch.to_bytes(1, 'little')
data2_pointer = 32 + header['data1_length_32']
for i in range(header['data2_length_32']):
ch = data[data2_pointer+i]
ch ^= dec_tbl2[i&3]
data[data2_pointer+i] = ch.to_bytes(1, 'little')
data3_pointer = data2_pointer + header['data2_length_32']
for i in range(header['data3_length_32']):
ch = data[data3_pointer+i]
ch ^= dec_tbl2[i&3]
data[data3_pointer+i] = ch.to_bytes(1, 'little')
data4_pointer = data3_pointer + header['data3_length_32']
for i in range(header['data4_length_32']):
ch = data[data4_pointer+i]
ch ^= dec_tbl2[i&3]
data[data4_pointer+i] = ch.to_bytes(1, 'little')
data = header_byte + b''.join(data[32:])
return data
用法:传入需要解密的文件地址,然后函数返回解密后的二进制Bytes串,保存后就可以看到解密后的文件。
二、解密后的ybn文件依然是一堆乱码
我们打开解密完的ybn文件,发现里面依然是一堆乱码,但是同时一些日文也显示了出来,原因是ybn文件和krkr的ks文本文件完全不一样,ybn由以下过程产生:
1)yu-ris引擎读取data/scripts文件夹。
2)把文件夹交给system/ YSCom/ YSCom.exe打包编译成二进制文件。
3)把刚刚打包好的文件切割成许多ybn文件放入ysbin文件夹。
4)yu-ris执行ysbin文件夹内的ybn。
ybn文件本质上是被打碎的压缩包,所以不会像其他引擎的脚本文件一样直接就能看到脚本,而我到现在也没有找到可以把ybn文件还原成scripts文件夹的工具,因此汉化只能把ybn文件夹内可以看到的日文翻译成中文,替换的时候一定要注意参数的长度和地址要重新对齐,索引头的字符串区长度也要修改,(这个过程只能由程序来完成,所以需要一定的编程能力)中文使用的字符串一定是gb2312,不能Unicode,下面会讲为什么。
三、客户端显示的中文都是乱码
Yu-ris引擎只支持shift-jis编码,因此中文肯定都是乱码,一个解决方法是使用大佬汉化过的yu-ris但是我看到几乎所有的地址都失效了。我也下了汉化游戏的执行程序(女装山脉、EUPHORIA)但是在我电脑上都运行不了(估计能运行也不通用),唯一的办法就是按照:损疾 的那篇教程修改exe文件,核心步骤就两个:1)修正CharSet 0x86 。2)修改检查表,我说一下使用x32dbg定位这两个部分的要点
修正CharSet 0x86:
找到gdi32.CreateFontIndirectA 这个函数的引用位置,直接就是需要修改的目标位置,修改成如下形式
00437D14 8B15 3CC55A00 mov edx, dword ptr [5AC53C]
00437D1A 8B3495 3CD87D00 mov esi, dword ptr [edx*4+7DD83C]
00437D21 83C6 17 add esi, 17
00437D24 C606 86 mov byte ptr [esi], 86
00437D27 90 nop
00437D28 90 nop
00437D29 90 nop
00437D2A 90 nop
00437D2B 90 nop
00437D2C 90 nop
00437D2D 90 nop
00437D2E 90 nop
00437D2F 90 nop
00437D30 A1 3CC55A00 mov eax, dword ptr [5AC53C]
00437D35 FF3485 3CD87D00 push dword ptr [eax*4+7DD83C]
00437D3C FF15 38805600 call dword ptr [<&GDI32.CreateFontInd>; gdi32.CreateFontIndirectA
修改检查表:
这个找起来有点麻烦,折腾了我一个下午,主要技巧就是搜索ysbin\ysc.ybn 这个字符串(可能有好几个,随便点一个就行),跳转到引用位置,往下翻可以看到这样一堆代码
.text:0045B5F0 mov dword_7A8E98, offset loc_44B710
.text:0045B5FA mov dword_7A8EA0, offset sub_445624
.text:0045B604 mov dword_7A8E9C, offset sub_445624
.text:0045B60E mov dword_7A8EA4, offset sub_445624
.text:0045B618 mov dword_7A8EAC, offset loc_44B7DC
.text:0045B622 mov dword_7A8EB0, offset off_44CDE4
.text:0045B62C mov dword_7A8EB4, offset off_44CE0C
.text:0045B636 mov dword_7A8EB8, offset loc_44CE2C
.text:0045B640 mov dword_7A8EBC, offset sub_44DDE4
………
这是一个定义结构体的代码,翻倒最后的位置,从下往上找和 损疾 帖子里最后给出的一大串汇编代码一个一个对照,倒数10个以内可以找到找到负责访问检查表的函数,跳转到函数位置往下翻,找到如下位置:
0044A57C > 0FB6741D 00 movzx esi, byte ptr ss:[ebp+ebx] ; 取要判断的字的一个字节
0044A581 . 0FB68E A0F058>movzx ecx, byte ptr ds:[esi+58F0A0]
0044A588 . 0FBEF1 movsx esi, cl ; esi, 将会记录是否32h,31h
0044A58B . 8B78 4C mov edi, dword ptr ds:[eax+4C]
其中58F0A0 就是检查表的位置,不同的版本数字不一样,在内存区跳转后看到:
005B20A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
005B20B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
005B20C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
005B20D0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
005B20E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
005B20F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
005B2100 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
005B2110 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
005B2120 00 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 ................
005B2130 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 ................
005B2140 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
005B2150 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
005B2160 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
005B2170 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
005B2180 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 ................
005B2190 01 01 01 01 01 01 01 01 01 01 01 01 01 00 00 00 ................
005B21A0 00 00 00 00 96 30 07 77 2C 61 0E EE BA 51 09 99 .....0.w,a.îºQ..
005B21B0 19 C4 6D 07 8F F4 6A 70 35 A5 63 E9 A3 95 64 9E .Äm..ôjp5¥cé£.d.
把两个01串中间的00填充成01就可以了,如果使用的是x32dbg右键->补丁->修补文件就能保存exe。
最后我使用venus社的游戏(466版本): さまぁ☆ソルト进行了验证,可以显示中文,但是所有的日文将变成乱码,同时只支持gb2312,不过修改上面的86h似乎可以实现其他编码的显示,我还没有尝试过。
参考资料:
[1] 损疾https://www.cnblogs.com/sunjicccc/archive/2013/01/02/2841956.html
[2] flandrehttps://flandre-scarlet.moe/blog/629/
[3] 官网http://yu-ris.net/