这一题需要对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')