游戏包文件结构分析(2)
5.第二个例子——一个小游戏的包文件格式
下载地址:http://www.lanqie.net.cn/html/benzhanzuopin/20070604/43.html AAAKK版
包文件是安装文件夹中最大的文件Game.dat。
这个格式用到了简单的异或加密,但是文件索引表非常简单,因为没有文件夹格式。
打开文件,发现有一些文件名(1.BMP,1.WAV),而且每两个文件名的开头间隔一样,说明文件索引长度固定,为28。可以看到文件名占20字节,文件名的空白用空格(0x20)来填充。每两个文件名之间还有8个字节,即两个Int32。可以估计其中一个是文件位置,另一个是文件长度。
图2 Game.dat文件头
00000000h: 52 45 53 59 00 C2 09 00 00 88 47 03 00 4E 55 4D ; RESY.?..圙..NUM
00000010h: 2E 42 4D 50 20 20 20 20 20 20 20 20 20 20 20 20 ; .BMP
00000020h: 20 4B 51 03 00 C2 58 01 00 31 2E 42 4D 50 20 20 ; KQ..耎..1.BMP
00000030h: 20 20 20 20 20 20 20 20 20 20 20 20 20 0E AA 04 ; .?
00000040h: 00 2A 20 00 00 31 2E 57 41 56 20 20 20 20 20 20 ; .* ..1.WAV
00000050h: 20 20 20 20 20 20 20 20 20 39 CA 04 00 C0 58 01 ; 9?.繶.
00000060h: 00 32 2E 42 4D 50 20 20 20 20 20 20 20 20 20 20 ; .2.BMP
00000070h: 20 20 20 20 20 FA 22 06 00 D8 AF 02 00 32 2E 57 ; ?..丿..2.W
00000080h: 41 56 20 20 20 20 20 20 20 20 20 20 20 20 20 20 ; AV
00000090h: 20 D3 D2 08 00 C0 58 01 00 33 2E 42 4D 50 20 20 ; 右..繶..3.BMP
000000a0h: 20 20 20 20 20 20 20 20 20 20 20 20 20 94 2B 0A ; ?.
000000b0h: 00 1E 80 00 00 33 2E 57 41 56 20 20 20 20 20 20 ; ..€..3.WAV
000000c0h: 20 20 20 20 20 20 20 20 20 B3 AB 0A 00 C0 58 01 ; 倡..繶.
000000d0h: 00 34 2E 42 4D 50 20 20 20 20 20 20 20 20 20 20 ; .4.BMP
000000e0h: 20 20 20 20 20 74 04 0C 00 04 50 01 00 34 2E 57 ; t....P..4.W
000000f0h: 41 56 20 20 20 20 20 20 20 20 20 20 20 20 20 20 ; AV
00000100h: 20 79 54 0D 00 C0 58 01 00 35 2E 42 4D 50 20 20 ; yT..繶..5.BMP
00000110h: 20 20 20 20 20 20 20 20 20 20 20 20 20 3A AD 0E ; :?
00000120h: 00 18 B0 00 00 35 2E 57 41 56 20 20 20 20 20 20 ; ..?.5.WAV
00000130h: 20 20 20 20 20 20 20 20 20 53 5D 0F 00 C0 58 01 ; S]..繶.
00000140h: 00 36 2E 42 4D 50 20 20 20 20 20 20 20 20 20 20 ; .6.BMP
00000150h: 20 20 20 20 20 14 B6 10 00 08 30 01 00 36 2E 57 ; .?..0..6.W
00000160h: 41 56 20 20 20 20 20 20 20 20 20 20 20 20 20 20 ; AV
00000170h: 20 1D E6 11 00 C0 58 01 00 37 2E 42 4D 50 20 20 ; .?.繶..7.BMP
00000180h: 20 20 20 20 20 20 20 20 20 20 20 20 20 DE 3E 13 ; ?.
00000190h: 00 28 30 00 00 37 2E 57 41 56 20 20 20 20 20 20 ; .(0..7.WAV
000001a0h: 20 20 20 20 20 20 20 20 20 07 6F 13 00 C0 58 01 ; .o..繶.
000001b0h: 00 38 2E 42 4D 50 20 20 20 20 20 20 20 20 20 20 ; .8.BMP
图3 Game.dat文件索引和第一个文件结合部
00000970h: 00 C0 58 01 00 36 31 2E 42 4D 50 20 20 20 20 20 ; .繶..61.BMP
00000980h: 20 20 20 20 20 20 20 20 20 7D 9C 82 00 C0 58 01 ; }渹.繶.
00000990h: 00 36 32 2E 42 4D 50 20 20 20 20 20 20 20 20 20 ; .62.BMP
000009a0h: 20 20 20 20 20 3E F5 83 00 B7 C2 0C 00 44 41 54 ; >鮾.仿..DAT
000009b0h: 41 2E 42 4D 50 20 20 20 20 20 20 20 20 20 20 20 ; A.BMP
000009c0h: 20 42 4C 84 44 07 05 06 07 08 09 3C 0F 0C 0D 26 ; BL凞......<...&
000009d0h: 0F 10 11 02 11 14 15 83 16 18 19 1B 1B 14 1D 1E ; .......?.......
000009e0h: 1F 20 21 72 60 27 25 34 2C 28 29 38 20 2C 2D 2E ; . !r`'%4,()8 ,-.
000009f0h: 2F 30 31 32 33 34 35 36 37 38 39 3A 3B BC 3D 3E ; /0123456789:;?>
00000a00h: BF 40 41 42 C3 C4 45 C6 47 48 49 CA 4B CC 4D CE ; 緻AB媚E艷HI蔏蘉?
00000a10h: CF 50 51 92 93 94 55 96 8B 98 59 AA 91 FA 5D 5E ; 螾Q挀擴枊榊獞鷀^
00000a20h: 7F 20 61 62 43 04 65 66 47 E8 69 6A 4B CC 6D 6E ; abC.efG鑙jK蘭n
00000a30h: 4F B0 71 72 53 94 75 76 37 78 79 7A 3B 5C 7D 7E ; O皅rS攗v7xyz;\}~
00000a40h: 3F C0 81 82 C3 E4 85 86 C7 08 89 8A CB 2C 8D 8E ; ?纴偯鋮喦.墛?崕
00000a50h: CF 50 91 92 D3 74 95 96 F7 98 99 9A FB BC 9D 9E ; 螾憭觮晼鳂櫄潪
00000a60h: FF E0 A1 A2 C3 C4 A5 A6 C7 28 A9 AA CB 0C AD AE ; 唷⒚磨η(┆?
往下翻,一直翻到索引结束,如图3。
可以看到最后的文件名之后接的8个字节和前面的文件名后的8个字节不太一样。因此可以认为该格式的文件索引表中的每一个索引是文件位置和文件长度先于文件名的。
最后一个索引的结束位置是9C1h,第一个文件索引的开始位置(现在可以辨认出)是5h。每个索引的大小是28字节。可以算出共有89个索引。89的16进制写法是0x59,正好是开头第四个字节的值。而第五字节是00,所以我们可以认为这两个字节是一个16位整数(Int16)。
最开始的RES是文件类型标志。大多数文件都会有这种标志,多数长度为4和3。许多格式接下来还有版本号。
我们继续分析文件大小和文件长度。
第一个文件数据的开头位置为9C1h,而第一个文件索引的第一个Int32(5h处)是0x000009C2。转到第二个索引的第一个Int32(21h)指向的位置(0x003514B),我们可以看到文件开头是BL,和第一个文件数据的开头处一样,但是B的位置都比索引确定的位置要提前一个字节。
这里有几种理解,比如:这个字节可能是一个特殊的标志;文件索引中的文件位置应该减1,等等。但是,无论如何,文件索引中的第一个Int32和文件位置有关。我们假设文件索引中的文件位置应该减1。
我们还可以发现两个相邻文件索引的文件位置的差等于前一个的第二个Int32,因此我们能够确定,文件索引中的第二个Int32是文件的长度,而且文件应该没有压缩。
我们从最开始的两个文件的文件名可以知道这两个文件是位图文件,但是文件数据一点儿也不像位图文件。
对于位图文件,最明显的特征是文件开始的文件类型标志"BM"。
文件数据是加了密的。
我们是否应该放弃呢?我们先找一下规律吧。
9F1h处有个"0123456789"(ASCII),似乎比较奇怪。
9C6h处的"05 06 07 08 09",也有规律。
如果你对BMP格式有一点了解,你应该知道,BMP中充满了00。
从9EDh处开始,到9FFh,包括了"0123456789",全部是每次递增1的数字。
嗯,这些字节的值加密前应该是00吧。
9EDh相对于文件开始(9C1h)的偏移量是44(0x2C),正好是9EDh的值。
所以,可以确定,文件的每一个字节,都用该字节在该文件中的位置(相对于该文件的初始位置)进行了可逆变换。
最简单的变换是什么呢?加减?异或?异或是最简单的变换,因为不需要考虑整数溢出。
注意到A Xor B Xor B = A,我们可以猜测,加密算法应该是文件的每一个字节,与字节在该文件中的位置(相对于该文件的初始位置)进行了异或产生的。
编程,按此思路对该段数据(9C1h到35141h)进行变换,结果如下。
图4 解密后的NUM.BMP的文件头
00000000h: 42 4D 86 47 03 00 00 00 00 00 36 04 00 00 28 00 ; BM咷......6...(.
00000010h: 00 00 10 02 00 00 95 01 00 00 01 00 08 00 00 00 ; ......?........
00000020h: 00 00 50 43 03 00 12 0B 00 00 12 0B 00 00 00 00 ; ..PC............
00000030h: 00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80 ; ............€..€
00000040h: 00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80 ; ...€€.€...€.€.€€
00000050h: 00 00 C0 C0 C0 00 C0 DC C0 00 F0 CA A6 00 00 20 ; ..览?儡?鹗?.
00000060h: 40 00 00 20 60 00 00 20 80 00 00 20 A0 00 00 20 ; @.. `.. €.. ?.
00000070h: C0 00 00 20 E0 00 00 40 00 00 00 40 20 00 00 40 ; ?. ?.@...@ ..@
按照BMP打开,可以发现文件正常显示出一堆数字的图像。
于是,可以确认前面的所有假设。
总结一下:
DAT结构
文件索引表
NumIndex Int32 4 文件索引数
文件索引
Address Int32 4 文件位置+1
Length Int32 4 文件长度
Name String 20 文件名
文件数据
每个文件的数据通过文件的每一个字节与字节在该文件中的位置(相对于该文件的初始位置)进行了异或产生的。
本节中提到的游戏的下载地址
http://www.lanqie.net.cn/html/benzhanzuopin/20070604/43.html AAAKK版
(未完待续)