文件系统3:NTFS
NFTS总体结构如下
MFTMirr只备份前四个对象,但其位置相对不固定,通过Boot区确定其位置
Boot区
Boot区最多占16个扇区。第1个扇区是带有“引导”代码的引导扇区(DBR),接下来的15个扇区是引导扇区的初始程序加载器。在NTFS分区的最后一个扇区留有DBR备份。第一个扇区结构如下:
偏移 | 意义 |
---|---|
0-2 | 跳转指令 |
3-A | 厂商名 |
B-C | 每扇区的字节数 |
D | 每个簇的扇区数 |
E-F | 保留扇区 |
10-12 | 总是0 |
13-14 | NTFS不使用 |
15 | 介质描述符 |
16-17 | 总是0 |
18-19 | 每个轨道的扇区 |
1A-1B | 轨道数 |
1C-1F | 隐藏的扇区,其实就是从磁盘开始到第一个分区的扇区数 |
20-27 | NTFS不使用 |
28-2F | 总扇区数 |
30-37 | MFT的簇号 |
38-3F | MFTMirr的簇号 |
40 | int8,每个MFT占用的字节数,值为2^(-1*字段的值) |
41-43 | 保留 |
44 | 每个索引目录(文件夹记录文件名的地方)的簇数 |
45-47 | NTFS不使用 |
48-4F | 卷号 |
50-53 | 校验和 |
54-1FD | 引导代码 |
1FE-1FF | 扇区结束标记55 AA |
举例
以磁盘0的D分区为例,分区格式为NTFS
从分区起始处的Boot区出发,数据如下,可以看到每簇扇区数为8,MFT在3簇,所以MFT在相对此分区开始的8*3扇区,此分区从2048扇区开始,所以MFT在2048+8*3=2072扇区。
可以在偏移40处知道每个MFT对象占2^(-1*-10)=1024B
主文件表 (MFT)
MFT包含了所有文件的信息,每个文件对应一个MFT对象,其中有几个文件是初始化时就创建好的,被称为元文件
元文件种类
文件名 | 在MFT记录中的顺序,即索引号 | 作用 |
---|---|---|
$MFT | 0 | 主文件表,包含了所有文件的信息 |
\(MFTMMirr|1|\)MFT前4个表项的备份 | ||
$LogFile | 2 | 日志文件 |
$Volume | 3 | 卷标和卷版本信息 |
$AttrDef | 4 | 属性定义表 |
$Root | 5 | 根文件夹 |
$Bitmap | 6 | 位图,显示哪些簇在使用 |
$Boot | 7 | 引导扇区 |
$BadClus | 8 | 坏簇列表文件 |
$Secure | 9 | 安全文件,用来控制文件的访问权限 |
$UpCase | 10 | 大小写字符转换表,将小写字符转换为Unicode大写字符 |
$Extend | 11 | 用于各种扩展 |
保留 | 12-15 | 保留 |
$Quota | 24 | 配额管理文件,因为NTFS可以为每个用户设置其可以使用的最大空间 |
$ObjId | 25 | 对象ID文件 |
$Reoarse | 26 | 重解析点文件 |
$RmMetadata | 27 | 记录事务元数据,即最近对文件系统的修改 |
MFT对象结构
每个MFT对象由MFT记录头和多个不同的属性组成。结构图示大致如下:
MFT记录头的结构
偏移 | 意义 |
---|---|
0-3 | 签名,值为46 49 4C 45,即为FILE |
4-5 | 更新序列号的偏移,在每个MFT对象所在的扇区尾,都会有2字节相同的标记值,用于保持一致性,被称为更新序列号 |
6-7 | 更新序列号的个数 |
8-F | 日志序列号 |
10-11 | 序列号,第几个MFT对象(从1编号,备份$MFTMMirr的也为1) |
12-13 | 硬链接数 |
14-15 | 第一个属性的偏移地址 |
16-17 | 标志,0:删除的文件,1:正常的文件,2:删除的目录,3:正常的目录 |
18-1B | 此MFT对象的字节长度 |
1C-1F | 此MFT对象分配的字节长度 |
20-27 | 基本文件记录中的文件索引号,只有在一个MFT对象无法完全存储一个文件时才使用,从0开始编号 |
28-29 | 下一个属性ID |
2A-2B | 保留 |
2C-2F | 此MFT对象在MFT中的索引号(从0编号) |
30-31 | 更新序列号,在每个MFT对象所在的扇区尾,都会有2字节相同的标记值,用于保持一致性,被称为更新序列号 |
32-33 | 更新数组1,如果数据在第一个扇区还没有完,但是结尾已经有更新序列号占了两个字节,就把本应该写在此处的两字节写在更新数组1处 |
34-35 | 更新数组2,与上同理,是数据在第二个扇区还没有完 |
举例
由BOOT区知MFT在2072扇区,所以MFT数据如下:
- 其中红框偏移4-5处为更新序列号偏移,为30H处,所以为第二个红框处,其值为3A 00即更新序列号。在该扇区尾部即第三个红框处,也为更新序列号,要保持一致。
- 偏移14-15处显示第一个属性偏移为38H,所以在偏移38H即红线处为第一个属性开始。
- 2C-2F处显示为0,即索引号为0,表示该MFT对象对应的是一个元文件$MFT
属性的种类
属性类型(16进制) | 描述 |
---|---|
10 | 记录标准信息 |
20 | 属性列表:当一个文件需要多个文件记录时,用来描述文件的属性列表 |
30 | 文件名属性 |
40 | 对象ID |
50 | 安全描述 |
60 | 卷名 |
70 | 卷信息 |
80 | 文件数据内容 |
90 | 索引(可以看做是文件夹)根属性 |
A0 | 索引分配树节点,当90属性存储不下使用 |
B0 | MFT文件和索引的位图 |
C0 | 重解析点 |
D0 | 扩充属性信息 |
E0 | 扩充属性 |
F0 | 早期NTFS才有的属性 |
100 | EFS加密属性 |
属性结构
每个属性可以分为两个部分:属性头和属性体
因为一个MFT对象空间有限,如果要MFT对象要记录的属性超过空间大小,剩下的部分就要在MFT之外的区域存储,存储采用簇流运行的方式。因此对以上属性又可以分为常驻属性,即优先保存在MFT区域中,和非常驻属性,即优先放到MFT区域外。
簇流是存放数据的区域
簇流运行是记录簇流具体在文件系统哪个位置的代码
簇流运行第一个字节的低四位表示:该字节后几个字节为一组,这一组表示簇流的大小
簇流运行第一个字节的高四位表示:该字节后几个字节为一组,这一组表示簇流的起始簇号(相对于当前簇流),如果起始簇号为负,表示下个簇流在这个簇流前面
常驻属性的结构如下:
偏移(相对于每个属性内) | 意义 |
---|---|
0-3 | 属性类型 |
4-7 | 属性的总字节数 |
8 | 0:常驻属性,1:非常驻属性 |
9 | 属性名的长度 |
A-B | 相对于属性头的属性名的偏移 |
C-D | 0001:压缩,4000:加密,8000:稀疏 |
E-F | 属性ID |
10-13 | 属性体的字节数 |
14-15 | 属性体相对属性的偏移,因为在属性头后可能有属性名 |
16 | 索引标志 |
17 | 保留 |
18- | 属性体 |
非常驻属性结构如下:
偏移(相对于每个属性内) | 意义 |
---|---|
0-3 | 属性类型 |
4-7 | 属性的总字节数 |
8 | 0:常驻属性,1:非常驻属性 |
9 | 属性名的长度 |
A-B | 相对于属性头的属性名的偏移 |
C-D | 0001:压缩,4000:加密,8000:稀疏 |
E-F | 属性ID |
10-17 | 文件数据起始虚拟簇号,一定为00 |
18-1F | 文件数据结束虚拟簇号 |
20-21 | 簇流运行的偏移地址 |
22-23 | 压缩的大小,2的幂次,为0表示没有压缩 |
24-27 | 保留 |
28-2F | 属性体占用的字节数 |
30-37 | 属性体实际占用的字节数 |
38-3F | 属性体的初始大小 |
40- | 簇流运行信息 |
属性体
不同属性类型的属性体的结构不同
10属性的属性体
偏移(相对于每个属性体内) | 意义 |
---|---|
0-7 | 文件创建时间 |
8-F | 最后修改时间 |
10-17 | MFT修改时间 |
18-1F | 最后访问时间 |
20-23 | 文件属性,1:只读,2:隐藏,4:系统,20H:存档,40H:设备,80H:常规,100H:临时,200H:稀疏文件,400H:重解析点,800H:压缩,1000H:脱机,2000H:未编入索引,4000H:加密 |
24-27 | 最高版本号 |
28-2B | 版本号 |
2C-2F | 分类ID |
30-33 | 所有者ID |
34-37 | 安全ID |
38-3F | 磁盘配额 |
40-47 | 更新序列号 |
接着上面例子的红划线处看,首先是属性头(绿线表示)。
偏移0-3(相对于属性内),即图中38-3B处值为10,表示属性类型为记录标准信息的属性
4-7处属性总字节数,刚好为红框框处
8处是0,表示为常驻属性
9处是0,表示没有属性名
A-B是24,表示相对于属性头的属性名的偏移,但是属性名又为0,说明属性头占24B,在属性头后直接为属性体。所以在14-15处可以看到属性体相对属性头的偏移也为24
接着是属性体
偏移20-23处(相对于每个属性体内),即图中偏移70-73处,值为6,表示是系统隐藏文件
30属性的属性体
偏移(相对于每个属性体内) | 意义 |
---|---|
0-3 | 父目录的参考号,即MFT对象序列号 |
4-5 | 保留 |
6-7 | 父目录的更新序列号 |
8-F | 文件创建时间 |
10-17 | 文件修改时间 |
18-1F | MFT的修改时间 |
20-27 | 文件最后修改时间 |
28-2F | 文件分配大小 |
30-37 | 文件实际大小 |
38-3B | 文件属性,1:只读,2:隐藏,4:系统,20H:存档,40H:设备,80H:常规,100H:临时,200H:稀疏文件,400H:重解析点,800H:压缩,1000H:脱机,2000H:未编入索引,4000H:加密 |
3C-3F | 重解析点 |
40 | 文件名的长度 |
41 | 文件名的命名方式,00:文件名大小写敏感,字符\和空字符不能用,01:字符*/:<>\不能用,最后一个字符不能是.或空格,02:只能是大写字符,长度1-8,.是连接符,最后0-3个字符为扩展名,03:采用01或者02的命名方式 |
42- | unicode编码的文件名 |
还是接着上面的例子看,10属性下一个是30属性,其属性头是划红线处,30属性也为常驻属性。
然后看属性体
偏移0-3处,即绿色划线处表示父目录的MFT对象索引号为5,而在前面知道索引号为5的元文件为根文件夹
蓝线处为文件分配大小和文件实际大小
偏移38-3B处,即图中阴影E8-EB处为6,表示是系统隐藏文件
偏移40处,即图中阴影F0处为4,表示文件名为4字符长,之后的偏移41处,表示文件命名方式
之后就是unicode编码的文件名了,一个字符由两字节表示,为字符$MFT
80属性的属性体
如果是常驻属性,则属性体为数据内容
如果为非常驻属性,则属性体为簇流运行
继续接着看,30属性后为80属性
偏移8处为1,表示为非常驻属性。
红线处为文件数据起始虚拟簇号(一般为0)和文件数据的结束虚拟簇号(值为20415,起始就是占多少簇)
偏移20-21处,即绿色划线处为簇流的偏移地址,为64,即蓝色划线处为簇流运行
其第一个字节的低四位为2,表示后面两个字节为一组,即C0 4F,表示簇流大小,为几个簇,值为20416(与上面的结束虚拟簇号相对应),扇区为2072+20416*8=165400
其第一个字节的高四位为1,表示再后面一个字节为一组,即03,表示簇流起始簇号,算出扇区正好为2072,也就是这个文件的数据就从这里开始(因为就是$MFT文件)
90属性的属性体
索引根节点
偏移(相对于索引根节点内) | 意义 |
---|---|
0-3 | 属性类型 |
4-7 | 校对规则 |
8-B | 每个索引缓冲区的字节数 |
C | 每个索引缓冲区的簇数 |
D-F | 保留 |
索引头
偏移(相对于索引头内) | 意义 |
---|---|
0-3 | 第一个索引项的偏移,相对于属性体的偏移 |
4-7 | 索引项的字节数 |
8-B | 索引项的分配字节数 |
C | 0:根索引,1:索引分配 |
D-F | 保留 |
索引项
偏移(相对于索引头内) | 意义 |
---|---|
0-3 | 文件的MFT对象序列号 |
4-5 | 保留 |
6-7 | 更新序列号 |
8-9 | 本索引项字节数 |
A-B | 文件名属性体字节数(索引项从10到结尾字节数) |
C-D | 0:没有子节点,1:有子节点,2:最后一个索引项 |
E-F | 保留 |
10-13 | 父目录的MFT序列号 |
14-15 | 保留 |
16-17 | 父目录的更新序列号 |
18-1F | 文件创建时间 |
20-27 | 文件最后修改时间 |
28-2F | MFT最后修改时间 |
30-37 | 最后访问时间 |
38-3F | 文件分配大小 |
40-47 | 文件实际大小 |
48-4F | 文件属性,1:只读,2:隐藏,4:系统,20H:存档,40H:设备,80H:常规,100H:临时,200H:稀疏文件,400H:重解析点,800H:压缩,1000H:脱机,2000H:未编入索引,4000H:加密 |
50 | 文件名长度 |
51 | 文件名的命名方式 |
52- | 文件名 |
接着上面的例子,跳转到根目录对应的MFT对象区域,找到90属性,如图中阴影部分,分析可知其为常驻属性,属性头红色划线标记,属性名绿色划线标记,剩下为属性体
之后,蓝色括号部分为索引根节点,红框处为每个索引缓冲区的字节数,为4096,蓝色划线处为每个索引缓冲区簇数,为1
红色括号处为索引头,偏移4-7,即图中偏移为84-87处值为00 00 00 28,所以该索引项大小为28H(从索引头开始算,到阴影部分结尾)
偏移C处表示该索引项是索引分配,所以应该找后面紧接着的A0属性的属性体
A0属性的属性体
当文件夹中内容很少时,用90属性存,否则使用A0属性,属性使用簇流。
在其索引缓冲区包含一个索引头和多个索引项,索引项与90属性索引项相同
索引头结构
偏移 | 意义 |
---|---|
0-3 | 标志,为INDX |
4-5 | 更新序列号偏移 |
6-7 | 更新序列号与更新数组单位大小 |
8-9 | 日志文件序列号 |
10-17 | 本索引缓冲区的第几个簇(从0开始,有时候一个簇存放不下) |
18-1B | 索引项的偏移(相对于18位置) |
1C-1F | 索引项的大小 |
20-23 | 索引项的分配大小 |
24 | 0:叶节点,1:还有子节点 |
25-27 | 保留 |
28-29 | 更新序列号 |
2A | 更新序列号数组 |
继续接着上面的例子看,数据如下图阴影处所示,红线处为簇流运行,其余部分为非常驻属性体。分析其簇流运行,起始簇号为00 E6 8B 即59019,大小为一个簇,可以找到其索引缓冲区
索引缓冲区如下
红框处为索引头,剩下的为各个索引项,只看第一个索引项,即阴影处
偏移0-3处为04,表示为元文件$AttrDef的MFT对象的索引项
8-9表示本索引项的字节数
10-13表示父目录的MFT序列号,为5,也就是根目录
参考
https://www.bilibili.com/video/BV1ia411F7av?p=1
https://www.ntfs.com/ntfs_basics.htm
https://blog.csdn.net/enjoy5512/category_6144112.html
基于NTFS文件系统的文件恢复程序的设计与实现 于天佐