前几天发现从网上找的那个修复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()
先说一下文件头, 绿色部分是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]
就可以了
评论 (0)