RAR文件格式分析
突然心血来潮,分析了一下这个格式,在家无法专心学习,一篇文章拖了挺长时间。
对RAR文件格式的细节有了更深刻的了解。
1、RAR简介
wikipedia:
1、https://en.wikipedia.org/wiki/RAR_(file_format)
2、https://www.loc.gov/preservation/digital/formats/fdd/fdd000450.shtml
RAR是一种专利文件格式,用于数据压缩
与归档打包
,开发者为尤金·罗谢尔
(俄语:Евгений Лазаревич Рошал,拉丁转写:Yevgeny Lazarevich Roshal),RAR的全名是“Roshal ARchive
”,即“罗谢尔的归档”之意。首个公开版本RAR 1.3
发布于1993年。
尤金·罗谢尔,1972年3月10日生于俄罗斯
。毕业于俄罗斯车里雅宾斯克工业大学(Chelyabinsk Technical University,今南乌拉州立大学),也是FAR文件管理器
的作者。他开发程序压缩或解压RAR文件,最初用于DOS,后来移植到其它平台。主要的Windows版本编码器,称为WinRAR,以共享软件的形式发行。不过罗谢尔公开了解码器源码,UnRAR解码器许可证以不许发布编译RAR兼容编码器为条件下允许有条件自由发布与修改,而RAR编码器一直是有专利的。
最近的开发者是尤金·罗谢尔的胞兄亚历山大·罗谢尔
。虽然其解码器有专利,编译好的解压程序仍然存在于若干平台,例如开源的7-Zip。
RAR同时也拥有成熟的加密算法,2.0 版本前
加密算法未公开,2.0 版本后
使用AES算法加密,在没有密码情况下目前只有暴力破解
。
文件特点:
- RAR通常情况比ZIP压缩比高,但压缩/解压缩速度较慢。
- 分卷压缩:压缩后分割为多个文件。
- 固实压缩:将要压缩的文件视为同一个文件以加大压缩比,代价是取用压缩包中任何文件需要解压整个压缩包。
- 恢复记录:加入冗余数据用于修复,在压缩包本身损坏但恢复记录够多时可对损坏压缩包进行恢复。
- 加密:RAR 2.0使用AES-128-CBC,RAR5.0以后为AES-256-CBC。之前RAR的加密算法为私有。当前除了暴力破解之外不存在(至少没有公开)有效的破解方法。
1.1、RAR的历史版本
RAR文件格式的修订历史记录
:
1.3
第一个公开版本,没有“ Rar!” 签名。1.5
更改未知。2.0
与WinRAR 2.0和Rar一起发布,用于MS-DOS 2.0。2.9
在WinRAR版本3.00中发布。5.0
WinRAR 5.0及更高版本支持。
WinRAR 5.0和Android的RAR将2.9版本
称为RAR4
。
2、RAR压缩文件格式分析
2.1、RAR 1.5 - 4.0文件格式分析
参考资料:
1、http://acritum.com/winrar/rar-format
2、https://forensicswiki.xyz/page/RAR
3、https://blog.csdn.net/howeverpf/article/details/8909362
4、https://codedread.github.io/bitjs/docs/unrar.html
实例环境:
压缩文件由可变长度
的块组成。这些块的顺序
可以变化,但是第一个块必须是标记块
,然后是压缩文件头块
。
现在公开的块类型有:标记块
,压缩文件头块
,文件头块
,注释头块
,用户身份信息块
,子块
和恢复记录块
等。每一块的开始是由通用字段开始,且每一个不同的块的通用字段结构都是一样的。
通用字段结构
如下表:
字段名称 | 长度(byte) | 说明 |
---|---|---|
HEAD_CRC | 2 | 所有块或块部分的CRC |
HEAD_TYPE | 1 | 块类型 |
HEAD_FLAGS | 2 | 块标记 |
HEAD_SIZE | 2 | 块大小 |
如果块标记的第一位被置1的话((HEAD_FLAGS & 0x8000)!= 0
)还存在:
字段名称 | 长度(byte) | 说明 |
---|---|---|
ADD_SIZE | 4 | 可选结构 - 增加块大小 |
所以文件大小的计算分两种情况,当块标记HEAD_FLAGS
首位未置1,则总块大小就是HEAD_SIZE
,当块标记HEAD_FLAGS
首位置1,可选结构ADD_SIZE
存在,则总块大小为HEAD_SIZE
+ADD_SIZE
。
在每个块中,HEAD_FLAGS
中的以下位具有相同的含义:
0x4000
- 如果设置,则较旧的RAR版本将忽略该块,并在更新存档时将其删除。如果清除,则在更新存档时将此块复制到新的存档文件;0x8000
- 如果设置,则存在ADD_SIZE字段,且完整块大小为HEAD_SIZE + ADD_SIZE。
块类型:
HEAD_TYPE = 0x72
- MARK_HEAD(标记块)HEAD_TYPE = 0x73
- MAIN_HEAD(压缩文件头)HEAD_TYPE = 0x74
- FILE_HEAD(文件头)HEAD_TYPE = 0x75
- COMM_HEAD(旧风格的注释头)HEAD_TYPE = 0x76
- AV_HEAD(旧风格的授权信息块/用户身份信息块)HEAD_TYPE = 0x77
- SUB_HEAD(旧风格的子块)HEAD_TYPE = 0x78
- PROTECT_HEAD(旧风格的恢复记录)HEAD_TYPE = 0x79
- SIGN_HEAD(旧风格的授权信息块/用户身份信息块)HEAD_TYPE = 0x7A
- NEWSUB_HEAD(子块)HEAD_TYPE = 0x7B
- ENDARC_HEAD(结束块)
2.1.1、标记块( MARK_HEAD )
字段名称 | 长度(byte) | 说明 |
---|---|---|
HEAD_CRC | 2 | 总是0x6152 |
HEAD_TYPE | 1 | 0x72 |
HEAD_FLAGS | 2 | 总是0x1A21 |
HEAD_SIZE | 2 | 块大小 = 0x0007,即7个字节 |
所以这里标记块的大小固定是7 个字节,且是一个固定的字节序列。标记块
也称为Magic number
。
实例:
2.1.2、压缩文件头( MAIN_HEAD )
字段名称 | 长度(byte) | 说明 |
---|---|---|
HEAD_CRC | 2 | HEAD_TYPE到RESERVED2的CRC |
HEAD_TYPE | 1 | 0x73 |
HEAD_FLAGS | 2 | 位标记:0x0001 - MHD_VOLUME: 卷属性(压缩文件卷) 0x0002 - MHD_COMMENT: 压缩文件注释存在,RAR 3.x使用单独的注释块,不设置这个标记。 0x0004 - MHD_LOCK: 压缩文件锁定属性 0x0008 - MHD_SOLID: 固实属性(固实压缩文件) 0x0010 - MHD_NEWNUMBERING: 新的卷命名法则(‘volname.partN.rar’) 0x0020 - MHD_AV: 用户身份信息存在,RAR 3.x使用单独的用户身份信息块,不设置这个标记。 0x0040 - MHD_PROTECT: 恢复记录存在 0x0080 - HD_PASSWORD: 块头被加密 0x0100 - MHD_FIRSTVOLUME: 第一卷(只有RAR3.0及以后版本设置) 0x0200 - MHD_ENCRYPTVER: HEAD_FLAGS中的其他位保留用于内部使用。 |
HEAD_SIZE | 2 | 压缩文件头总大小(包括压缩文件注释) |
RESERVED1 | 2 | 保留 |
RESERVED2 | 4 | 保留 |
对于压缩文件头
里的位标记
,如果它的第9位(从左到右)被置1,块头被加密,也就是通常所说的加密文件名
,打开这样加密的RAR文件时,需要先输入密码才能看到压缩包内的文件列表。
实例:
这里头类型是0x73表示是压缩文件头块
,位标记为0x0000未有位被置1,如果块头被加密
则位标记应为0x0080,文件头大小
为0x000D,所以这个压缩文件头块
占用13 个字节,保留字节用0x00 填充。
2.1.3、文件头( FILE_HEAD )
字段名称 | 长度(byte) | 说明 |
---|---|---|
HEAD_CRC | 2 | 从HEAD_TYPE到FILEATTR的CRC |
HEAD_TYPE | 1 | 0x74 |
HEAD_FLAGS | 2 | 位标记: 0x0001 - LHD_SPLIT_BEFORE: 文件从上一卷继续 0x0002 - LHD_SPLIT_AFTER: 文件从后一卷继续 0x0004 - LHD_PASSWORD: 文件使用密码加密 0x0008 - LHD_COMMENT: 文件注释存在,RAR 3.x使用独立的注释块,不设置这个标记。 0x0010 - LHD_SOLID: 前一文件信息被使用(固实标记) (对于RAR 2.0 和以后版本) 7 6 5 位(对于RAR 2.0和以后版本) 0 0 0 - 字典大小 64KB 0 0 1 - 字典大小 128KB 0 1 0 - 字典大小 256KB 0 1 1 - 字典大小 512KB 1 0 0 - 字典大小 1024KB 1 0 1 - 字典大小 2048KB 1 1 0 - 字典大小 4096KB 1 1 1 - 文件作为字典 0x0100 - LHD_LARGE: HIGH_PACK_SIZE和HIGH_UNP_SIZE结构存在。这些结构仅用在非常大(大于2GB)的文档,对于小文件这些结构不存在。 0x0200 - LHD_UNICODE: FILE_NAME是用0隔开的包含普通的和Unicode编码的文件名。所以NAME_SIZE字段的值等于普通文件名的长度加Unicode编码文件名的长度再加1。如果此标记存在,但是FILE_NAME不包含0字节,它意味文件名使用UTF-8编码。 0x0400 - LHD_SALT: 文件头在文件名后包含附加的8byte,它对于增加加密的安全性是必需的。(所谓的’Salt’)。 0x0800 - LHD_VERSION: 版本标记。它是旧文件版本,版本号作为’;n’附加到文件名后。 0x1000 - LHD_EXTTIME: 扩展时间区域存在。 0x2000 - LHD_EXTFLAGS: 0x8000 - 此位总被设置,所以完整的块的大小是HEAD_SIZE + PACK_SIZE(如果0x100 位被设置,再加上HIGH_PACK_SIZE) |
HEAD_SIZE | 2 | 文件头的全部大小(包含文件名和注释) |
PACK_SIZE | 4 | 已压缩文件大小 |
UNP_SIZE | 4 | 未压缩文件大小 |
HOST_OS | 1 | 保存压缩文件使用的操作系统 0x00 - MS DOS 0x01 - OS/2 0x02 - Win32 0x03 - Unix 0x04 - Mac OS 0x05 - BeOS |
FILE_CRC | 4 | 文件CRC |
FTIME | 4 | MS DOS标准格式的日期和时间 |
UNP_VER | 1 | 解压文件所需要最低RAR版本,版本编码方法:10 * 主版本 + 副版本。 |
METHOD | 1 | 压缩方式: 0x30 - 存储 0x31 - 最快压缩 0x32 - 较快压缩 0x33 - 标准压缩 0x34 - 较好压缩 0x35 - 最好压缩 |
NAME_SIZE | 2 | 文件名大小 |
ATTR | 4 | 文件属性 |
HIGH_PACK_SIZE | 4 | 可选值,已压缩文件大小 64位值的高4字节。只HEAD_FLAGS中的0x100 位被设置才存在。 |
HIGH_UNP_SIZE | 4 | 可选值,未压缩文件大小 64位值的高4字节。只有HEAD_FLAGS中的0x100 位被设置才存在。 |
FILE_NAME | NAME_SIZE | 文件名 - NAME_SIZE字节大小字符串 |
SALT | 8 | 可选值,如果(HEAD_FLAGS & 0x400)!= 0,则存在 |
EXT_TIME | 可变大小 | 可选值,扩展时间区域,如果(HEAD_FLAGS & 0x1000)!= 0,则存在 |
实例1:
实例2:
在这个块中,存在两个CRC值
,一个是文件头块中从块类型
到文件名
这38(实例1)或40(实例2)个字节的校验,后一个则是压缩包中所含文件的CRC校验
,解压时,会计算解压后生成文件的CRC值,如果等于这里的CRC,则解压完成,如果不同,则报错中断。
位标记0x9020
(10010000 00100000B) = 0x0020 || 0x1000 || 0x8000,0x0020
(字典大小 128KB)、0x1000
(扩展时间区域存在)、0x8000
(此位总被设置)。
2.1.4、结尾块( ENDARC_HEAD )
字段名称 | 长度(byte) | 说明 |
---|---|---|
HEAD_CRC | 2 | 从HEAD_TYPE 到HEAD_SIZE 的CRC校验值 |
HEAD_TYPE | 1 | 0x7B |
HEAD_FLAGS | 2 | 位标记 |
HEAD_SIZE | 2 | 结尾块大小 |
与标记块类似的是,结尾块
也是一个固定字节串的块,依次是C4 3D 7B 00 40 07 00
。
实例:
前一个文件块起始位置偏移
为81,而前一个文件块的大小
是HEAD_SIZE + PACK_SIZE(0x002F + 0x153A = 0x1569) = 5481byte。所以结尾块的偏移
为5481 + 81 = 5562。
2.1.5、旧风格的块类型
除以上格式块以外,还存在一些旧风格的块类型,不过在新的版本中已经不存在了。
旧风格的注释头块:
字段名称 | 长度(byte) | 说明 |
---|---|---|
HEAD_CRC | 2 | 从HEAD_TYPE 到COMM_CRC 的CRC校验值 |
HEAD_TYPE | 1 | 0x75 |
HEAD_FLAGS | 2 | 位标记 |
HEAD_SIZE | 2 | 注释头大小 |
UNP_SIZE | 2 | 未压缩注释大小 |
UNP_VER | 1 | 提取注释的RAR最低版本 |
METHOD | 1 | 压缩方法 |
COMM_CRC | 2 | 注释CRC |
COMMENT | N | 注释正文 |
旧风格的授权信息块/用户身份信息块:
字段名称 | 长度(byte) | 说明 |
---|---|---|
HEAD_CRC | 2 | 从HEAD_TYPE 到HEAD_SIZE的CRC校验值 |
HEAD_TYPE | 1 | 0x76 |
HEAD_FLAGS | 2 | 位标记 |
HEAD_SIZE | 2 | 块大小 |
INFO | N | 授权信息/用户身份信息正文 |
旧风格的子块:
在压缩文件中任意文件头块
后面都可以附加一个子块
。这个子块依赖于它前面的这个主块
。当更新时新版本的RAR压缩包可能会删除或者移动这个子块。
字段名称 | 长度(byte) | 说明 |
---|---|---|
HEAD_CRC | 2 | 块CRC |
HEAD_TYPE | 1 | 0x77 |
HEAD_FLAGS | 2 | 位标记 |
HEAD_SIZE | 2 | 总块大小 |
DATA_SIZE | 4 | 总数据块大小 |
SUB_TYPE | 2 | 子块类型 |
RESERVED | 1 | 保留字段,必须为0 |
其余字段 | 由SUB_TYPE 决定其余字段类型 |
以SUB_TYPE
为0x100为例,0x100定义子块类型为扩展属性类型
,一般用于压缩一些文件属性信息较详细的文件。
字段名称 | 长度(byte) | 说明 |
---|---|---|
HEAD_CRC | 2 | 块CRC |
HEAD_TYPE | 1 | 0x77 |
HEAD_FLAGS | 2 | 位标记 |
HEAD_SIZE | 2 | 总块大小 |
DATA_SIZE | 4 | 总数据块大小 |
SUB_TYPE | 2 | 子块类型,定义子块为扩展属性类型 |
RESERVED | 1 | 保留字段,必须为0。以上为子块中固定格式 |
UNP_SIZE | 4 | 未压缩扩展属性大小。以下为扩展属性附加字段。 |
UNP_VER | 1 | 提取扩展属性的RAR最低版本 |
METHOD | 1 | 压缩方式 |
EA_CRC | 4 | 扩展属性CRC |
2.2、RAR 5+文件格式分析
Here we describe basic data structures of archive format introduced in RAR 5.0. If you need information about algorithms or more detailed information on data structures, please use UnRAR source code.
在这里,我们描述了RAR 5.0
中引入的存档格式的基本数据结构
。如果您需要有关算法的信息或有关数据结构的更多详细信息,请使用UnRAR
源代码。
实例环境:
设置的密码未加密文件名
。
2.2.1、Data types(数据类型)
vint
Variable length integer. Can include one or more bytes, where lower 7 bits of every byte contain integer data and highest bit in every byte is the continuation flag. If highest bit is 0, this is the last byte in sequence. So first byte contains 7 least significant bits of integer and continuation flag. Second byte, if present, contains next 7 bits and so on.
可变长度
整数。可以包含一个
或多个
字节,其中每个字节的低7位
包含整数数据,而每个字节中的最高位
是连续标志。如果最高位为0
,则这是序列中的最后一个字节。因此,第一个字节包含低位7个有效位的整数
和连续标志
。第二个字节(如果存在)包含下一个7位,依此类推。
Currently RAR format uses vint to store up to 64 bit integers, resulting in 10 bytes maximum. This value may be increased in the future if necessary for some reason.
当前的RAR格式使用vint
最多存储64位
整数,所以vint
最大可以包含10个字节
。如果出于某种原因,将来可能会增加此值。
Sometimes RAR needs to pre-allocate space for vint before knowing its exact value. In such situation it can allocate more space than really necessary and then fill several leading bytes with 0x80 hexadecimal, which means 0 with continuation flag set.
有时,RAR需要在知道确切值之前为vint
预先分配空间。在这种情况下,它可以分配超出
实际需要的空间,然后用0x80
十六进制填充几个前导字节,这意味着设置了连续标志
。
byte
, uint16
, uint32
, uint64
Byte, 16-, 32-, 64- bit unsigned integer in little endian format.Byte
,16bit
、32bit
、64bit
的无符号整型使用的都是小端存储格式
。
Variable length data(可变长度的数据)
We use ellipsis … to denote variable length data areas.
我们使用省略号(...)
表示可变长度
的数据区域。
Hexadecimal values(十六进制值)
We use 0x prefix to define hexadecimal values, such as 0xf000.
我们使用0x前缀定义十六进制值,例如0xf000
。
2.2.2、General archive structure(通用压缩文档结构)
General archive block format(通用压缩文档块格式)
字段名称 | 大小(类型) | 说明 |
---|---|---|
Header CRC32 | uint32 | 头数据的CRC32,从“Header size ”字段开始,直至“Extra area ”字段。 |
Header size | vint | 头数据的大小,从“Header type ”字段开始,直至“Extra area ”字段。在当前的实现中,该字段不得超过3个字节 ,从而导致最大的头大小为2MB 。 |
Header type | vint | 压缩文档头的类型。可能的值为:0x01 - 压缩文档头。0x02 - 文件头。0x03 - 服务头。0x04 - 压缩文档加密头。0x05 - 结尾块。 |
Header flags | vint | 所有头共有的标志:0x01 - 头末尾存在扩展区域。0x02 - 头末尾存在数据区域。0x04 - 当更新压缩文档时,必须跳过类型未知并拥有该标志的块。0x08 - 数据区域从上一卷继续。0x10 - 数据区域从下一卷继续。0x20 - 块取决于前一个文件块。0x40 - 如果修改了主块,则保留一个子块。 |
Extra area size | vint | 可选字段 ,扩展区域的大小。仅当设置了0x01 头标志时才存在。 |
Data area size | vint | 可选字段 ,数据区域的大小。仅当设置了0x02 头标志时才存在。 |
… | … | 当前块类型专用的字段。有关详细信息,请参见具体块类型描述。 |
Extra area | … | 可选字段 ,扩展区域。仅当设置了0x01 头标志时才存在。 |
Data area | vint | 可选字段 ,数据区域。仅当设置了0x02 头标志时才存在。用于存储大量数据,例如压缩文件数据。不包括“Header CRC ”和“Header size ”字段。 |
General extra area format(通用扩展区域格式)
Extra area can include one or more records having the following format:
扩展区域可以包含一个或多个具有以下格式的记录:
字段名称 | 大小(类型) | 说明 |
---|---|---|
Size | vint | 从Type开始的记录数据的大小。 |
Type | vint | 记录类型 。不同的压缩文档块具有不同的关联的扩展区域记录类型。阅读具体的压缩文档块描述以获取详细信息。将来可以添加新的记录类型,因此需要跳过未知的记录类型而不中断操作。 |
Data | … | 记录相关数据 。如果记录仅由Size和Type组成,则可能会丢失。 |
General archive layout(通用压缩文档布局)
1
2
3
4
5
6
7
8
9
10
11
12
13
14Self-extracting module(optional):自解压模块(可选的)
RAR 5.0 signature:RAR5.0签名
Archive encryption header(optional):压缩文档加密头(可选的)
Main archive header:压缩文档头
Archive comment service header(optional):压缩文档注释服务头(可选的)
File header 1:文件头1
Service headers(NTFS ACL, streams, etc.)for preceding file(optional):前一个文件的服务头(可选的)
...
File header N:文件头N
Service headers(NTFS ACL, streams, etc.)for preceding file(optional):前一个文件的服务头(可选的)
Recovery record(optional):恢复记录(可选的)
End of archive header:结尾块
2.2.3、Archive blocks(压缩文档块)
2.2.3.1、Self-extracting module (SFX)(自解压模块)
Any data preceding the archive signature. Self-extracting module size and contents is not defined. At the moment of writing this documentation RAR assumes the maximum SFX module size to not exceed 1 MB, but this value can be increased in the future.
压缩文档签名
之前的所有数据。自解压模块
的大小和内容未定义。在撰写本文档时,RAR假定SFX模块
的最大大小不超过1 MB,但是以后可以增加该值。
实例:
2.2.3.2、RAR 5.0 signature(RAR5.0签名)
RAR 5.0 signature consists of 8 bytes: 0x52 0x61 0x72 0x21 0x1A 0x07 0x01 0x00. You need to search for this signature in supposed archive from beginning and up to maximum SFX module size. Just for comparison this is RAR 4.x 7 byte length signature: 0x52 0x61 0x72 0x21 0x1A 0x07 0x00.
RAR 5.0签名
由8个字节组成:0x52 0x61 0x72 0x21 0x1A 0x07 0x01 0x00
。您需要从假想的压缩文档中搜索该签名,从开始到最大SFX模块大小。只是为了比较,这是RAR 4.x
7字节长度的签名:0x52 0x61 0x72 0x21 0x1A 0x07 0x00
。
实例:
2.2.3.3、Archive encryption header(压缩文档加密块)
字段名称 | 大小(类型) | 说明 |
---|---|---|
Header CRC32 | uint32 | 头数据的CRC32,从“Header size ”字段开始,直至“Check value ”字段的CRC32校验码。 |
Header size | vint | 头数据的大小,从“Header type ”字段开始,直至“Check value ”字段。 |
Header type | vint | 0x04 |
Header flags | vint | 所有头共有的标志:0x01 - 头末尾存在扩展区域。0x02 - 头末尾存在数据区域。0x04 - 当更新压缩文档时,必须跳过类型未知并拥有该标志的块。0x08 - 数据区域从上一卷继续。0x10 - 数据区域从下一卷继续。0x20 - 块取决于前一个文件块。0x40 - 如果修改了主块,则保留一个子块。 |
Encryption version | vint | 加密算法的版本 。现在仅支持0版本(AES-256)。 |
Encryption flags | vint | 0x00 - 不存在密码检查数据(Check value字段)。 0x01 - 存在密码检查数据(Check value字段)。 |
KDF count | 1 byte | PBKDF2函数 的迭代数 的二进制对数 。 RAR可以拒绝处理超过 某个阈值的KDF计数。阈值的具体值取决于版本 。 |
Salt | 16 byte | 全局地用于所有加密 的压缩文档头的盐值。 |
Check value | 12 byte | 用于验证密码有效性 的值。仅当设置了0x01 加密标志时才存在。前8个字节 是使用额外的PBKDF2轮次计算的,最后4个字节 是额外的校验和。与标准Header CRC32 一起,我们具有64位校验和 ,以可靠地验证此字段的完整性 并区分无效的密码 和损坏的数据 。可以在UnRAR源代码中找到更多详细信息。 |
This header is present only in archives with encrypted headers. Every next header after this one is started from 16 byte AES-256 initialization vector followed by encrypted header data. Size of encrypted header data block is aligned to 16 byte boundary.
该头仅存在于带有加密头
的压缩文档中。此后的每下一个头
均从16字节AES-256初始化向量
开始,然后是加密的头数据
。加密头数据块的大小与16字节边界对齐。
实例:
这是设置密码时勾选了加密文件名
后,出现的块。
1 | 00000000 - 00310783 SFX(自解压模块) |
2.2.3.4、Main archive header(压缩文件头)
字段名称 | 大小(类型) | 说明 |
---|---|---|
Header CRC32 | uint32 | 头数据的CRC32,从“Header size ”字段开始,直至“Extra area ”字段。 |
Header size | vint | 头数据的大小,从“Header type ”字段开始,直至“Extra area ”字段。 |
Header type | vint | 0x01 |
Header flags | vint | 所有头共有的标志:0x01 - 头末尾存在扩展区域。0x02 - 头末尾存在数据区域。0x04 - 当更新压缩文档时,必须跳过类型未知并拥有该标志的块。0x08 - 数据区域从上一卷继续。0x10 - 数据区域从下一卷继续。0x20 - 块取决于前一个文件块。0x40 - 如果修改了主块,则保留一个子块。 |
Extra area size | vint | 可选字段 ,扩展区域的大小。仅当设置了0x01 头标志时才存在。 |
Archive flags | vint | 0x01 - 卷。压缩文档是多卷集的一部分。 0x02 - “Volume number”字段存在。除第一卷外,所有的卷都存在此标志。 0x04 - 可靠的压缩文档。 0x08 - 存在恢复记录。 0x10 - 压缩文档已锁定。 |
Volume number | vint | 可选字段 ,仅当设置了Archive flags的0x02 位时才显示。第一卷不存在,第二卷为1,第三卷为2,依此类推。 |
Extra area | … | 可选字段 ,扩展区域。仅当设置了0x01 头标志时才存在。 |
Extra area of main archive header can contain following record types:压缩文件头
的扩展区域
可以包含以下记录类型:
类型编号 | 类型名称 | 说明 |
---|---|---|
0x01 | Locator | 包含不同服务块 的位置,因此可以快速访问 它们,而无需扫描整个压缩文档。该记录是可选的 。如果缺少它,仍然有必要扫描整个压缩文件 以验证服务块的存在。 |
Locator record(定位记录)
字段名称 | 大小(类型) | 说明 |
---|---|---|
Size | vint | 从Type开始的记录数据的大小。 |
Type | vint | 0x01 |
Flags | vint | 0x01 - “Quick open record offset”字段存在。 0x02 - “Recovery record offset”字段存在。 |
Quick open offset | vint | 可选字段 ,从“Quick open”服务块的开始 到Main archive header的开始 的距离。仅当设置了0x01 标志时才存在。如果等于0,则应忽略。如果预分配的空间不足以存储产生的偏移量,则可以将其设置为零。 |
Recovery record offset | vint | 可选字段 ,从“Recovery record”服务块的开始 到Main archive header的开始 的距离。仅当设置了0x02 标志时才存在。如果等于0,则应忽略。如果预分配的空间不足以存储产生的偏移量,则可以将其设置为零。 |
实例:
1 | 00310792 - 00310811 |
2.2.3.5、File header and service header(文件头和服务头)
These two header types use the similar data structure, so we describe them both here.
这两种头类型使用相似的数据结构,因此我们在这里对它们一起进行描述。
字段名称 | 大小(类型) | 说明 |
---|---|---|
Header CRC32 | uint32 | 头数据的CRC32,从“Header size ”字段开始,直至“Name ”字段。 |
Header size | vint | 头数据的大小,从“Header type ”字段开始,直至“Name ”字段。 |
Header type | vint | 0x02 - 文件头 0x03 - 服务头 |
Header flags | vint | 所有头共有的标志:0x01 - 头末尾存在扩展区域。0x02 - 头末尾存在数据区域。0x04 - 当更新压缩文档时,必须跳过类型未知并拥有该标志的块。0x08 - 数据区域从上一卷继续。0x10 - 数据区域从下一卷继续。0x20 - 块取决于前一个文件块。0x40 - 如果修改了主块,则保留一个子块。 |
Extra area size | vint | 可选字段 ,扩展区域的大小。仅当设置了0x01 头标志时才存在。 |
Data area size | vint | 可选字段 ,数据区域的大小。仅当设置了0x02 头标志时才存在。 |
File flags | vint | 这些头类型专用的标志:0x01 - 目录文件系统对象(文件头)。0x02 - 存在Unix格式的时间字段。0x04 - 存在CRC32字段。0x08 - 解压后大小未知。如果设置了标志 0x08 ,则“Unpacked size ”字段仍然存在,但是必须忽略,并且必须执行提取,直到到达压缩流的末尾。如果实际文件大小大于操作系统报告的大小,或者文件大小未知(例如,除从stdin到multivolume archive归档时的最后一个卷以外的所有卷),则可以设置此标志。 |
Unpacked size | vint | 解压缩的文件 或服务数据 大小。 |
Attributes | vint | 如果是文件头 ,则为操作系统特定的文件属性。如果是服务头 ,可以用于特定数据需求,也可以保留,并可以设置为0。 |
mtime | uint32 | 可选字段 ,Unix时间格式的文件修改时间 。如果设置了0x02 文件标志,则存在。 |
Data CRC32 | uint32 | 可选字段 ,已解压缩的文件 或服务数据 的CRC32。对于在卷之间分割的文件,它包含当前卷中除最后文件部分以外的所有文件部分所包含的文件打包数据的CRC32。如果设置了0x04 文件标志,则存在。 |
Compression information | vint | 低6位(0x003f) :压缩算法的版本,可能有0-63个值。当前版本是0。第7位(0x0040) :定义solid flag。如果已设置,RAR将在处理之前的文件后继续使用剩下的压缩字典。只能为文件头设置,而不能为服务头设置。第8-10位(0x0380) :定义压缩方法。当前仅使用值0-5。10 9 8 位 0 0 0 - 存储 0 0 1 - 最快压缩 0 1 0 - 较快压缩 0 1 1 - 标准压缩 1 0 0 - 较好压缩 1 0 1 - 最好压缩第11-14位(0x3c00) :定义提取数据所需的字典大小的最小大小。14 13 12 11 位 0 0 0 0 - 字典大小 128KB0 0 0 1 - 字典大小 256KB0 0 1 0 - 字典大小 512KB0 0 1 1 - 字典大小 1MB0 1 0 0 - 字典大小 2MB0 1 0 1 - 字典大小 4MB0 1 1 0 - 字典大小 8MB0 1 1 1 - 字典大小 16MB1 0 0 0 - 字典大小 32MB1 0 0 1 - 字典大小 64MB1 0 1 0 - 字典大小 128MB1 0 1 1 - 字典大小 256MB1 1 0 0 - 字典大小 512MB1 1 0 1 - 字典大小 1024MB1 1 1 0 - 字典大小 2048MB1 1 1 1 - 字典大小 4096MB |
Host OS | vint | 用于创建压缩文档的操作系统的类型: 0x00 - Windows 0x01 - Unix |
Name length | vint | 文件 或服务头 名称的长度。 |
Name | N bytes | 1、可变长度字段,包含UTF-8格式的名称,不以0结尾。 2、对于 文件头 ,这是已压缩文件的名称。正斜杠字符用作Unix和Windows名称的路径分隔符。对于Unix文件名称,反斜杠被视为名称的一部分,对于Windows文件名称,反斜杠被视为无效字符。名称类型由“Host OS”字段定义。3、如果Unix文件名包含无法正确转换为Unicode和UTF-8的任何高级ASCII字符,我们会将这些字符映射到0xE080-0xE0FF私有Unicode区域,并在结果字符串中插入Unicode非字符0xFFFE以表明它包含已映射字符,提取时需要转换回去。没有定义0xFFFE的具体位置,我们需要搜索整个字符串。此类映射的名称不可移植,并且只能在创建它们的同一系统上正确解压缩。 4、对于 服务头 ,此字段包含服务头的名称。现在使用以下名称:CMT - 压缩文档注释 QO - 压缩文档Quick open数据 ACL - NTFS文件权限 STM - NTFS交换数据流 RR - 恢复记录 |
Extra area | … | 可选字段 ,扩展区域,包含附加的头字段。仅当设置了0x01 头标志时才存在。 |
Data area | vint | 可选字段 ,数据区域,仅当设置了0x02 头标志时才存在。如果是文件头 ,则存储文件数据;对于服务头 ,则存储服务数据。根据压缩方法中的值,可以对压缩信息进行未压缩(压缩方法0)或压缩。 |
File and service headers use the same types of extra area records:文件头
和服务头
使用相同类型的扩展区域记录类型:
类型 | 类型名称 | 说明 |
---|---|---|
0x01 | File encryption | 文件加密信息。 |
0x02 | File hash | 文件数据哈希。 |
0x03 | File time | 高精度文件时间。 |
0x04 | File version | 文件版本号。 |
0x05 | Redirection | 文件系统重定向。 |
0x06 | Unix owner | Unix所有者和组信息。 |
0x07 | Service data | 服务头数据数组。 |
File encryption record(文件加密记录)
This record is present if file data is encrypted.
如果文件数据被加密
,则存在该记录。
字段名称 | 大小(类型) | 说明 |
---|---|---|
Size | vint | 从Type开始的记录数据的大小。 |
Type | vint | 0x01 |
Version | vint | 加密算法的版本。现在仅支持0版本 (AES-256)。 |
Flags | vint | 0x01 - 存在密码验证数据。0x02 - 使用调整过的校验和而不是普通校验和。如果存在标志 0x02 ,则RAR转换保留的校验和文件或服务数据的完整性,因此它取决于加密密钥。它使得不可能根据校验和猜测文件内容。它会影响文件头中的数据CRC32和扩展区域中文件哈希记录中的校验和。 |
KDF count | 1 byte | PBKDF2函数 的迭代数的二进制对数 。 RAR可以拒绝处理超过某个阈值 的KDF计数。阈值的具体值取决于版本 。 |
Salt | 16 byte | 设置加密文件解密密钥 的盐值。 |
IV | 16 byte | AES-256初始化向量 。 |
Check value | 12 byte | 可选字段 ,用于验证密码有效性的值。仅当设置了0x01 加密标志时才存在。前8个字节 是使用额外的PBKDF2轮次计算的,最后4个字节 是额外的校验和。与标准Header CRC32 一起,我们具有64位校验和 ,以可靠地验证此字段的完整性 并区分无效的密码 和损坏的数据 。可以在UnRAR源代码中找到更多详细信息。 |
File hash record(文件哈希记录)
Only the standard CRC32 checksum can be stored directly in file header. If other hash is used, it is stored in this extra area record:
仅标准CRC32校验和
可以直接存储在文件头
中。如果使用其他哈希
,它将存储在此扩展区域记录
中:
字段名称 | 大小(类型) | 说明 |
---|---|---|
Size | vint | 从Type开始的记录数据的大小。 |
Type | vint | 0x02 |
Hash type | vint | 0x00 - BLAKE2sp哈希函数。 |
Hash data | N bytes | 0x00哈希类型 的32个字节的BLAKE2sp哈希值。 |
For files split between volumes it contains a hash of file packed data contained in current volume for all file parts except the last. For files not split between volumes and for last parts of split files it contains an unpacked data hash.
对于在卷之间分割
的文件,它包含当前卷中除最后文件部分以外的所有文件部分所包含的文件压缩数据的哈希。对于未在卷之间拆分
的文件以及拆分文件的最后部分,它包含未压缩的数据哈希。
File time record(文件时间记录)
This record is used if it is necessary to store creation and last access time or if 1 second precision of Unix mtime stored in file header is not enough:
如果需要存储创建
和上次访问
时间,或者文件头
中存储的Unix mtime的1秒精度不够
,则使用此记录:
字段名称 | 大小(类型) | 说明 |
---|---|---|
Size | vint | 从Type开始的记录数据的大小。 |
Type | vint | 0x03 |
Flags | vint | 0x01 - 如果设置了此标志,则时间以Unix time_t格式存储,否则以Windows FILETIME格式存储。0x02 - 存在“mtime”字段。0x04 - 存在“ctime”字段。0x08 - 存在“atime”字段。0x10 - Unix时间格式,具有纳秒级精度。 |
mtime | uint32 or uint64 | 修改时间 。如果设置了0x02 标志,则存在。根据0x01 ,标志可以采用Unix time_t或Windows FILETIME格式。 |
ctime | uint32 or uint64 | 创建时间 。如果设置了0x04 标志,则存在。根据0x01 ,标志可以采用Unix time_t或Windows FILETIME格式。 |
atime | uint32 or uint64 | 上次访问时间 。如果设置了0x08 标志,则存在。根据0x01 ,标志可以采用Unix time_t或Windows FILETIME格式。 |
mtime nanoseconds | uint32 | 添加到mtime 的纳秒值。如果0x01 、0x02 和0x10 标志都设置了,则存在。 |
ctime nanoseconds | uint32 | 添加到ctime 的纳秒值。如果0x01 、0x04 和0x10 标志都设置了,则存在。 |
atime nanoseconds | uint32 | 添加到atime 的纳秒值。如果0x01 、0x08 和0x10 标志都设置了,则存在。 |
File version record(文件版本记录)
This record is used in archives created with -ver switch.
该记录用于通过-ver开关
创建的压缩文档中。
字段名称 | 大小(类型) | 说明 |
---|---|---|
Size | vint | 从Type开始的记录数据的大小。 |
Type | vint | 0x04 |
Flags | vint | 尚未定义文件版本标志,因此将其设置为0。 |
Version number | vint | 文件版本号。 |
File system redirection record(文件系统重定向记录)
字段名称 | 大小(类型) | 说明 |
---|---|---|
Size | vint | 从Type开始的记录数据的大小。 |
Type | vint | 0x05 |
Redirection type | vint | 0x01 - Unix符号链接 0x02 - Windows符号链接 0x03 - Windows交接点 0x04 - 硬链接 0x05 - 文件复制 |
Flags | vint | 0x01 - 链接目标为目录 |
Name length | vint | 链接目标名称的长度 |
Name | vint | UTF-8 格式的链接目标名称,不以0结尾 |
Unix owner record(Unix所有者记录)
字段名称 | 大小(类型) | 说明 |
---|---|---|
Size | vint | 从Type开始的记录数据的大小。 |
Type | vint | 0x06 |
Flags | vint | 0x01 - “User name”符串存在 0x02 - “Group name”字符串存在 0x04 - 存在数字“User ID” 0x08 - 存在数字“Group ID” |
User name length | vint | 可选字段 ,所有者用户名的长度。如果设置了0x01 标志,则存在。 |
User name | N bytes | 可选字段 ,所有者用户名(采用本机编码)。非零终止。如果设置了0x01 标志,则存在。 |
Group name length | vint | 可选字段 ,所有者组名称的长度。如果设置了0x02 标志,则存在。 |
Group name | N bytes | 可选字段 ,所有者组名称(采用本机编码)。非零终止。如果设置了0x02 标志,则存在。 |
User ID | vint | 可选字段 ,数字所有者用户ID。如果设置了0x04 标志,则存在。 |
Group ID | vint | 可选字段 ,数字所有者组ID。如果设置了0x08 标志,则存在。 |
Service data record(服务数据记录)
This record is used only by service headers to store additional parameters.
该记录仅由服务头
使用,以存储其他参数。
字段名称 | 大小(类型) | 说明 |
---|---|---|
Size | vint | 从Type开始的记录数据的大小。 |
Type | vint | 0x07 |
Data | N bytes | 服务数据的具体内容取决于服务头类型 。 |
实例:
1 | 00310850 - 00311002 |
2.2.3.6、Recovery record(恢复记录)
加入冗余数据用于修复,在压缩包本身损坏
但恢复记录够多
时可对损坏压缩包进行恢复。实例:
我们可以从例子RAR环境的图片中看到,恢复记录的大小约为19.6KB。1
2336483 - 356643 (20161B 恢复记录)
20161B/1024 = 19.6KB
2.2.3.7、End of archive header(结尾块)
End of archive marker. RAR does not read anything after this header letting to use third party tools to add extra information such as a digital signature to archive.
标记压缩文档结束
。 RAR在此头之后不读取任何内容,从而允许使用第三方工具
来添加扩展的信息
,例如压缩文档的数字签名
。
字段名称 | 大小(类型) | 说明 |
---|---|---|
Header CRC32 | uint32 | 头数据的CRC32,从“Header size ”字段开始,直至“End of archive flags ”字段。 |
Header size | vint | 头数据的大小,从“Header type ”字段开始,直至“End of archive flags ”字段。 |
Header type | vint | 0x05 |
Header flags | vint | 所有头共有的标志:0x01 - 头末尾存在扩展区域。0x02 - 头末尾存在数据区域。0x04 - 当更新压缩文档时,必须跳过类型未知并拥有该标志的块。0x08 - 数据区域从上一卷继续。0x10 - 数据区域从下一卷继续。0x20 - 块取决于前一个文件块。0x40 - 如果修改了主块,则保留一个子块。 |
End of archive flags | vint | 0x00 - 压缩文档不使用卷分割。或是集合中的最后一个卷。 0x01 - 压缩文档是卷,不是集合中的最后一个卷。 |
实例:
1 | 00356644 - 00356651 |
2.2.4、Service headers(服务头)
RAR uses service headers based on the file header data structure to store different supplementary information.
RAR使用基于文件头数据结构
的服务头
来存储不同的补充信息。
2.2.4.1、Archive comment header(压缩文档注释服务头)
Optional header storing the main archive comment. Contains CMT identifier in file name field. Placed before any file headers and after the main archive header. Comment data is stored in UTF-8 immediately after the archive comment header. Now RAR does not use compression for archive comments, so packed and unpacked data sizes in header are equal and they both define the comment data size. Compression method in header is set to 0.
可选的头,用于存储压缩文档注释
。在文件名字段
中包含CMT标识符
。放在任何文件头
之前和压缩文档头
之后。注释数据
在压缩文档注释头
之后用UTF-8存储。现在,RAR不对压缩文件注释
使用压缩,因此头中的压缩数据大小
和未压缩数据大小
相等,并且它们都定义了注释数据大小
。头中的压缩方法
设置为0。
实例:
1 | 00310812 - 00310849 |
2.2.4.2、Quick open header(快速打开服务头)
Optional header storing the quick open record. Contains QO identifier in file name field. Placed after all file headers, but before the recovery record and end of archive header. It is possible to locate the quick open header with locator record in main archive header.
可选的头,用于存储快速打开记录
。在文件名
字段中包含QO标识符
。置于所有文件头
之后,但在恢复记录
和压缩文档结尾块
之前。可以在压缩文档头
中找到带有定位记录的快速打开头
。
Quick open record data is stored immediately after the quick open header. RAR does not use compression for quick open data, so packed and unpacked data sizes in header are equal and they both define the quick open data size. Compression method in header is set to 0.
快速打开记录数据
将立即存储在快速打开头
之后。 RAR不对快速打开数据
使用压缩,因此头中的压缩数据大小
和未压缩数据大小
相等,并且它们都定义了快速打开数据大小
。头中的压缩方法设置为0。
Quick open data is the array consisting of data cache structures. Every data cache structure stores a portion of archived data and has the following format:
快速打开数据
是由数据缓存结构
组成的数组。每个数据缓存结构
都存储一部分压缩数据
,并具有以下格式:
字段名称 | 大小(类型) | 说明 |
---|---|---|
Structure CRC32 | uint32 | 从“Structure size ”字段开始的结构数据的CRC32 。 |
Structure size | vint | 从标志字段 开始的结构数据的大小。在当前实现中,该字段不得超过3个字节 ,因此最大大小为2 MB 。 |
Flags | vint | 当前设置为0。 |
Offset | vint | 从快速打开头的开始 到当前结构中缓存的压缩文档数据的开始 的偏移量。我们可以使用该值来计算存储当前结构的压缩数据的绝对位置 。从结构数组的开头到结尾,可以保证数据缓存结构引用的绝对存档位置始终在增长。 |
Data size | vint | 当前结构中存储的压缩文档数据的大小 。 |
Data | N bytes | 存储在当前结构中的压缩文档数据 。 |
Normally RAR uses the quick open data to store copies of file and service headers. It can store either all headers or only a part of them. If required header is missing in quick open data or if structure CRC32 is invalid, data are read from its original archive position.
通常,RAR使用快速打开数据
来存储文件的副本
和服务头
。它可以存储所有头
,也可以只存储其中的一部分
。如果快速打开数据中缺少必需的标头
,或者结构CRC32无效
,则从其原始存档位置
读取数据。
Using the quick open data is optional. You can skip it completely and read only standard archive headers. But it is important to use the same access pattern when reading file names to display them to user and to extract files. Otherwise it would be possible to see one file name and extract another in case the quick open data and real archive data are intentionally created different. It could introduce a security threat. So if you use the quick open data when displaying the archive contents, use it when extracting. If you do not use it when displaying the archive contents, do not use it when extracting.
使用快速打开数据
是可选的。您可以完全跳过它,而仅读取标准压缩文档头
。但是,重要的是在读取文件名
时使用相同的访问模式以将其显示给用户
并提取文件
。否则,如果有意创建的快速打开数据
和实际存档数据
不同,则可能会看到一个文件名
并提取另一个文件名
。它可能会带来安全威胁。因此,如果在显示存档内容时
使用快速打开的数据,请在提取时
使用它。如果在显示存档内容时
不使用它,则在提取时
不要使用它。
实例:
1 | 00336299 - 00336482 |
3、针对RAR的主要攻击方式
3.1、爆破
RAR 5.0 密码破解
https://blog.xugr.me/post/rar-crack/
3.2、伪加密
伪加密
只发生在RAR5.0以前的版本
中,我们只需要修改FILE_HEAD
中的HEAD_FLAGS
的0x0004
标记为1,就可以造成RAR伪加密
。