在找到 End Of Central Directory 签名后,我尝试使用 python 解析 zip 文件
b'\x50\x4b\x05\x06'
这些是我使用 zip 文件实现的提取说明。看起来像 ZIP(文件格式)- Wikipidea。
从 compressed_size
复制大小为 file_header_offset
的二进制内容后,有时我会在输出文件的开头获得额外的 4 个字节。
解析逻辑:
# End Of Central Directory
file.seek(centralDirOffset)
res['disc_number'] = int.from_bytes(file.read(2), 'little')
res['cd_start_disc'] = int.from_bytes(file.read(2), 'little')
res['n_cd_on_disc'] = int.from_bytes(file.read(2), 'little')
res['n_c_total'] = int.from_bytes(file.read(2), 'little')
res['cd_size'] = int.from_bytes(file.read(4), 'little')
res['cd_offset'] = int.from_bytes(file.read(4), 'little')
res['comment_len'] = int.from_bytes(file.read(2), 'little')
# Files Specific
file.seek(res['cd_offset'])
res['signature'] = binascii.hexlify(file.read(4)).decode("utf-8")
res['version'] = struct.unpack('<H', file.read(2))[0]
res['min_ver'] = struct.unpack('<H', file.read(2))[0]
res['bit_flag'] = struct.unpack('<H', file.read(2))[0]
res['compression_method'] = struct.unpack('<H', file.read(2))[0]
res['f_last_modif_time'] = struct.unpack('<H', file.read(2))[0]
res['f_last_modif_date'] = struct.unpack('<H', file.read(2))[0]
res['crc_32'] = struct.unpack('<I', file.read(4))[0]
res['compressed_size'] = struct.unpack('<I', file.read(4))[0]
res['uncompressed_size'] = struct.unpack('<I', file.read(4))[0]
res['f_name_length'] = struct.unpack('<H', file.read(2))[0]
res['extra_field_length'] = struct.unpack('<H', file.read(2))[0]
res['file_comment_length'] = struct.unpack('<H', file.read(2))[0]
res['disc_n_file_start'] = struct.unpack('<H', file.read(2))[0]
res['intern_file_attr'] = struct.unpack('<H', file.read(2))[0]
res['extern_file_attr'] = struct.unpack('<I', file.read(4))[0]
res['file_header_offset'] = struct.unpack('<I', file.read(4))[0]
res['file_name'] = struct.unpack(f'{res["f_name_length"]}s', file.read(res['f_name_length']))[0].decode()
res['extra_field'] = struct.unpack(f'{res["extra_field_length"]}s', file.read(res['extra_field_length']))[0]
res['file_comment'] = struct.unpack(f'{res["file_comment_length"]}s', file.read(res["file_comment_length"]))[0].decode()
# Skipping to file header
res['file_offset'] = res['file_header_offset'] + 30 + res['f_name_length'] + res['extra_field_length']
res['file_size'] = res['compressed_size']
如何重现 使用以下函数获取任何采用 Deflate 压缩方法(id 8)的 zip 文件的中央目录偏移量和一个文件 zip。
def findCentralDirectory(file):
eocd_signature = b'\x50\x4b\x05\x06'
file.seek(-22, 2)
while True:
h = file.read(4)
if not h:
logging.error("[!] Error -02: EOCD signature cannot be found. Make sure file is not corrupt.")
sys.exit(-2)
if h == eocd_signature:
return file.tell()
我在期待什么 我期望脚本计算正确的偏移量,以便能够通过 zlib.decompress 解压缩结果块。
您需要从本地标头获取文件名长度和额外字段长度,而不是使用中央标头中的这些值。对于同一条目,中央和本地标头中的额外字段长度可以不同。虽然文件名长度应该相同,但格式并不禁止不同,因此您还需要从本地标头获取该长度。
您对 zip 格式的解析仅适用于不使用 Zip64 扩展名的 zip 文件。大型 (> 4GB-1) zip 文件、具有大型未压缩条目 (> 4GB-1) 或具有大量条目 (>65535) 的 zip 文件需要这些。