引子

千里码PNG-1
文档 PNG格式

被损坏的PNG图片:
仅仅被修改了一个byte,图片就损坏了。
145682845224096.png

开始分析

没有搞过这种分析,所以就按照文档一点一点来。装好WINHEX就开工了。

数据块:

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

PNG文件署名域

8byte
89 50 4E 47 0D 0A 1A 0A
每个PNG图片开头8个byte都是这一串。

固定文件头 IHDR

13byte

域的名称字节数说明数据
Width4 bytes图像宽度,以像素为单位0x034e
Height4 bytes图像高度,以像素为单位0x047f
Bit depth1 byte图像深度:索引彩色图像:1,2,4或8灰度图像:1,2,4,8或16真彩色图像:8或160x08
ColorType1 byte颜色类型:0:灰度图像, 1,2,4,8或162:真彩色图像,8或163:索引彩色图像,1,2,4或84:带α通道数据的灰度图像,8或166:带α通道数据的真彩色图像,8或160x04
Compression method1 byte压缩方法(LZ77派生算法)0x00
Filter method1 byte滤波器方法0x00
Interlace method1 byte隔行扫描方法:0:非隔行扫描1: Adam7(由Adam M. Costello开发的7 遍隔行扫描方法)0x00

文本信息数据块 tEXt

71byte
信息内容:
Funny how one single corrupted byte can render the whole image useless.

图像数据块 IDAT

8192byte

图像数据块 IDAT

4096byte
再往下就是一大堆IDAT数据块。
在这个地方我发现了问题所在,第二个数据块的大小是0x1000,我按照这个大小跳过了对应长度的byte之后,没有看到下一个数据块的开始,所以我断定,这个长度应该是有问题的。我重新查找了0x2000长度的数据末尾,发现是下一个数据块的起始,所以问题就在这个数据块的长度数据上,修改长度数据,图片恢复。
修复之后的PNG图片
145682845224096_2.png

讨论

其实我一开始是准备大干一场的,因为我猜是某个数据块的数据出现了问题,需要结合CRC验证来暴力破解。搞出来了才发现,原来是长度错误导致后面全面崩盘,才大半个图片都看不到了。本来是打算用python写个脚本自动找的,结果人肉解决了,有点尴尬的。

隐写

PNG图片里面的两个文本区域是天然的数据隐藏地点,但是很容易被发现,不够隐蔽。
从PNG图片的结构上来说,连续且大量的IDAT数据块是隐藏数据的好地方,每个数据块的长度其实是不定的,可以把数据隐藏在数据块长度的4byte上,用不同长度的数据块来隐藏数据。
还有图像透明数据块和数据点也可以隐藏数据,但是会导致图片失真。

最后修改:2021 年 02 月 19 日
如果觉得我的文章对你有用,请随意赞赏