文件系统取证分析(第12章:NTFS分析)
/*
Skogkatt 开始翻译于2015-02-01,仅作为学习研究之用,谢绝转载。
2015-09-26 更新第六节全景
译注:我翻译这本书的这三章虽然蓄谋已久,但并不是一个计划好的工作。因为之前和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的第二章,我们现在将要开始讨论分析技术和注意事项,我们将会使用第8章“文件系统分析”中使用的五分类模型。NTFS与其他文件系统非常不同,因此我们在深入这些材料之前,在上一章我们覆盖了NTFS的核心概念。如果你对NTFS并不熟悉并且跳过了第11章,我建议你在开始阅读本章之前返回先阅读第11章。第13章“NTFS数据结构”覆盖了NTFS的数据结构。本书的大部分被组织为你可以并行的阅读文件系统分析和数据结构章节。但是这对于NTFS来说是非常困难的,因为一切都是文件,很难在查阅元数据分类的属性之前看有关文件系统分类的文件系统元数据部分。也就是说,在开始阅读第13章之前阅读本章会令你有较少的困惑。
文件系统分类
内容分类
簇
NTFS文件由一系列的属性构成,有些属性为常驻保存在MFT entry之中,其他非常驻属性保存在簇之中。簇是一组连续的扇区,每个簇含有的扇区数量是2的幂(例如,1,2,4,8,16)。
每个簇都有一个地址,从0开始。簇0从文件系统的第一个扇区开始,相较FAT的计算方式而言更加清晰明了。要想将簇地址换算为扇区地址,可以将簇地址乘以每簇的扇区数:
扇区号 = 簇编号*每簇扇区数
NTFS没有严格的布局要求,除了$Boot始终分配第一个簇以外,任意一个簇可以被分配给任意一个文件或者属性。微软有一些通用的布局策略,这些策略将会在”分配算法“一节中讨论。如果一个卷的大小不是簇大小的整数倍,这个磁盘末尾的一些扇区不会成为一个簇的一部分。这个区域的大小小于一个簇。
$Bitmap文件概况
使用$Bitmap文件系统元数据文件可以获得一个簇的分配状态,这个文件在MFT entry 6。这个文件有一个$DATA属性,它的每一个bit代表了文件系统中的一个簇;例如,bit 0代表了簇0,bit1代表了簇1。如果这个bit被设置为1,簇被标记为分配;0代表没有被分配。可以在第13章$Bitmap文件这一节来了解bitmap的布局细节和例子讨论。
我们例子文件系统镜像中的$Bitmap文件的细节如下:
# istat -f ntfs ntfs1.dd 6
[REMOVED]
Attributes:
Type:$STANDARD_INFORMATION (16-0) Name:N/A Resident size:72
Type:$FILE_NAME (48-2) Name:N/A Resident size:80
Type:$DATA (128-1) Name:$Data Non-Resident size:128520
514113 514114 514115 514116 514117 514118 514119 514120
514121 514122 514123 514124 514125 514126 514127 514128
[REMOVED]
我们可以看到$Bitmap文件具有标准文件的属性, 它的当前数据和我们之前分析的文件系统元数据是一致的。
$BadClus文件概况
NTFS跟踪坏簇的状态,并将其保存在$BadClus文件系统元数据文件的$DATA属性中,这个文件在MFT entry 8。这个$DATA属性名字叫做$Bad,是一个稀疏文件,当一个簇被报告为损坏的时候,它被标记在这个属性中。回忆在Chapter 11章中所介绍的,稀疏文件如果被填充为0,它使用不分配簇来节约空间。$Bad属性的大小等于整个文件系统的大小,但是一开始并没有为其分配任何簇。Windows将其发现的坏簇添加到$Bad属性中,但是很多硬盘会在文件系统发现坏簇前就发现坏扇区了(译注:这是硬盘的自检功能)。
我们例子文件系统镜像中的$BadClus文件的细节如下:
# istat -f ntfs ntfs1.dd 8
[REMOVED]
Attributes:
Type:$STANDARD_INFORMATION (16-0) Name:N/A Resident size:72
Type:$FILE_NAME (48-3) Name:N/A Resident size:82
Type:$DATA (128-2) Name:$Data Resident size:0
Type:$DATA (128-1) Name:$Bad Non-Resident size:1052803072
注意这个文件有两个$DATA属性,缺省的那个$Data是常驻的,大小为0。名叫$Bad的那个$DATA属性是非常驻的,大小为1,052,803,072字节,但是没有显示簇地址,因为这个文件系统没有坏簇。这个属性的大小和文件系统的大小相同,和我们看到的fsstat的输出一致。
分配算法
这一节记录了我所观察到的,当Windows XP分配一个新的NTFS簇的时候,它所使用的策略。与其他文件系统类似,分配策略是操作系统相关的,不同的NTFS实现可能会使用不同的策略。我观察到Windows XP使用最佳适配算法。最佳适配算法指的是,数据将会被放置在最有效使用可用空间的位置上,即便这个位置不是第一个或者下一个可用的。也就是说,如果有少量的数据要被写入磁盘,它将会被写入到一小组未分配的簇中而不是那些大的未分配的簇中,这样可以为大文件留下空间。例如,图12.1显示了我们需要为一个文件分配10个簇的情形。有三块未分配簇。第一块从簇100到199,第二块从簇280到319,第三块从簇370到549。最佳适配算法将把簇280到289分配给新文件,因为这是最小的可放下文件的可用簇组。
图12.1 最佳分配算法将把10个新簇放在可以放下它们的最小空间中。
文件系统布局
NTFS文件系统并没有严格的布局要求,但是Windows使用一些通用的策略来格式化文件系统。大部分版本的NTFS的布局都不相同,但基本概念还是共同的。
一个所有版本NTFS的基本概念是MFE Zone。Windows在创建MFT时尽可能的小,并仅在需要更多的entry时才扩展它。也就是说,这样做有一个风险,当MFT后面的空间被分配给一个文件之后,MFT很容易碎片化。为了避免这种情况,微软将文件系统的一部分保留给了MFT。MFT Zone是不会被用来保存的文件或者目录的一系列连续的簇,除非磁盘的其他部分已经满了才会用到这部分空间。缺省情况下,微软为MFT预留了12.5%的文件系统空间。如果文件系统的其他部分已经用掉了,MFT Zone将会被使用、
所有版本的NTFS和Windows都把第一个簇分配给$Boot文件。Windows NT和2000将他们的文件系统元数据文件分配在$Boot文件之后和文件系统中部。例如,如果文件系统的簇大小是1 KB,前八个簇将会被分配给$Boot文件,并且$MFT文件的簇可能会从簇16或者32开始。MFT Zone将会占据接下来的12.5%的文件系统空间。文件系统中部的簇将会被分配给$MFTMirr文件和剩余的文件系统元数据文件,如$LogFile, $Root, $Bitmap和$Upcase,一个接一个。一个我所观察到的Windows NT和2000之间的差异是NT将$AttrDef文件放在文件系统的末尾,而Windows 2000将其放在$MFT文件的前面。
我发现Windows XP将一些数据移动到了文件系统的三分之一处。$LogFile,$AttrDef,$MFT和$Secure文件的簇被分配到了文件系统的三分之一处。其他文件系统元数据文件被放在了文件系统的一半的位置。只有$Boot文件被放在了文件系统起始的几个簇的位置。所有的在文件系统元数据文件之间的簇都可以被分配用于存放用户文件和目录。图12.2显示了Windows 2000或XP格式化的文件系统的不同的文件系统元数据文件的位置。
图12.2一个由Windows 2000和Windows XP格式化的文件系统的文件系统元数据布局。
分析的技巧
内容分类的分析涉及到定位一个指定的簇,检查它的分配状态,以某种形式处理它的内容。查找一个指定的从很容易,因为第一个簇在文件系统的开始处,并且簇的大小在第一个扇区给出。
一个簇的分配状态可以通过定位$Bitmap文件然后处理它的$DATA属性来获知。属性中的每一个bit都代表了文件系统中的一个簇。
一个常见的分析技巧是获取文件系统的未用空间。我们可以通过检查$Bitmap文件,并且获取每一个0bit的簇来完成这个任务。所有的NTFS文件系统管理数据都是放在文件里面的,因此在这个分析过程中不应认为会有任何的数据在这些未分配空间中。
分析的考量
当分析NTFS的内容分类的时候,与其它文件系统相比并没有必须要做的独特的考量。簇地址从第一个簇开始,所以只需要一种地址格式。微软一般只将必要数量的扇区分配给文件系统,因此在文件系统的末尾不应该有没有粗地址的任何扇区。从另一方面来说,这也意味着在文件系统之后卷结束之前可能会有一些扇区隐藏有数据。
当执行关键字搜索的时候,逻辑卷搜索和逻辑文件系统搜索并没有什么不同,因为被文件系统使用的每一个扇区都被分配到了一个簇中。由于文件系统分类中的所有数据搜被分配到了文件中,哪个簇被分配了哪个没有是很清晰的。回一下FAT,一个工具将FAT area和reserved areas认为是分配的还是未分配的并不是很明确。
和所有现代系统一样,你应该检查那些被文件系统标记为损坏的簇,因为很多的硬盘会在文件系统发现扇区损坏之前就将它们做了重映射。
分析的场景
在这个例子中,我们将会定位簇9,900,009。第一步是检查簇大小。我们读取文件系统的第一个扇区,并确认每个扇区都是512字节大小,每一个簇由8个扇区组成,大小为4,096字节。
NTFS的簇0从扇区0开始。也就是说,我们可以通过将我们的簇编号乘以每簇的扇区数来计算我们的簇的扇区地址。计算得知,我们得到了扇区编号792,00,072。为了得到字节位置,我们将扇区地址乘以512计算出字节地址40,550,436,864。可以将这个过程和在FAT中查找一个簇的扇区或者字节地址的诸多步骤做一个比较。
元数据分类
文件名分类
应用程序分类
全景
在这满是不同的数据结构和复杂交互的一章的最后,让我们看看当一个文件创建和删除的时候会经历哪些步骤。希望这将一切(之前介绍的)合在一起。注意这些步骤的顺序并不一定是实际上发生的。
文件分配示例
我们将会创建 \dir1\file1.dat 这个文件,并且假设 dir1 这个目录是已经存在于根目录的。文件的大小是 4,000 字节,每一个簇的大小是 2,048 字节。
我们读取文件系统的第一个扇区,处理引导扇区来确定簇的大小,MFT的起始地址以及每一个 MFT entry 的大小。
我们读取MFT的第一个 entry ,也就是 $MFT 文件,用$DATA 属性来确定 MFT 剩余部分的布局。
我们首先为新文件分配一个 MFT entry 。为了查找一个未分配的 entry,我们处理 $MFT 文件的 $BITMAP 属性。第一个可用的 entry,entry 304 被分配给新文件并且相应的位被置为1。(译注:$BITMAP中的位)
我们在 MFT 中定位到 MFT entry 304 的位置,通过清理它的内容来初始化它。$STANDARD_INFORMATION 和 $FILE_NAME 属性被创建出来,时间被设置为当前时间。MFT entry 头部中的在用标志被设置。
我们下一步要做的是为文件分配两个簇,这将通过 MFT entry 6的 $Bitmap 文件的 $DATA 属性来完成。这个文件需要两个簇,所以最佳适配算法找到两个连续的簇692和693。这些簇相应的位被置为1。(译注:$BITMAP文件$DATA属性中的位)文件的内容被写入簇中,并且将簇的地址更新到 $DATA 属性中。MFT entry 被更改了,所以文件修改时间被更新。
我们下一步是给这个文件增加一个文件名入口。MFT entry 5,也就是根目录,被用于定位 dir1。我们读取 $INDEX_ROOT 和 $INDEX_ALLOCATION 属性,遍历排序树。可以发现 dir1 的索引入口,并且它的 MFT entry 地址是200。目录的最后访问时间被更新。
我们定位到 MFT entry 200 并且处理它的 $INDEX_ROOT 属性来确定 file1.dat 应该放在哪里。给这个文件创建一个新的索引入口,并且重新排序树。这可能会发生在节点的索引入口中。新的索引入口在它的文件引用地址中含有 MFT entry 304,并且设置相应的时间和标志。目录的最后写入,修改,访问时间被更新。
在前述的步骤中,可能会在文件系统日志文件 $LogFile 和修改日志文件 \$Extend\$UsrJrnl 中创建新的入口。如果配额是强制的,新文件的大小将会加入到用户的配额文件 \$Extend\$Quota 中。
图12.13增加 '\dir1\file1.dat' 文件后的最终状态。
文件删除示例
现在我们将会看看 \dir1\file1.dat 文件删除时会发生什么。
我们读取文件系统的第一个扇区,处理引导扇区来确定簇的大小,MFT的起始地址以及每一个 MFT entry 的大小。
我们读取MFT的第一个 entry ,也就是 $MFT 文件,用$DATA 属性来确定 MFT 剩余部分的布局。
我们需要找到 dir1 目录,所以我们处理 MFT entry 5 根目录,遍历 $INDEX_ROOT 和 $INDEX_ALLOCATION 属性中的索引。我们发现 dir1 入口,它的 MFT entry 地址是200。目录的最后访问时间被更新。
我们处理 MFT entry 200 的 $INDEX_ROOT 属性,查找 file1.dat 的入口。我们可以发现文件的 MFT 地址是entry 304。
我们删除索引中的入口,导致节点中的入口都将被移动并覆盖掉原来的入口。目录的最后写入,修改,访问时间被更新。
我们将 MFT entry 304 的在用标志清除来释放它。我们还将 $Bitmap 文件的 $DATA 属性中这个MFT entry的标记清除。
处理 MFT entry 304 的非驻留属性,在 \$Bitmap 文件中相应的簇被标记为未分配状态。在这个例子总,我们释放了簇 692 和 693。
在前述的步骤中,可能会在文件系统日志文件 $LogFile 和修改日志文件 \$Extend\$UsrJrnl 中创建新的入口。如果配额是强制的,文件的大小将会从用户的配额文件 \$Extend\$Quota 中减掉。
最终的状态在图12.14中。注意当一个文件在 NTFS 中被删除后,Windows 并不清除任何指针。也就是说,MFT entry 和簇之间的联系依然存在,文件和 MFT entry 之间的联系可能由于重排序并没有覆盖入口项而依然存在。
图12.14删除 '\dir1\file1.dat' 文件后的最终状态。灰色的方框表示已经被释放。
其他话题
本节讨论一些不适合放进特定数据分类的话题。我们将会讨论恢复删除的文件和文件系统一致性检查。
文件恢复
在NTFS中恢复被删除文件相较其他文件系统来说比较容易。当一个文件被删除后,名字被从父目录索引中删除,MFT entry被释放,所使用的簇也被释放。微软没有清除任何指针,尽管在未来他们有可能会这么做。
NTFS最大的不利之处是,当一个文件名被从父目录索引中删除以后,索引被重新排序,名字信息可能丢失。也就是说,你可能在文件所在的原目录里看不到它的名字了。不过,这一缺点由于所有的MFT entry都在一个表里,所有的未分配的entry都可以很容易被找到而抵消。进一步说,每一个entry都有一个$FILE_NAME属性含有其父目录的引用地址。也就是说,当发现一个未分配的entry,我们通常可以获知其完整路径,除非其父目录中有一些被重新分配到了新文件或者目录。
恢复已删除的 NTFS 文件的另一个考虑因素是寻找额外的 $DATA 属性。你可以使用一个从DFTT站点下载的测试镜像来测试你的NTFS恢复工具。这个镜像包含有一些带有多个$DATA属性的已删除文件,没有任何索引指向这些文件。
为了恢复NTFS中所有的已删除文件,应该检查MFT中的未分配entry。当发现这种entry时,它们的名字可以通过$FILE_NAME属性和父目录引用来获得。簇指针应该还存在,这样数据在没有被覆盖的情况下还可以恢复。即便文件非常碎片化,被恢复也是很有可行的。如果属性值是常驻的,数据不会被覆盖,除非MFT entry被重新分配了。如果文件需要多一个MFT entry来保存它的属性,其它的MFT entry也需要进行恢复,Windows使用第一个可用的分配策略来分配MFT entry,所以低序号的MFT entry比高序号的更经常被分配。
当恢复文件或检查已删除内容的时候,文件系统日志或者变更日志可能对于新近的删除比较有用。变更日志不是始终打开的,但是它显示了文件是何时被删除的以及最后编辑的时间。
一致性检查
一致性检查用于在调查中找出损坏的镜像,或来检测篡改行为。本节描述了一些可以用于NTFS文件系统镜像的检查方法。第一个可以检查的是引导扇区。NTFS引导扇区只有很少的数据,但是Microsoft强制一些无用值必须为零。我发现在$Boot文件中的引导代码之后经常有很多未用的簇。与其它文件系统类似,$BadClus文件中所标记出来的坏簇用该被检查,因为很多硬盘在文件系统发现坏簇之前就修正了这些坏簇(译注:也就是说,文件系统中的坏簇通常是人为的)。
$MFT文件,也就是MFT它自己的文件,仅随Windows的需要而增加大小。一个高级的攻击者可能会试图使这个表变得非常长,然后在它的末端隐藏数据,但是当新文件被创建的时候这些数据可能会被覆盖。前16个MFT entry是保留的,但是目前有些并没有被使用。其它文件系统的保留的和未用的元数据结构有被用于隐藏数据的历史,同样的事情也会发生在NTFS文件系统上。
每个已分配的簇都应该是某个文件的簇run的一部分。每个已分配的NTFS簇都是文件或者目录的一部分,一致性检查应该验证这点。每个已分配的MFT entry都应该设置了其在用标志,并且在$BITMAP属性中设置了标志位。每个已分配的MFT entry的每一个文件名还应该有一个目录索引。文件系统的元数据文件在根目录中有一个名称。
就每一个目录索引和MFT entry来说,每个entry都有太多的标志和选项,检查每一个标志是不值得的。处理NTFS的一个难点是它非常灵活并且提供数量众多的选项。在没有一个官方规范的情况下,哪些值组合是合法的哪些是不合法的是无法确定的。
总结
读到这里,或许你已发现NTFS是如此复杂和强大的文件系统。当我们检查FAT文件系统的时候,它的复杂是由于它最初并不是被设计为适应现在的数据大小或者应用需求。就NTFS而言,它的复杂性是由于它被设计为应对现在的需求和很多未来的需求。NTFS还将很多应用级别的功能增加进来,这进一步增加了复杂性。
在写作本书的时候,NTFS已成为支配地位的Windows文件系统。安装XP的家庭用户已将他们的磁盘格式化为NTFS而不是FAT。NTFS帮助了调查人员,因为它很容易恢复被删除的文件,并且如果各种日志被开启,历史事件也会存在。从另一方面来说,它的复杂性也使调查人员描述证据被发现的地方更加困难。
参考资料
略,请看原著。