CRC检验错误

pngcheck -v 分析png格式,报错CRC ERROR

对一张正常的图片,通过修改其宽度或者高度隐藏信息,使计算出的CRC校验码与原图的CRC校验码不一致;windows的图片查看器会忽略错误的CRC校验码,因此会显示图片,但此时的图片已经是修改过的,所以会有显示不全或扭曲等情况,借此可以隐藏信息。

而Linux、macOS下的图片查看器不会忽略错误的CRC校验码,因此用Linux打开修改过宽或高的png图片时,会出现打不开的情况

png格式:

  • 前八个字节

    89 50 4E 47 0D 0A 1A 0A

    为png的文件头,

    该段格式是固定的

    • 前四个字节00 00 00 0D(即为十进制的13)代表数据块的长度为13,数据块包含了png图片的宽高等信息,该段格式是固定的

    • 之后的四个字节49 48 44 52(即为ASCII码的IHDR)是文件头数据块的标示,该段格式也是固定的

    • 数据块格式(十三字节):

      • 00 00 05 8C 该四字节为图片的宽,该段数据是由图片的实际宽决定的
      • 00 00 01 f4( 00000406原图)该四字节为图片的高,该段数据是由图片的实际高度决定的
      • 后五字节08 06 00 00 00 凑满十三字节,数据块
    • 再往后四位是CRC校验码94F3FED1

      校验码是由IHDR文件头标示与宽高共同计算出来的所以,一旦修改高或宽,便不符合校验码了,就会出错

爆破,找出正确的高

可以选择爆破的方法,找出修改前的高度来匹配CRC校验码,用正确的宽高修复

# -*- coding: utf-8 -*-
import binascii
import struct


#\x49\x48\x44\x52\x00\x00\x02\xA7\x00\x00\x01\x00\x08\x06\x00\x00\x00
crc32key = 0x6D7C7135
for i in range(0, 65535):
  height = struct.pack('>i', i)
  #CRC: 6D7C7135
  #把height的位置留出来,data减去四字节
  data = '\x49\x48\x44\x52\x00\x00\x02\xA7' + height + '\x08\x06\x00\x00\x00'

  crc32result = binascii.crc32(data) & 0xffffffff

  if crc32result == crc32key:
    print ''.join(map(lambda c: "%02X" % ord(c), height))

评论