8.1.1
引导记录扇区 ExFAT文件系统也将0号扇区做为引导记录扇区,除引导信息外,还记录着文件系统的各项参数,如分区大小、FAT表位置及大小、簇起始位置、根目录起始簇号、每扇区大小、每簇扇区数等等。 ExFAT引导记录扇区的主要结构见表8.1。 表8.1 ExFAT引导记录扇区结构 偏移字节 (十六进制) | 字节数 | 含义 | 00~02 | 3 | 跳转代码,“EB 76 90”,跳转过0x76个字节,至0x78字节处 | 03~07 | 5 | 分区类型“4558464154”,明文“EXFAT” | 08~0A | 3 | “202020” | 0B~3F | 53 | “00” | 40~47 | 8 | 分区起始扇区号(似乎总是相对于磁盘物理0号扇区) | 48~4F | 8 | 分区大小扇区数,最小为1MB,最大为264-1个扇区 | 50~53 | 4 | FAT表起始扇区号 | 54~57 | 4 | FAT表大小扇区数 | 58~5B | 4 | 数据区起始扇区号(注意,虽然只有一个FAT表,但该值并不一定等于FAT表起始扇区号加上FAT表大小扇区数,也就是说为FAT表分配的空间与簇起始扇区之间可能会有未使用的扇区) | 5C~5F | 4 | 卷内簇数 | 60~63 | 4 | 根目录起始簇 | 64~67 | 4 | 卷ID | 68~69 | 2 | 文件系统版本 | 6A~6B | 2 | 卷标志 | 6C~6C | 1 | 每扇区大小字节数,假设此处值为N,则每扇区大小字节数为2的N次方个字节,此处值通常为“09”,最大值为“12” | 6D~6D | 1 | 每簇扇区数,假设该位置值为N,则簇大小为2的N次方个扇区 | 6E~6E | 1 | FAT表个数 | 6F~6F | 1 | 介质描述符 | 70~70 | 1 | 已用比例 | 71~77 | 7 | 保留 | 78~1FD | 390 | 引导代码 | 1FE~1FF | 2 | 签名标志“55AA” |
(1) 0x00~0x02:3个字节,跳转代码。 (2) 0x03~0x0A:分区类型标志,也称为OEM标签,是一个8字节的ASCII码,用以说明文件系统的类型名称,即“45 58 46 41 54”,明文“EXFAT”,剩余未用的字节使用“20”填充。由于ExFAT与NTFS一样使用0x07做为分区表中的分区类型值,单纯由分区表项中的该值无法判断这个分区是NTFS分区还是ExFAT分区,这时可以通过引导记录扇区中的分区类型标志值对它们进行区分。 (3) 0x0B~0x3F:53个字节,全部为“00”。 (4) 0x40~0x47:8个字节,分区起始扇区号。 注意:实验中发现,该值为当前扇区的物理扇区号,即使该分区位于扩展分区内也不例外,这点与FAT32或NTFS引导记录扇区中“分区前已用扇区数”的描述方法略有不同。 (5) 0x48~0x4F:8个字节,分区大小扇区数。 (6) 0x50~0x53:4个字节,FAT表起始扇区号,该值为相对于文件系统0号扇区而言。 (7) 0x54~0x57:4个字节,FAT表大小扇区数。 (8) 0x58~0x5B:4个字节,簇起始位置扇区号,该值用以描述文件系统中的第1个簇(即2号簇)的起始扇区号。通常2号簇分配给簇位图使用,因此,该值也就是簇位图的起始扇区号。虽然该簇跟在FAT表后,但实际上它并不一定等于FAT表起始扇区号加上FAT表的大小。 (9) 0x5C~0x5F:4个字节,卷内的总簇数。 (10) 0x60~0x63:4个字节,根目录起始簇号。 (11) 0x64~0x67:4个字节,卷ID。 (12) 0x68~0x69:2个字节,文件系统版本。 (13)0x6A~0x6B:2个字节,卷标志。该标志用以描述主FAT号、卷是否干净等信息。 (14) 0x6C~0x6C:1个字节,每扇区大小字节数,表示方法为,假设此处值为N,则每扇区大小字节数为2的N次方个字节。此处的值通常为“09”,即每扇区大小字节数为512。微软将该处的值限定为最大为12,也就是每扇区大小字节数最大为212 = 4096。 (15) 0x6D~0x6D:1个字节,每簇扇区数,表示方法为,假设此处值为N,则每簇大小扇区数为2的N次方个扇区。此处值最小为1,最大值取决于每扇区大小字节数,因为ExFAT的簇大小上限为32MB,也就是225个字节,所以0x6C处的值与0x6D处的值相加不得超过25。 (16) 0x6E~0x6E:1个字节,FAT表个数,事务ExFAT中为2个FAT表,版本01.00只有一个FAT表。 (17) 0x6F~0x6F:1个字节,介质描述符。 (18) 0x70~0x70:1个字节,似乎是卷中已用簇空间的百分比。 (19) 0x71~0x77:7个字节,保留。 (20) 0x78~0x1FD:390个字节,引导代码。 (21) 0x1FE~0x1FF:2个字节,有效结束标志“55AA”。如果扇区大小超过512个字节,“55AA”仍然位于扇区的最后两个字节,引导代码至“55AA”之间可能会使用“00”进行填充。 现在,我们来实验分析一个ExFAT文件系统的引导记录扇区部分参数,如图8.2所示。
图8.2
(1) 0x00~0x02: 3个字节,“EB 76 90”,跳转代码。
(2) 0x03~0x0A:分区类型标志,“45 58 46 41 54”,明文“EXFAT”。 (3) 0x0B~0x3F:53个字节,全部为“00”。 (4) 0x40~0x47:8个字节,“3F00000000000000”,分区起始扇区号,63。 (5) 0x48~0x4F:8个字节,“0014A80400000000”,分区大小扇区数,78124032。 (6) 0x50~0x53:4个字节,“00080000”,FAT表起始扇区号,2048。 (7) 0x54~0x57:4个字节,“000A0000”,FAT表大小扇区数,2560。 (8) 0x58~0x5B:4个字节,“00180000”,数据区起始位置扇区号,6144。我们可以看前面的FAT表起始扇区号为2048,FAT表大小为2560,则FAT表的结束位置为4608号扇区。而数据区的起始位置是6144号扇区,所以数据区的起始位置并不一定是紧跟在FAT表之后的。 (9) 0x5C~0x5F:4个字节,“FCA70400”,卷内的总簇数,305148。 (10) 0x60~0x63:4个字节,“04000000”,根目录起始簇号,4。 (11) 0x64~0x67:4个字节,卷ID。 (12) 0x68~0x69:2个字节,“0001”,文件系统版本,01.00。 (13)0x6A~0x6B:2个字节,“0000”,卷标志。 (14) 0x6C~0x6C:1个字节,“09”,每扇区大小字节数,即扇区大小为29=512字节。 (15) 0x6D~0x6D:1个字节,“08”,每簇扇区数,即28=256个扇区。 (16) 0x6E~0x6E:1个字节,“01”,FAT表个数,1。 (17) 0x6F~0x6F:1个字节,“80”,介质描述符。 (18) 0x70~0x70:1个字节,“00”,卷中已用簇空间的百分比,这是一个刚刚格式化的文件系统,基本尚未使用。 (19) 0x1FE~0x1FF:2个字节,有效结束标志“55AA”。 8.1.1
校验扇区 主引导区域的11号扇区,记录的是前11个扇区的校验值。严格来讲,主引导区域应该只包括前11个扇区,只是为了叙述方便,我们将11号扇区也归入主引导区域,不过只有前11个扇区参与校验值的计算,计算结果记录在11号扇区中。如图8.3所示。
图8.3 可以看到,校验扇区记录的内容是一个重复的4字节值,该4字节值不断被重复直到写满整个扇区。 资料《Reverse Engineering the Microsoft exFAT File System》中给出的校验值计算函数如下: UINT32 VBRChecksum(const unsigned char octets[], long NumberOfBytes) {
UINT32 Checksum = 0;
long Index; for (Index = 0; Index < NumberOfBytes; Index++)
{
if (Index == 106 || Index == 107 || Index == 112)
{
continue;
}
Checksum = ((Checksum <<31) | (Checksum>> 1)) + (UINT32) octets[Index];
}
return Checksum; } 8.2
FAT表 在FAT12/16/32中,FAT表不只用于记录FAT链,同时还用于表示当前FAT对应的簇是否被使用:表项为0表示该表项对应的簇未使用,否则为已分配使用。ExFAT文件系统的FAT表则只用于描述FAT链,而不再用以说明某个簇的分配情况,簇的分配情况另外使用簇位图进行描述。 FAT32中,虽然每个FAT表项占用32个bit,但真正使用的却只是其中的28个bit。ExFAT的FAT表项也占用32个bit,并且全部启用了这32bit。 ExFAT中,FAT项的取值含义见表8.2。 表8.2 FAT项取值含义 取值 | 含义 | 0x00000000 | 从未被分配使用 | 0x00000001 | 此值无效 | 0x00000002~0xFFFFFFF6 | 可用簇号 | 0xFFFFFFF7 | 坏块 | 0xFFFFFFF8 | 介质描述符 | 0xFFFFFFF9~0xFFFFFFFE | 未定义 | 0xFFFFFFFF | 文件簇链结束 |
0x00000000,刚刚格式化后,未被分配使用的FAT项将会设置为零,表示该FAT项对应的簇是空闲的;对于ExFAT,删除文件时并不对其FAT表链进行清除,所以即使某FAT项对应的簇中的数据已被删除,该FAT项中仍然会有非零数值存在。因此,如果一个FAT项的内容为零,只能说明该FAT项对应的簇从未被分配使用过。 u
0x00000001,因为簇号是由2开始编号的,所以在FAT表中不可能出现该值。 u
0x00000002~0xFFFFFFF6,这个范围内的值是可以使用的簇号值,0x00000002是最小值,0xFFFFFFF6是最大值。 u
0xFFFFFFF7,坏块标记。 u
0xFFFFFFF8,介质描述符。 u
0xFFFFFFF9~0xFFFFFFFE,该范围内的值未定义。 u
0xFFFFFFFF,文件簇链结束,表示拥有该簇链的数据结束。 对于ExFAT系列文件系统,拥有的最大簇数等于最大簇号减1,所以一个ExFAT文件系统拥有的最大簇数为0xFFFFFFF6-0x01个。 通常,ExFAT的第一簇(也就是2号簇)分配给簇位图文件,再后面则是大写转换表文件,跟在大写转换表后的是根目录。图8.4为一个新格式化的ExFAT文件系统的FAT表。
图8.4 由图中可以看到,2、3、4号FAT项都写入了结束标记0xFFFFFFFF,说明这三个FAT项对应的簇分别分配给了三个文件或目录。这三个文件或目录即簇位图文件,大写转换表文件和根目录。 提示:实验发现,格式化成ExFAT文件系统时,只对FAT表的第一个扇区进行清零并写入需要的内容,其他扇区不进行任何操作。 8.3
簇位图 ExFAT文件系统中簇的分配情况由簇位图描述,它是ExFAT文件系统的第一个文件,占用文件系统的第一簇,也就是2号簇。文件中每个字节的8个bit,每个bit对应文件系统中的一个簇。如果bit为0,表示该bit对应的簇为空闲;如果为1,则表示该bit对应的簇已经分配使用。 由于簇号由2开始编号,所以位图中的最低位对应2号簇,例如第一个字节中的8个字节,分配为0~7号bit,它对应的是2~9号簇。 要计算某个簇在位图中的对应bit,可以将该簇的簇号减去2,然后用得到的差对除以8,得到的商即该簇在位图中的字节号,余数为该簇在该字节中的bit号。 例如,要计算12号簇在位图中的对应bit位置,计算方法如下: ( 12 – 2 ) / 8 = 1….. 2 也就是说,12号簇在位图中的对应bit是1号字节中的2号bit。 字节号 | 0号字节 | 1号字节 | bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 对应簇号 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 |
现在我们来看一下前面刚刚格式化的ExFAT文件系统的簇位图,如图8.5所示。
图8.5 簇位图中只有第一个字节是非零数值0x07,转换成二进制为00000111,由后三个bit可知它们对应的2、3、4号簇已经分配使用。这与前面由FAT表得出的结论相一致。 格式化成ExFAT时,分配给簇位图的空间中未使用的部分将全部被清零。 8.4
根目录 ExFAT文件系统中,根目录跟在大写转换表之后。它的起始簇号记录在引导扇区中,数据区起始位置(2号簇)的起始扇区号也记录在引导扇区中。同时,每簇大小扇区数也可以在引导扇区中找到,通过这三个参数就可以计算出根目录的起始扇区号。 例如,以前面格式化的ExFAT为例,由偏移0x58~0x5B处的4个字节“00180000”,得到数据区起始位置扇区号为6144;由0x60~0x63处的4个字节“04000000”得到根目录起始簇号4;由~0x67:4个字节,卷ID。由0x6D处的1个字节“08”得到每簇扇区数为28=256个扇区。最后可以计算出根目录的起始扇区号: 6144 + 256 * ( 4 – 2 ) = 6656 跳转到6656号扇区,内容如图8.6所示。
图8.6 ExFAT的每个目录项仍然占用32个字节,刚刚格式化的ExFAT,其根目录下会有三个目录项位置被占用,第一个是卷标目录项;第二个是簇位图目录项;第三个是大写转换表目录项。 格式化时我们设置了卷标为Ex-TEST,这由第一个目录项可以看到。但即使不设置卷标,ExFAT也总是将第一个目录项预留为卷标目录项,如图8.7所示,这是一个没有卷标的ExFAT文件系统的根目录。
图8.7 可以看到,在没有卷标时,第一个目录项设置为一个0x03类型的目录项,做为卷标目录项进行预留。 |