ZLIB deflate [word] ::0028CC2C : :0068E02C ADLER32和CRC32应该是用来校验文件的,我们先不管。ZLIB这个是游戏资源包压缩很 常用的压缩算法,而且压缩后的文件开头的标志就是78 90,所以可以确定这个游戏是先用zlib算法将文件压缩,然后放到一个大文件(PAK)中的。 接下来就该od+ida分析文件结构中还没有搞明白的地方。od载入游戏的主程序,先 Ctrl+N查看下游戏都调用了哪些跟文件有关的API,经过一番查找发现调用了 CreateDirectoryA、CreateFileA、ReadFile、SetFilePointer、WriteFile 几个api。先都下上断点, 然后f9,程序断在createFile上,从堆桟上看参数如下: 0012F5A4 0061A407 /CALL to CreateFileA from NyxQuest. 0061A405 0012F5A8 0012F7C8 |FileName = 〃DataPC/DataCommon.pak〃 0012F5AC 80000000 |Access = GENERIC_READ 0012F5B0 00000003 |ShareMode = FILE_SHARE_READ|FILE_SHARE_WRITE 0012F5B4 0012F5D0 |pSecurity = 0012F5D0 0012F5B8 00000003 |Mode = OPEN_EXISTING 0012F5BC 00000080 |Attributes = NORMAL 0012F5C0 00000000 \hTemplateFile = NULL Ctrl+F9返回,到ida中看一下这个地方做了些啥,结果发现这个地方很复杂 ![]() 查看下函数名,发现这里是c的库函数,_tsopen_nolock,既然如此就不在这里浪 费力气了,继续ctrl+F9 N次,并在ida中观察函数的名字,发现程序其实调用的是fopen, 并且还发现下面有fseek、ftell、rewind,但是并没有发现fread,所以继续F9,然后会 在SetFilePointer上中断三次,分别是fseek、ftell、rewind调用的,继续F9,就会中断到ReadFile上,这个就应该是fread调用的了,然后Ctrl+F9返回多次,找到是在004317M 处调用的fread。 分别在fopen、fseek、ftell、rewind、fread上下断点,并把在api上的断点去掉, 重新载入游戏,F9运行。中断到了 fopen上,从参数可以看出是以“rb”的方式打开了 “DataPC/DataCommon.pak”。ctrl+F9,发现返回值是006C6C60h,记下这个值,然后继续 F9,中断到了 fseek,从堆栈看参数是 0012F700 0043170D RETURN to NyxQuest. 0043170D from NyxQuest. 005F5370 0012F704 006C6C60 NyxQuest. 006C6C60 0012F708 00000000 0012F70C 00000002 还原成 C 就是 fseek(0x006C6C60,0, SEEK_END); 可以看出是将DataPC/DataCommon.pak的指针移动到了文件最后。继续F9中断到了 ftell, 参数是: 0012F708 0043171F RETURN to NyxQuest. 0043171F from NyxQuest. 005F5278 0012F70C 006C6C60 NyxQuest. 006C6C60 还原成 C 就是 fteN(0x006C6C60); 这个函数是返回当前文件指针的位置的,ctrl+F9发现返回值是013DD0C0h,用Winhex打开datapc/DataCommon.pak,发现指向的是文件末尾,这里应该就是确定下前面的fseek,是不是把指针设置到了文件的末尾,没有什么用,继续F9,中断到了rewind,参数是: 0012F708 0043173A RETURN to NyxQuest. 0043173A from NyxQuest. 005F5015 0012F70C 006C6C60 NyxQuest. 006C6C60 这个函数又将文件的指针设置回了文件开头(有意思么? ?)。 继续F9,在Fread上断下来了,参数如下: 0012F8F4 004317AF RETURN to NyxQuest. 004317AF from NyxQuest. 005F4FBD 0012F8F8 0012FAA4 ;将读取的东西放到这个缓冲区 0012F8FC 00000001 ;sizeSl,以字节为单位读取的 0012F900 00000020 ;读取的大小为20h字节 0012F904 006C6C60 NyxQuest. 006C6C60 ;读取的是前面fopen打开 的 DataCommon. oak Ctrl+F9,然后在00的内存窗口看下0012FAA4位置到底读了些什么,结果发现就是我们定义为HEAD结构体的部分。继续F9,又中断到了fseek,参数如下: 0012F8F8 00431828 RETURN to NyxQuest. 00431828 from NyxQuest. 005F5370 0012F8FC 006C6C60 NyxQuest. 006C6C60 0012F900 013D4F60 0012F904 00000000 还原成 C 就是 fseek(0x006C6C60, 0x013D4F60, SEEK_SET); 在winhex里面看看这个0x013d4f60位置是什么,结果发现是第一个文件名的开头。那么这个值是如何来的呢?我们在IDA中逆着向上看,发现这个值有可能从两个地方来,用 OD在0x00430621这个跳转处下断点,重新载入,看一下到底是执行了哪个分支,结果发 5见跳转并没有执行,所以这个值是00430627 . E8 C40A0000 CALL 004310F0这条指令调用的函数的返回值,然后在下面经过多次传递后又乘以12011所得到的。这个函数是有 一个参数,从od中看这个参数是一个指针,指向读取到内存中的pak文件的偏移018处的一个DWORD,也就是head中的第三个dword,而这个函数的作用就是将这个值每个字节从后往前排,并把得到的值返回(感觉好乱啊)。举个例子,比如DataCommon.pak的HEAD中的第三个双字在WinHex中看是00 00 00 73,经过转换之后就是73 00 00 00 (这个转换是 在01 00430627处调用一个函数转换的),在程序中读取后就是73h乘以12011就是801611 而DataExt.pak中的这个位置是00 00 03 D7,转换后就是D7 03 00 00,在程序中读取后 就是3D7h,乘以120h就是451E0ho |