查看原文
其他

Galgame汉化中的逆向 (一):文本加密(压缩)与解密

devseed 看雪学院 2021-03-06

本文为看雪论坛优秀文章

看雪论坛作者ID:devseed





0x0 前言


看到关于游戏汉化相关的逆向教程挺少的,作为某汉化组的成员也帮过别的汉化组,于是就想把我见到的几个典型的例子整理分析一下,还是挺有意思的。此教程和我在贴吧和隔壁发的一样。





0x1 观察与定位


这个游戏还是很典型的,cpk 封包,文本应该在 sn.bin 里面。


打开一看没有明显的字符,而且数据看起来很紧凑,应该是压缩或者加密了。


 

相比与主机游戏 ida 费劲的静态分析,pc 动态调试真是太舒服了。


找文本很简单,等游戏运行起来后直接暂停,搜索内存 sjis 字符串。比如说“椿子”。


然后记住这个地址(或附近的某个),下硬断点 write,重新启动游戏运行,游戏中断在这里。






0x2 解密函数观察


然后顺腾摸瓜,我们能看到了解密函数,只不过这个游戏奇怪,用了 eax 和 ecx 传参(之后分析这个应该是指向了全局变量)。


进一步分析发现 eax 应该是解密后的缓冲区,ecx 是 sn.bin 文件缓冲区。

这里提取解密后的文本可以直接 memdump 了。


其实汉化游戏我们甚至可以不管它用了什么加密,直接 hook 这里然后替换为其他缓冲区。


但是这样就没有分析的意义了,为了练习和游戏封包兼容性,我们最好还是要去分析算法。







0x3 反汇编初步分析


怎么进行反汇编?


方便的办法是直接用 ida 的 f5,但是这里我不想太依赖插件,就去直接看汇编代码了。


如果写汇编程序不多的可以先用c语言写一个接近汇编的版本,测试结果正确后,然后再从这个版本中继续写一个接近于人写的程序(合并中间变量,改变量名),这样就方便逆向算法了。


用接近汇编的c语言如下:


#include <stdio.h>#include <stdlib.h>#include <string.h> typedef unsigned int DWORD;typedef unsigned char BYTE; size_t decrypt_asm(BYTE* dst, BYTE *src, size_t src_size) //445f40, dst=eax, src=ecx{ BYTE *buf=(BYTE*)malloc(3*src_size); //6975F28 BYTE *edi = src; BYTE *esi = dst; DWORD t1, t2, t3; //[ebp-4], [ebp-8], [ebp-c] DWORD eax, ebx, ecx, edx; ebx = *(DWORD*)edi + (DWORD)esi; //edge t2 = ebx; edi += 4; memset(buf, 0, 0xFEE); eax = 0XFEE; edx = 0; while(1) { edx >>= 1; t1 = edx; if (!(edx & 0x100)) // 00 01 { edx = *edi; edi++; edx |= 0xff00; t1 = edx; } ecx = *edi; if ((BYTE)edx & 1) { buf[eax] = (BYTE)ecx; eax++; *esi = (BYTE)ecx; esi++; edi++; eax &= 0xFFF; if(esi >= ebx) { free(buf); return (size_t)(ebx-(DWORD)dst); } } else { edx = *(edi+1); ebx = (edx & 0XF0)<<4; ecx |= ebx; edx &= 0xF; ebx = edx+ecx+2; edi += 2; t3 = ebx; ebx = t2; edx = ecx; if(ecx>ebx) { edx = t1; continue; } do{ ecx = edx & 0xFFF; ecx = buf[ecx]; buf[eax] = (BYTE) ecx; eax ++; (*esi) = (BYTE) ecx; esi++; eax &= 0XFFF; if(esi >= ebx) { free(buf); return (size_t)(ebx-(DWORD)dst); } edx++; } while (edx<=t3); edx = t1; } }}





0x4 算法进一步分析


