/*算法
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章中的分類項目。
參考資料
略,請看原著。