数据恢复专题:学习 NTFS 分区的文件记录结构和其中属性的大致结构(6)
前言
本篇将继续学习 NTFS 分区结构下的文件记录结构。
知识点总览
- NTFS 分区结构文件记录分析
- NTFS 文件记录头的结构
- NTFS 文件记录中属性的结构
NTFS 分区结构文件记录的分析
文件记录的结构
$MFT 以文件记录来实现对文件的管理,相对于 FAT32 分区结构以 32 字节储存每条文件记录,NTFS 分区结构的文件记录大小固定为 1024 字节,也就是两个扇区。
如果一个文件有很多属性或者是分散成很多碎片,就很可能需要多个文件记录。此时,存放其文件记录的第一个记录就被称为“基本文件记录”。文件记录在 $MFT 中物理上是连续的,从 0 开始依次按顺序编号。
文件记录由两部分组成,一部分是文件记录头,另一部分是属性列表。
文件属性结构表:
文件记录头的结构
文件记录头的长度和具体偏移位置的数据含义是不变的,而属性列表是可变的,其不同的属性有着不同的含义。
NTFS 文件记录头的信息:
字节偏移 | 字段长度(字节) | 字段名和含义 |
---|---|---|
0x00 | 4 | MFT 标志,一定为字符串“FILE” |
0x04 | 2 | 更新序列号(Update Sequence Number)的偏移 |
0x06 | 2 | 更新序列号的大小与数组,包括第一个字节 |
0x08 | 8 | 日志文件序列号($LogFile Sequence Number,LSN) |
0x10 | 2 | 序列号(Sequence Number) |
0x12 | 2 | 硬连接数(Hard Link Count),即有多少目录指向该文件 |
0x14 | 2 | 第一个属性的偏移地址 |
0x16 | 2 | 标志(Flag),00H 表示文件被删除,01H 表示文件正在使用,02H 表示目录被删除,03H 表示目录正在使用 |
0x18 | 4 | 文件记录的实际长度 |
0x1C | 4 | 文件记录的分配长度 |
0x20 | 8 | 基本文件记录中的文件索引号 |
0x28 | 2 | 下一属性 ID,当增加新的属性时,将该值分配给新属性,然后该值增加,如果 MFT 记录重新使用,则将它置 0,第一个实例总是 0 |
0x2A | 2 | 边界,Windows XP 中为偏移 0x30 处 |
0x2C | 4 | 文件记录号 |
0x30 | 2 | 更新序列号 |
0x32 | 4 | 更新数组 |
偏移 00H ~ 03H 为 MFT 的标志字符串,它总为“FILE”。
每次记录被修改都将导致偏移 08H ~ 09H 处的日志文件序列号$LogFile Sequence Number(LSN)发生变化。
偏移 10H ~ 11H 处序列号 Sequence Number(SN)用于记录主文件表记录被重复使用的次数。
偏移 12H ~ 13H 处为硬连接数记录硬连接的数目,只出现在基本文件记录中。
偏移 18H ~ 1BH 处文件记录的实际长度也即文件记录在磁盘上实际占用的字节空间。
偏移 1CH ~ 1FH 为系统分配给文件记录的长度,一般为“00 04 00 00”,也就是 1KB 的长度。
偏移 20H ~ 27H 处为基本文件记录中的文件索引号,基本文件记录在此的值总为 0。如果不为 0,则是一个主文件表的文件索引号,指向所属的基本文件记录中的文件记录号。在基本文件记录中包含有扩展文件记录的信息,存储在“属性列表 ATTRIBUTE_LIST”属性中。
偏移 2CH ~ 2FH 处为文件记录编号,从 0 开始编号。
偏移 30H ~ 31H 处为更新序列号,这两个字节同时会出现在该文件记录第一个扇区最后两个字节处及该文件记录第二个扇区最后两个字节处,如下图所示。
偏移 32H ~ 35H 处为更新数组,这 4 个字节很重要,它的作用如下:
因为上述的“更新序列号”的两个字节同时会出现在该文件记录第一个扇区最后两个字节处及该文件记录第二个扇区最后两个字节处,也就是事先占用了文件记录的 4 个字节,当文件记录中的信息需要往这 4 个字节处写入时,就跳转到了 32H ~ 35H 处来写。
具体对应关系是:文件记录第一个扇区最后两个字节对应 32H ~ 33H 处,文件记录第二个扇区最后两个字节对应 34H ~ 35H 处
当信息还没有写入该文件记录第一个扇区最后两个字节处及该文件记录第二个扇区最后两个字节处时,更新数组处的 4 个字节就为 0。
文件记录中属性的结构
属性的类型
文件记录由两部分构成,一部分是文件记录头,另一部分是属性列表。在 NTFS 文件系统中所有与文件相关的数据均被认为是属性,包括文件的内容。文件记录是一个文件相对应的文件属性数据库,它记录了文件数据的所有属性。
每个文件记录中都有多个属性,它们相对独立,它们相对独立,有各自的类型和名称。一个属性开头的 4 个字节,为该属性的类型标志,不同的属性其结构和含义各不相同,下表为所有属性的类型和含义。
属性类型(Little-Endian) | 属性类型名 | 属性描述 |
---|---|---|
10 00 00 00 | $STANDARD_INFORMATION | 标准信息:包括一些基本文件属性,如只读、系统、存档;时间属性,如文件的创建时间和最后修改时间;有多少目录指向该文件(即其硬连接数(hard link count)) |
20 00 00 00 | $ATTRIBUTE_LIST | 属性列表:当一个文件需要多个文件记录时,用来描述文件的属性列表 |
30 00 00 00 | $FILE_NAME | 文件名:用 Unicode 字符表示的文件名,由于 MS-DOS 不能识别长文件名,所以 NTFS 系统会自动生成一个 8.3 文件名 |
40 00 00 00 | $VOLUME_VERSION | 在早期的 NTFS v1.2 中为卷版本 |
40 00 00 00 | $OBJECT_ID | 对象 ID:一个具有 64 字节的标识符,其中最低的 16 字节对卷来说是唯一的(链接跟踪服务为外壳快捷方式,即 OLE 链接源文件赋予对象 ID;NTFS 提供的 API 是直接通过这些对象的 ID 而不是文件名来打开文件的) |
50 00 00 00 | $SECURITY_DESCRIPTOR | 安全描述符:这是为向后兼容而保留的,主要用于保护文件以防止没有授权的访问,但 Windows 2000/XP 中已将安全描述符存放在$Secure 元数据中,以便于共享(早期的 NTFS 将其与文件目录一起存放,不便于共享) |
60 00 00 00 | $VOLUME_NAME | 卷名(卷标识):该属性仅存在于$Volume 元文件中 |
70 00 00 00 | $VOLUME_INFORMATION | 卷信息:该属性仅存在于$Volume 元文件中 |
80 00 00 00 | $DATA | 文件数据:该属性为文件的数据内容 |
90 00 00 00 | $INDEX_ROOT | 索引根 |
A0 00 00 00 | $INDEX_ALLOCATION | 索引分配 |
B0 00 00 00 | $BITMAP | 位图 |
C0 00 00 00 | $SYMBOLIC_LINK | 在早期的 NTFS v1.2 中为符号链接 |
C0 00 00 00 | $REPARSE_POINT | 重解析点 |
D0 00 00 00 | $EA_INFORMATION | 扩充属性信息 |
E0 00 00 00 | $EA | 扩充属性 |
F0 00 00 00 | $PROPERTY_SET | 早期的 NTFS v1.2 中才有 |
00 10 00 00 | $LOGGED_UTILITY_STREAM | EFS 加密属性:该属性主要用于存储实现 EFS 加密的有关加密信息,如合法用户列表、解码密钥等 |
需要注意的是,上表中不是所有属性都会在一个文件记录中出现,属性有常驻和非常驻之分。当一个文件很小时,它的所有属性体都可以存放在$MFT 的文件记录中,该属性就称为常驻属性。
有些属性总是常驻的,这样 NTFS 才可以确定其他非常驻属性,例如:标准信息属性和根索引属性就是常驻属性。
如果属性体能直接存放在$MFT 中,那么访问该文件所需的时间将大大缩短,系统只需要访问磁盘一次即可获得数据;也就是文件的数据直接存放在文件记录的 $DATA 属性中(如果这个文件的数据大小+属性大小小于 1KB 的话)。
属性的结构
每一个属性都可以分为两个部分,属性头和属性体。
属性头
每一个属性都有一个属性头,这个属性头包含了该属性的基本信息:
- 属性类型
- 属性大小
- 属性名字(不是一定有的)
- 是否为常驻属性
以下为常驻属性和非常驻属性的结构
- 常驻属性:
字节偏移 | 字段长度(字节) | 含义 |
---|---|---|
0x00 | 4 | 属性类型(如 90H、B0H 等类型) |
0x04 | 4 | 包括属性头在内的本属性的长度(字节) |
0x08 | 1 | 是否为常驻属性(00 表示常驻,01H 表示非常驻) |
0x09 | 1 | 属性名长度(N) |
0x0A | 2 | 属性名开始的偏移 |
0x0C | 2 | 压缩、加密、稀疏标志 |
0x0E | 2 | 属性 ID |
0x10 | 4 | 属性体的长度(L) |
0x14 | 2 | 属性体的开始偏移 |
0x16 | 1 | 索引标志 |
0x17 | 1 | 无意义 |
0x18 | 2N | 属性的名字(如果没有名字 N=0,则该位置为属性体的内容) |
2N + 0x18 | L | 属性体的内容 |
- 非常驻属性
字节偏移 | 字段长度(字节) | 含义 |
---|---|---|
0x00 | 4 | 属性类型(如 80H、A0H 等类型) |
0x04 | 4 | 包括属性头在内的本属性的长度(字节) |
0x08 | 1 | 是否为常驻属性(为 01 表示该属性为非常驻属性) |
0x09 | 1 | 属性名长度(N) |
0x0A | 2 | 属性名开始的偏移 |
0x0C | 2 | 压缩、加密、稀疏标志 |
0x0E | 2 | 属性 ID |
0x10 | 8 | 属性体的起始虚拟簇号(VCN) |
0x18 | 8 | 属性体的结束虚拟簇号 |
0x20 | 2 | Run List(Run 即 Data Run,是一个在逻辑簇号上连续的区域,它是不存储在 MFT 中的数据)信息的偏移地址 |
0x22 | 2 | 压缩单位大小(2x 簇,如果为 0 表示未压缩) |
0x24 | 4 | 无意义 |
0x28 | 8 | 属性体的分配大小[该属性体占的大小,这个属性体大小是该属性体所有的簇所占的空间大小(字节)] |
0x30 | 8 | 属性体的实际大小(因为属性体长度不一定正好占满所有簇) |
0x38 | 8 | 属性体的初始大小 |
0x40 | 2N | 该属性的属性名(如果没有名字 N=0,则该位置为属性体的内容) |
2N + 0x40 | 属性的 Run List 信息,它记录了属性体开始的簇号、簇数等信息 |