天天酷跑 资源格式分析
以 天天酷跑 1.0.16.0 安卓版本为基准。 一般应用的安卓版本和 iOS 版本都可以做分析,两者对资源的处理方式非常相似,只不过安卓版本更容易下载到。 默认情况下,iOS 会对 png 等图片资源进行格式转换,算法是已知的,主要是位图坐标和 mask 的问题,但目前不少软件都是用自己的方式处理资源,所以基本无不影响。 避免涉及到版权问题,所以不能提供解析和提取代码,也不提供解析成品。
基本情况
assets 是存放资源的目录,classes.dex 是编译后的 java 代码包。素材都在这个文件夹里。 dex 格式是公开的,可以自己解析或者用第三方工具转换为 jar 包,有兴趣可以使用 Java 反编译器查看代码,但是实际上一般可读性略很差。难以区别引用的包和游戏本身的代码,关键代码也通常被混处理过淆了。反正我在处理天天酷跑的过程中,没去折腾这段 dex。 lib 是一些非java的库。 META-INF、res 通常没有什么帮助。里面有文件列表、LOGO、界面布局什么的。
NPEngine
从各种命名看,很显然他们使用了一个叫 NPEngine 的引擎。网上查不到资料,可能是内部使用的。 从命名和所在目录,基本就可以猜出每个文件是干啥的。 如 .npLayout.bin .npAction.bin .npCourse.bin .npModule.bin 云云。 fsp、xzd、pzd则是一些处理后的资源文件。 注意,在下面的格式说明中,有的是会出现个别特例的。就算没有特例,也不能保证一定正确,毕竟我没有源码。
pzd
其实就是PNG格式图片。 32字节HASH值 PNG格式数据 32字节HASH值我无法确定是什么,可能是验证数据,也有可能就是个id,也有可能是id+验证数据。后面就完全是未处理的PNG数据。 这么设计很正常,1 是资源文件通常需要快速载入,因此应该避免复杂算法。 2 是快速定位一个资源,既可以使用路径,也可以使用uuid。
xzd
相比,xzd麻烦一些。它其实是个dds文件,一种位图文件,最初是用在DirectDraw里的,但是这个DDS格式并不能对应上官方的DDS说明,因此可能是修改的自定义格式。 44 44 53 20 02 00 01 00 20 00 00 00 04 00 00 00 XX XX XX XX YY YY YY YY 00 00 00 00 FF 00 00 00 F0 FF F0 FF F0 FF F0 FF … 看出来的解释如下: 44 44 53 20 // “DDS “ DDS头 02 00 01 00 // 未知,正统的DDS文件,这里应该是DDS头的长度。这里可能是自定义的文件格式,如2.1?。 20 00 00 00 // 32,可能是掩码,也可能是 DDS 头的长度。 04 00 00 00 // 4,可能是掩码,也可能是接下来有4个INT32。 XX XX XX XX // 宽 YY YY YY YY // 高 00 00 00 00 // 未知 FF 00 00 00 // 未知 剩下的就是一行一行的像素了。 如 F0 FF,由于是小端,所以实际是 0xFFF0,以 RBGA 的方式存放。如0x3210,R就是316,A就是016。 这样存放图片,质量低,体积大。我猜测可能是由于这些图片需要参与碰撞计算,因此使用现成的位图可能比较方便。
.npModule.bin
以上两种格式都是图片格式,大多数图片是由多个图片合并在一起的。 .npModule.bin 文件通常指明的这些图片的每个部分。 01 01 01 00 01 01 04 00 00 00 00 04 01 00 00 00 19 00 00 00 4D 6F 64 75 6C 65 2F 50 65 74 2F 4D 4F 44 55 4C 45 2E 70 65 74 5F 31 30 2F 0E 00 00 00 70 65 74 5F 31 30 2E 42 49 47 2E 70 7A 64 04 06 00 00 00 04 B2 00 00 00 0A 00 00 00 49 6D 61 67 65 5F 6C 6D 5F 31 02 41 00 02 00 00 02 3E 00 02 35 00 01 01 04 8A 01 00 00 0A 00 00 00 49 6D 61 67 65 5F 6C 6D 5F 32 02 00 00 02 00 00 02 41 00 02 36 00 01 01 04 8F 02 00 00 0A 00 00 00 49 6D 61 67 65 5F 6C 6D 5F 33 02 00 00 02 36 00 02 41 00 02 33 00 01 01 04 05 03 00 00 0A 00 00 00 … 如这样的格式,可以分割如下。 01 01 01 00 01 01 04 00 00 00 00 04 01 00 00 00 19 00 00 00 4D 6F 64 75 6C 65 2F 50 65 74 2F 4D 4F 44 55 4C 45 2E 70 65 74 5F 31 30 2F 0E 00 00 00 70 65 74 5F 31 30 2E 42 49 47 2E 70 7A 64 04 06 00 00 00 04 B2 00 00 00 0A 00 00 00 49 6D 61 67 65 5F 6C 6D 5F 31 02 41 00 02 00 00 02 3E 00 02 35 00 01 01 04 8A 01 00 00 0A 00 00 00 49 6D 61 67 65 5F 6C 6D 5F 32 02 00 00 02 00 00 02 41 00 02 36 00 01 01 04 8F 02 00 00 0A 00 00 00 49 6D 61 67 65 5F 6C 6D 5F 33 02 00 00 02 36 00 02 41 00 02 33 00 01 01 04 05 03 00 00 0A 00 00 00 49 6D 61 67 65 5F 6C 6D 5F 34 02 00 00 02 69 00 02 41 00 02 35 00 01 01 04 80 00 00 00 0A 00 00 00 49 6D 61 67 65 5F 6C 6D 5F 35 02 3E 00 02 9E 00 02 40 00 02 35 00 01 01 04 2B 03 00 00 0A 00 00 00 49 6D 61 67 65 5F 6C 6D 5F 36 02 00 00 02 9E 00 02 3E 00 02 38 00 01 01
其中 04 01 00 00 00 19 00 00 00 4D 6F 64 75 6C 65 2F 50 … 这一行,可以拆分如下 04 // 4 01 00 00 00 // 1 19 00 00 00 // 19 4D 6F 64 75 6C 65 2F 50 65 74 2F 4D 4F 44 55 4C 45 2E 70 65 74 5F 31 30 2F // Module/Pet/MODULE.pet_10/ 0E 00 00 00 // 14 70 65 74 5F 31 30 2E 42 49 47 2E 70 7A 64 // pet_10.BIG.pzd 已经能很明了的看出来了,是一种BinaryStream。确定的变量有确定的长度,不确定的均使用。长度+数值的方式存放。 如 04 01 00 00 00 // 长度是4,数值是01 00 00 00。(即1) 0E 00 00 00 70 65 74 5F 31 30 2E 42 49 47 2E 70 7A 64 // 长度是14,数值是pet_10.BIG.pzd。 但是有个数值长度是1字节,有的是4字节,猜测是对应不同的数据结果。 而对于 04 B2 00 00 00 0A 00 00 00 49 6D 61 67 65 5F 6C 6D 5F 31 02 41 00 02 00 00 02 3E 00 02 35 00 01 01 解析如下 04 B2 00 00 00 // 0xB2,资源ID 0A 00 00 00 49 6D 61 67 65 5F 6C 6D 5F 31 // Image_lm_1,资源名称,有可能没有名字 02 41 00 // 65 x 02 00 00 // 00 y 02 3E 00 // 62 宽度 02 35 00 // 53 高度 01 01 // 1,可能是某种属性 这样整体刚才的格式文件解释如下 01 01 01 00 // 可能是文件类型 1 个什么东西 0 个什么东西 1 个父图片 Module/Pet/MODULE.pet_10/ pet_10.BIG.pzd 6 个子图片 0xB2 Image_lm_1 65 0 62 53 1 0x8A Image_lm_2 0 0 65 54 1 0x8F Image_lm_3 0 54 65 51 1 0x05 Image_lm_4 0 105 65 53 1 0x80 Image_lm_5 62 158 64 53 1 0x2B Image_lm_6 0 158 62 56 1 bg001.npModule.bin 是个例外,大概猜出如下 0A 00 02 00 // 可能是文件类型 14 80 6E B6 BE 31 BC D0 DB 85 // 某种HASH 04 00 // 4 03 00 34 61 39 34 61 62 34 39 64 65 33 66 39 64 37 65 34 30 30 31 66 62 63 66 36 37 62 66 37 37 36 61 // 某种HASH 03 00 36 33 66 36 63 66 66 35 34 65 31 35 37 64 38 30 32 61 62 38 35 37 63 63 61 63 35 61 66 30 65 64 // 某种HASH 02 00 62 38 66 66 66 63 34 38 34 62 62 31 38 38 30 39 34 62 33 37 33 38 65 62 37 31 39 65 36 38 64 38 // 某种HASH 00 00 64 34 32 36 62 65 34 33 65 33 34 36 39 32 35 30 37 38 62 33 62 65 31 38 33 39 63 32 64 62 34 31 // 某种HASH
.npAction.bin
.npAction.bin 差不多可以看出是动画配置,设定动画名字,动画层,以及动画sequence(指明资源ID)。 .npAction.bin 比较大,字段也比较多,大量的0,因此难以猜测结构,不去分析源码估计不能给出格式分析了。 (比如定位,通常有上下左右高宽,就是6个值,如果没有强制设置可能都是0,再加上变化方式等等,每个sequence很长很相似,很难看出顺序。。。)