USN ジャーナルを扱う上で最も難しいのは、しばしばパース処理ではなく、そもそもファイルを手に入れることです。$UsnJrnl:$J は 代替データ ストリーム であり、通常のファイルではありません。エクスプローラには現れず、素朴な copy には耐えません。本記事では、フォレンジック イメージ、マウント済みボリューム、稼働中のマシンという三つの場面それぞれから、現実的にどう抽出するかを順を追って見ていきます。
何を探すのか
ジャーナルは以下のパスに存在します:
\$Extend\$UsnJrnl:$J
$Extend は隠し NTFS メタデータ ディレクトリ、$J はメタデータ ファイル $UsnJrnl が持つ二つの代替ストリームのうちの一つです (もう一方の $Max はサイズ メタデータのみを保持します)。Microsoft はこのレイアウトを NTFS 内部リファレンス と USN_RECORD_V2 構造体 で文書化しています。
実世界の $J は fsutil usn の設定次第で 30 MB から数 GB に及びます。
フォレンジック ディスク イメージ (E01, dd, AFF4) から
DFIR でもっとも頻出するケースです。
FTK Imager (無償, GUI)
- イメージを開く (
File → Add Evidence Item)。 [root]/$Extend/$UsnJrnlまで掘り下げる。$Jデータ ストリームを右クリック → Export Files。
FTK Imager は代替データ ストリームを第一級のエントリとして扱います — ファイルの兄弟行として表示されるので、$J の行を確実に選択してください ($Max ではなく)。
X-Ways Forensics (商用)
X-Ways も同じパスを公開します。ディレクトリ ツリーで Root directory → $Extend → $UsnJrnl を展開し、$J ストリームを選んで Recover/Copy を実行します。
The Sleuth Kit (無償, CLI, クロス プラットフォーム)
Mac/Linux のアナリストが多く使う選択肢です。中心的なツールは TSK の icat です:
# $UsnJrnl の MFT エントリを探す
fls -r -p image.dd | grep '\$UsnJrnl'
# 仮に inode 81、$J ストリームが属性 128-2 とすると:
icat image.dd 81-128-2 > UsnJrnl-J.bin
<inode>-<type>-<id> の三組は TSK が代替ストリームを指す方法です。必要な type/id は属性名が :$J で終わるもので、fls の長い出力に含まれています。
Velociraptor / KAPE
広範な分析対象収集の場面では、Velociraptor の Windows.NTFS.MFT アーティファクト と KAPE が自動でジャーナルを取得します。KAPE はターゲット (!ALL や USNJournal) を使い、Velociraptor は parse_ntfs プラグインを使います。
マウント済みボリュームから
イメージが読み取り専用でマウントされている (Linux なら mount -t ntfs-3g、Windows なら Arsenal Image Mounter) 場合、パスは通常のファイルとして現れますが、多くのツールは代替ストリームを透過的に読むことを拒否します。
ntfs-3g を用いた Linux では、ストリームを直接読めます:
sudo cat '/mnt/image/$Extend/$UsnJrnl:$J' > UsnJrnl-J.bin
streams_interface のマウント オプション次第で、:$J はサフィックスではなく別のパス要素として現れる場合があります — ls -la /mnt/image/\$Extend/ で確認してください。
稼働中の Windows ホストから
Windows は通常の API 経由ではメタデータ ファイルへのアクセスを遮断するため、管理者権限と NTFS を理解する読み取り手段が必要です。
ボリュームの生読み取りを行う PowerShell
Eric Zimmerman のツール群 には標準ファイル API を迂回する RawCopy.exe (もしくは RawCopy64.exe) が含まれます:
RawCopy.exe /FileNamePath:"C:\$Extend\$UsnJrnl:$J" /OutputPath:"D:\Out"
バイナリを置けない場面では、PowerForensics が純粋な PowerShell で同じことを行います:
Import-Module PowerForensics
Get-ForensicFileRecord -Path 'C:\$Extend\$UsnJrnl' |
ForEach-Object { $_.GetContent() } |
Set-Content -Path 'C:\Out\UsnJrnl-J.bin' -Encoding Byte
標準の fsutil
fsutil usn はジャーナル向けのサポート済み制御面ですが、抽出用ツールではありません — レコードの読み取り、問い合わせ、削除はできますが、$J ブロブ全体をストリームすることはできません。抽出前にジャーナルが有効で適切にサイズ設定されているかを確認するには便利です:
fsutil usn queryjournal C:
Status: 0x00000000 で Maximum Size が非ゼロならジャーナルは稼働中です。0x80000005 などはジャーナルが無効で、抽出するものが無いことを意味します — ライフサイクル コマンドは fsutil usn のリファレンス を参照してください。
抽出後
$J ファイルを得たら、本サイトにドロップするか、お使いのツールに渡してください。カービングしたバイト列は usnrs、PoorBillionaire/USN-Journal-Parser、Eric Zimmerman の MFTECmd などが期待する入力そのものです。
$MFT (同じ $Extend 近辺、MFT エントリ 0) も取得すれば、単なるファイル名ではなくフル パスを解決できます — usnrs のフル パス解決機構 と本パーサの $MFT 入力を参照。
よくある落とし穴
- エクスプローラでのコピー:
$UsnJrnlをドラッグ アンド ドロップすると、無名の既定ストリーム (空) が静かにコピーされ、$Jはコピーされません。常にフォレンジック ツールを用いること。 - ジャーナルが無効: ワークグループ環境のマシンでは無効化されていることがあります。
fsutil usn queryjournalがもっとも安価な確認手段です。 $J先頭のスパースなゼロ: ジャーナルはスパース ストリームで、最初の数百 MB は最初の本物のレコードまで全部ゼロになり得ます。usnrs、本パーサ、その他多くが自動でスキップします。自前パーサを書くなら、usnrs のSkip::find_first_recordが最短のリファレンス実装です。- ストリームのラップ: ボリュームの活動次第で、ジャーナルのリング バッファは一巡しているかもしれません — 古いエントリは失われています。見つかる最小の USN が、利用可能な履歴がどこまで遡るかを示します。