跳轉到

目錄索引 ($I30)

什麼是 $I30

每個 NTFS 目錄都會保存其中檔案的索引,名為 $I30。小型目錄將其保存在 自身的 $MFT 記錄中($INDEX_ROOT);較大的目錄則另外在 $INDEX_ALLOCATION:$I30 資料流中擁有 INDX 記錄,每筆通常為 4,096 位元組。每個索引項目都保存一份檔案 $FILE_NAME 的副本:其 名稱、MFT 參照、父目錄、四個時間戳記以及兩個大小,內容為 NTFS 最後一次更新該項目時的狀態。

當檔案被刪除或被重新命名而移出目錄時,NTFS 會移除其項目,並移動其後的項目。 舊的位元組會留在 INDX 記錄的 slack 中,即使用中項目之後的區域,直到 後續項目將其覆寫為止。索引 slack 可能保留某個檔案的名稱、時間與大小,即使該檔案的 $MFT 記錄已被重複使用、其 USN Journal 記錄也已被循環覆寫。

最佳結論:在索引 slack 中找到的名稱,曾在某個時間點 存在於此目錄的索引中,並具有所述的 $FILE_NAME 時間與大小。slack 項目並不會 說明它何時被移除,也不會說明它是遭刪除、重新命名,還是因重新平衡而被移動。

位置與收集

C:\<directory>:$I30:$INDEX_ALLOCATION

$I30 是 NTFS 中繼資料:請使用支援原始存取、且能匯出目錄 $I30 資料流的鑑識工具來收集(匯出的檔案通常命名為 $I30)。Juntei 也可以在磁碟映像檔或 未配置空間中搜尋 INDX 記錄。也請收集同一磁碟區的 $MFT 與 $J,以判斷 slack 項目原本是什麼。

分析注意事項

  • 索引 slack 是不完整且無序的。項目會隨著目錄的變更而被覆寫;某個 名稱不存在並不能證明任何事。
  • 許多 slack 項目是仍在使用中之項目的副本,是在項目移動時所遺留下來的。 CopyOfEntryInUse 會標示它們。同一個已刪除的名稱也可能在 slack 中出現多次。
  • 索引項目中的時間是該項目最後一次更新時的 $FILE_NAME 時間。它們可能與 檔案 $MFT 記錄中的 $STANDARD_INFORMATION 時間及 $FILE_NAME 時間都不同。
  • AllocatedSize 與 RealSize 同樣是項目最後一次更新時的值,可能已經過時。
  • 當後續的位元組覆寫了 slack 項目時,其 FileEntry(或 ParentEntry)可能會缺漏。 即使存在,其所指的 MFT 記錄也可能在之後已被重複使用:請比較序號。
  • parse-ntfs i30 讀取的是 INDX 記錄。小型目錄的索引只存在於其 $MFT 記錄中 ($INDEX_ROOT);其檔案請見 $MFT。

使用 Juntei 剖析

Usage: juntei parse-ntfs i30 <INPUT> [OPTIONS]

Input:
  -d, --directory <DIR>  Recursively find $I30 files (with $I30 in their name, or starting with an INDX record)
  -f, --file <FILE>      Parse one $I30 stream, or any file holding INDX records (a disk image, unallocated space)

Filtering:
      --slack-only  Only the entries found in slack
      --no-copies   Leave out the slack entries that copy an entry in use

Output:
  -o, --output <FILE>       Save every entry
  -t, --output-type <TYPE>  csv, json, or jsonl
juntei parse-ntfs i30 -f 'Users_$I30'
juntei parse-ntfs i30 -d evidence/ -o i30.csv
juntei parse-ntfs i30 -f 'Users_$I30' --slack-only --no-copies -t jsonl
juntei parse-ntfs i30 -f disk.raw -o carved-i30.csv

摘要會列出 INDX 記錄(以及其中有多少筆僅部分寫入)、使用中與位於 slack 中的項目,以及並非使用中項目之完全副本的 slack 項目名稱。這些名稱 是已刪除或已重新命名檔案的候選,本身並不構成定論。

CSV 輸出欄位

欄位 判讀
SourcePath 輸入檔案;用以區分主機與目錄。
RecordOffset, EntryOffset INDX 記錄與項目在輸入中的位元組位移。對驗證以及從磁碟映像檔中找到的記錄至關重要。
RecordVCN, RecordLSN 記錄在索引資料流中的位置,以及其 $LogFile 序號。
FromSlack 對於在使用中項目之後找到的項目為 True。
CopyOfEntryInUse 與同一目錄索引中某個使用中項目具有相同名稱、命名空間、檔案(若已知)、父目錄與時間的 slack 項目。通常是項目移動後的殘留,而非已刪除的檔案。
Filename 目錄中的名稱。
Namespace win32、dos(8.3 短檔名)、win32_and_dos 或 posix。
FileEntry, FileSequence 檔案的 MFT 參照。若 slack 項目的標頭已被覆寫則為空白。
ParentEntry, ParentSequence 目錄的 MFT 參照。若被其他位元組覆寫則為空白。
CreatedUTC, ModifiedUTC, MFT-ModifiedUTC, AccessedUTC 項目最後一次更新時的 $FILE_NAME 時間,精度為 100 ns。
AllocatedSize, RealSize NTFS 複製到項目中的大小;請參閱上方的注意事項。
FileAttributes 以 | 連接的屬性名稱(hidden|archive);子目錄則為 is_directory。此版本 Juntei 未命名的位元會以十六進位保留(0x00800000)。
ReparseValue 來自 $FILE_NAME 的重新剖析標籤或延伸屬性大小。
Problems 記錄中的損毀,例如僅部分寫入的磁區。來自損毀記錄的項目仍值得審慎檢視。

JSON/JSONL 具有相同的欄位,但以 snake_case 命名,其中 problems 為清單,未知值則為 null。

如何找到 slack 項目

slack 會在項目起始的每個 8 位元組邊界上進行掃描,尋找完整的項目、 項目標頭已被覆寫的 $FILE_NAME 屬性,以及在 slack 起始處,父參照被使用中項目結尾所覆寫的 $FILE_NAME。候選項目必須看起來像 Windows 實際寫入的內容:不含控制字元或路徑分隔符號的有效 UTF-16 名稱、 四個介於 1980 年至 2100 年之間的時間、已知的命名空間,以及已知的屬性旗標。超過 32 位元的父參照視為被覆寫的位元組,並保留為空白。

每筆記錄都會套用其更新序列陣列。若某個磁區的結尾不是更新序列值,表示它 僅被部分寫入;Juntei 會依原樣讀取該記錄,並在 Problems 中列出這些磁區。

調查策略

  1. 從摘要中位於 slack 的非副本名稱著手,然後使用 --slack-only --no-copies 進行篩選。
  2. 在 $MFT 中查詢 FileEntry。FileSequence 相同表示是同一個檔案; 較大則表示該記錄之後曾被釋放,且可能已被重複使用。
  3. 在 USN 日誌中搜尋該名稱,以得知它何時被刪除或重新命名。
  4. 將 $FILE_NAME 時間與 $MFT 的 $STANDARD_INFORMATION 時間比較,以檢查時間戳記竄改。
  5. 與 Prefetch、LNK、Jump Lists 以及事件記錄交叉比對,以了解該檔案的使用方式。

延伸資訊