前几天发现从网上找的那个修复PNG宽高的脚本不好用了, 今天仔细研究了一下, 其实修改一行代码就可以啦

import binascii
import struct
import sys

file = input("图片地址:")
fr = open(file,'rb').read()
data = bytearray(fr[0x0c:0x1d])
crc32key = eval('0x'+str(binascii.b2a_hex(fr[0x1d:0x21]))[2:-1])
#原来的代码: crc32key = eval(str(fr[29:33]).replace('\\x','').replace("b'",'0x').replace("'",''))
n = 4095
for w in range(n):
    width = bytearray(struct.pack('>i', w))
    for h in range(n):
        height = bytearray(struct.pack('>i', h))
        for x in range(4):
            data[x+4] = width[x]
            data[x+8] = height[x]
        crc32result = binascii.crc32(data) & 0xffffffff
        if crc32result == crc32key:
            print(width,height)
            newpic = bytearray(fr)
            for x in range(4):
                newpic[x+16] = width[x]
                newpic[x+20] = height[x]
            fw = open(file+'.png','wb')
            fw.write(newpic)
            fw.close
            sys.exit()

QQ截图20200306184859.png

先说一下文件头, 绿色部分是IHDR数据, 里面的00 00 01 f4是宽, 00 00 01 af是高
红色部分是CRC32, 是根据绿色部分算出来的
在Windows中, 图片查看器不校验图片的CRC32, 所以高度修改后还可以正常的开, 但是在linux中会校验CRC32, 如果修改了宽高, 在Linux中就打不开了, 所以判断一个图片高度有没有被修改可以直接放到linux中看看能不能正常打开

原作者的代码为什么不好用呢, 这个问题出在获取crc32key那里, 原来的代码是直接把fr[29:33]转成字符串, 如果fr[29:33]b'\x90\x90\x90\x90'那么转换成str没有问题,就是"b'\x90\x90\x90\x90'", 但是如果取出来的是b'\x61\x62\x63\x90', 转成str后就变成了"b'abc\\x90'", 所以在数据中没有可打印字符的时候, 原来的代码可以正常执行, 如果出现了可打印字符, 那么原来的代码就会出错
binascii.b2a_hex()函数是把bytes转成hex, 如果原来的数据是b'\x61\x62\x63\x90', 用这个函数后就变成了b'61626390' 这样再转成字符串就可以了

还有一个隐藏的bug,原来代码用replace替换不好,如果最后一个字母是b的话,就会出现两个b',这时候用replace就会出错,所以直接写成[2:-1]就可以了

最后修改:2020 年 04 月 15 日 10 : 35 PM