Mar 14, 2019
ZIP 文件常用结构分析和修复
发生场景
在不同的平台,给多个文件打包成一个 zip 压缩文件,常常会出现文件压缩损坏,损坏的形式很多
- 比如 Central Directory 损坏
- 或者由于压缩文件里面各个文件相对独立,可能其中一个文件损坏
- 或者文件在持久化的时候在内存中被清理了一段内容,最终文件某一部分全是数据 0
- 还有就是不是被清理而是内存中随机的一段数据
- 甚至是整个文件都是 0
- 或者 0kb 文件
- 前面两种都能比较容易修复,后面三种情况不可能修复,第三种情况如果幸运,也可以修复
常见的 zip 结构
[文件头+文件数据+数据描述符]{此处可重复n次}+核心目录+目录结束标识
当压缩包中包含多个文件,就会有多个
文件头+文件数据+数据描述符
使用 xxd 可以获得压缩文件的 hexdump 内容,如下:
1 | 00000000: 504b 0304 0a00 0000 0000 615e 6d4e 3f41 PK........a^mN?A |
如果需要每个 flag 的意思,可以去 ZIP [^ZIP Wikipedia] 或者下面的参考链接中查看
在不了解 zip 结构的情况下,可以使用专业的修复工具处理
常见的可以使用 zip 自带的修复功能:
1 | 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 ,在恢复的时候数据会丢失,有可能要用vim -b filename
用二进制打开文件) - 自己建立的一个 zip 文件,里面包含了一个同名
fileA.json
,并且内容要大于 37 Bytes,否则会 zip 会使用 store 的压缩方式
1 | echo aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa > fileA.json |
- 在 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 Wikipedia]: ZIP: https://en.wikipedia.org/wiki/Zip_(file_format)