NTFS (New Technology File System),是 Windows NT 环境的文件系统。新技术文件系统是Windows NT家族(如,Windows 2000、Windows XP、Windows Vista、Windows 7和 windows 8.1)等的限制级专用的文件系统(操作系统所在的盘符的文件系统必须格式化为NTFS的文件系统,4096簇环境下)。NTFS取代了老式的FAT文件系统。
NTFS对FAT和HPFS作了若干改进,例如,支持元数据,并且使用了高级数据结构,以便于改善性能、可靠性和磁盘空间利用率,并提供了若干附加扩展功能。NTFS文件系统拥有以下特点:
安全性高:NTFS支持基于文件或目录的ACL,并且支持加密文件系统(EFS)。
可恢复性:NTFS支持基于原子事务概念的文件恢复,比较符合服务器文件系统的要求。
文件压缩:NTFS支持基于文件或目录的文件压缩,可以很方便的节省磁盘空间。
磁盘配额:NTFS支持磁盘配额,可针对系统中每个用户分配磁盘资源。
当用户将硬盘的一个分区格式化为NTFS分区时,就建立了一个NTFS文件系统。NTFS文件系统同FAT32文件系统一样,也是用“簇”为存储单位,一个文件总是占用一个或多个簇。
NTFS文件系统使用逻辑簇号(LCN)和虚拟簇号(VCN)对分区进行管理。
逻辑簇号:既对分区内的第一个簇到最后一个簇进行编号,NTFS使用逻辑簇号对簇进行定位。
虚拟簇号:既将文件所占用的簇从开头到尾进行编号的,虚拟簇号不要求在物理上是连续的。
NTFS文件系统一共由16个“元文件”构成,它们是在分区格式化时写入到硬盘的隐藏文件(以”$”开头),也是NTFS文件系统的系统信息。
NTFS的16个元文件介绍:
序号 | 元文件 | 功能 |
---|---|---|
0 | $MFT | 主文件表本身,是每个文件的索引 |
1 | $MFTMirr | 主文件表的部分镜像 |
2 | $LogFile | 事务型日志文件 |
3 | $Volume | 卷文件,记录卷标等信息 |
4 | $AttrDef | 属性定义列表文件 |
5 | $Root | 根目录文件,管理根目录 |
6 | $Bitmap | 位图文件,记录了分区中簇的使用情况 |
7 | $Boot | 引导文件,记录了用于系统引导的数据情况 |
8 | $BadClus | 坏簇列表文件 |
9 | $Quota(NTFS4) | 在早期的Windows NT系统中此文件为磁盘配额信息 |
10 | $Secure | 安全文件 |
11 | $UpCase | 大小写字符转换表文件 |
12 | $Extend metadata directory | 扩展元数据目录 |
13 | $Extend\$Reparse | 重解析点文件 |
14 | $Extend\$UsnJrnl | 加密日志文件 |
15 | $Extend\$Quota | 配额管理文件 |
16 | $Extend\$ObjId | 对象ID文件 |
下面我们分析一下DBR中的各参数:
EB 52 90(跳转指令)
本身占2字节它将程序执行流程跳转到引导程序处。“EB 52 90”清楚地指明了OS引导代码的偏移位置。jump 52H加上跳转指令所需的位移量,即开始于0×55。
4E 54 46 53 20 20 20 20(OEM代号)
这部分占8字节,其内容由创建该文件系统的OEM厂商具体安排,本例为“NTFS”。
BPB
NTFS文件系统的BPB从DBR的第12个字节开始,占用73字节,记录了有关该文件系统的重要信息,下表中的内容包含了“跳转指令”、“OEM代号”以及“BPB”的参数。
偏移(offset) | 长度(字节) | 含义 |
---|---|---|
00-02H | 3 | 跳转指令EB 52 90 |
03-0AH | 8 | 文件系统的ASIIC码,表示形式NTFS |
0B-0CH | 2 | 每个扇区内的字节总数,一般为00 02H |
0DH | 1 | 簇大小 |
0E-0FH | 2 | 保留扇区 |
10-12H | 3 | 总为0 |
13H | 1 | 不使用 |
14-15H | 2 | 介质描述,硬盘为F8 |
16-17H | 2 | 总为0 |
18-19H | 2 | 每磁头扇区数 |
1A-1BH | 2 | 每柱面磁头数 |
1C-1FH | 4 | 隐含扇区(从MBR到DBR的扇区总数) |
20-23H | 4 | 不使用 |
24-27H | 4 | 不使用,总为80 00 80 00 |
28-2FH | 8 | 扇区总数,即分区大小 |
30-37H | 8 | $MFT的开始簇号 |
38-3FH | 8 | $MFTmirr的开始簇号 |
40-43H | 4 | 每个MFT记录的簇数 |
44-47H | 4 | 每索引的簇数 |
48-4FH | 8 | 分区的逻辑序列号 |
对照上表,对BPB的分析如下:
- | - |
---|---|
02 00 | 每个扇区512个字节 |
08 | 每个簇8个扇区 |
00 00 | 保留扇区为 0 |
00 00 00 | 为 0 |
00 00 | 不使用 |
F8 | 硬盘 |
00 00 | 为0 |
00 3F | 每磁道63个扇区 |
00 FF | 每柱面255个磁头 |
00 00 00 3F | 隐藏扇区数(MBR到DBR) |
00 00 00 00 | 不使用 |
80 00 80 00 | 不使用 |
00 00 00 00 04 FF D5 E5 | 扇区总数 83875301 |
00 00 00 00 00 0C 00 00 | MFT的开始簇号 786432 |
00 00 00 00 00 00 00 10 | MFTmirr的开始簇号 16 |
00 00 00 F6 | 每个MFT记录的簇数 |
00 00 00 01 | 每索引的簇数 |
B6 FC 23 AA FC 23 63 B9 | 分区的逻辑序列号 |
引导程序:DBR的引导程序占用426字节,其负责完成将系统文件NTLDR装入,对于没有安装系统的分区是无效的。
在NTFS文件系统中,磁盘上的所有数据都是以文件的形式存储,其中包括元文件。每个文件都有一个或多个文件记录,每个文件记录占用两个扇区,而MFT元文件就是专门记录每个文件的文件记录。由于NTFS文件系统是通过MFT元文件就是专门记录每个文件的文件记录。由于NTFS文件系统是通过MFT来确定文件在磁盘上的位置以及文件的属性,所以MFT是非常重要的,MFT是非常重要的,MFT的起始位置在DBR中有描述。MFT的文件记录在物理上是连续的,并且从0开始编号。MFT的文件记录在物理上是连续的,并且从0开始编号。MFT的前16个文件记录总是元文件的,并且顺序是固定不变的。
根据上面BPB的数据可以得到条件
说明 | 数值 |
---|---|
MBR开始扇区 | 63 |
每个扇区内的字节总数 | 512 |
簇大小 | 8 |
每个MFT记录的簇数 | 1 |
MFT的开始簇号 | 786432 |
每个MFT字节总数 = 簇大小 * 每个扇区内的字节总数
= 8 * 512 = 4096
MBR开始扇区字节总数 = MBR起始扇区 * 每个扇区内的字节总数
= 63 * 512 = 32256
MFT的开始位置的字节总数 = MBR开始扇区字节总数 + MFT的开始簇号 * 每个MFT字节总数
= 32256 + 786432 * 4096 = 3221257728
将3221257728
转换为十六进制,即得到MFT开始位置偏移地址C0007E00
文件记录由两部分构成,一部分是文件记录头,另一部分是属性列表,最后结尾是四个“FF”。
查看文件记录格式,如下是一个完整的文件记录:
在同一系统中,文件记录头的长度和具体偏移位置的数据含义是不变的,而属性列表是可变的,其不同的属性有着不同的含义。后文将对属性进行具体分析,先来看看文件记录头的信息。
偏移(offset) | 长度(字节) | 描述 |
---|---|---|
0x0 | 4 | 固定值,一定是“FILE” |
0x4 | 2 | 更新序列号的偏移 |
0x6 | 2 | 更新序列号与更新数组以字为单位大小(S) |
0x8 | 8 | 日志文件序列号(每次记录被修改,都将导致该序列号加1) |
0x10 | 2 | 序列号(记录本文件记录被重复使用的次数,每次文件删除时加1,跳过0值,如果为0,则保持为0) |
0x12 | 2 | 硬连接数,只出现在基本文件记录中,目录所含项数要使用到它 |
0x14 | 2 | 第一个属性流的偏移地址 |
0x16 | 2 | 标志字节,1表示记录使用中,2表示记录为目录 |
0x18 | 4 | 文件记录实际大小(填充到8字节,即以8字节为边界) |
0x1C | 4 | 文件记录分配大小(填充到8字节,即以8字节为边界) |
0x20 | 8 | 所对应的基本文件记录的文件参考号(扩展文件记录中使用,基本文件记录中为0,在基本文件记录的属性列表0x20属性存储中扩展文件记录的相关信息) |
0x28 | 2 | 下一个自由ID号,当增加新的属性时,将该值分配给新属性,然后该值增加,如果MFT记录重新使用,则将它置0,第一个实例总是0。 |
0x2A | 2 | 边界,windows xp中使用,也就是本记录使用的两个扇区的最后两个字节的值 |
0x2C | 4 | windows xp中使用,本MFT记录号 |
- | 2 | 更新序号 |
- | 2S-2 | 更新序列数组 |
在NTFS文件系统中所有与文件相关的数据结构均被认为是属性,包括文件的内容。文件记录是一个与文件相对应的文件属性数据库,它记录了文件的所有属性。每个文件记录中都有多个属性,他们相对独立,有各自的类型和名称。每个属性都由两部分组成,既属性头和属性体。属性头的前四个字节为属性的类型。从文件记录头可以看到第一个属性流的偏移地址,(C0007E00+0038=C0007E38)如下是以10H属性为例的属性结构。
属性有常驻与非常驻之分。
当一个文件很小时,其所有属性体都可以存放在文件记录中,该属性就称为常驻属性。
如果某个文件很大,1KB的文件记录无法记录所有属性时,则文件系统会在MFT元文件之外的区域(也称数据流)存放该文件的其他文件记录属性,这些存放在非MFT元文件之外的区域(也称数据流)存放该文件的其他文件记录属性,这些存放在非MFT元文件内的记录就称为非常驻属性。
每个属性都有一个属性头,这个属性头包含了一些该属性的重要信息,如属性类型,属性大小,名字(并非都有)及是否为常驻属性等。
常驻属性的属性头分析表:
偏移(offset) | 长度(字节) | 常用值 | 含义 |
---|---|---|---|
00-03 | 4 | - | 属性类型 |
04-07 | 4 | - | 属性的长度,8的整数倍(整个属性长度) |
08 | 1 | 00 | 是否为常驻属性,00表示为常驻属性 |
09 | 1 | 00 | 属性名的长度,00表示没有属性名 |
0A-0B | 2 | 18 00 | 属性值的开始偏移 |
0C-0D | 2 | 00 | 标志,如压缩、加密、稀疏等 |
0E-0F | 2 | 00 | 标识 |
10-13 | 4 | Length | 属性长度 |
14-15 | 2 | 18 | 属性体开始位置 |
16 | 1 | - | 索引标志 |
17 | 1 | - | 填充 |
18 | Length | - | 属性体开始 |
非常驻属性的属性头分析表:
偏移(offset) | 长度(字节) | 常用值 | 含义 |
---|---|---|---|
00-03 | 4 | - | 属性类型 |
04-07 | 4 | - | 属性的长度,8的整数倍(整个属性长度) |
08 | 1 | 01 | 是否为常驻属性,01表示为非常驻属性 |
09 | 1 | 00 | 属性名的长度,00表示没有属性名 |
0A-0B | 2 | - | 属性值的开始偏移 |
0C-0D | 2 | - | 标志,如压缩、加密、稀疏等 |
0E-0F | 2 | - | 属性ID |
10-17 | 8 | - | 起始虚拟簇号VCN |
18-1F | 8 | - | 结束虚拟簇号VCN |
20-21 | 2 | 40 | Data Run的偏移地址 |
22-23 | 2 | - | 压缩单位大小,2的N次方 |
24-27 | 4 | - | 不使用 |
28-2F | 8 | - | 属性分配大小 |
30-37 | 8 | - | 属性实际大小 |
38-3F | 8 | - | 属性原始大小 |
40 | - | - | Data Run信息 |
前面说过了,属性的种类有很多,因此各属性体的含义也不同。下表是NTFS文件系统中的所有属性体的简介。
属性类型(即属性偏移00H-03H处的十六进制数据) | 属性类型名 | 属性描述 |
---|---|---|
10H 00H 00H 00H | $STANDARD_INFORMATION | 标准信息:包括一些基本文件属性,如只读、系统、存挡,时间属性,如文件的创建时间和最后修改时间;有多少目录指向该文件( 即其硬链接数) |
20H 00H 00H 00H | $ATTRIBUTE_LIST | 属性列表,当一个文件需要多个MFT文件记录时,用来描述文件的属性列表 |
30H 00H 00H 00H | $FILE_NAME | 文件名,用Unicode字符表示的文件名,由于MS DOS不能识别长文件名, 所以NTFS系统会自动生成一个8.3文件名 |
40H 00H 00H 00H | $VOLUME_VERSION | 在早期的NTFS v1.2中为卷版本 |
40H 00H 00H 00H | $OBJECT_ID | 对象ID:一个具有64个字节的标识符,其中最低的16个字节对卷来说是惟一的(链接跟踪服务为外壳快捷方式即OLE链接源文件赋予对象ID,NTFS提供的API是直接通过这些对象的ID而不是文件名来打开文件的) |
50H 00H 00H 00H | $SECURITY_DESCRIPTOR | 安全描述符:这是为向后兼容而保留的,主要用于保护文件以防止没有授权的访问,但Windows 2000、Windows XP中巳将安全描述符存放在$Secure元数据中,以便于共享(早期的NTFS将其与文件目录一起存放,不便于共享) |
60H 00H 00H 00H | $VOLUME_NAME | 卷名(卷标识):该属性仅存在于$Volume元数据中 |
70H 00H 00H 00H | $VOLUME_INFORMATION | 卷信息,该属性仅存在于$Volume元数据中 |
80H 00 ll 00H 00H | $DATA | 文件数据:该属性为文件的数据内容 |
90H 00H 00H 00H | $INDEX_ROOT | 索引根 |
A0H 00H 00H 00H | $INDEX_ALLOCATlON | 索引分配 |
B0H 00H 00H 00H | $BITMAP | 位图 |
C0H 00H 00H 00H | $SYMBOLIC_LINK | 在早期的NTFS v1.2中为符号链接 |
C0H 00H 00H 00H | $REPARSE_POINT | 重解析点 |
D0H 00H 00H 00H | $EA_INFORMATION | 扩充属性信息 |
E0H 的H 00H 00H | $EA | 扩允属住 |
F0H 00H 00H 00H | $PROPERTY_SET | 早期的NTFS v1.2中才有 |
00H 10H 00H 00H | $LOGGED_UTILITY_STREAM | EFS加密屈性:该属性主要用于存储实现EFS加密的有关加密信息,如合法用户列表、解码密钥等 |
接下来来看几个重要的属性:
偏移(offset) | 长度(字节) | 操作系统 | 描述 |
---|---|---|---|
- | - | - | 标准属性头(已经分析过) |
0x00 | 8 | - | C TIME 文件创建时间 |
0x08 | 8 | - | A TIME 文件修改时间 |
0x10 | 8 | - | M TIME MFT变化时间 |
0x18 | 8 | - | R TIME 文件访问时间 |
0x20 | 4 | - | 文件属性(按照DOS术语来称呼,都是文件属性) |
0x24 | 4 | - | 文件所允许的最大版本号(0表示未使用) |
0x28 | 4 | - | 文件的版本号(最在版本号为0,则他为0) |
0x2C | 4 | - | 类ID(一个双向的类索引) |
0x30 | 4 | 2K | 所有者ID(表示文件的所有者,是文件配额$QUOTA中$O和$Q索引的关键字,为0表示未使用磁盘配额) |
0x34 | 4 | 2K | 安全ID是文件$SECURE中$SII和$SDS数据流的关键字,注意不要与安全标识相混淆 |
0x38 | 8 | 2K | 本文件所占用的字节数,它是文件所有流占用的总字节数,为0表示未使用磁盘配额 |
0x40 | 8 | 2K | 更新系列号(USN),是到文件$USNJRNL的一个直接的索引,为0表示USN日志未使用 |
如下是一个10H属性偏移0×20处属性体的解释:
标志 | 描述 | 标志 | 描述 |
---|---|---|---|
0001H | 只读文件 | 0200H | 稀疏文件 |
0002H | 隐含文件 | 0400H | 重点解析文件 |
0004H | 系统文件 | 0800H | 压缩文件 |
0020H | 存档文件 | 1000H | 脱机文件 |
0040H | 设备文件 | 2000H | 未编入文件 |
0080H | 常规文件 | 4000H | 加密文件 |
0100H | 临时文件 | - | - |
偏移(offset) | 长度(字节) | 描述 |
---|---|---|
- | - | 标准属性头(已经分析过) |
0x00 | 4 | 类型 |
0x04 | 2 | 记录长度 |
0x06 | 1 | 属性名长度(N,为0表示没有属性名) |
0x07 | 1 | 属性名偏移(如果没有属性名,则指向属性内容) |
0x08 | 8 | 起始VCN(属性常驻时为0) |
0x10 | 8 | 属性的基本文件记录中的文件参考号(所有MFT的文件都有一个文件索引号,引用到这个文件参考号,等价于引用这个文件记录,这个参考号在文件记录头中有定义) |
0x18 | 2 | 属性ID(每个属性都有一个唯一的ID号) |
0x1A | 2N | Unicode属性名(如果有属性名) |
偏移(offset) | 长度(字节) | 描述 |
---|---|---|
- | - | 标准属性头(已经分析过) |
0x00 | 8 | 父目录的文件参考号(即父目录的基本文件记录号,分为两部分,前6个字节48位为父目录的文件记录号,此处为0x05,即根目录,所以$MFT的父目录为根目录,后2个字节为序列号) |
0x08 | 8 | 文件创建时间 |
0x10 | 8 | 文件修改时间 |
0x18 | 8 | 最后一次MFT更新时间 |
0x20 | 8 | 最后一次访问时间 |
0x28 | 8 | 文件分配大小 |
0x30 | 8 | 文件实际大小 |
0x38 | 4 | 标志,如目录、压缩、隐藏等 |
0x3C | 4 | 用于EAS和重解析点 |
0x40 | 1 | 以字符计的文件名长度,每字符占用字节数由下一字节命名空间确定,一个字节长度,所以文件名最长255字节。 |
0x41 | 1 | 文件名命名空间 |
0x42 | 2L | 以Unicode方式表示的文件名 |
其中,Run List是最难理解,也是最重要的。当属性不能存放完数据,系统就会在NTFS数据区域开辟一个空间存放,这个区域是以簇为单位的。Run List就是记录这个数据区域的起始簇号和大小,一个Run List例子上所示。这个示例中,Run List的值为“32 CC 26 00 00 0C”,因为后面是00H,所以知道已经是结尾。如何解析这个Run List呢? 第一个字节是压缩字节,高位和低位相加,3 + 2 = 5,表示这个Data Run信息占用五个字节,其中高位表示起始簇号占用多少个字节,低位表示大小占用的字节数。在这里,起始簇号占用3个字节,值为0C 00 00,大小占用2个字节,值为26 CC。解析后,得到这个数据流起始簇号为C0000,大小为9932簇。
索引根结构表:
偏移(offset) | 长度(字节) | 描述 |
---|---|---|
- | - | 标准属性头(已经分析过) |
0x00 | 4 | 属性类型 |
0x04 | 4 | 排序规则 |
0x08 | 4 | 索引项分配大小(字节数) |
0x0C | 1 | 每索引记录的簇数 |
0x0D | 3 | 填充(到8字节) |
索引头结构表:
偏移(offset) | 长度(字节) | 描述 |
---|---|---|
- | - | 标准属性头(已经分析过) |
0x00 | 4 | 第一个索引项的偏移 |
0x04 | 4 | 索引项的总大小 |
0x08 | 4 | 索引项的分配大小 |
0x0C | 1 | 标志 |
0x0D | 3 | 填充(到8字节) |
索引项结构表:
偏移(offset) | 长度(字节) | 描述 |
---|---|---|
0x00 | 8 | 文件的MFT参考号 |
0x08 | 2 | 索引项大小 |
0x0A | 2 | 文件名偏移 |
0x0C | 2 | 索引标志 |
0x0E | 2 | 填充(到8字节) |
0x10 | 8 | 父目录的MFT文件参考号 |
0x18 | 8 | 文件创建时间 |
0x20 | 8 | 最后修改时间 |
0x28 | 8 | 文件记录最后修改时间 |
0x30 | 8 | 最后访问时间 |
0x38 | 8 | 文件分配大小 |
0x40 | 8 | 文件实际大小 |
0x48 | 8 | 文件标志 |
0x50 | 1 | 文件名长度(F) |
0x51 | 1 | 文件名命名空间 |
0x52 | 2F | 文件名 |
2F+0x52 | P | 填充(到8字节) |
P+2F+0x52 | 8 | 子节点索引缓存的VCN |
根据上图A0H属性的“Run List”可以找到索引区域,偏移到索引区域所在的簇,如下图:
起始簇:18265
簇大小:3
起始扇区号 = 该分区的其实扇区 + 簇号 * 每个簇的扇区数 也就是
64 + 18265 * 8 = 146124
上面的偏移0x28,还要加上0x18 = 0×40
起始簇:18265
簇大小:3
起始扇区号 = 该分区的起始扇区 + 簇号 * 每个簇的扇区数
也就是
64 + 18265 * 8 = 146124
标准索引头的解释如下:
偏移(offset) | 长度(字节) | 描述 |
---|---|---|
0x00 | 4 | 总是“INDX” |
0x04 | 2 | 更新序列号的偏移 |
0x06 | 2 | 更新序列号与更新数组以字为单位的大小(S) |
0x08 | 8 | 日志文件序列号 |
0x10 | 8 | 本索引缓存在索引分配中的VCN |
0x18 | 4 | 索引项的偏移 |
0x1C | 4 | 索引项大小 |
0x20 | 4 | 索引项分配大小 |
0x24 | 1 | 如果不是叶节点,置1,表示还有子节点 |
0x25 | 3 | 用0填充 |
0x28 | 2 | 更新序列 |
0x2A | 2S-2 | 更新序列数组 |
索引项的解释如下:
偏移(offset) | 长度(字节) | 描述 |
---|---|---|
0x00 | 8 | 文件的MFT参考号 |
0x08 | 2 | 索引项大小 |
0x0A | 2 | 文件名偏移 |
0x0C | 2 | 索引标志 |
0x0E | 2 | 填充(到8字节) |
0x10 | 8 | 父目录的MFT文件参考号 |
0x18 | 8 | 文件创建时间 |
0x20 | 8 | 最后修改时间 |
0x28 | 8 | 文件记录最后修改时间 |
0x30 | 8 | 最后访问时间 |
0x38 | 8 | 文件分配大小 |
0x40 | 8 | 文件实际大小 |
0x48 | 8 | 文件标志 |
0x50 | 1 | 文件名长度(F) |
0x51 | 1 | 文件名命名空间 |
0x52 | 2F | 文件名 |
2F+0x52 | P | 填充(到8字节) |
P+2F+0x52 | 8 | 子节点索引缓存的VCN |
到此一些常用属性基本介绍的差不多了。
1. 定位DBR,通过DBR可得到“$MFT”的起始簇号及簇大小;
2. 定位并找到“MFT”后,在其中寻找根目录的文件记录,一般在5号文件记录;
3. 在90H属性中得到B+树索引的根节点文件信息,重点在A0属性上。通过属性中的“Run List”定位到其数据流;
4. 从“Run List”定位到起始簇后,再分析索引项可以得到文件名等信息;
5. 从索引项中可以获取“MFT”的参考号;
6. 进入到“MFT”的参考号;
7. 进入到“MFT”找到对应的文件记录;
8. 然后再根据80H属性中的数据流就,可以找到文件真正的数据了。