初步分析后,我们大概熟悉了算法流程。


然后可以用c语言写一个人能理解的版本了:


size_t decrypt(BYTE* dst, BYTE *src, size_t src_size){ BYTE *buf=(BYTE*)malloc(0x1000); BYTE *cur_src = src; BYTE *cur_dst = dst; BYTE *end_dst = (DWORD)cur_dst + *(DWORD*)cur_src; DWORD idx_buff, i, last, c1, c2; cur_src += 4; memset(buf, 0, 0xFEE); idx_buff = 0XFEE; c1 = 0; //index byte while(1) { c1 >>= 1; if (!(c1 & 0x100)) // c1 bit[9] is 0, it means do 8 times { c1 = *cur_src; c1 |= 0xff00; //make a mark, and to 16bit cur_src++; } if ((BYTE)c1 & 0x1) //copy to buf directly { buf[idx_buff] = *cur_src; *cur_dst = *cur_src; idx_buff++; idx_buff &= 0xFFF; //cicle buffer cur_dst++; cur_src++; if(cur_dst >= end_dst) { free(buf); return (size_t)((BYTE*)end_dst - dst); } } else { c2 = *(cur_src+1); //index byte2 i = *cur_src | ((c2 & 0XF0)<<4); //use c1 and c2 (higher 4bits) to determine index last = (c2 & 0xf) + i +2; // length = c2 lower 4bit, 2 without length 2 chars cur_src += 2; //c1, c2 two index byte if(i > end_dst) { continue; } do { buf[idx_buff] = buf[i & 0xFFF]; *cur_dst = buf[i & 0xFFF]; idx_buff++; idx_buff &= 0xFFF; cur_dst++; if(cur_dst >= end_dst) { free(buf); return (size_t)((BYTE*)end_dst - dst); } i++; } while (i <= last); } }}


并且可以总结出怎么来解密文本了。


sn.bin 结构

0x0 size 4
0x4~ data


data 部分第一字节为索引,每一位代表当前 byte 的状态。

索引为1:直接 copy 当前 byte 到环状缓存区

索引为0:则表示当前 byte 和下一个 byte 是索引,高12位为位置,低4位为长度。

环状缓存区大小0x1000,起始位置0xFEE。

 

顺便说一下位运算充当循环遍历的方法吧:
a = 0b0011111, a>>1需要移位5次a=0,则循环次数是5。

 

测试一下文本没问题:






0x5 后记


之前在分析 psv 版 ida 看了半天也没有找到文本位置。


psv 的 ida loader 真的不好用,好多函数识别不出来,字符串也无法定位,ps4 版还稍微好点,至少 x64 比 arm 汇编看着要舒服。所以这次来分析一下 pc 版文本。


定位还算简单,然后又稍微逆向了一下算法,还算比较容易。


iwaihime psv eboot:



 

iwaihime ps4 eboot:


 

其实对数据比较敏感的看到 0x1000,0XFEE 就知道这其实不是加密,就是LZSS 的压缩,游戏里就是原封不动地把源码复制过去了。


我分析完算法后还以为是变种的 RLE 结果,再仔细想想竟然就是 LZSS,以前只是简单了解,这次逆向算法后基本上对 LZSS 有了更深刻的了解了。




- End -




看雪ID:devseed

https://bbs.pediy.com/user-259962.htm

  *本文由看雪论坛 devseed 原创,转载请注明来自看雪社区。




推荐文章++++

* Youpk: 又一款基于ART的主动调用的脱壳机

* 新手系列教程——用bfinject脱壳、注入自己的动态framework、cycript的使用

* 新手教程——按键精灵脚本来模拟合成灯笼

* RCTF 2020逆向Cipher

* ELF文件格式解析器 原理 + 代码









好书推荐






公众号ID:ikanxue
官方微博:看雪安全
商务合作:wsc@kanxue.com



“阅读原文”一起来充电吧!

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存