发生场景
在不同的平台,给多个文件打包成一个 zip 压缩文件,常常会出现文件压缩损坏,损坏的形式很多
- 比如 Central Directory 损坏
- 或者由于压缩文件里面各个文件相对独立,可能其中一个文件损坏
- 或者文件在持久化的时候在内存中被清理了一段内容,最终文件某一部分全是数据 0
- 还有就是不是被清理而是内存中随机的一段数据
- 甚至是整个文件都是 0
- 或者 0kb 文件
- 前面两种都能比较容易修复,后面三种情况不可能修复,第三种情况如果幸运,也可以修复
常见的 zip 结构
[文件头+文件数据+数据描述符]{此处可重复n次}+核心目录+目录结束标识
当压缩包中包含多个文件,就会有多个
文件头+文件数据+数据描述符
使用 xxd 可以获得压缩文件的 hexdump 内容,如下:
00000000: 504b 0304 0a00 0000 0000 615e 6d4e 3f41 PK........a^mN?A
Signature Ver flag thod moti moda CRC-
00000010: 2435 0300 0000 0300 0000 0500 1c00 612e $5............a.
32 Comprsize UnComSize flen elen filename-n
00000020: 7478 7455 5409 0003 267e 3f5c 277e 3f5c txtUT...&~?\'~?\
5 Bytes End name|Extral field 28 Bytes
00000030: 7578 0b00 0104 3f01 0000 0414 0000 0061 ux....?........a
EndExtralField|dataArea
00000040: 6263 504b 0304 0a00 0000 0000 715e 6d4e bcPK........q^mN
Signature Ver flag ...
00000050: 033f 2c51 0300 0000 0300 0000 0700 1c00 .?,Q............
00000060: 6566 672e 7478 7455 5409 0003 457e 3f5c efg.txtUT...E~?\
00000070: 467e 3f5c 7578 0b00 0104 3f01 0000 0414 F~?\ux....?.....
00000080: 0000 0065 6667 504b 0102 1e03 0a00 0000 ...efgPK........
CentraDir Ver VMin flag
00000090: 0000 615e 6d4e 3f41 2435 0300 0000 0300 ..a^mN?A$5......
thod moti moda CRC-32 ComprSize Unco
000000a0: 0000 0500 1800 0000 0000 0100 0000 3f3f ..............??
mSize flen elen clen dnum Iatt ExterAttr
000000b0: 0000 0000 612e 7478 7455 5405 0003 267e ....a.txtUT...&~
offsetHeader |FileName |46 Bytes
000000c0: 3f5c 7578 0b00 0104 3f01 0000 0414 0000 ?\ux....?.......
000000d0: 0050 4b01 021e 030a 0000 0000 0071 5e6d .PK..........q^m
000000e0: 4e03 3f2c 5103 0000 0003 0000 0007 0018 N.?,Q...........
|ExtraField 24 Bytes
000000f0: 0000 0000 0001 0000 003f 3f42 0000 0065 .........??B...e
End|File comment, there is zero
00000100: 6667 2e74 7874 5554 0500 0345 7e3f 5c75 fg.txtUT...E~?\u
00000110: 780b 0001 043f 0100 0004 1400 0000 504b x....?........PK
00000120: 0506 0000 0000 0200 0200 3f00 0000 3f00 ..........?...?.
0x06054b50 End
00000130: 0000 0000 0a .....
如果需要每个 flag 的意思,可以去 ZIP 1 或者下面的参考链接中查看
在不了解 zip 结构的情况下,可以使用专业的修复工具处理
常见的可以使用 zip 自带的修复功能:
zip -FF --out fixed.zip ./corrupt.zip
其中 如果一个 -F
是在 Central Directory 存在的情况下,能修复部分功能,两个F -FF
是能直接扫描所有文件头,并提取出来。
这样会出现一种现象就是解压厚的文件会出现替换的提示,这是因为里面有一个文档在之前的 Central Directory 中标记为删除,现在被提取出来了。可惜的是, zip 自带的方法还是有问题,对于只有一部分正常的数据,是无法正常修复对应的文件的。并且一旦文件头损坏, zip 也不能自主修复。
Windows 上的工具比较专业,大部分可能修复的文件都能修复:
- 使用 ZIP Repair 修复,目前感觉最优秀的修复工具,下载地址是 https://www.diskinternals.com/download/zip_repair.exe
- 常见的压缩工具也有一定的修复能力,其中试过最好的应该是 haozip
尝试修复压缩包中一个文件 fileA.json
- 使用
xxd filename.zip > filename.hex
生成一个 hexdump 文件(不要用 vim 的 !xxd ,在恢复的时候数据会丢失,具体原因尚不清楚) - 自己建立的一个 zip 文件,里面包含了一个同名
fileA.json
,并且内容要大于 37 Bytes,否则会 zip 会使用 store 的压缩方式
echo aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa > fileA.json
zip filename_correct.zip fileA.json
xxd filename_correct.zip > filename_correct.hex
- 在 filename.hex 找到 0x04034b50 以 ascii 为 PK 开头的位置,拷贝 [文件头+文件数据+数据描述符] 到
filename_correct.hex
中对应的位置 - 把左边的地址和右边的 ascii 全部删除,并且去掉空格和换行,然后使用
xxd -r -p filename_correct.hex > filename_correct_fixed.zip
获得新的 zip 包 - 尝试用
unzip filename_correct_fixed.zip
解压缩文件,如果文件正常,是能正常释出文件 - 如果不正常,比如 unzip 报告说:
warning: filename too long--truncating.
那就是文件名长度附近的位置值不正确,可以看看周围的数据是否能人为的推断 - 实在不行那暂时没有方法了,因为数据有可能是离散无序的
附录
- 这里没有讲 Deflate 算法的实现,不过如果上面的方式还不能修复,那希望基本很渺茫了,以后有机会再说。
- ZIP 最开始是 PKZIP 工具支持的一种压缩文件,最开始由 Phil Katz 开发,由 PKWARE 公司维护,所以文件二进制开头是 PK,不过 Phil Katz 没赚到钱。
- 当时以 Floppy Disk 为主,转换磁头很慢,多个文件压缩成一个文件,其中的每个文件都是独立的,所以可以为 zip 添加新内容。通过操作 Central Directory 来控制,这样减少了磁头频繁大角度移动。
参考链接
- https://en.wikipedia.org/wiki/Zip_(file_format)
- https://pkware.cachefly.net/webdocs/APPNOTE/APPNOTE-6.2.0.txt
- https://blog.csdn.net/a200710716/article/details/51644421
- https://superuser.com/questions/125376/how-do-i-compare-binary-files-in-linux
-
ZIP: https://en.wikipedia.org/wiki/Zip_(file_format) ↩