首页
论坛
专栏
课程

[商业保护] [原创]单刀逆向分析某网游资源解压过程

2012-7-24 09:55 7537

[商业保护] [原创]单刀逆向分析某网游资源解压过程

2012-7-24 09:55
7537
疑似标识文件头:whzlib, 2003
文件组成:
1.nam文件(ANSI编码,使用Windows-936可正常显示)
2.idx文件
3.dat文件

推测分别为文件名、索引及具体数据。
包含有mesh(pmf文件,模型)、Texture(tga文件,材质)、Animation(paf文件,动画)、Skeleton(psf文件,骨骼)

选取较小的PM.nam(idx,dat)文件进行分析。
其中文件大小分别为:
PM.nam 2135字节
PM.idx 4387字节
PM.dat 236,701字节

PM.nam 总共包含文件名 128个+1个空文件占位=129个文件

.nam
文件头两字节,01表示文件,02表示进入路径,03表示离开路径
数据格式=1字节文件名长度+文件名+0x00结尾
示例:
文件头 00000000h: 01 00                                           ; ..
数据            00000002h: 0C 33 44 4D 6F 64 65 6C 2E 74 78 74 00          ; .3DModel.txt.
                   0000000fh: 0F 41 63 74 69 6F 6E 6C 69 73 74 2E 74 78 74 00 ; .Actionlist.txt.
                   ...

.idx
文件头97字节,示例:
00000000h: 77 68 7A 6C 69 62 2C 20 32 30 30 33 00 00 00 00 ; whzlib, 2003....
00000010h: 02 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 ; ................
00000020h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
00000030h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
00000040h: 02 00 00 00 00 01 BA 00 00 00 00 00 00 00 00 00 ; ......?........
00000050h: 00 00 00 00 00 00 00 00 00 9F 00 00 00 05 01 00 ; .........?.....

数据固定长度33字节,示例:
00000060h: 00 01 02 00 00 00 EA E0 E4 4C F2 3A 93 89 2B 62 ; ......赅銵?搲+b
00000070h: 50 91 85 B6 2D 4F A3 BC 8E 6B 00 00 00 00 7F 5F ; P憛?O<巏...._
00000080h: 00                                              ; .
占位数据33字节,示例:
1.
00002205h: 00 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
00002215h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
00002225h: 00 00                                           ; ..
2.
000003bbh: 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
000003cbh: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
000003dbh: 00                                              ; .

因此包内含有文件数目可用如下公式计算:
文件总数=(文件字节数-97)/33 - 占位数据条数
示例mb.idx = (8743-97)/33 - 4 = 258个文件(路径名也视为一个文件)
实际文件数目应为258-路径数

索引数据格式推测:
00000082h: 01 0F 00 00 00 31 5F AD 4D CD 48 C2 26 C5 04 D2 ; .....1_璏虷???
00000092h: 04 AB 33 8D 59 E3 20 79 40 5C 10 00 00 C4 08 00 ; .?峐?y@\...?.
000000a2h: 00                                              ; .
取出倒数8个字节
为 5C 10 00 00 C4 08 00 00
其中5C 10 00 00为dat文件中的索引位置
推测C4 08 00 00为解压后的文件大小,即十进制2244字节
----字节存放方式为大尾法----
索引位置5~24疑为20字节的SHA1信息摘要
00000087h: 31 5F AD 4D CD 48 C2 26 C5 04 D2 04 AB 33 8D 59 ; 1_璏虷????峐
00000097h: E3 20 79 40                                     ; ?y@

索引位置0~4字节提取:
00000061h: 01 02 00 00 00                                  ; .....
00000082h: 01 0F 00 00 00                                  ; .....
000000a3h: 01 1F 00 00 00                                  ; .....
000000c4h: 01 2D 00 00 00                                  ; .-...
000000e5h: 01 42 00 00 00                                  ; .B...
00000106h: 01 4E 00 00 00                                  ; .N...
...
...
00002182h: 01 AC 0F 00 00                                  ; .?..
000021a3h: 01 C8 0F 00 00                                  ; .?..
000021c4h: 01 D8 0F 00 00                                  ; .?..
000021e5h: 01 E5 0F 00 00                                  ; .?..
疑似为nam中的文件名位置索引!!!!
首字节可能值为 01 02 03 ,推测01表示正常文件,02表示进入下一路径,03表示返回上一路径

