简单套娃DX
这一题需要对png图片的结构有所了解。详细可参考https://www.w3.org/TR/png/
幸好每一张图片只有一个错误,逐步调试,就可以发现所有错误,修正即可。具体错误参看python程序中的注释:
import ossrc_dir = '.\\XD\\'
des_dir = '.\\out\\'
src_files = os.listdir(src_dir)
des_files = os.listdir(des_dir)f_count={0:0,1:0,2:0,3:0,4:0,5:0,6:0,7:0}
for fname in src_files:if fname in des_files:continuewith open(src_dir+fname,'rb') as f:srcdata = f.read()#丢掉了文件头标识if srcdata[1:4] != b'PNG':desdata = 0x89504E470D0A1A0A.to_bytes(8,'big') + srcdataf_count[1] += 1#IHDR块长度和标识码被清零elif srcdata[8:0x10] == 0x0000000000000000.to_bytes(8, 'big'): desdata = srcdata[:8] + 0x0000000D49484452.to_bytes(8,'big') + srcdata[16:]f_count[2] += 1#IHDR宽高值不对elif srcdata[0xc:0x10] == b'IHDR' and srcdata[0x10:0x18] != 0x0000000500000005.to_bytes(8,'big'): desdata = srcdata[:0x10] +0x5.to_bytes(4,'big') + 0x5.to_bytes(4,'big') + srcdata[0x18:]f_count[3] += 1#IDAT块长度被清零elif srcdata[0x21:0x29] == 0x00000000.to_bytes(4, 'big')+b'IDAT': if srcdata.index(b'eXIf') >= 0:IDAT_len = srcdata.index(b'eXIf') - 0x29 - 4 -4else:print('[!] Error!! %s'%fname)breakdesdata = srcdata[:0x21] + IDAT_len.to_bytes(4,'big') + srcdata[0x25:]f_count[4] += 1#IDAT块标识被删除elif srcdata[0xc:0x10] == b'IHDR' and srcdata[0x25:0x29] != b'IDAT': desdata = srcdata[:0x25] + b'IDAT' + srcdata[0x25:]f_count[5] += 1#IHDR头的颜色类型错误elif srcdata[0xC:0x10] == b'IHDR' and srcdata[0x18:0x1A] != 0x0100.to_bytes(2,'big'): desdata = srcdata[:0x18] + 0x0100.to_bytes(2,'big') + srcdata[0x1A:]f_count[6] += 1#IHDR块被放到了倒数第二块,IDAT变为第一块elif srcdata[0xc:0x10] == b'IDAT': IHDR_block_begin = srcdata.index(b'IHDR') - 4 IHDR_block = srcdata[IHDR_block_begin:IHDR_block_begin+25]desdata = srcdata[:8] + IHDR_block + srcdata[8:IHDR_block_begin] + srcdata[IHDR_block_begin+25:]f_count[7] += 1else:desdata = srcdataf_count[0] += 1with open(des_dir+fname,'wb') as f:f.write(desdata)
print(f_count)
图片修正以后,观察图片内容,应该是二维码碎片。查看每个图片的exif信息,发现数据:
import os
from PIL import Imagebasedir = '.\\out\\'
list = []
for fname in os.listdir(basedir):image = Image.open(basedir+fname)exif = image.getexif()list.append([ int(exif[282]),int(exif[283]) ])image.close()
list.sort(key=lambda x: [x[0], x[1]])
print(list)#[[0, 0], [0, 1], [0, 2], [0, 3], [0, 4], [0, 5], [0, 6], [0, 7], [0, 8], [0, 9], [0, 10], [0, 11], [0, 12], [0, 13], [0, 14], [0, 15], [0, 16], [0, 17], [0, 18], [0, 19],
#...
# [449, 0], [449, 1], [449, 2], [449, 3], [449, 4], [449, 5], [449, 6], [449, 7], [449, 8], [449, 9], [449, 10], [449, 11], [449, 12], [449, 13], [449, 14], [449, 15], [449, 16], [449, 17], [449, 18], [449, 19]]
因此这些应该是每个图片的坐标,依据这些坐标进行拼接图片,得到flag:
import os
from PIL import Image
basedir = '.\\out\\'
list = []
newimg = Image.new('RGB',(450*5,20*5),(255,255,255)) #白底
for fname in os.listdir(basedir):image = Image.open(basedir+fname)exif = image.getexif()x,y = int(exif[282])*5,int(exif[283])*5newimg.paste(image,(x,y,x+5,y+5)) image.close()
newimg.save('new.png')