/*算法
Skogkatt 开始翻译于2015-01-24,仅做为学习研究之用,谢绝转载。安全
2015-01-31更新MFT entry 属性概念。数据结构
2015-02-01翻译完成。ide
译注:我翻译这本书的这三章虽然蓄谋已久,但并非一个计划好的工做。由于以前和vczh、mili、darkfall曾讨论过everything这个软件,也曾想过要写一个开源的everything,因而就出来一个坑。everything这个软件实际上是从底层直接parse了NTFS MFT,而后parse类每个FILE entry,从里面拆出来了每个文件的信息,这个操做速度远快于Win32 FindFirstFile和FindNextFile。道理虽然简单,可是实现起来代码不会不多。工具
又,我从2013年原由工做缘由开始研究和分析NTFS文件系统,而且看过数遍《File System Forensic Analysis》这本书的NTFS三章。这三章的信息已经略显过期而且存在一些技术细节谬误,翻译出来仅仅是给英语很差的朋友们作为拓展知识所用。若是想认真研究NTFS实现细节,建议看看泄露的Windows源代码、开源的NTFS3g库并使用磁盘编辑工具实际看看磁盘的布局。布局
另外,NTFS3g目前公开的代码坑不少,在高负荷压力测试中会出现严重的数据丢失损坏甚至文件系统挂掉,,不建议做为一个严谨的NTFS实现来使用。学习
*/测试
新技术文件系统(NTFS)是由Microsoft设计的并做为Micrtosoft Windows NT、Windows 2000、 Windows XP和Windows Server的缺省文件系统。在写做本书的时候,Microsoft已经中止了Windows 98 和 ME 产品线的销售,Windows XP家庭版成为新的消费系统。FAT仍将会存在于移动和小型存储设备之中,但NTFS将会成为Windows研究中最为常见的文件系统。NTFS是比FAT更为复杂的文件系统,这是因为它具备众多的功能特性和伸缩性。因为NTFS的复杂性,咱们须要三章来讨论它。本章将会讨论NTFS的核心概念,覆盖到咱们模型中的五个分类。第12章,“NTFS分析”讨论了NTFS分析和使用五分类模型来展现咱们从哪里获取证据。第13章,“NTFS数据结构”介绍了NTFS相关的数据结构。加密
简介spa
NTFS被设计为具备可靠性、安全性和支持大型存储设备。伸缩性是由通用的数据结构所封装的具备特定内容的数据来实现的。这之因此是一个可伸缩的设计,是因为内部的数据结构能够根据文件系统新增的需求而变化,二外部的封装能够保持不变。一个通用封装的例子是,NTFS文件系统的每个字节都被分配到文件之中。咱们稍后在本章中将会讨论NTFS文件的概念。
NTFS是一个复杂的文件系统,不幸的是,并无一个从Microsoft公开的规范来描述其在磁盘上的布局。文件系统高层组件的描述已经公开了,可是底层细节信息仍然很是匮乏。幸运的是,其余组织已经公开了他们所认为的磁盘布局结构信息,这些信息包含在本书之中,而且咱们将会用它们来手工深刻到磁盘之中。尽管这听起来颇有难度,然而,咱们仍然没法确保这里所描述的数据结构和磁盘上面的彻底一致。
NTFS是大量Windows系统的标准,而且在免费的Unix发行版中也愈加常见(译注:Linux)。没有官方规范和单一支配应用来建立文件系统两个因素合并在一块儿,使得难以区分应用指定的功能和文件系统通用的功能。例如,存在着Microsoft所不使用的初始化文件系统的方法,然而这种方法的结果是否被认为是一个“合法的NTFS”文件系统还难以定论。Microsoft在每一次新发布Windows系统的时候都会更改文件系统内部,我将会在这里指出这些改变。
一切都是文件
为了了解NTFS的设计,一个最重要的概念是一切重要的数据都被分配为文件。这包括其余文件系统一般隐藏起来的基本的文件系统管理数据。事实上,包含管理数据的文件能够存在放卷的任何位置,和普通文件同样。也就是说,NTFS文件系统并不像其余文件系统那样有一个特定的布局。整个文件系统被认为是一个数据区,每个扇区均可以分配给一个文件。惟一不变的布局是每个卷开始的几个扇区,包含有引导扇区和引导代码。
MFT概念
主文件表(MFT)是NTFS的心脏,这是由于它包含全部文件和目录的信息。每个文件和目录在表中至少有一个入口(Entry),entry自己很简单。每个entry都是1KB大,可是只有前42字节有定义的用途。剩余的空间用来存储属性(Attributes),属性是很小的具备特性用途的数据结构。例如,有一个属性用来保存文件的名称,另外一个属性用来保存文件的内容。图11.1一个MFT entry的基本布局,包括头信息和三个属性。
图11.1 一个MFT entry,有一个小头部,剩余的部分用来存储不一样的属性。这个entry有三个属性。
Microsoft称每个表中的entry为一个文件记录,可是我想把每个entry简称为MFT entry,这样更便于记忆。每个entry都基于其在表中的位置有一个地址,从0开始。全部的entry的大小都是1024字节,不过实际的大小定义在引导扇区中。
如NTFS中的全部一切同样,MFT也是一个文件。致使这个使人困惑的是MFT有一个它本身的entry。表中第一个entry名字叫作$MFT,它描述了MFT在磁盘上的位置。实际上,这是惟一描述MFT在磁盘上的位置的地方;也就是说,你须要处理这个entry才能得知MFT的布局和大小。MFT的起始位置在引导扇区给出,引导扇区始终是文件系统的第一个扇区。咱们能够在图11.2看到这个,如何使用引导扇区找到第一个MFT entry,它显示出MFT被分为碎片,有32到34和56到58的簇组成。相似于FAT,NTFS使用簇,簇由连续的扇区组成。
图11.2 引导扇区和$MFT的关系,用来肯定MFT的布局。
在Microsoft实现的NTFS中,MFT开始保持尽可能小的尺寸,当须要更多的entry时扩展MFT。理论上说,操做系统能够在建立文件系统的时候建立固定数量的entry,可是Microsoft实现的动态特性容许很方便的经过分卷扩展文件系统容量。Microsoft在MFT entry建立后不删除它们。
MFT entry内容
每个MFT entry的大小定义在引导扇区之中,可是Microsoft使用的全部版本都使用1024字节大小。数据结构开始的42个字节包含12个域,剩余的982字节没有特定的结构,能够用属性填充。你能够把一个MFT entry想一想为一个用来存放你物品的大盒子。盒子外面是你的基本信息,好比你的名字和地址。基本信息等价于MFT entry的固定域。盒子里面一开始是空的,可是它能够用来保存任何比它小的容器。这很是像MFT entry没有内部结构而且它含有一些包含特定信息的属性。
每个MFT entry的第一个域是签名,一个标准的entry是ASCII字符串“FILE”,若是一个entry里面发现了错误,它可能含有字符串“BAAD”,还有一个标志域用来标识这个entry是否使用、这个entry是不是一个目录。一个MFT entry的分配状态也能够经过$MFT文件的$BITMAP属性来检查,详见第13章。
若是一个文件没法把它的全部属性放进一个entry,它可使用多个entry。当这种状况发生的时候买第一个entry被称为基本文件记录,或者基本MFT entry,后续的每个entry都在它的固定域保存有基本entry的地址。
第13章显示了一个MFT entry的数据结构,并分解了咱们的示例文件系统镜像。
MFT entry 地址
每个MFT entry都使用一个48位的顺序地址,第一个entry地址是0。MFT最大地址随着MFT的增加而增大,它的值由$MFT的大小除以每个entry的大小来计算。Microsoft称这个顺序地址为文件编号(File number)。
每个MFT entry还有一个16位的顺序号,当entry分配的时候这个顺序号增加。例如,想象一下MFT entry313的顺序号是1.entry313的文件删除了,而后这个entry被分配给一个新的文件。当这个entry被从新分配,它获得了一个新的顺序号2。MFT entry和顺序号组合起来,顺序号放在高16位,组成了一个64位的文件参考地址,见图11.3。
图11.3 MFT地址和顺序号组成一个文件参考地址的例子。
NTFS使用文件参考地址来引用MFT entry,这是因为顺序号使得检查文件系统是否处于一种损坏状态变得容易。例如,若是系统在一个文件的数据结构被分配的时候崩溃了,顺序号能够用来判断一个数据结构是否包含MFT entry,是由于上一个文件使用了它仍是它是新文件的一部分。咱们也能够用它来恢复被删除的内容。例如,若是咱们有一个未分配的数据结构,里面有文件参考号,咱们能够判断这个数据结构被使用以来MFT entry是否被从新分配过。顺序号在信息挖掘中有很大的做用,可是在本章为简单起见,我将主要讨论文件号,或者MFT entry地址。
文件系统元文件
因为卷的每个字节都被分配给了文件,一定有文件保存了文件系统的管理数据。Microsoft称它们为元文件,但这样会致使困惑,由于咱们还要讨论文件元数据。我将会称这些特殊文件为文件系统元文件。
Microsoft保留了前16个MFT entry做为文件系统元文件(Microsoft文档声称只保留了前16个entry,可是实际上第一个用户文件或者目录从entry24开始。entry17到23做为缓冲entry防止预留的不够用致使溢出),这些保留而且未用的entry被置为分配状态而且只有基本的信息。每一个文件系统元文件都列在根目录,尽管一般状况下普通用户是看不到它们的。每个文件系统元文件的名字都由“$”开始,而且第一个字母大写。咱们将在第12章讨论每个文件系统元文件,可是咱们如今把它们列在表11.1做为一个方便参考。
表11.1标准的NTFS文件系统元文件
Entry |
File Name |
Description |
0 | $MFT | MFT自身的entry |
1 | $MFTMirr | 含有MFT起始的几个entry的备份 |
2 | $LogFile | 含有元数据事务的日志 |
3 | $Volume | 含有卷信息 |
4 | $AttrDef | 含有属性信息 |
5 | . | 文件系统根目录 |
6 | $Bitmap | 文件系统簇的分配状态 |
7 | $Boot | 引导扇区和文件系统引导代码 |
8 | $BadClus | 含有坏扇区的簇 |
9 | $Secure | 还有安全和访问控制相关信息 |
10 | $Upcase | 含有每个Unicode字符的大写形式 |
11 | $Extend | 含有可选扩展文件的目录。 |
MFT entry属性概念
一个MFT entry只有不多的内部结构,它的大部分空间都被用来存储属性,属性是用来存储特定类型数据的数据结构。有许多类型的属性,每种都有其独特的内部结构。例若有用于文件名、日期和时间乃至其内容的属性。这是NTFS相较于其它文件系统的不一样之处之一。大部分文件系统仅用来读写文件内容,而NTFS读写属性,属性的一种包含有文件内容。
想象一下咱们以前把MFT entry比喻成一个开始是空的大盒子,而属性则是在这个大盒子之中的小盒子,这些小盒子有任意的形状以最有效的存放物品。例如,一顶帽子能够存储在一个短圆盒中,一张海报能够存储在一个长圆筒中。
尽管每种属性都保存着不一样类型的数据,全部的属性都有两个部分:头部和内容。图11.4显示了一个MFTentry有四个头部和内容对(译注:应该是三个,怀疑做者笔误)。头部是全部属性通用的。内容和属性类型相关,而且能够是任意大小。若是咱们从盒子来类比,每个小盒子外面都有相同的基本信息,可是每一个盒子形状都不同。
图11.4 示例MFT entry,标记了头部和内容的位置。
属性头部
属性头部标识了属性的类型、大小和名称。头部还有是否压缩和加密的标识。属性类型是一个数值的标识用来标识数据的类型,咱们将会在“标准属性类型”一节讨论缺省的属性类型。一个MFT entry能够有多个相同类型的属性。
有些属性能够被赋予一个名字,以UTF-16的Unicode字符串的形式存储在属性头部。属性同时还有一个在此MFT entry中惟一的标识值。若是一个entry有多个同一类型的属性,这个标识值能够用来区分它们。属性头数据结构将会在第13章“属性头”中给出。
属性内容
属性的内容能够是任意格式任意大小。例如,一种属性被用来存储文件的内容,因此其大小多是几个MB乃至数个GB。将这么多数据存储在仅有1024字节大小的MFT entry中是不切实际的。
为了解决这个问题,NTFS提供了两种存储属性内容的位置。常驻属性将它的内容和头部一同存储在MFT entry以内。这仅适用于小属性。很是驻属性将其内容存储在文件系统的簇中。属性的头部中标识了这个属性是常驻的仍是很是驻的。若是一个属性是常驻的,则其内容紧跟头部。若是一个属性是很是驻的,头部将会给出簇地址。图11.5咱们看到以前给出的MFT entry例子,不过此次它的第三个属性太大了没法放入MFT,因此被放到了829号簇中。
图11.5 MFT entry例子,第三个属性变得太大因此变成了很是驻。
很是驻属保存在cluster runs(译注:run在这里很难找到一个恰当的中文词汇,姑且不翻译了)中,由连续的簇构成,而每个run由起始簇地址和run长度来描述。例如,若是一个属性分配了4八、4九、50、51和52这几个簇,则它有一个run,这个run开始于簇48,长度为5.若是这个属性还分配了簇80和81,则它有第二个run,起始于80长度为2。第三个run可能起始于簇56长度为4.能够看图11.6。
图11.6 示例runlist,有三个描述分配簇的run。
在本书中,咱们区分了不一样类型的地址。例如,咱们定义了文件系统逻辑地址是文件系统数据单元的地址,二文件逻辑地址是相对于文件起始的地址。NTFS对这些地址使用了不一样的术语。逻辑簇编号(Logical Cluster Number,LCN)等价于文件系统逻辑地址,虚拟簇编号(Virtual Cluster Number,VCN)等价于文件逻辑地址。
NTFS使用VCN到LCN的映射来描述很是驻属性的run。回到刚才的例子,这个属性的run显示了VCN地址0到4映射到了LCN地址48到52,VCN地址5到6映射到了LCN地址80到81,VCN地址7到10映射到了LCN地址56到59。runlist的数据结构将会在第13章“属性头”中给出。
标准属性类型
到目前为止咱们已经讨论了属性类型的通常术语。如今咱们要看看一些标准属性的基础知识。它们之中的大部分将会在第12章中详细讨论。
以前咱们已经说起,每一种属性类型都被定义了一个编号,微软使用这个编号对一个entry中的属性进行排序。标准属性被赋予了缺省的类型值,但咱们稍后将会看到这能够在$AttrDef文件系统元文件中重定义。除了编号以外,每个属性类型有一个名字,都是大写而且以“$”开头。部分缺省属性类型和它们的标识在表11.2中给出。不是全部的属性类型和标识都会出如今每个文件之中。更详细的描述请看第12章,数据结构详见第13章。
表11.2 缺省的MFT entry属性类型。
(译注:Live Writer太操蛋,粘贴表格蛋都碎了,暂且略过)
几乎每个被分配的MFT entry都有$FILE_NAME和$STANDARD_INFORMATION类型的属性。一个例外是非基础MFT entry(译注:base MFT entry),稍后将会讨论。$FILE_NAME属性包含有文件的名字、大小和时间信息。$STANDARD_INFORMATION属性含有时间、全部关系和安全信息。后者(译注:$STANDARD_INFORMATION)存在于每个文件和目录的缘由是因为其含有用于确保数据安全和配额的数据。在抽象的意义上,在此属性中并没有必要的数据,但文件系统的应用程序层功能要求这些数据。这两个属性都是常驻的。
每个文件都有一个$DATA 属性,其包含有文件的内容。若是内容尺寸超过大约700字节,它就会变成一个很是驻属性,保存到外面的簇中。当一个文件含有多于一个$DATA 属性时,这些多出的属性有时被称为附加数据流(alternate data streams,ADS)。当建立文件时建立的缺省$DATA并无名字,可是多出的$DATA属性必须有。注意属性名字和类型名字是不一样的。例如,$DATA是属性类型名,属性的名字多是“fred”。有些工具,包括The Sleuth Kit (TSK),会给缺省的$DATA属性指定一个叫作“$DATA”的名字。
每个目录都有一个$INDEX_ROOT属性,这个属性含有其包含的文件和目录的信息。若是这个目录很大,$INDEX_ALLOCATION和$BITMAP属性也用于存储信息。令事情更复杂的是,一个目录也能够在$INDEX_ROOT以外还含有额外的$DATA属性。也就是说,目录能够同时存储文件内容和其所包含的文件和子目录的列表。$DATA属性能够存储应用程序或者用户想存储的任何数据。一个目录的$INDEX_ROOT和$INDEX_ALLOCATION属性一般其名字是“$I30”。
图11.7 显示了咱们以前演示的一个MFT entry,它的属性被赋予了类型和名字。它有三个标准文件属性。在这个例子中,全部的属性都是常驻的。
图11.7 咱们的MFT entry例子,属性被加上了名字和标识。
其余属性概念
上一节咱们讨论了适用于全部NTFS属性的基本概念。不过不是全部的属性都是基本的,本节咱们将会看到更高级的概念。特别的,咱们将会看到当一个文件有太多的属性时将会发生什么,咱们也会看到文件的属性内容被压缩和加密地方法。
基础 MFT entry(base MFT entry)
一个文件最多能够有65536个属性(因为标识符是16位的),因此其可能须要多于一个MFT entry来保存它的全部的属性的头部(即使是很是驻属性也须要它们的头部保存在MFT entry内部)。当附加的MFT entry被分配给一个文件的时候,原来的MFT entry被称为基础MFT entry。非基础entry会在它们的MFT entry域中保存有基础MFT entry的地址。
基础MFT entry有一个$ATTRIBUTE_LIST类型的属性,这个属性含有文件的每个属性和MFT地址,以便于查找到它们。非基础MFT entry没有$FILE_NAME和$STANDARD_INFORMATION属性。咱们将会在第12章“元数据分类”中详细讨论$ATTRIBUTE_LIST属性。
稀疏属性
NTFS能够下降文件的空间需求,这是经过将某些很是驻$DATA属性的数据保存为稀疏来实现的。稀疏属性是那些全为零的簇没有写入磁盘的属性。做为替代,一个特殊的run用来保存零簇(译注:含有全零数据的簇)。通常来讲,一个run含有起始簇位置和长度,可是一个稀疏run只含有长度没有起始位置。有一个标志指出一个属性是稀疏的。
例如,假设一个文件占用了12个簇。起始的五个簇非零,接下来的三个簇都是零,最后的四个簇非零。当它保存为一个普通的属性,一个长度为12的run将会被建立出来以保存这个文件,如图11.8A所示。当保存为稀疏属性,将会有三个run被建立出来,而且只有9个簇被实际分配,如图11.8B所示。
图11.8 一个12簇长的文件被保存为(A)普通布局或,(B)稀疏布局,有三个簇在稀疏run中。
压缩属性
NTFS容许属性被保存为压缩格式,尽管实际的算法并无公开给出。注意这是一个文件系统级别的压缩,并非一个经过诸如zip或者gzip等外部应用程序实现的应用级压缩。微软表示只有很是驻的$DATA属性会被压缩。NTFS经过稀疏run和压缩数据来减小磁盘空间需求。属性头有一个标识来肯定其是否压缩,$STANDARD_INFORMATION和$FILE_NAME属性内的标识也显示了这个文件是否含有压缩属性。
属性内容压缩以前,数据被划分红等大的块,称为压缩单元。压缩单元的大小在属性头中给出。有三种情形会发生在每一个压缩单元中:
让咱们以一个简单的例子来检验每一种场景。假设压缩单元大小事16个簇,而且咱们有一个长度为64个簇的$DATA属性,见图11.9。咱们把数据切分为四个压缩单元并检查每个。第一个单元压缩为16个簇,因此它没有压缩。第二个单元全为零,因此建立了一个16簇的稀疏run,没有分配实际的簇。,第三个单元压缩成了10个簇,因此压缩后的数据以10个簇的run写入到磁盘,而且添加了一个6个簇的稀疏run。最后一个单元压缩为16个簇,因此他没有压缩,建立了一个16簇的run来保存它。
图11.9 一个属性有两个压缩单元没有被压缩,一个单元稀疏,一个单元压缩为10个簇。
当操做系统,或者取证工具读取这个属性,它们会发现压缩标志,而且run被组织成压缩单元大小的块,第一个run的大小和压缩单元同样,因此咱们知道它没有被压缩。第二个run的大小和压缩单元同样,而且是稀疏的,因此咱们知道它们是16个簇的零。第三个和第四个run组成了一个压缩单元,咱们发现它只须要10个簇也就是须要解压缩,最后一个run大小和压缩单元同样,也就是没有压缩。
最后一个例子太简单了,因此我将会演示一个更具挑战性的文件,见图11.10,之因此更复杂是因为初始的布局并非按照压缩单元来分配的。为了处理这个文件,咱们首先须要从新组织这6个run中的数据并将数据分配为16个簇的压缩单元中。在合并了碎片化的run以后,咱们看到有一个含有内容的run,一个稀疏run,一个内容run,另外一个稀疏run。合并的数据被组织为压缩单元,咱们将会看到,前两个单元没有稀疏run,也没有被压缩。第三个和第五个单元有稀疏run,被压缩了。第四个单元是稀疏的,相应的数据全为零。
图11.10 一个将要被压缩的属性,它的run碎片化而且没有符合压缩单元边界。
加密属性
NTFS提供属性内容被加密的能力。这一节将给出一个其实现和保存磁盘上形式的概要。理论上说,任意属性均可以加密,可是Windows仅容许$DATA属性被加密。当一个属性被加密,只有其内容被加密,属性头没有加密。会建立一个$LOGGED_UTILITY_STREAM属性给文件,其含有解密数据所须要的密钥。
在Windows中,用户能够选择加密特定的文件或者目录。一个加密的目录没有任何加密数据,可是在这个目录中建立的文件或者目录将会被加密。一个被加密的文件或者目录将会在$STANDARD_INFORMATION属性中设置一个特殊的标志,每个被加密的属性都会在其属性头设置一个特殊的标志位。
密码学常识
在咱们讨论NTFS的加密实现以前,我将会简单介绍一下密码学的基本概念。加密过程是使用加密算法和密钥将明文变换为密文。解密过程是使用解密算法和密钥将密文变换为明文。若是有人拿出密文,那么在没有密钥的状况下应该是没法获知明文内容的。
有两类加密算法:对称和非对称。对称算法使用相同的密钥来加密和解密数据。例如,密钥“spot”能够被用来将明文加密成密文,而后通用的密钥能够被用来将密文解密成明文。对称加密很是快,可是当共享密文数据的时候就会很麻烦。若是咱们使用对称加密来加密一个文件而且想让不少人访问这个文件,咱们要么须要使用一个谁都知道的密钥来加密这个文件,要么把这个文件复制多份并使用每一个人惟一的密钥来分别加密这个文件。若是咱们为全部人只使用一个密钥,那么为某一我的撤销访问许可而不更换密钥就会变得很是困难。若是咱们为每个人单独加密,就会浪费大量的磁盘空间。
非对称加密手机用一个密钥来加密而且使用另外一个密钥进行解密。例如,密钥“spot”被用来将明文加密成密文,密钥“felix”被用来将密文解密。非对称加密的最多见用途是将一个密钥公开,例如“spot”,而另外一个密钥不公开,例如“felix”。这样你们就能够用公钥对数据进行加密,可是仅能用私钥进行解密。显然,在真实世界里密钥会比“spot”和“felix”长的多。事实上,通常至少有1024位那么长。
NTFS实现
当一个NTFS的$DATA属性被加密时,它的内容被一个称为DESX的对称加密算法所加密。为每个MFT entry的加密数据都随机生成了一个密钥,这个密钥被称为“file encryption key,FEK”。若是一个MFT entry有多个$DATA属性,它们使用同一个FEK进行加密。
FEK以加密的形式储存在$LOGGED_UTILITY_STREAM属性中。这个属性包含一个数据加密域“data decryption fields,DDF”和数据恢复域“data recovery fields,DRF”的列表。DDF被建立用来存放每个有权访问这个文件的用户的安全ID(SID),加密信息,和使用用户公钥加密的FEK。数据恢复域被建立用于每个数据恢复方法,它含有当管理员或者其余受权用户须要访问数据的时候所使用的用数据恢复公钥加密的FEK。咱们能够在图11.11看到这个过程。
图11.11 加密过程起始于文件内容和公钥,结束于已加密内容和已加密密钥。
要想解密一个$DATA属性,$LOGGED_UTILITY_STREAM属性须要被处理来获取用户的DDF入口。用户的私钥被用来解密FEK,FEK被用来解密$DATA属性。当一个用户的访问权限被撤销时,他的密钥被从管理表中移除。用户的私钥保存在Windows的注册表中,并使用用户的登陆口令做为密钥进行对称加密。这也就是说,在取证分析过程当中须要用户的口令和注册表来解密任何已被加密的文件。咱们能够在图11.12看到这个过程。
图11.12 解密过程起始于已加密内容,密钥和用户口令,结束于已解密内容。
有些安全工具能够用于暴力攻击用户的登陆口令,这也能够被用于解密数据。若是只有部分目录和文件被加密,未加密的文件内容副本也可能存在于未分配的磁盘空间中。事实上,NTFS的设计上存在小小的瑕疵,它建立一个名叫EFS0.TMP的临时文件,这个文件用来保存被加密文件的明文。在操做系统对原始文件完成加密后,它删除了临时文件,可是文件的内容并无被清除。也就是说,一个明文版的文件依然存在,数据恢复工具能够在MFT entry没有被再分配的状况下恢复出这个文件。交换空间或页面文件也有可能提供未加密数据的副本。有报告称,若是管理员、域控制器或者其余帐号被配置为具备恢复代理权限,则任意文件能够被解密,由于这个帐号有权访问任意文件。
索引
NTFS在不少情形下使用索引数据结构,本节描述它们。NTFS中的索引是一个属性的集合,它们有序存放。索引最多见的用途是目录,这是由于目录含有$FILE_NAME属性。
在NTFS版本3.0(Win2000引入)之前,只有$FILE_NAME属性保存在索引中,可是如今其它含有属性的地方也使用索引。例如,安全信息保存在索引中,配额也是。本节展示了什么是索引和它是怎么是现实的。
B树
NTFS索引将属性排序到树中,特指B树。树是一组称为节点的数据结构彼此链接在一块儿,有一个头节点以及该节点的分支连接到其余节点。在图11.13(A)中,咱们看到节点A,而且它连接到节点B和C。节点B连接到节点D和E。父节点是连接到其余节点的节点,子节点是被连接的节点,例如,A是B和C的父节点,B和C是A的子节点。叶节点是没有子节点的节点,节点C、D和E是叶节点。这个例子是二叉树,由于每一个节点最多只有两个字节点。
图11.13 (A)5个节点的树,(B)同一个树,按照节点值排序。
树之因此有用是由于它们很容易排序和查找。图11.13(B)显示了同左边同样的树,可是如今每一个节点都被赋予了一个值。若是咱们试图查找一个值,咱们将它和根节点比较,若是根节点较大,咱们接下来查找左子节点。若是根节点较小,咱们查找右子节点。例如,若是咱们想要查找6,咱们和根节点7比较。节点较大,因此咱们去左边的子节点比较它的值,它是5。这个节点较小,因此咱们继续从右子节点继续查找并比较它的值,此次是6。仅经过三次比较咱们就找到了。咱们能够仅用两次查找就找到9,若是是在列表中就须要搜索5次。
NTFS使用B树,恨咱们刚才看见的二叉树很类似,可是每一个节点有多于两个子节点。通常来讲,一个节点有多少个子节点取决于一个节点可以存储多少个值。例如,在二叉树中一个节点能存储一个值和两个字节点。若是咱们能在一个节点中存储五个值,咱们能够有六个字节点。有不少B树的变种,相对于我在这里讨论的而言它们有更多的规则,这是因为本节是用来讨论它们的基本概念,而不是你如何建立一个B树。
图11.14显示了一棵B树,包含名字而不是数值。节点A含有三个值和四个子节点。若是咱们查找文件ggg.txt,咱们在根节点中查找而且发现名字在字母排序的eee.txt和lll.txt之间。也就是说,咱们接下来去节点C来查找,咱们将在这个节点中找到咱们所要的。
图11.14 一个以文件名做为值的B树。
如今咱们让状况更复杂些,咱们看看如何增长和删除值。这是一个很重要的概念,它解释了为何在NTFS中删除的文件名很难找回。让咱们假设一个节点仅能存储三个文件名,而后文件jjj.txt被添加进来。听起来很容易,可是咱们将看到这会致使两个节点被删除,五个新节点被建立。当咱们查找jjj.txt放在哪里合适时,咱们发现它应该在节点C的末尾,紧跟iii.txt后面。图11.15的上面显示了这种状况,可是不幸的是,如今有四个名字在这个节点了,而它只能放下三个。也就是说,咱们从中间把节点C断开,将ggg.txt移动到上一层,并建立节点F和G来存放节点C的内容。这显示在图11.15的下面。
图11.15 上面的树显示了“jjj.txt”添加到节点C,下面的树是删除节点C的结果,由于每一个节点只能有三个文件名。
不幸的是,如今节点A有了四个值。因此咱们拆分它并将ggg.txt移动到顶层节点。最终的结果能够在图11.16中看到。添加一个文件致使了删除节点A和C,增长了节点F,G,H,I和J。节点A和C中先前删除的文件信息如今不复存在。
图11.16 增长了文件“jjj.txt”以后的最终状态。
如今删除文件zzz.txt,这个操做从节点E删除了文件名,并不须要其它改变。和实现有关,文件zzz.txt的细节可能依然存在于节点中而且能够被恢复。
为了使事情变得困难些,想象一下fff.txt被删除。节点F变为空节点而且须要填充。咱们将eee.txt从节点I移动到节点F并将bbb.txt从节点B移动到节点I。这建立了一棵仍然平衡的树,全部的叶节点到节点H距离相同。最终的状态见图11.17.
图11.17 删除文件“zzz.txt”和文件“fff.txt”以后的树。
节点B可能在其未分配空间里含有bbb.txt,由于bbb.txt移动到了节点I。咱们的分析工具可能会显示文件bbb.txt已经删除,但实际上并不是如此。它仅仅由于fff.txt的删除而被移动了。
从树中添加和删除值的过程代表这个过程可能会是多么复杂。其余文件系统,例如FAT,其目录使用名字列表,很容易描述为何一个已删除的名称存在或者不存在,可是在使用树的状况下很难预测最终结果。
NTFS索引属性
如今咱们描述B树的通常概念,咱们须要描述NTFS中它们是如何实现以建立索引的。树中的每个数据项使用一个被称为index entry的数据结构来在节点中保存数据。有不少种index entry,可是它们都有相同的标准头域,详见第13章。例如,一个目录index entry包含一些头数据和一个$FILE_NAME属性。index entry被组织到树的节点中,并被保存到列表中。一个空的enrry表示列表结束。图11.18显示了一个示例目录节点,有四个$FILE_NAME index entry。
图11.18 NTFS目录中的一个节点,有四个index entry。
索引节点能够保存在两种MFT enrty属性中。$INDEX_ROOT属性是常驻的,而且仅能够用来保存一个含有少许index entry的节点。$INDEX_ROOT属性始终是索引树的根节点。
更大的索引须要分配一个很是驻的$INDEX_ALLOCATION属性,它含有所需的全部节点。这个属性的内容是一个大缓冲区,含有一个或多个索引记录。索引记录是固定大小的,通常是4096字节,它含有一个index entry的列表。每个索引记录有一个从0开始的地址。咱们能够在图11.19中看到咱们有一个含有三个index entry的$INDEX_ROOT属性,和一个很是驻的$INDEX_ALLOCATION属性,它含有一个分配的簇713,使用了三个索引记录。
图11.19 这个目录在它的常驻$INDEX_ROOT属性中有三个index entry,同时在它的很是驻$INDEX_ALLOCATION属性中有三个索引记录。
$INDEX_ALLOCATION属性能够有还未被索引记录使用的已分配空间。$BITMAP属性用来管理索引记录的分配状态。若是一个新的节点须要为树分配,$BITMAP被用来查找一个可用的索引记录;不然的话,更多的空间被加入进来(以完成分配)。每个索引都被赋予一个名字,与之相关的$INDEX_ROOT、$INDEX_ALLOCATION和$BITMAP 属性也在属性头中被赋予相同的名字。
每个index entry都有一个标志来显示其是否具备子节点。若是有子节点,它们的索引记录地址将会在index entry中给出。每个节点中的index entry是排序的,若是你正在查找的值比index entry小而且index entry有子节点,那么在子节点中查找。若是你到达了列表末尾的空entry,那么在它的子节点中查找。
然咱们用一些例子说明。想象一下一个索引有三个entry正好放进$INDEX_ROOT。在这种状况下,仅有一个$INDEX_ROOT被分配出来,它含有这三个index entry数据结构和一个空的entry在列表的末尾。图11.20(A)中能够看到这种状况。如今想一想一下一个索引有15个entry的状况,这样$INDEX_ROOT就放不下了,可是能够放进$INDEX_ALLOCATION属性的一个索引记录中。能够在图11.20(B)中看到这种状况。当咱们填充了索引记录的index entry后,咱们须要增长一个新的层次,咱们建立了一个三结点树。这种情形显示在图11.20(C)中。有一个值在根节点和两个字节点。每个子节点保存在同一个$INDEX_ALLOCATION属性的不一样索引记录中,而且$INDEX_ROOT节点中的entry指向它们。
图11.20 三种NTFS索引情形:(A)小的索引有三个entry,(B)大索引有两个节点和15个entry,(C)三结点树含有25个entry。
分析工具
第1章说起的全部工具都支持NTFS镜像,他们能够访问不一样数量的属性。若是你对查看你的Windows系统上的不一样属性有兴趣,可使用微软的nfi.exe。它显示了活动系统中的MFT内容,包括属性名和簇地址。这对于取证分析并无太大的用处,由于系统必须运行,可是有助于学习NTFS。Mark Russinovich的NTFSInfo提供了相似的活动系统上的信息。
TSK容许你查看任意属性的内容,为了使后续两章的例子更清晰,我将会描述查看不一样属性的语法。回想一下,每个属性都有类型值,而且MFT entry的每个属性都有一个惟一的标识符。经过这两个值,咱们能够显示任意属性。
取代指定元数据地址的是,咱们能够给icat指定地址和属性类型。若是有多于一个的指定类型的属性,咱们给出惟一的标识符。例如,若是咱们检查MFT entry 34,咱们能够经过指定“34-48”来查看$FILE_NAME属性(类型48)。若是咱们想看它的$DATA属性(类型128),咱们指定“34-128”,若是有多个$DATA属性,咱们还须要指定惟一的属性标识符。若是咱们想要查看的有ID3,指定“34-128-3”。
TSK中的istat工具能够列出一个文件的全部属性。下面是一个MFT entry的属性输出:
[REMOVED]
Type: $STANDARD_INFORMATION (16-0) Name: N/A Resident size: 72
Type: $FILE_NAME (48-2) Name: N/A Resident size: 84
Type: $OBJECT_ID (64-8) Name: N/A Resident size: 16
Type: $DATA (128-3) Name: $Data Non-Resident, Encrypted size: 4294
94843 94844 94845 94846 94847 94848 102873 102874
102875
Type: $DATA (128-5) Name: ADS Non-Resident, Encrypted size: 4294
102879 102880 102881 102882 102883 102884 102885 102886
102887
Type: $LOGGED_UTILITY_STREAM (256-7) Name: $EFS Non-Resident size: 552
102892 102893
总结
NTFS之中的每个关键元素都被关联给了一个文件或者一个索引。本章之中,咱们讨论了NTFS的核心概念:MFT入口、属性和索引。经过使用这些基本的概念,咱们如今就能够检查特定的属性和分析第12章中的分类项目。
参考资料
略,请看原著。