MFT
NTFSファイルシステムから分析者にとって最も価値のある情報源は、マスターファイルテーブル(MFT)である。 MFTの開始セクタの場所は、ディスクのブート セクタで見つけることができ、ボリューム内のすべてのファイルとディレクトリは、MFTのエントリを持っています。 MFTの各エントリーは1024バイトの大きさで、MFTの解析が非常に簡単になっています。 各MFTレコードまたはエントリは、ASCII文字列「FILE」(エントリにエラーがある場合は「BAAD」で始まる)で始まり、それぞれ独自の識別子と構造を持つ1つ以上(多くの場合、複数)の属性で構成されています。 図4.1はMFTエントリーの一部を示しています。
このヘッダー情報を使用すると、MFT エントリを解析して、各属性から貴重な情報を抽出することができます。 たとえば、$STANDARD_INFORMATION 属性 (常に常駐) はすべてのファイルおよびディレクトリ エントリに存在し、0x10 (すなわち 16) の識別子を持ちます。 この属性には、コマンド プロンプトで “dir” と入力したときに表示される、MFT エントリのファイル時間(とにかく 3 つ)が含まれています。ファイルまたはディレクトリの変更時間、最終アクセス時間、作成(誕生)日(「MAC」時間とも呼ばれる)が含まれています。 この属性には、MFTエントリが最後に変更された時刻を指定する4番目の時刻値が含まれています。 これらの時間をすべて合わせて、「MACE」(「E」は MFT エントリ変更時間を指す)または「MACB」(「C」は MFT エントリ変更時間を指す)時間と呼びます。
警告
ファイル時間
NTFS ファイルの時間は、グリニッジ標準時と同様の協定世界時 (UTC) 形式で記録されます。 これはすべての時刻に当てはまります。各 MFT エントリで、ファイル レコードには少なくとも 8 つの時刻が関連付けられ、多くの場合、12 またはそれ以上があります。 FAT ファイル システムでは、ファイルの時刻はローカル システム時刻形式で管理されます。
$FILE_NAME 属性 (識別子 0x30、または 48) もほとんどのファイルおよびディレクトリ MFT エントリで見つかります。 STANDARD_INFORMATION属性と同様に、この属性は常に常駐し、4つの時間値も含みますが、これらの時間値は通常、ファイルがシステム上に作成されるときに設定されます。 STANDARD_INFORMATION属性のファイル時刻とは異なり、これらのファイル時刻は通常のシステム活動や悪意のある改ざんの影響を受けないため、不正な活動の指標として使用でき、システムが感染した時刻を難読化するための措置を講じることができます。 以下のコードサンプル(parseSIAttr()関数)は、$STANDARD_INFORMATION属性の解析方法の一例を示しています。
sub parseSIAttr {
my $si = shift;
my %si;
my ($type,$len,$res,$name_len,$name_ofs,$flags,$id,$sz_content,$ofs_content)
= unpack(“VVCCvvv”,substr($si,0,22));
my $content = substr($si,$ofs_content,$sz_content).My %si;$sz_content;my %si;$sz_content;$sz_content;$sz_content;$sz_content;my %sz_content;$sz_content;$sz_content;$sz_content;$sz_content;$sz_content
my ($t0,$t1) = unpack(“VV”,substr($content,0,8));
$si{c_time} = getTime($t0,$t1);
my ($t0,$t1) = unpack(“VV”,substr($content,8,8));
$si{m_time} = getTime($t0,$t1);
my ($t0,$t1) = unpack(“VV”,substr($content,16,8));
$si{mft_m_time} = getTime($t0,$t1)を実行。
my ($t0,$t1) = unpack(“VV”,substr($content,24,8));
$si{a_time} = getTime($t0,$t1);
$si{flags} = unpack(“V”,substr($content,32,4));
return %si.VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
}
Tip
GetTime
先ほどの parseSIAttr() 属性のコードリストで見られた getTime() 関数は Andreas Schuster から借りたコードで、64 ビットの FILETIME オブジェクトタイムスタンプを 32 ビット Unix 時間に変換し、さらに Perl の内蔵関数 gmtime() により人間の読める時間に翻訳しているものです。 そのコードは以下のように表示されます。
sub getTime($$) {
my $lo = shift;
my $hi = shift;
my $t;
if ($lo == 0 && $hi == 0) {
$t = 0.0
$t = 0;
} else {
$lo -= 0xd53e8000;
$hi -= 0x019db1de;
$t = int($hi*429.0);
$lo -= 0xd53e8000;
$hi -= 0x019db1de4967296 + $lo/1e7);
};
$t = 0 if ($t < 0);
return $t;
}
このコードはどこから展開されたか関係なくあらゆるFILEIMEオブジェクトを解析、翻訳するのに非常に有用である。
通常のシステムでは、多くの MFT エントリは 2 つの $FILE_NAME 属性を持ちます。1 つはファイル (またはディレクトリ) のフルネーム、もう 1 つは DOS, 8.3 ファイル名を保持するためのものです。 たとえば、ファイル名が “myreallylongfile.txt” である場合、8.3 ファイル名は “myreal~1.txt” と表示されます。 これは、古いファイルシステムや長いファイル名をサポートしていないファイルシステムとの互換性のために残されています。 そのため、通常のWindowsシステムでは、ほぼ同じ内容の2つの$FILE_NAME属性を持つMFTエントリーが多数存在することは珍しくありません。 次のコードサンプル(parseFNAttr()関数)は、MFTエントリから$FILE_NAME属性を解析し、利用可能なデータを抽出する方法の例を示しています。
sub parseFNAttr {
my $fn = shift;
my %fn;
my ($type,$len,$res,$name_len,$name_ofs,$flags,$id,$sz_content,$ofs_content)
= unpack(“VVCCvvv”,substr($fn,0,22));
my $content = substr($fn,$ofs_content,$sz_content).My %sz_content;my %sz_content;my %sz_content;My %sz_content;my %sz_content;my %sz_content;my %sz_content;my %sz_content;My %sz_content;my %sz_content
$fn{parent_ref} = unpack(“V”,substr($content,0,4));
$fn{parent_seq} = unpack(“v”,substr($content,6,2))とする。
my ($t0,$t1) = unpack(“VV”,substr($content,8,8));
$fn{c_time} = getTime($t0,$t1);
my ($t0,$t1) = unpack(“VV”,substr($content,16,8));
$fn{m_time} = getTime($t0,$t1);
my ($t0,$t1) = unpack(“VV”,substr($content,24,8)).My (vv), $t1) = unpack(“VV”,substr($ontent,20,8));
$fn{mft_m_time} = getTime($t0,$t1);
my ($t0,$t1) = unpack(“VV”,substr($content,32,8));.
$fn{a_time} = getTime($t0,$t1);
$fn{flags} = unpack(“V”,substr($content,56,4));
$fn{len_name} = unpack(“C”,substr($content,64,1));
$fn{namespace} = unpack(“C”,substr($content,65,1));
$fn{len_name} = $fn{len_name}。 * 2 if ($fn{namespace} > 0);
$fn{name} = substr($content,66,$fn{len_name});
$fn{name} = cleanStr($fn{name}) if ($fn{namespace} > 0).If ($fn{nameespace}).If ($fn{nameespace} > 0).If ($fn{name}).If ($fn{namepass}
$fn{name} =~ s/x0c/msx2e/g;
$fn{name} =~ s///g;
return %fn;
}
最後に述べるのは$DATA属性(識別子 0x80、128)である。 この属性は、ファイルの実際の内容を含むか、または参照します。 属性ヘッダーの非居住者フラグが設定されていない場合、ファイルの内容はMFTエントリーの$DATA属性内に常駐し、ヘッダーと2つの追加構造体に続いて存在します。 これは一般に、短いテキスト・ファイルなど、700バイト未満のファイルに当てはまります。 データが常駐しない場合、”data runs” (データがディスク上にある場所) を翻訳する必要があります。
$DATA 属性の data runs を解析するサンプル コードは非常に複雑なので、ここでは紹介しません。 同様に、常駐する $DATA 属性から情報を抽出するコードは些細なもので、属性ヘッダーの後のいくつかの追加情報 (コンテンツのサイズとコンテンツへのオフセット) を解析することからなります。
いくつかのオープン ソース ツールが、MFT を解析し (特に $STANDARD_INFORMATION および $FILE_NAME 属性)、解析者がタイムスタンプ付きデータを利用できるようにします。 その1つがDavid Kovar氏のanalyzemft.py Pythonスクリプトで、Web上のhttp://www.integriography.com/projects/analyzeMFTに掲載されています。 これは、http://code.google.com/p/winforensicaanalysis にある WinForensicAnalysis Google Code Project で入手できます。
Brian Carrier の “The SleuthKit” (TSK) ツールは、取得した画像やライブ システムからファイル システムおよびファイル システム メタデータ情報を幅広く収集するツールとしておそらく最もよく知られています。 たとえば、取得したイメージからファイル システムの $STANDARD_INFORMATION 属性ファイル時間のリストを収集するために、解析者は次のようなコマンドを使用します:
C:\tsk>fls -f ntfs -m C:/ -p -r G:\casexp.img > G:\casefiles
このコマンドは、ファイルシステムの活動のタイムラインに変換する前にこの情報を保存するための中間ファイル形式である「bodyfile」と呼ばれるものを生成します。 このオフセット情報は、Hex エディターまたは mmls.exe を使用して手動で決定することができます。 アナリストがリモート システムに正しく接続し、システムの C:\ ドライブを自分のシステムで F:\ としてマウントしている場合、次のようなコマンドを使用して、C:⽋パーティション内のファイルに対する $STANDARD_INFORMATION 属性ファイル時間を収集できます:
C:\tsk>fls -f ntfs -m C:/ -p -r \.\F: > g:\casefiles
TSKツール一式、およびドキュメントと使用情報は、SleuthKit Webサイト、http://www.sleuthkit.org.
で見ることができる。