冒险解谜游戏中文网 ChinaAVG
标题:
某热门游戏的资源文件格式揭秘
[打印本页]
作者:
shane007
时间:
2009-12-8 11:50
标题:
某热门游戏的资源文件格式揭秘
此文可以作为分析文件格式的参考。
$ z6 v3 u S8 l1 P/ ]; J
' r- |# r- u" `6 O2 \! r- b1 D
原文
7 H( _9 _% @: \0 A& V, {
http://vivimice.blog.163.com/blog/static/161001200952035527294/
* V& C( E5 A* ?* M' o p3 o9 Y! q7 X
' u" G% E4 w- A6 g/ [0 O
美国某知名2D小游戏公司最近出了一个很好玩的小游戏,非常热门啊,最近水木和88的PCGame板都在讨论这个。玩了一下发现确实不错,尤其是音乐,做得很不错,颇有味道。于是想把它给扒出来。
" @" E2 ^/ a4 ^. F. X
' g! J* }. D( P H7 j5 o0 F
自己观察了一下,发现游戏目录下的sounds文件夹只有一些RIFF格式的音效,没有音乐。倒是游戏可执行文件的下面有一个main.pak文件,体积庞大。估计就是在这个文件里面。
6 m& R6 X& p, R8 ?6 C! s; g/ n% b/ q
5 E$ L( f/ T s. e1 L# W+ R! @7 `
去该公司的开发者论坛上转了一圈,得知这个文件格式尚未公开。网上能够找到的资源提取程序都不能读取这个文件。估计是比较新的打包格式。干脆自己人肉解解看,或许能够成功。
5 t. k$ J; t z+ Z6 l z
) S. [: V# K7 l
& A! J( C2 X8 Y1 x. B( h1 B
用UE打开这个文件,初步瞄了一眼,发现内容比较乱,用PNG、MP3等等常见文件的文件头搜索了一下,没有找到。文件内容比较紧凑,没有发现成段的连续同内容字节。这说明文件可能经过压缩。如果真是经过压缩的话,那么直接啃文件是基本上啃不动的,因为压缩算法实在是太多了,而且特征比较难找。于是想想换一条路试试看:如果这个文件是经过压缩的,那么程序在运行的时候肯定要将整个文件进行解压缩(因为压缩文件缺乏直接随机读写的能力),将解出来的资源放在内存里面,在内存里面找也许可以找到有价值的内容。
( y0 s/ F) W1 A, j4 B2 }' J, g
l1 t5 S# B2 W8 V* }
首先将程序启动,在资源全部加载完毕以后马上使用工具将程序运行时的内存完全dump到文件中,接下来开始分析,结果却只找到了一副PNG图。文件经过压缩的可能性变小了。
g/ q* Y6 g( {. G) I
' t% e. M$ k+ v' r4 X4 I# q" X& W
4 _& }/ f9 ~) k9 N- A
既然文件没有经过压缩,但是缺又缺乏常规文件的特征(文件头的地方一般比较稀疏),到底该怎么办呢?无聊之中无意将编辑模式切换到了纯文本模式,这个无意的操作却让我发现了一些蛛丝马迹。
5 S7 \! Q- R& w8 f* k
文本模式下,这个文件仍然是乱码,但是却发现文件头部有很多行的开头都一模一样。这种打包的文件,内容组织上一般都比较像文件系统,前面是子文件的入口列表,后面是子文件的具体数据。这些开头一模一样的行,可能说明这些是具有相同路径前缀的子文件。
8 _0 x7 X! n: C' ?. Q
' @8 h D" d2 L1 l( \5 I
不过路径名都是乱码,说明这些路径名被加密过了。首先想到的最常用也是最古老的加密方式就是XOR。尽管不知道XOR的密钥是什么,但是可以通过穷举的方式来尝试。可以长度为1的密钥开始尝试,如果不成功再尝试不同长度的。幸运的是,我找到了1个长度为1的密钥,它可以让这些乱码变成一串有意义的全大写的单词,尽管路径的分隔符是管道符,而不是反斜杠。
( `* o7 z% [8 P0 j2 i
' l. G6 I% K+ J2 S: {3 g
+ p3 C3 |1 W% P! s$ R
在这个之后,文件的内容看起来有意义多了。但是这个时候我使用常见资源的文件头进行搜索,仍然找不到匹配。这可能说明文件仍存在另外一层加密(要不就是根本就没有这些资源文件)。我想尽了办法,也没能找到这些文件的入口在哪里。
2 M% y: H; t# x( a) Y
忽然我想到前面XOR出来的文件名都是大写,这也许并不是程序员确定的原本文件名,原本文件名如果是小写的话,那么说明打包的时候把所有的小写字符变成了大写字符。而PNG的文件头是"\x80PNG",结果被我找到了"\xA0png"的若干个匹配,在这若干个匹配的后面,可以找到"ihdr"继以"iend"的匹配,而在正常的PNG中,应该是"IHDR"继以"IEND"。这起码说明了存在如下的映射:"\x80A-Z"到"\xA0a-z",即上述区间的所有字节被加上了0x20,也就是左移了5位。
4 D( x# n0 Z+ S
7 ^, B: O! f7 m+ k
在我准备编写针对这个算法的还原程序之前,我发现的另外一个现象,让我陷入了混乱。我在这个文件里面发现了OGG文件的文件头,OGG的文件头"OggS"如果按照上面的推测,应该被编码成为"o\x87\x87s"("g"的十六进制表示为0x67),但是文件中的实际编码是"oGGs",也就是说对于所有的小写字符而言,他们被减去了0x20,也就是右移了5位。这说明编码的时候针对不同的字节范围进行了不同的移位。
. W( X# ], H" Q4 f) Y/ Y2 t
8 r2 n1 r% L! e6 d4 }, @
4 y a9 q9 t) c$ Q1 R `" A
最后经过大量的比对,我终于找到了实际位移的算法,终于可以将main.pak还原到了被加密之前的样子。下面的工作就是将这个打包的文件解包成为单独的文件。
% h5 }1 F' f3 M: E
* q# G$ f& G" d$ A2 |' {$ J
! g% R) E# j/ q- p U+ m4 C" D# X6 ]
相比于上面猜测加密的过程来说,解包的过程太简单了,基本上猜测再实验一下就可以知道打包的格式:
! C1 [, A8 Z$ c/ _
9 K% a, |# J$ E8 }
" {6 U1 K. o7 T7 N) A1 N: S
文件头:
W- w: I# ]4 e7 M: f" q7 v1 |
Addr Length Type Description
' {4 A! ?+ | e& ~: Z
0x0000 9 byte [] 未知
- z( _% ^4 t. Z1 X# }
5 \4 A4 s) r2 A; G* i5 ~! d/ M
- A4 N/ y+ M# D$ m" ?9 n( h! M
然后接下来是文件入口的定义:
+ W6 v. k8 x/ K" `0 o5 @
0x0000 1 byte 接下来的字符串的长度(假定为N)
( Q/ s: ^$ L" J$ s7 n0 f
0x0001 N char [] 文件的相对路径,例如:foo/bar/sound.ogg
" a& }0 L' F6 T- i" Q
0x0001+N 4 long 文件的长度
9 O9 L. b7 G c6 B4 X
0x0005+N 8 byte [] 未知
/ d0 g) A9 u4 J! c; e4 L
0x000d+N 1 byte 终结符
5 x0 Y$ w- v1 p8 f* g% l+ Q
) s7 {! e6 a" I& \
% y' [0 u/ O z" f( W
如果上述终结符为0x00的表示接下来的内容仍然是文件入口,如果是0x80则表示从下面开始是文件的数据。各个文件的数据之间没有分隔。放置的顺序就是按照文件入口的顺序来确定。
9 z2 m: J0 B6 y7 Z4 @
8 k' \8 _. ^6 Q8 h
$ ~& V8 ]: n1 R( j* L
最后写了一个java小程序来将算法实现了一下,然后成功将这个文件解包。音乐那是相当不错啊,我已经整理出了一个mp3格式的专辑,这下不用玩游戏也可以享受了。
欢迎光临 冒险解谜游戏中文网 ChinaAVG (https://chinaavg.com/)
Powered by Discuz! X3.2