媒体数据格式解析分析未知文件数据结构格式时需要熟悉不同文件类型的一种或多种该类公开文件的数据存储格式,因为通常情况下未知文件数据结构格式很可能是在公开的文件格式上建立起来的,或只稍微修改了一些地方。编程人员一般不会自己发明一种文件格式,因为编程人员大多数都很懒,他们通常的做法是参考一些公开文件的格式,稍微修改一下。例如,如果要分析的未知文件格式是属于图像类的,那么这个未知的图像文件格式必定与BMP文件格式有相似的地方。熟悉BMP格式对研究和分析这个未知的图像文件格式有极大的帮助,如果掌握了BMP图像文件存储格式就可以利用BMP格式去匹配和猜测未知图像文件格式。例如,如要分析的未知文件格式是属于3D模型的,那么这个未知的3D模型文件格式必定与3DS和X文件格式有相似的地方,所以研究未知的3D模型文件前需要先参考和学习一些常见的公开格式的模型文件,这与解密某个加密算法之前需要研究一些公开的加密算法是同一个道理。因为本书是针对游戏资源文件解密,所以下面将要介绍和分析游戏资源文件的常用文件存储格式。游戏资源文件大体上可以归到多媒体数据格式上,学习和研究这些多媒体文件格式对日后分析未知的游戏资源文件格式有很大帮助。通过本章的学习读者可以掌握以下内容:BMP图像文件格式;PNG图像文件格式;X模型文件格式;md3模型文件格式。BMP图像文件格式BMP图像文件格式是游戏中常用的图像资源文件格式,BMP图像文件起源早,程序员对BMP都比较熟悉,再加上BMP格式简单,读取和写入非常容易实现,所以无论Windows的还是DriectX,都有支持读取和写入BMP文件格式的API函数。针对BMP压缩的算法比较成熟,压缩效果也不差,而且都是无损压缩编码,即可以100%还原BMP图像质量。虽然JPG格式压缩效果比较理想,但游戏编程人员一般极少使用,因为JPG要牺牲图像的质量来换取大的压缩率,加上JPG解码速度较慢和格式复杂,所以游戏中使用JPG格式的图像的情况不多(笔者目前只发现一款网络游戏使用JPG格式作为游戏里的图像格式,并且使用额外的数据保存了图像中的透明通道信息来让JPG支持透明色)。GIF格式虽然支持多帧动画效果,但GIF最大仅支持256色,不能表达色彩丰富的图像,所以对于对速度要求非常苛刻而且图像质量要高的游戏来说,使用BMP格式存储图像是不错的选择。BMP图像文件介绍MP图像文件格式是微软公司发明的,BMP图像文件的后缀名通常是.BMP,但也有少数是.DIP。不过单凭文件的后缀名并不能惟一确定是不是BMP图像文件,要惟一确定BMP图像文件还需要分析文件的存储格式。BMP图像文件和GIF图像文件不同,BMP图像文件只能存储一幅图像,即一帧。GIF图像文件能保存多帧图像,从而可以实现动画的效果。BMP图像文件支持单色、16色、256色和真彩色4种颜色的图像。BMP图像的数据即可压缩也可以不压缩,如果选择了压缩数据,那么根据颜色的不同,BMP使用不同的RLE压缩方式。RLE是一种无损压缩方法,使用RLE压缩的数据能完整还原。如果图像是16色,则可以采用RLE4压缩,如果图像是256色,则可以采用RLE8压缩,真彩色的图像不使用压缩。BMP的图像数据排列方式有点特别,BMP的图像数据排列方式首先从图像的左下角第一个像素开始存储每一行数据,即BMP图像数据存储的最后一个像素等于实际图像的右上角第一个像素。BMP图像文件存储结构(1)BMP文件存储结构的格式可以在Windows中的WINGDI.h文件中找到定义。BMP文件总体上由4部分组成,分别是位图文件头、位图信息头、调色板和图像数据,如表5-1所示。表5-1BMP文件的组成结构位图文件头(bitmap-fileheader)位图信息头(bitmap-informationheader)彩色表/调色板(colortable)位图数据(bitmap-data)下面来详细看一下每个组成部分的细节。位图文件头(bitmap-fileheader)位图文件头(bitmap-fileheader)包含了图像类型、图像大小、图像数据存放地址和两个保留未使用的字段。打开WINGDI.h文件,搜索BITMAPFILEHEADER就可以定位到BMP文件的位图文件头的数据结构定义。typedefstructtagBITMAPFILEHEADER{WORDbfType;DWORDbfSize;WORDbfReserved1;WORDbfReserved2;DWORDbfOffBits;}BITMAPFILEHEADER,FAR*LPBITMAPFILEHEADER,*PBITMAPFILEHEADER;列出了tagBITMAPFILEHEADER中各字段的含义。tagBITMAPFILEHEADER结构字段名大小(单位:字节)描述bfType2位图类别,根据不同的操作系统而不同,在Windows中,此字段的值总为‘BM’bfSize4BMP图像文件的大小bfReserved12总为0bfReserved22总为0bfOffBits4BMP图像数据的地址位图信息头(bitmap-informationheader)位图信息头(bitmap-informationheader)包含了位图信息头的大小、图像的宽高、图像的色深、压缩说明图像数据的大小和其他一些参数。打开WINGDI.h文件,搜索tagBITMAPINFOHEADER就可以定位到BMP文件的位图信息头的数据结构定义。typedefstructtagBITMAPINFOHEADER{DWORDbiSize;LONGbiWidth;LONGbiHeight;WORDbiPlanes;WORDbiBitCount;DWORDbiCompression;DWORDbiSizeImage;LONGbiXPelsPerMeter;LONGbiYPelsPerMeter;DWORDbiClrUsed;DWORDbiClrImportant;}BITMAPINFOHEADER,FAR*LPBITMAPINFOHEADER,*PBITMAPINFOHEADER;列出了tagBITMAPFILEHEADER中各字段的含义。tagBITMAPFILEHEADER结构字段名大小(单位:字节)描述biSize4本结构的大小,根据不同的操作系统而不同,在Windows中,此字段的值总为28h字节=40字节biWidth4BMP图像的宽度,单位像素biHeight4BMP图像的高度,单位像素biPlanes2位图的位面数,总为1biBitCount2BMP图像的色深,即一个像素用多少位表示,常见有1、4、8、16、24和32,分别对应单色、16色、256色、16位高彩色、24位真彩色和32位增强型真彩色biCompression4压缩方式,0表示不压缩,1表示RLE8压缩,2表示RLE4压缩,3表示每个像素值由指定的掩码决定biSizeImage4BMP图像数据大小,必须是4的倍数,图像数据大小不是4的倍数时用0填充补足biXPelsPerMeter4水平分辨率,单位像素/mbiYPelsPerMeter4垂直分辨率,单位像素/mbiClrUsed4BMP图像使用的颜色,0表示使用全部颜色,对于256色位图来说,此值为100h=256biClrImportant4重要的颜色数,此值为0时所有颜色都重要,对于使用调色板的BMP图像来说,当显卡不能够显示所有颜色时,此值将辅助驱动程序显示颜色BMP图像文件存储结构(2)彩色表/调色板(colortable)彩色表/调色板(colortable)是单色、16色和256色图像文件所特有的,相对应的调色板大小是2、16和256,调色板以4字节为单位,每4个字节存放一个颜色值,图像的数据是指向调色板的索引。可以将调色板想象成一个数组,每个数组元素的大小为4字节,假设有一256色的BMP图像的调色板数据为:调色板[0]=黑、调色板[1]=白、调色板[2]=红、调色板[3]=蓝…调色板[255]=黄图像数据010002FF表示调用调色板[1]、调色板[0]、调色板[2]和调色板[255]中的数据来显示图像颜色。在早期的计算机中,显卡相对比较落后,不一定能保证显示所有颜色,所以在调色板中的颜色数据应尽可能将图像中主要的颜色按顺序排列在前面,位图信息头的biClrImportant字段指出了有多少种颜色是重要的。每个调色板的大小为4字节,按蓝、绿、红存储一个颜色值。打开WINGDI.h文件,搜索tagRGBTRIPLE就可以定位到BMP文件的调色板的数据结构定义。typedefstructtagRGBQUAD{BYTErgbBlue;BYTErgbGreen;BYTErgbRed;BYTErgbReserved;}RGBQUAD;列出了tagRGBTRIPLE中各字段的含义。tagRGBTRIPLE结构字段名大小(单位:字节)描述rgbBlue1蓝色值rgbGreen1绿色值rgbRed1红色值rgbReserved1保留,总为0位图数据(bitmap-data)如果图像是单色、16色和256色,则紧跟着调色板的是位图数据,位图数据是指向调色板的索引序号。如果位图是16位、24位和32位色,则图像文件中不保留调色板,即不存在调色板,图像的颜色直接在位图数据中给出。16位图像使用2字节保存颜色值,常见有两种格式:5位红5位绿5位蓝和5位红6位绿5位蓝,即555格式和565格式。555格式只使用了15位,最后一位保留,设为0。24位图像使用3字节保存颜色值,每一个字节代表一种颜色,按红、绿、蓝排列。32位图像使用4字节保存颜色值,每一个字节代表一种颜色,除了原来的红、绿、蓝,还有Alpha通道,即透明色。如果图像带有调色板,则位图数据可以根据需要选择压缩与不压缩,如果选择压缩,则根据BMP图像是16色或256色,采用RLE4或RLE8压缩算法压缩。RLE4是压缩16色图像数据的,RLE4采用表5-5所示方式压缩数据。表5-5RLE4压缩方法方案1字节2字节3字节4字节N字节A重复次数颜色索引B设为0后面有效的颜色索引数颜色索引颜色索引颜色索引…假设有如下16色位图数据,共20字节,数据使用了RLE4压缩:0500040500080905040004050809040807010000数据解压时首先读取05,因为05不等于0,所以选择A方案,根据A方案,05表示后面数据重复的次数,接着读取00,00表示有两个颜色索引,每个索引占4位,第一个像素在高4位,第二个像素在低4位,即在一个字节中低像素在高位,高像素在低位。0500解压后等于00000。读取04,选择A方案,按照上面的操作解析,04是后面数据重复的次数,05是两个颜色索引,第3个颜色索引为5,第4个颜色索引为0。0405解压后等于0505。读取00,选择B方案,读取08,08表示后面有效的颜色索引数。0008解压后等于09050400。读取04,选择A方案,按照上面的操作解析,04是后面数据重复的次数,05是两个颜色索引。0405解压后等于0505。读取08,选择A方案,按照上面的操作解析,08是后面数据重复的次数,09是两个颜色索引。0809解压后等于09090909。读取04,选择A方案,按照上面的操作解析,04是后面数据重复的次数,08是两个颜色索引。0408解压后等于0808。读取07,选择A方案,按照上面的操作解析,07是后面数据重复的次数,01是两个颜色索引。0701解压后等于0101010。读取00,选择B方案,读取00,00表示后面有效的颜色索引数,0表示无,即解压完一行数据。综合上面的操作,解压后的数据为:0000005050905040005050909090908080101010看上去和原来的数据大小一样,没有体现到压缩效果,这是因为上面的例子只选择了20字节数据,而且这20字节数据中重复的数据不多,使用RLE压缩重复数据不多的数据时,有时可能压缩后的大小反而比原来的数据