zip 文件格式分析: 附实例介绍

来源:互联网 发布:邮件服务器软件选择 编辑:程序博客网 时间:2024/06/07 07:57
zip 文件格式分析: 附实例介绍
ZIP format
Byte order: Little-endian

Overall zipfile format:
[Local file header + Compressed data [+ Extended local header]?]*
[Central directory]*
[End of central directory record]

Local file header:
Offset   Length   Contents
  0      4 bytes  Local file header signature (0x04034b50)
  4      2 bytes  Version needed to extract
  6      2 bytes  General purpose bit flag
  8      2 bytes  Compression method
 10      2 bytes  Last mod file time
 12      2 bytes  Last mod file date
 14      4 bytes  CRC-32
 18      4 bytes  Compressed size (n)
 22      4 bytes  Uncompressed size
 26      2 bytes  Filename length (f)
 28      2 bytes  Extra field length (e)
        (f)bytes  Filename
        (e)bytes  Extra field
        (n)bytes  Compressed data

Extended local header:
Offset   Length   Contents
  0      4 bytes  Extended Local file header signature (0x08074b50)
  4      4 bytes  CRC-32
  8      4 bytes  Compressed size
 12      4 bytes  Uncompressed size

Central directory:
Offset   Length   Contents
  0      4 bytes  Central file header signature (0x02014b50)
  4      2 bytes  Version made by
  6      2 bytes  Version needed to extract
  8      2 bytes  General purpose bit flag
 10      2 bytes  Compression method
 12      2 bytes  Last mod file time
 14      2 bytes  Last mod file date
 16      4 bytes  CRC-32
 20      4 bytes  Compressed size
 24      4 bytes  Uncompressed size
 28      2 bytes  Filename length (f)
 30      2 bytes  Extra field length (e)
 32      2 bytes  File comment length (c)
 34      2 bytes  Disk number start
 36      2 bytes  Internal file attributes
 38      4 bytes  External file attributes
 42      4 bytes  Relative offset of local header
 46     (f)bytes  Filename
        (e)bytes  Extra field
        (c)bytes  File comment

End of central directory record:
Offset   Length   Contents
  0      4 bytes  End of central dir signature (0x06054b50)
  4      2 bytes  Number of this disk
  6      2 bytes  Number of the disk with the start of the central directory
  8      2 bytes  Total number of entries in the central dir on this disk
 10      2 bytes  Total number of entries in the central dir
 12      4 bytes  Size of the central directory
 16      4 bytes  Offset of start of central directory with respect to the starting disk number
 20      2 bytes  zipfile comment length (c)
 22     (c)bytes  zipfile comment

compression method: (2 bytes)
          0 - The file is stored (no compression)
          1 - The file is Shrunk
          2 - The file is Reduced with compression factor 1
          3 - The file is Reduced with compression factor 2
          4 - The file is Reduced with compression factor 3
          5 - The file is Reduced with compression factor 4
          6 - The file is Imploded
          7 - Reserved for Tokenizing compression algorithm
          8 - The file is Deflated

单看上面的介绍不会有多少印象,也可能不知道它在说什么,
下面以一个android 的apk 来举例分析, 它包含289个文件,文件大小7.4M,是个真枪实弹的东西。
看完实例,结合上面介绍,就理解了数据结构!
我把central directory 翻译为中央目录, 为什么这么翻译呢?
因为目录区是一块连续的区域(由一系列pk0102区块构成),位于文件的尾部。
但最后的文件尾部由(pk0506)占据
文件前部是一系列pk0304开头+压缩数据+pk0708结尾的区域。
所以可以说目录区算中央。
原来我把它翻译为核心,后来觉得没有"核心"这个意思,又翻译为"中心",也觉得不妥,
还是觉得中央目录或者中部目录更贴贴吧,或者简单就叫目录,个人之见!

