欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  网络运营

单刀逆向分析某网游资源解压过程

程序员文章站 2022-04-22 10:59:30
疑似标识文件头:whzlib, 2003 文件组成: 1.nam文件(ANSI编码,使用Windows-936可正常显示) 2.idx文件 3.dat文件   推测分别为...
疑似标识文件头: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多文件,是不是有点得寸进尺了。。。。

作者 龙之冰点