PNG文件格式详解 – 作者:orio1e

png是一种采用无损压缩算法的位图格式,其设计目的是试图替代GIF和TIFF文件格式,同时增加一些GIF文件格式所不具备的特性。PNG使用从LZ77派生的无损数据压缩算法,一般应用于JAVA程序、网页或S60程序中,原因是它压缩比高,生成文件体积小。

PNG文件经常出现在CTF杂项题目当中,常见的考察方法有更改图片长宽高、修改区块信息等方式。难度不等。因此想要做好这一类题目必须要对PNG文件对格式有深入理解。

PNG文件结构:

根据PNG文件的定义来说,其文件头位置总是由位固定的字节来描述的:

十进制数 137 80 78 71 13 10 26 10
十六进制数 89 50 4E 47 0D 0A 1A 0A

其中第一个字节0x89超出了ASCII字符的范围,这是为了避免某些软件将PNG文件当做文本文件来处理。文件中剩余的部分由3个以上的PNG的数据块(Chunk)按照特定的顺序组成,因此,一个标准的PNG文件结构应该如下:

PNG文件标志 PNG数据块 …… PNG数据块

PNG数据块(Chunk)

PNG 定义了两种数据块,一种是关键数据块(critical chunk),这是标准数据块,是PNG文件中必须所具备的。另一种是辅助数据块(ancillary chunk),这是可选的数据块。PNG文件一共定义了四种关键数据块,每一个PNG文件当中都具备有这些关键数据块。

PNG文件格式中的数据块
数据块符号 Hex 数据块名称 多数据块 可选否 位置限制 关键数据块
IHDR 49 48 44 52 文件头数据块 第一块
cHRM 基色和白色点数据块 在PLTE和IDAT之前
gAMA 图像γ数据块 在PLTE和IDAT之前
sBIT 样本有效位数据块 在PLTE和IDAT之前
PLTE 调色板数据块 在IDAT之前
bKGD 背景颜色数据块 在PLTE之后IDAT之前
hIST 图像直方图数据块 在PLTE之后IDAT之前
tRNS 图像透明数据块 在PLTE之后IDAT之前
oFFs (专用公共数据块) 在IDAT之前
pHYs 物理像素尺寸数据块 在IDAT之前
sCAL (专用公共数据块) 在IDAT之前
IDAT 49 44 41 54 图像数据块 与其他IDAT连续
tIME 图像最后修改时间数据块 无限制
tEXt 文本信息数据块 无限制
zTXt 压缩文本数据块 无限制
fRAc (专用公共数据块) 无限制
gIFg (专用公共数据块) 无限制
gIFt (专用公共数据块) 无限制
gIFx (专用公共数据块) 无限制
IEND 49 45 4E 44 图像结束数据 最后一个数据块

数据块结构

PNG文件中,每个数据块由4个部分组成并按照如下顺序排列:

名称 字节数 说明
Length (长度) 4字节 指定数据块中数据域的长度,其长度不超过(231-1)字节
Chunk Type Code (数据块类型码) 4字节 数据块类型码由ASCII字母(A-Z和a-z)组成。例如:IDAT
Chunk Data (数据块数据) 可变长度 存储按照Chunk Type Code指定的数据
CRC 32(循环冗余检测) 4字节 存储用来检测是否有错误的循环冗余码

在这里需要详细讲解一下这里的Length的计算范围,Length的计算长度不包含Chunk Type Code和CRC校验数据,只包括ChunkData。CRC校验的范围包括了Chunk Type Code和Chunk Data

截屏2020-10-20 下午9.47.44

下面,我们依次来了解一下各个关键数据块的结构。

IHDR

文件头数据块IHDR(header chunk):它包含有PNG文件中存储的图像数据的基本信息,并要作为第一个数据块出现在PNG数据流中,而且一个PNG数据流中只能有一个文件头数据块。

文件头数据块由13字节组成,它的格式如下表所示。

