zlib压缩数据解压报校验错误 可尝试的配置与处理方案问询
zlib解压报错incorrect data check排查方案
问题描述
需要对采用zlib算法压缩的数据执行解压操作,最初在Python环境中使用如下标准代码解压:
zlib.decompress(data)
执行后返回报错:zlib.error: Error -3 while decompressing data: incorrect data check
随后尝试使用跳过数据校验的解压实现,代码如下:
def decompress_corrupted(data): d = zlib.decompressobj(zlib.MAX_WBITS | 32) f = BytesIO(data) result_str = b'' buffer = f.read(1) try: while buffer: result_str += d.decompress(buffer) buffer = f.read(1) except zlib.error: pass return result_str
该方法可以返回部分解压结果,但产出的.rtf格式内容存在少量错误。
已知前提:
- 压缩过程确定使用zlib算法,文件本身未损坏,官方已停更的查看器可以正常展示全部内容,开发商无技术支持
- 压缩数据头部字节序列:
789C 95 54 5D 6F D3 30 14 ... - 压缩数据尾部字节序列:
... 79 AE C5 E2 17 82 5E 3F 85
核心问题
需要明确可调整的zlib配置项、前置/后置处理步骤,拿到完整正确的原始rtf文档,完成方案迁移。
可行排查与调整步骤
根据头部字节78 9C判断,这是默认压缩级别的标准zlib流,不存在自定义压缩字典、gzip封装的情况,当前解压结果出错的核心原因是自定义解压逻辑的错误处理存在缺陷,并非压缩数据损坏。
- 修正解压初始化参数:将
zlib.decompressobj的wbits参数从zlib.MAX_WBITS | 32改为zlib.MAX_WBITS(值为15),这是标准zlib流对应的参数,加32是开启gzip头自动识别的兼容模式,无使用必要,反而可能引入头识别偏差。 - 替换错误的逐字节读取逻辑:zlib返回-3错误仅代表流末尾的adler32校验值与计算值不匹配,不代表压缩的正文数据损坏。当前逐字节喂入数据、一旦抛错就直接跳出循环的逻辑,会直接丢弃错误触发时缓存的未输出数据、以及后续的有效解压内容,这是rtf内容出现错误的直接原因。调整为一次性喂入全部待解压数据,捕获校验错误后先取出解压对象已缓存的已解压数据,不要直接终止流程。
- 前置裁剪多余数据:开发商大概率在标准zlib流尾部追加了自定义元数据,导致zlib读到流末尾时校验失败。可以先定位deflate压缩流的真实结束标记:deflate流的最后一个块是携带结束标记的存储块,对应字节序列为
0x00 0x00 0xFF 0xFF(注意deflate为位对齐,标记可能出现在字节的非零位起始位置,需要按位扫描匹配),找到标记后往后数4字节就是标准zlib流的结束位置,裁掉之后的多余字节再调用标准zlib.decompress即可。 - 修复校验值:如果裁剪后仍然报校验错,说明开发商修改了zlib流末尾的4字节adler32校验值。可以先通过跳过校验的方式拿到初步解压内容,计算这段内容的adler32值,替换回原zlib流的最后4字节,再用标准解压函数验证即可,无需长期依赖跳过校验的逻辑。
- 逆向官方查看器获取准确逻辑:这是准确率最高的方案,无需猜测参数。给运行中的官方查看器进程挂载调试器,在
inflateInit2_、inflate这几个zlib标准导出函数上下断点,直接抓取调用时传入的wbits参数、输入缓冲区起止位置、输出缓冲区的解压结果,一次即可拿到准确的解压逻辑和完整数据。 - 后置校验rtf结构:rtf格式有明确的结构特征:文件头固定为
{\rtf,整个文件的大括号完全配对。如果解压后内容仍有少量异常,可以微调数据起始偏移(分别尝试跳过0、1、2、3字节头部再解压),直到解压出的rtf括号完全配对、内容与官方查看器展示结果一致即可。
内容的提问来源于stack exchange,提问作者MendelYev
相关产品推荐
相关产品推荐