.dat
前25字节为数据头信息,其中最后4字节表示raw data size,无分段前21字节固定为:
00000000h: 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
00000010h: 00 00 00 00 01                                  ; .....

0000105ch: 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
0000106ch: 00 00 00 00 01                                  ; .....

多块段举例(29字节):
00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 B0 14 00 00 01 AB 14 00 00

00 02 表示分段数,后接18字节00(保留位),然后是压缩标志,'0x01'表示数据已压缩,如此处为0则表示未压缩,然后是分段长度,此例中00 00 14 AB即第一段长度,00 00 14 B0位置为第二段起始偏移,
但第二段的数据长度保存在偏移14B0-5 ~ 14B0中。(举例:01 DA 0A 00 00)
00 00 0A DA即为第二段的数据长度。

提出出来的原始数据无法用zlib解压,推测可能经过了加密,只能进到OD里跟,原程序加了vmp壳,用特制OD即可调试。
其实这里有两种方案,一种是hook,一种是完全逆推,可我前面费了那么大劲,到头来还是用的hook未免太丢脸了,所以。。。继续把。
先用ximo大大的Zeus把vm_return跑出来,下断此处,F9几下即可看到内存区原程序数据已经还原了,下断CreateFile,注意堆栈区,F9可以一步一步看到其打开文件的顺序。
打开顺序是idx->dat->nam,等到打开了需求数据组的.nam文件之后,下断到ReadFile,回主线程,大致看了下数据的还原过程,很简单,基本没什么技术含量。
解密用了如下操作:1. 按字节XOR 一个字符串 2.DES ECB解密(需要找出8字节密匙) 3. zlib解压
1和2的代码如下:
        /* 简单的异或解密 */
        char xorkeyword[16]="shuangjianhebing" ;
        unsigned long b_step = 0 ;
        unsigned int key_step = 0 ;
        for (b_step = 0; b_step < raw_size; ++b_step){
            raw_data[b_step] ^= xorkeyword[key_step++] ;
            key_step = (key_step >= 16) ? 0 : key_step ;
        }
       /* 以下开始DES解密 */
        unsigned long des_size = 0 ;
        unsigned char* des_data = NULL;
        unsigned char* cpy_data = NULL;

        des_size = ((long)(raw_size/8))*8 ;
        des_data = malloc(des_size) ;
        cpy_data = malloc(des_size) ;
        if (des_data !=NULL && cpy_data !=NULL){
            memcpy(des_data,raw_data,des_size) ;

            DES_cblock key= {'\x12','\x06','\x1d','\x04','\x0c','\x0e','\x04','\x0e'} ;
            DES_key_schedule keysched;
            DES_set_key((C_Block *)key, &keysched);
            unsigned int temp_step = 0;
            for (temp_step = 0 ; temp_step < (des_size / 8) ; ++temp_step)
                DES_ecb_encrypt((C_Block *)(des_data+temp_step*8),(C_Block *)(cpy_data+temp_step*8), &keysched, DES_DECRYPT);

            memcpy(raw_data,cpy_data,des_size) ;
        }
        else{
            free(raw_data) ;
            free(des_data) ;
            free(cpy_data) ;
            error("\n错误:分配内存失败!") ;
        }

        free(des_data) ;
        free(cpy_data) ;
        /*DES解密完成*/
这里DES解密是直接使用的openssl(神器啊),然后对数据用zlib解压就可以了,只是有些文件分段较多,解压后拼起来。

其实我想说虽然记录出来内容不多,但也花了我前前后后一个多星期的时间,哪里不会学哪里,so easy!
PS:最开始我只是想从游戏资源里解压出自己喜欢的原版音乐,到最后把整个游戏资源全解压出来了,2g多文件,是不是有点得寸进尺了。。。。

[公告][征集寄语] 看雪20周年年会 | 感恩有你,一路同行

最新回复 (4)
lookzo 2012-7-24 13:33
2
0
膜拜,资源解密
游戏神通 2012-9-25 13:37
3
0
破解资源是一个蛋疼的过程
hudouhudou 2012-10-16 08:30
4
0
希望LZ大神提供个工具什么的,我等菜鸟不会写啊,泪奔~~
zphdt 2012-10-16 09:03
5
0
有图片的话就好了啊。
游客
登录 | 注册 方可回帖
返回