电脑里寄存了一堆ANIM游戏没玩了,为了减少通关耗时我尝试汉化了一下这个引擎
主要有三步
- 1.解密文本包
- 2.汉化exe
- 3.插入中文并加密文本包
1. 解密文本包
文本就是一个dat文件,文件命一般为 {game}_sce.dat,所有的文本就在一个文件里,不需要拆解,尝试解密,打开x32dbg,追了半天定位到解密模块
0045E79F | 85 C0 | test eax,eax |
0045E7A1 | 74 0A | je kabetuma.45E7AD |
0045E7A3 | B8 0A 00 00 00 | mov eax,A | A:'\n'
0045E7A8 | E9 B9 00 00 00 | jmp kabetuma.45E866 |
0045E7AD | C7 45 E4 00 00 00 00 | mov dword ptr ss:[ebp-1C],0 |
0045E7B4 | EB 09 | jmp kabetuma.45E7BF |
0045E7B6 | 8B 4D E4 | mov ecx,dword ptr ss:[ebp-1C] | 应该在这里解密
0045E7B9 | 83 C1 01 | add ecx,1 |
0045E7BC | 89 4D E4 | mov dword ptr ss:[ebp-1C],ecx |
0045E7BF | 83 7D E4 10 | cmp dword ptr ss:[ebp-1C],10 | i < 0x10
0045E7C3 | 73 12 | jae kabetuma.45E7D7 |
0045E7C5 | 8B 55 E0 | mov edx,dword ptr ss:[ebp-20] |
0045E7C8 | 03 55 E4 | add edx,dword ptr ss:[ebp-1C] |
0045E7CB | 8B 45 E4 | mov eax,dword ptr ss:[ebp-1C] |
0045E7CE | 8A 4A 04 | mov cl,byte ptr ds:[edx+4] |
0045E7D1 | 88 4C 05 E8 | mov byte ptr ss:[ebp+eax-18],cl |
0045E7D5 | EB DF | jmp kabetuma.45E7B6 |
0045E7D7 | 8B 55 E0 | mov edx,dword ptr ss:[ebp-20] |
0045E7DA | 83 C2 14 | add edx,14 |
0045E7DD | 89 55 E0 | mov dword ptr ss:[ebp-20],edx |
0045E7E0 | C7 45 DC 00 00 00 00 | mov dword ptr ss:[ebp-24],0 |
0045E7E7 | C7 45 E4 00 00 00 00 | mov dword ptr ss:[ebp-1C],0 |
0045E7EE | EB 09 | jmp kabetuma.45E7F9 |
0045E7F0 | 8B 45 E4 | mov eax,dword ptr ss:[ebp-1C] |
0045E7F3 | 83 C0 01 | add eax,1 |
0045E7F6 | 89 45 E4 | mov dword ptr ss:[ebp-1C],eax |
0045E7F9 | 8B 4D 18 | mov ecx,dword ptr ss:[ebp+18] |
0045E7FC | 8B 55 E4 | mov edx,dword ptr ss:[ebp-1C] |
0045E7FF | 3B 11 | cmp edx,dword ptr ds:[ecx] |
0045E801 | 73 61 | jae kabetuma.45E864 |
0045E803 | 8B 45 E0 | mov eax,dword ptr ss:[ebp-20] |
0045E806 | 03 45 E4 | add eax,dword ptr ss:[ebp-1C] |
0045E809 | 0F B6 08 | movzx ecx,byte ptr ds:[eax] |
0045E80C | 8B 55 DC | mov edx,dword ptr ss:[ebp-24] |
0045E80F | 0F B6 44 15 E8 | movzx eax,byte ptr ss:[ebp+edx-18] |
0045E814 | 23 C8 | and ecx,eax |
0045E816 | F7 D1 | not ecx |
0045E818 | 8B 55 E0 | mov edx,dword ptr ss:[ebp-20] |
0045E81B | 03 55 E4 | add edx,dword ptr ss:[ebp-1C] |
0045E81E | 0F B6 02 | movzx eax,byte ptr ds:[edx] |
0045E821 | 8B 55 DC | mov edx,dword ptr ss:[ebp-24] |
0045E824 | 0F B6 54 15 E8 | movzx edx,byte ptr ss:[ebp+edx-18] |
0045E829 | 0B C2 | or eax,edx |
0045E82B | 23 C8 | and ecx,eax |
0045E82D | 8B 45 D8 | mov eax,dword ptr ss:[ebp-28] | [ebp-28]:"LdrpInitializeProcess"
0045E830 | 03 45 E4 | add eax,dword ptr ss:[ebp-1C] |
0045E833 | 88 08 | mov byte ptr ds:[eax],cl |
0045E835 | 8B 4D DC | mov ecx,dword ptr ss:[ebp-24] |
0045E838 | 83 C1 01 | add ecx,1 |
0045E83B | 89 4D DC | mov dword ptr ss:[ebp-24],ecx |
0045E83E | 83 7D DC 10 | cmp dword ptr ss:[ebp-24],10 |
0045E842 | 75 1E | jne kabetuma.45E862 |
0045E844 | C7 45 DC 00 00 00 00 | mov dword ptr ss:[ebp-24],0 | 更新key
0045E84B | 8B 55 D8 | mov edx,dword ptr ss:[ebp-28] | [ebp-28]:"LdrpInitializeProcess"
0045E84E | 03 55 E4 | add edx,dword ptr ss:[ebp-1C] |
0045E851 | 0F B6 42 FF | movzx eax,byte ptr ds:[edx-1] |
0045E855 | 50 | push eax |
0045E856 | 8D 4D E8 | lea ecx,dword ptr ss:[ebp-18] |
0045E859 | 51 | push ecx |
0045E85A | 8B 4D D0 | mov ecx,dword ptr ss:[ebp-30] |
0045E85D | E8 3E F9 FF FF | call kabetuma.45E1A0 |
0045E862 | EB 8C | jmp kabetuma.45E7F0 |
0045E864 | 33 C0 | xor eax,eax |
0045E866 | 8B 4D F8 | mov ecx,dword ptr ss:[ebp-8] |
0045E869 | 33 CD | xor ecx,ebp | 解密完成
0045E86B | E8 BE 00 00 00 | call kabetuma.45E92E |
0045E870 | 8B E5 | mov esp,ebp |
0045E872 | 5D | pop ebp |
0045E873 | C2 14 00 | ret 14 |
总结一下:
文件 4-20字节为key,之后为数据。解密方式为循环异或运算,每16次运算利用特定函数修改一下key,我用python实现了一个,自取,有bug不负责
class ANIM():
def switch_key(key: bytearray, ch: int):
t = ch
ch &= 7
if ch == 0:
key[0] = byte_add(key[0], t)
key[3] = byte_add(key[3], t, 2)
key[4] = byte_add(key[2], t, 11)
key[8] = byte_add(key[6]+7)
elif ch == 1:
key[2] = byte_add(key[9], key[10])
key[6] = byte_add(key[7], key[15])
key[8] = byte_add(key[8], key[1])
key[15] = byte_add(key[5], key[3])
elif ch == 2:
key[1] = byte_add(key[1], key[2])
key[5] = byte_add(key[5], key[6])
key[7] = byte_add(key[7], key[8])
key[10] = byte_add(key[10], key[11])
elif ch == 3:
key[9] = byte_add(key[2], key[1])
key[11] = byte_add(key[6], key[5])
key[12] = byte_add(key[8], key[7])
key[13] = byte_add(key[11], key[10])
elif ch == 4:
key[0] = byte_add(key[1], 111)
key[3] = byte_add(key[4], 71)
key[4] = byte_add(key[5], 17)
key[14] = byte_add(key[15], 64)
elif ch == 5:
key[2] = byte_add(key[2], key[10])
key[4] = byte_add(key[5], key[12])
key[6] = byte_add(key[8], key[14])
key[8] = byte_add(key[11], key[0])
elif ch == 6:
key[9] = byte_add(key[11], key[1])
key[11] = byte_add(key[13], key[3])
key[13] = byte_add(key[15], key[5])
key[15] = byte_add(key[9], key[7])
key[1] = byte_add(key[9], key[5])
key[2] = byte_add(key[10], key[6])
key[3] = byte_add(key[11], key[7])
key[4] = byte_add(key[12], key[8])
elif ch==7:
key[1] = byte_add(key[9], key[5])
key[2] = byte_add(key[10], key[6])
key[3] = byte_add(key[11], key[7])
key[4] = byte_add(key[12], key[8])
return key
def decrypt(data: bytes):
'''
key 54 C8 58 54 0A D8 CD 3C B5 EC 98 0F E6 9E F3 E8
data 1F 6C 5C 54 71 0E C9 3C FE ED DA 23 E7 9E F3 AA
ans 4B A4 04 00 7B D6 04 00 4B 01 42 2C 01 00 00 42
'''
key = bytearray(data[4:20])
data = bytearray(data[20:])
length = len(data)
v = 0
for i in range(length):
data[i] = key[v] ^ data[i]
v += 1
if v == 16:
v = 0
key = ANIM.switch_key(key, data[i-1])
return data
2.汉化exe
这个引擎的显示文字的流程是:
- logfont -> createfontindirecta -> getglyphoutline
所以把logfont内传入的0x80改为0x86就可以了
004150F2 | 85 C0 | test eax,eax |
004150F4 | 7D 05 | jge kabetuma.4150FB |
004150F6 | E9 7F 01 00 00 | jmp kabetuma.41527A |
004150FB | 8B 55 DC | mov edx,dword ptr ss:[ebp-24] |
004150FE | 89 55 C8 | mov dword ptr ss:[ebp-38],edx |
00415101 | 8B 45 C4 | mov eax,dword ptr ss:[ebp-3C] |
00415104 | C7 80 C8 3E 00 00 00 00 | mov dword ptr ds:[eax+3EC8],0 |
0041510E | 8B 4D C4 | mov ecx,dword ptr ss:[ebp-3C] |
00415111 | 8B 55 1C | mov edx,dword ptr ss:[ebp+1C] |
00415114 | 89 91 8C 3E 00 00 | mov dword ptr ds:[ecx+3E8C],edx |
0041511A | 8B 45 C4 | mov eax,dword ptr ss:[ebp-3C] |
0041511D | 8B 4D 18 | mov ecx,dword ptr ss:[ebp+18] |
00415120 | 89 88 90 3E 00 00 | mov dword ptr ds:[eax+3E90],ecx |
00415126 | 8B 55 C4 | mov edx,dword ptr ss:[ebp-3C] |
00415129 | C7 82 94 3E 00 00 00 00 | mov dword ptr ds:[edx+3E94],0 |
00415133 | 8B 45 C4 | mov eax,dword ptr ss:[ebp-3C] |
00415136 | C7 80 98 3E 00 00 00 00 | mov dword ptr ds:[eax+3E98],0 |
00415140 | 8B 4D C4 | mov ecx,dword ptr ss:[ebp-3C] |
00415143 | C7 81 9C 3E 00 00 90 01 | mov dword ptr ds:[ecx+3E9C],190 |
0041514D | 8B 55 C4 | mov edx,dword ptr ss:[ebp-3C] |
00415150 | C6 82 A0 3E 00 00 00 | mov byte ptr ds:[edx+3EA0],0 |
00415157 | 8B 45 C4 | mov eax,dword ptr ss:[ebp-3C] |
0041515A | C6 80 A1 3E 00 00 00 | mov byte ptr ds:[eax+3EA1],0 |
00415161 | 8B 4D C4 | mov ecx,dword ptr ss:[ebp-3C] |
00415164 | C6 81 A2 3E 00 00 00 | mov byte ptr ds:[ecx+3EA2],0 |
0041516B | 8B 55 C4 | mov edx,dword ptr ss:[ebp-3C] |
0041516E | C6 82 A3 3E 00 00 80 | mov byte ptr ds:[edx+3EA3],80 | 改为86h
00415175 | 8B 45 C4 | mov eax,dword ptr ss:[ebp-3C] |
00415178 | C6 80 A4 3E 00 00 00 | mov byte ptr ds:[eax+3EA4],0 |
0041517F | 8B 4D C4 | mov ecx,dword ptr ss:[ebp-3C] |
00415182 | C6 81 A5 3E 00 00 00 | mov byte ptr ds:[ecx+3EA5],0 |
00415189 | 8B 55 C4 | mov edx,dword ptr ss:[ebp-3C] |
0041518C | C6 82 A6 3E 00 00 04 | mov byte ptr ds:[edx+3EA6],4 |
00415193 | 8B 45 C4 | mov eax,dword ptr ss:[ebp-3C] |
00415196 | C6 80 A7 3E 00 00 00 | mov byte ptr ds:[eax+3EA7],0 |
0041519D | 83 7D 20 00 | cmp dword ptr ss:[ebp+20],0 |
004151A1 | 75 17 | jne kabetuma.4151BA |
004151A3 | 68 0C CE 48 00 | push kabetuma.48CE0C |
然后修改字符的边界判定,搜一下 cmp eax, 9Fh 这个命令就可以定位,把9F改为FE就可以显示中文
.text:004152F6 cmp edx, [ebp+var_8]
.text:004152F9 jge loc_415751
.text:004152FF mov eax, [ebp+lpString]
.text:00415302 add eax, [ebp+var_20]
.text:00415305 movzx ecx, byte ptr [eax]
.text:00415308 cmp ecx, 81h
.text:0041530E jl short loc_415320
.text:00415310 mov edx, [ebp+lpString]
.text:00415313 add edx, [ebp+var_20]
.text:00415316 movzx eax, byte ptr [edx]
.text:00415319 cmp eax, 9Fh ;9F改成FE
.text:0041531E jle short loc_41533D
.text:00415320
.text:00415320 loc_415320: ; CODE XREF: sub_415280+8E↑j
.text:00415320 mov ecx, [ebp+lpString]
.text:00415323 add ecx, [ebp+var_20]
.text:00415326 movzx edx, byte ptr [ecx]
.text:00415329 cmp edx, 0E0h
.text:0041532F jge short loc_41533D
.text:00415331 mov [ebp+var_B4], 0
.text:0041533B jmp short loc_415347
这个时候在文本内插入中文就可以显示了,但是注意其中全角空格会显示成乱码,所以记得搜索 81 40 都改为 A1 A1 这样全角空格就能正常显示了
3.插入中文并加密文本包
文件内没有记录每句的偏移和长度,每句以00结束,读取文本只和相对序号有关,所以替换的时候不要打乱顺序就好了。
还有一个我暂时无法解决的问题,就是替换为中文以后内容会跑到人名的后面,就像下面这样:
小明 「今
天也很开心」
应该是替换中文后人名处理函数不能正常处理文本了,我目前的解决方案是在一句话的前面加3个全角空格,把文本顶到第二行,这样勉强还能看
加密的话自己照着解密写就行了,不再赘述
网友评论