文件系統取證分析(第11章:NTFS概念)


/*

Skogkatt 開始翻譯於2015-01-24,僅作為學習研究之用,謝絕轉載。

2015-01-31更新MFT entry 屬性概念。

2015-02-01翻譯完成。

譯注:我翻譯這本書的這三章雖然蓄謀已久,但並不是一個計划好的工作。因為之前和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相關的數據結構。

簡介

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有三個屬性。

image

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的布局。

image

在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地址和順序號組成一個文件參考地址的例子。

image

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,標記了頭部和內容的位置。

image

屬性頭部

屬性頭部標識了屬性的類型、大小和名稱。頭部還有是否壓縮和加密的標識。屬性類型是一個數值的標識用來標識數據的類型,我們將會在“標准屬性類型”一節討論缺省的屬性類型。一個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例子,第三個屬性變得太大所以變成了非常駐。

image

非常駐屬保存在cluster runs(譯注:run在這里很難找到一個恰當的中文詞匯,姑且不翻譯了)中,由連續的簇構成,而每一個run由起始簇地址和run長度來描述。例如,如果一個屬性分配了48、49、50、51和52這幾個簇,則它有一個run,這個run開始於簇48,長度為5.如果這個屬性還分配了簇80和81,則它有第二個run,起始於80長度為2。第三個run可能起始於簇56長度為4.可以看圖11.6。

圖11.6 示例runlist,有三個描述分配簇的run。

image

在本書中,我們區分了不同類型的地址。例如,我們定義了文件系統邏輯地址是文件系統數據單元的地址,二文件邏輯地址是相對於文件起始的地址。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例子,屬性被加上了名字和標識。

image

其他屬性概念

上一節我們討論了適用於所有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中。

image

壓縮屬性

NTFS允許屬性被保存為壓縮格式,盡管實際的算法並沒有公開給出。注意這是一個文件系統級別的壓縮,並不是一個通過諸如zip或者gzip等外部應用程序實現的應用級壓縮。微軟表示只有非常駐的$DATA屬性會被壓縮。NTFS通過稀疏run和壓縮數據來減少磁盤空間需求。屬性頭有一個標識來確定其是否壓縮,$STANDARD_INFORMATION和$FILE_NAME屬性內的標識也顯示了這個文件是否含有壓縮屬性。

屬性內容壓縮之前,數據被划分成等大的塊,稱為壓縮單元。壓縮單元的大小在屬性頭中給出。有三種情形會發生在每個壓縮單元中:

  1. 所有的簇都是零,在這種情況下,稀疏run被創建出來用來保存這個壓縮單元大小的數據,不需要磁盤空間。
  2. 壓縮過后,壓縮結果需要同樣數量的簇來保存(也就是說,數據壓縮率很低)。在這種情況下,壓縮單元沒有壓縮,一個run被用來保存原始數據。
  3. 壓縮過后,壓縮結果使用較少數量的簇。在這種情況下,數據被壓縮並被保存在一個run中。一個稀疏run緊跟這個壓縮run以確保整個run的長度等於壓縮單元的簇數量。

讓我們以一個簡單的例子來檢驗每一種場景。假設壓縮單元大小事16個簇,並且我們有一個長度為64個簇的$DATA屬性,見圖11.9。我們把數據切分為四個壓縮單元並檢查每一個。第一個單元壓縮為16個簇,所以它沒有壓縮。第二個單元全為零,所以創建了一個16簇的稀疏run,沒有分配實際的簇。,第三個單元壓縮成了10個簇,所以壓縮后的數據以10個簇的run寫入到磁盤,並且添加了一個6個簇的稀疏run。最后一個單元壓縮為16個簇,所以他沒有壓縮,創建了一個16簇的run來保存它。

圖11.9 一個屬性有兩個壓縮單元沒有被壓縮,一個單元稀疏,一個單元壓縮為10個簇。

image

當操作系統,或者取證工具讀取這個屬性,它們會發現壓縮標志,並且run被組織成壓縮單元大小的塊,第一個run的大小和壓縮單元一樣,所以我們知道它沒有被壓縮。第二個run的大小和壓縮單元一樣,並且是稀疏的,所以我們知道它們是16個簇的零。第三個和第四個run組成了一個壓縮單元,我們發現它只需要10個簇也就是需要解壓縮,最后一個run大小和壓縮單元一樣,也就是沒有壓縮。

最后一個例子太簡單了,所以我將會演示一個更具挑戰性的文件,見圖11.10,之所以更復雜是由於初始的布局並不是按照壓縮單元來分配的。為了處理這個文件,我們首先需要重新組織這6個run中的數據並將數據分配為16個簇的壓縮單元中。在合並了碎片化的run之后,我們看到有一個含有內容的run,一個稀疏run,一個內容run,另一個稀疏run。合並的數據被組織為壓縮單元,我們將會看到,前兩個單元沒有稀疏run,也沒有被壓縮。第三個和第五個單元有稀疏run,被壓縮了。第四個單元是稀疏的,相應的數據全為零。

圖11.10 一個將要被壓縮的屬性,它的run碎片化並且沒有符合壓縮單元邊界。

image

加密屬性

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 加密過程起始於文件內容和公鑰,結束於已加密內容和已加密密鑰。

image

要想解密一個$DATA屬性,$LOGGED_UTILITY_STREAM屬性需要被處理來獲取用戶的DDF入口。用戶的私鑰被用來解密FEK,FEK被用來解密$DATA屬性。當一個用戶的訪問權限被撤銷時,他的密鑰被從管理表中移除。用戶的私鑰保存在Windows的注冊表中,並使用用戶的登錄口令作為密鑰進行對稱加密。這也就是說,在取證分析過程中需要用戶的口令和注冊表來解密任何已被加密的文件。我們可以在圖11.12看到這個過程。

圖11.12 解密過程起始於已加密內容,密鑰和用戶口令,結束於已解密內容。

image

有些安全工具可以用於暴力攻擊用戶的登錄口令,這也可以被用於解密數據。如果只有部分目錄和文件被加密,未加密的文件內容副本也可能存在於未分配的磁盤空間中。事實上,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)同一個樹,按照節點值排序。

image

樹之所以有用是因為它們很容易排序和查找。圖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樹。

image

現在我們讓情況更復雜些,我們看看如何增加和刪除值。這是一個很重要的概念,它解釋了為什么在NTFS中刪除的文件名很難找回。讓我們假設一個節點僅能存儲三個文件名,然后文件jjj.txt被添加進來。聽起來很容易,但是我們將看到這會導致兩個節點被刪除,五個新節點被創建。當我們查找jjj.txt放在哪里合適時,我們發現它應該在節點C的末尾,緊跟iii.txt后面。圖11.15的上面顯示了這種情況,但是不幸的是,現在有四個名字在這個節點了,而它只能放下三個。也就是說,我們從中間把節點C斷開,將ggg.txt移動到上一層,並創建節點F和G來存放節點C的內容。這顯示在圖11.15的下面。

圖11.15 上面的樹顯示了“jjj.txt”添加到節點C,下面的樹是刪除節點C的結果,因為每個節點只能有三個文件名。

image

不幸的是,現在節點A有了四個值。所以我們拆分它並將ggg.txt移動到頂層節點。最終的結果可以在圖11.16中看到。添加一個文件導致了刪除節點A和C,增加了節點F,G,H,I和J。節點A和C中先前刪除的文件信息現在不復存在。

圖11.16 增加了文件“jjj.txt”之后的最終狀態。

image

現在刪除文件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”之后的樹。

image

節點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。

image

索引節點可以保存在兩種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屬性中有三個索引記錄。

image

$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。

image

分析工具

第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章中的分類項目。

參考資料

略,請看原著。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM