Zip 文件结构解析不一致,通过二进制文件操作缩小 Zip 文件

问题描述 投票:0回答:1

在找到 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 解压缩结果块。

python-3.x zip compression gzip zlib
1个回答
0
投票

您需要从本地标头获取文件名长度和额外字段长度,而不是使用中央标头中的这些值。对于同一条目,中央和本地标头中的额外字段长度可以不同。虽然文件名长度应该相同,但格式并不禁止不同,因此您还需要从本地标头获取该长度。

您对 zip 格式的解析仅适用于不使用 Zip64 扩展名的 zip 文件。大型 (> 4GB-1) zip 文件、具有大型未压缩条目 (> 4GB-1) 或具有大量条目 (>65535) 的 zip 文件需要这些。

© www.soinside.com 2019 - 2024. All rights reserved.