/*
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幫助了調查人員,因為它很容易恢復被刪除的文件,並且如果各種日志被開啟,歷史事件也會存在。從另一方面來說,它的復雜性也使調查人員描述證據被發現的地方更加困難。
參考資料
略,請看原著。