先说说最尾部目录,
这个东西是全局唯一的,位置在尾部,因此特别重要。
结构长度:22 bytes
举例:
0761e70: 6c61 7368 5f68 2e6a 7067 504b 0506 0000  lash_h.jpgPK....
0761e80: 0000 2101 2101 2a54 0000 50ca 7500 0000  ..!.!.*T..P.u...
它的signature 是0x50,0x4b,0x05,0x06
后面2byte: 0x00,0x00                  //当前磁盘编号,现在都不用了,
后面2byte: 0x00,0x00                //中央目录开始的磁盘编号,现在都不用了,
后面2byte: 0x21,0x01                   //小端序,实际为0x0121,下同. 该磁盘的中央目录个数
后面2byte: 0x21,0x01                   //0x0121, 中央目录结构总数, 现在硬盘时代,数值跟上面一样了。
后面4byte: 0x2a,0x54,0x00,0x00       //0x542a, 中央目录大小
后面4byte: 0x50,0xca,0x75,0x00       //0x75ca50, 中央目录的偏移
后面2byte: 0x00,0x00                //注释长度为0
可见它交代了中央目录的大小和位置,也告诉了你中央目录的个数。

再看看0x75ca50处中央目录数据: 大小0x542a
075ca50: 504b 0102 1400 1400 0800 0800 7965 d344  PK..........ye.D
075ca60: ebde ad91 221f 0000 785b 0000 1400 0000  ...."...x[......
075ca70: 0000 0000 0000 0000 0000 0000 0000 4d45  ..............ME
075ca80: 5441 2d49 4e46 2f4d 414e 4946 4553 542e  TA-INF/MANIFEST.
075ca90: 4d46 504b 0102 1400 1400 0800 0800 7965  MFPK..........ye
075caa0: d344 b39e 168c 5421 0000 f15b 0000 1200  .D....T!...[....
075cab0: 0000 0000 0000 0000 0000 0000 641f 0000  ............d...
075cac0: 4d45 5441 2d49 4e46 2f55 4e49 434f 4d2e  META-INF/UNICOM.
075cad0: 5346 504b 0102 1400 1400 0800 0800 7965  SFPK..........ye
075cae0: d344 efc7 cd57 ed0b 0000 fe12 0000 1300  .D...W..........
075caf0: 0000 0000 0000 0000 0000 0000 f840 0000  .............@..
075cb00: 4d45 5441 2d49 4e46 2f55 4e49 434f 4d2e  META-INF/UNICOM.
075cb10: 5253 4150 4b01 0214 0014 0008 0008 0078  RSAPK..........x
075cb20: 65d3 4444 e759 a3b6 0500 00e0 1300 0013  e.DD.Y..........
075cb30: 0004 0000 0000 0000 0000 0000 0026 4d00  .............&M.
075cb40: 0041 6e64 726f 6964 4d61 6e69 6665 7374  .AndroidManifest
075cb50: 2e78 6d6c feca 0000 504b 0102 1400 1400  .xml....PK......
075cb60: 0800 0800 7865 d344 ........ (忽略)
每个结构长度46bytes,
signature: 0x50,0x4b,0x01,0x02
后边2btes: 0x14,0x00            //压缩时的版本
后边2btes: 0x14,0x00            //解压缩需要的最低版本
后边2btes: 0x08,0x00            //通用位标记
后边2btes: 0x08,0x00            //压缩方法标记
后边2btes: 0x79,0x65            //文件修改时间
后边2btes: 0xd3,0x44            //文件修改日期
后边4btes: 0xeb,0xde,0xad,0x91    //crc-32
后边4btes: 0x22,0x1f,0x00,0x00    //压缩后大小
后边4btes: 0x78,0x5b,0x00,0x00    //未压缩大小
后边2btes: 0x14,0x00            //文件名长度
后边2btes: 0x00,0x00            //扩展域长度
后边2btes: 0x00,0x00            //文件注释长度
后边2btes: 0x00,0x00            //磁盘号开始,已经不用了
后边2btes: 0x00,0x00            //内部文件属性
后边4btes: 0x00,0x00,0x00,0x00    //外部文件属性
后边4btes: 0x00,0x00,0x00,0x00    //本地文件头的相对偏移
META-INF/MANIFEST.MF             //文件名
每一个目录项对应一个文件,记录了压缩,解压的版本,压缩方法。
文件日期,时间,文件名,文件大小,压缩大小,文件偏移地址,crc32等

下一个中央目录记录:
signature: 0x50,0x4b,0x01,0x02
后边2btes: 0x14,0x00            //压缩时的版本
后边2btes: 0x14,0x00            //解压缩需要的最低版本
后边2btes: 0x08,0x00            //通用位标记
后边2btes: 0x08,0x00            //压缩方法标记
后边2btes: 0x79,0x65            //文件修改时间
后边2btes: 0xd3,0x44            //文件修改日期
后边4btes: 0xb3,0x9e,0x16,0x8c    //crc-32
后边4btes: 0x54,0x21,0x00,0x00    //压缩后大小
后边4btes: 0xf1,0x5b,0x00,0x00    //未压缩大小
后边2btes: 0x12,0x00            //文件名长度
后边2btes: 0x00,0x00            //扩展域长度
后边2btes: 0x00,0x00            //文件注释长度
后边2btes: 0x00,0x00            //磁盘号开始,已经不用了
后边2btes: 0x00,0x00            //内部文件属性
后边4btes: 0x00,0x00,0x00,0x00    //外部文件属性
后边4btes: 0x64,0x1f,0x00,0x00    //本地文件头的相对偏移
META-INF/UNICOM.SF                 //文件名
下同...... 忽略

第一个目录提到了,文件头偏移位置为0
第二个目录提到了,文件头偏移位置为0x1f64,
下面分析一下数据:

0000000: 504b 0304 1400 0800 0800 7965 d344 0000  PK........ye.D..
0000010: 0000 0000 0000 0000 0000 1400 0000 4d45  ..............ME
0000020: 5441 2d49 4e46 2f4d 414e 4946 4553 542e  TA-INF/MANIFEST.
0000030: 4d46 b57c c9ae db58 b2ed bc80 fa87 1cbe  MF.|...X........
本地文件头结构: 30bytes
signature: 0x50,0x4b,0x03,0x03
后边2btes: 0x14,0x00            //解压缩时的最低版本
后边2btes: 0x08,0x00            //通用位标记
后边2btes: 0x08,0x00            //压缩方法标记
后边2btes: 0x79,0x65            //文件修改时间
后边2btes: 0xd3,0x44            //文件修改日期
后边4btes: 0x00,0x00,0x00,0x00    //crc-32
后边4btes: 0x00,0x00,0x00,0x00    //压缩后大小
后边4btes: 0x00,0x00,0x00,0x00    //未压缩大小
后边2btes: 0x14,0x00            //文件名长度
后边2btes: 0x00,0x00            //扩展域长度
META-INF/MANIFEST.MF + zipData
可见本地文件头和目录结构信息是有冗余的。
.....
0001f50: cffa f7bf 504b 0708 ebde ad91 221f 0000  ....PK......"...
0001f60: 785b 0000 504b 0304 1400 0800 0800 7965  x[..PK........ye
注意:在本地文件尾部我们看到了PK0708,这是扩展本地头,由12byte组成
signature: 0x50,0x4b,0x07,0x08
后边4btes: 0xeb,0xde,0xad,0x91    //crc-32
后边4btes: 0x22,0x1f,0x00,0x00    //压缩后大小
后边4btes: 0x78,0x5b,0x00,0x00    //未压缩大小

我们看到一个本地头加上一个扩展本地头可以构成一个中央目录项。

再分析一下第二个文件:
0001f50: cffa f7bf 504b 0708 ebde ad91 221f 0000  ....PK......"...
0001f60: 785b 0000 504b 0304 1400 0800 0800 7965  x[..PK........ye
0001f70: d344 0000 0000 0000 0000 0000 0000 1200  .D..............
0001f80: 0000 4d45 5441 2d49 4e46 2f55 4e49 434f  ..META-INF/UNICO
0001f90: 4d2e 5346 957c c7b2 a3d8 b66d ff46 dc7f  M.SF.|.....m.F..
本地文件头结构: 30bytes
signature: 0x50,0x4b,0x03,0x03
后边2btes: 0x14,0x00            //解压缩时的最低版本
后边2btes: 0x08,0x00            //通用位标记
后边2btes: 0x08,0x00            //压缩方法标记
后边2btes: 0x79,0x65            //文件修改时间
后边2btes: 0xd3,0x44            //文件修改日期
后边4btes: 0x00,0x00,0x00,0x00    //crc-32
后边4btes: 0x00,0x00,0x00,0x00    //压缩后大小
后边4btes: 0x00,0x00,0x00,0x00    //未压缩大小
后边2btes: 0x12,0x00            //文件名长度
后边2btes: 0x00,0x00            //扩展域长度
META-INF/UNICOM.SF + zipData

至此,压缩的数据格式就分析清楚了,至于加压算法,
如上述9种,实际7种, 就不在本帖之内了。


0 0