用Python脚本5分钟自动化修复PNG图片CRC校验与宽高问题在CTF竞赛或日常安全研究中经常会遇到被故意篡改宽高或CRC校验错误的PNG图片。传统方法是用010 Editor等十六进制编辑器手动修改不仅效率低下还容易出错。本文将教你用Python编写自动化脚本5分钟内完成CRC校验修复与宽高爆破。1. PNG文件结构与CRC校验原理PNG文件由多个数据块Chunk组成每个数据块包含长度、类型、数据和CRC校验码四部分。关键的数据块是IHDR它存储了图片的宽、高、颜色深度等元信息。CRC校验码的计算范围是从数据块类型到数据块内容结束不包括长度字段。当图片被修改宽高但未更新CRC时校验就会失败。典型的错误提示包括PNG error: Invalid IHDR CRC计算CRC32的核心Python代码import zlib def calc_crc(data): return zlib.crc32(data) 0xFFFFFFFF2. 自动化修复脚本开发2.1 基础脚本框架首先构建一个能读取PNG文件并检查CRC的脚本import struct import zlib def check_png_crc(file_path): with open(file_path, rb) as f: data f.read() # IHDR块从第12字节开始到第29字节结束 ihdr_data data[12:29] original_crc struct.unpack(I, data[29:33])[0] calculated_crc zlib.crc32(ihdr_data) 0xFFFFFFFF return original_crc calculated_crc2.2 宽高爆破算法当CRC校验失败时我们需要爆破正确的宽高值def brute_force_png_dimensions(file_path, max_dim4096): with open(file_path, rb) as f: data f.read() original_crc struct.unpack(I, data[29:33])[0] for width in range(max_dim): for height in range(max_dim): # 替换宽高字段并计算CRC new_data data[12:16] struct.pack(i, width) struct.pack(i, height) data[24:29] crc zlib.crc32(new_data) 0xFFFFFFFF if crc original_crc: return width, height return None, None2.3 性能优化技巧原始的双重循环效率较低我们可以进行以下优化多进程并行计算from multiprocessing import Pool def worker(args): width, data, original_crc, max_dim args for height in range(max_dim): new_data data[12:16] struct.pack(i, width) struct.pack(i, height) data[24:29] crc zlib.crc32(new_data) 0xFFFFFFFF if crc original_crc: return (width, height) return None def parallel_brute_force(file_path, max_dim4096, processes4): with open(file_path, rb) as f: data f.read() original_crc struct.unpack(I, data[29:33])[0] with Pool(processes) as p: results p.map(worker, [(w, data, original_crc, max_dim) for w in range(max_dim)]) return next((r for r in results if r is not None), (None, None))基于已知信息的范围缩小如果知道图片大致比例可以限制宽高比范围根据文件大小估算最大可能尺寸3. 完整解决方案实现将上述模块整合成一个完整的命令行工具#!/usr/bin/env python3 import argparse import struct import zlib from multiprocessing import Pool def parse_args(): parser argparse.ArgumentParser(descriptionPNG CRC修复工具) parser.add_argument(input, help输入PNG文件路径) parser.add_argument(-o, --output, help输出PNG文件路径) parser.add_argument(-m, --max-dim, typeint, default4096, help最大宽高值(默认4096)) parser.add_argument(-p, --processes, typeint, default4, help并行进程数(默认4)) return parser.parse_args() def worker(args): width, data, original_crc, max_dim args for height in range(max_dim): new_data data[12:16] struct.pack(i, width) struct.pack(i, height) data[24:29] crc zlib.crc32(new_data) 0xFFFFFFFF if crc original_crc: return (width, height) return None def main(): args parse_args() with open(args.input, rb) as f: data bytearray(f.read()) original_crc struct.unpack(I, data[29:33])[0] calculated_crc zlib.crc32(data[12:29]) 0xFFFFFFFF if original_crc calculated_crc: print(PNG CRC校验正常无需修复) return print(检测到CRC校验错误开始爆破宽高...) with Pool(args.processes) as p: results p.map(worker, [(w, data, original_crc, args.max_dim) for w in range(args.max_dim)]) result next((r for r in results if r is not None), None) if not result: print(未找到匹配的宽高组合) return width, height result print(f找到正确宽高: {width}x{height}) # 修改文件中的宽高字段 data[16:20] struct.pack(i, width) data[20:24] struct.pack(i, height) output_path args.output or args.input with open(output_path, wb) as f: f.write(data) print(f文件已保存到: {output_path}) if __name__ __main__: main()4. 高级应用场景4.1 CTF竞赛中的实战技巧在CTF比赛中PNG文件常被用于隐藏信息。除了宽高修改外还可能遇到隐藏数据附加在IEND之后def extract_after_iend(file_path): with open(file_path, rb) as f: data f.read() iend_pos data.find(bIEND) if iend_pos -1: return None return data[iend_pos8:] # IEND标记后可能有额外数据LSB隐写分析from PIL import Image def check_lsb_stego(file_path): img Image.open(file_path) pixels img.load() for y in range(img.height): for x in range(img.width): r, g, b pixels[x, y][:3] if (r 1) or (g 1) or (b 1): return True return False4.2 批量处理与自动化对于需要处理大量图片的情况可以扩展脚本支持批量操作import os def batch_process(directory): for filename in os.listdir(directory): if filename.lower().endswith(.png): filepath os.path.join(directory, filename) if not check_png_crc(filepath): print(f处理文件: {filename}) width, height brute_force_png_dimensions(filepath) if width and height: fix_png_dimensions(filepath, width, height)5. 错误处理与调试在实际使用中可能会遇到各种问题需要完善的错误处理文件格式验证def is_valid_png(file_path): with open(file_path, rb) as f: header f.read(8) return header b\x89PNG\r\n\x1a\n异常处理增强try: with open(file_path, rb) as f: data f.read() except IOError as e: print(f文件读取失败: {e}) return调试日志输出import logging logging.basicConfig(levellogging.DEBUG) logger logging.getLogger(pngfix) def debug_brute_force(...): logger.debug(f尝试宽高: {width}x{height}) ...这个Python脚本相比手动使用010 Editor修改有显著优势处理速度快、可批量操作、结果准确。在最近的一次CTF比赛中我用它成功修复了20多张被篡改的PNG图片而其他选手还在手动计算CRC值。