域的名称 字节数 说明
Width 4 bytes 图像宽度,以像素为单位
Height 4 bytes 图像高度,以像素为单位
Bit depth 1 byte 图像深度: 索引彩色图像:1,2,4或8 灰度图像:1,2,4,8或16 真彩色图像:8或16
ColorType 1 byte 颜色类型: 0:灰度图像, 1,2,4,8或16 2:真彩色图像,8或16 3:索引彩色图像,1,2,4或8 4:带α通道数据的灰度图像,8或16 6:带α通道数据的真彩色图像,8或16
Compression method 1 byte 压缩方法(LZ77派生算法)
Filter method 1 byte 滤波器方法
Interlace method 1 byte 隔行扫描方法: 0:非隔行扫描 1: Adam7(由Adam M. Costello开发的7遍隔行扫描方法)

PLTE

调色板数据块PLTE(palette chunk)包含有与索引彩色图像(indexed-color image)相关的彩色变换数据,它仅与索引彩色图像有关,而且要放在图像数据块(image data chunk)之前。

PLTE数据块是定义图像的调色板信息,PLTE可以包含1~256个调色板信息,每一个调色板信息由3个字节组成:

颜色 字节 意义
Red 1 byte 0 = 黑色, 255 = 红
Green 1 byte 0 = 黑色, 255 = 绿色
Blue 1 byte 0 = 黑色, 255 = 蓝色

因此,调色板的长度应该是3的倍数,否则,这将是一个非法的调色板。

对于索引图像,调色板信息是必须的,调色板的颜色索引从0开始编号,然后是1、2……,调色板的颜色数不能超过色深中规定的颜色数(如图像色深为4的时候,调色板中的颜色数不可以超过2^4=16),否则,这将导致PNG图像不合法。

真彩色图像和带alpha通道数据的真彩色图像也可以有调色板数据块,目的是便于非真彩色显示程序用它来量化图像数据,从而显示该图像。

IDAT

图像数据块IDAT(image data chunk):它存储实际的数据,在数据流中可包含多个连续顺序的图像数据块。

IDAT存放着图像真正的数据信息,因此,如果能够了解IDAT的结构,我们就可以很方便的生成PNG图像。

IEND

图像结束数据IEND(image trailer chunk):它用来标记PNG文件或者数据流已经结束,并且必须要放在文件的尾部。

如果我们仔细观察PNG文件,我们会发现,文件的结尾12个字符看起来总应该是这样的:

00 00 00 00 49 45 4E 44 AE 42 60 82

不难明白,由于数据块结构的定义,IEND数据块的长度总是0(00 00 00 00,除非人为加入信息),数据标识总是IEND(49 45 4E 44),因此,CRC码也总是AE 42 60 82。

举个栗子

修改长宽高

image-20201020223717845

可以看到IHDR(49 48 44 52)数据块关键字之后紧接的就是定义宽与高的两个四个字节块,很多入门类型的ctf题目乐意修改长宽高来隐藏某些信息。

计算IDAT 长度 CRC类型

这是一段IDAT,在数据块关键字IDAT 49 44 41 54 前的00 01 00 00定义了该数据块的长度,也就是65536个字节。

image-20201020224608689

我们从数据块关键字选择区块,长度为00 01 00 00。

image-20201020225136750

被选中的区块后的四个字节为该数据块的CRC校验码。

CRC校验码的计算所选择的区块还要包含数据块关键字,以这个IDAT区块为例。该数据块的数据块数据为00 01 00 00 ,加上数据块关键字后是 00 01 00 04,我们从标定Length之后即开始选择00 01 00 04。

image-20201020225615343

image-20201020225707266

对所选择块进行CRC32计算,得出结果与数据块数据后的CRC校验码相同。当数据块中的CRC校验码与实际不符合时,该区块不会被使用或显示。

来源:freebuf.com 2021-03-11 19:11:02 by: orio1e

© 版权声明
THE END
喜欢就支持一下吧
点赞0
分享
评论 抢沙发

请登录后发表评论