简单套娃DX
这一题需要对png图片的结构有所了解。详细可参考https://www.w3.org/TR/png/
幸好每一张图片只有一个错误,逐步调试,就可以发现所有错误,修正即可。具体错误参看python程序中的注释:
import os
src_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:
continue
with open(src_dir+fname,'rb') as f:
srcdata = f.read()
#丢掉了文件头标识
if srcdata[1:4] != b'PNG':
desdata = 0x89504E470D0A1A0A.to_bytes(8,'big') + srcdata
f_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 -4
else:
print('[!] Error!! %s'%fname)
break
desdata = 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] += 1
else:
desdata = srcdata
f_count[0] += 1
with open(des_dir+fname,'wb') as f:
f.write(desdata)
print(f_count)
图片修正以后,观察图片内容,应该是二维码碎片。查看每个图片的exif信息,发现数据:
import os
from PIL import Image
basedir = '.\\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])*5
newimg.paste(image,(x,y,x+5,y+5))
image.close()
newimg.save('new.png')