プリフェッチファイル分析による実行履歴調査 は何をしますか?
使用すべき場面
- Windowsシステムで実行されたプログラムとその実行時刻を特定する必要がある場合
- マルウェア調査において不審なバイナリの実行を確認する場合
- インシデント中のアプリケーション使用状況のタイムラインを構築する場合
- プログラム実行を他のフォレンジック証拠と関連付ける場合
- アンチフォレンジックツールや不正なソフトウェアの実行を特定する場合
前提条件
- フォレンジックイメージからWindows Prefetchディレクトリ(C:\Windows\Prefetch\)にアクセスできること
- PECmd(Eric Zimmerman)、WinPrefetchView、またはpython-prefetchパーサーが利用可能であること
- プリフェッチファイル形式(バージョン17、23、26、30)に関する知識
- Prefetchが有効なWindowsシステム(クライアントOSではデフォルト有効、サーバーでは無効)
- プリフェッチの命名規則(APPNAME-HASH.pf)の理解
ワークフロー
ステップ1:フォレンジックイメージからプリフェッチファイルを抽出
# フォレンジックイメージをマウント
mount -o ro,loop,offset=$((2048*512)) /cases/case-2024-001/images/evidence.dd /mnt/evidence
# すべてのプリフェッチファイルをコピー
mkdir -p /cases/case-2024-001/prefetch/
cp /mnt/evidence/Windows/Prefetch/*.pf /cases/case-2024-001/prefetch/
# プリフェッチファイルの数とリストを確認
ls -la /cases/case-2024-001/prefetch/ | wc -l
ls -la /cases/case-2024-001/prefetch/ | head -30
# すべてのプリフェッチファイルのハッシュを取得(完全性確認用)
sha256sum /cases/case-2024-001/prefetch/*.pf > /cases/case-2024-001/prefetch/pf_hashes.txt
# 注:プリフェッチファイル名の形式は EXECUTABLE_NAME-XXXXXXXX.pf
# ハッシュ(XXXXXXXX)は実行可能ファイルのパスに基づく
# 同一の実行ファイルでもパスが異なると別のプリフェッチファイルが作成される
ステップ2:PECmdでプリフェッチファイルを解析
# Eric ZimmermanのPECmdを使用(Windows、またはLinux上のMono/Wine経由)
# ダウンロード先: https://ericzimmerman.github.io/
# 単一のプリフェッチファイルを解析
PECmd.exe -f "C:\cases\prefetch\POWERSHELL.EXE-A]B2C3D4.pf"
# すべてのプリフェッチファイルを解析しCSV出力
PECmd.exe -d "C:\cases\prefetch\" --csv "C:\cases\analysis\" --csvf prefetch_results.csv
# JSON出力で解析
PECmd.exe -d "C:\cases\prefetch\" --json "C:\cases\analysis\" --jsonf prefetch_results.json
# 各ファイルについて以下の情報を出力:
# - 実行可能ファイル名とパス
# - 実行回数
# - 最終実行時刻(Windows 10では最大8タイムスタンプ)
# - 実行中に参照されたファイルとディレクトリ
# - ボリューム情報(シリアル番号、作成日)
# - プリフェッチファイル作成時刻
ステップ3:Linux環境でのPython解析
pip install prefetch
python3 << 'PYEOF'
import os
import json
from datetime import datetime
# pythonを使用してプリフェッチファイルを解析
import struct
def parse_prefetch(filepath):
"""Windows Prefetchファイルを解析する。"""
with open(filepath, 'rb') as f:
data = f.read()
# MAM圧縮形式(Windows 10)の確認
if data[:4] == b'MAM\x04':
import lznt1 # または DecompressBuffer を使用
# Windows 10のプリフェッチファイルは圧縮されている
print(f" [圧縮Win10形式 - 完全解析にはPECmdを使用してください]")
return None
# バージョン 17 (XP), 23 (Vista/7), 26 (8.1), 30 (10)
version = struct.unpack('<I', data[0:4])[0]
signature = data[4:8]
if signature != b'SCCA':
print(f" 無効なプリフェッチシグネチャ")
return None
file_size = struct.unpack('<I', data[8:12])[0]
exec_name = data[16:76].decode('utf-16-le').strip('\x00')
run_count = struct.unpack('<I', data[208:212])[0] if version >= 23 else struct.unpack('<I', data[144:148])[0]
result = {
'version': version,
'executable': exec_name,
'file_size': file_size,
'run_count': run_count,
}
# 最終実行タイムスタンプの抽出
if version == 23: # Vista/7 - 1タイムスタンプ
ts = struct.unpack('<Q', data[128:136])[0]
result['last_run'] = filetime_to_datetime(ts)
elif version >= 26: # Win8+ - 最大8タイムスタンプ
timestamps = []
for i in range(8):
ts = struct.unpack('<Q', data[128+i*8:136+i*8])[0]
if ts > 0:
timestamps.append(filetime_to_datetime(ts))
result['last_run_times'] = timestamps
return result
def filetime_to_datetime(ft):
"""Windows FILETIMEを日時文字列に変換する。"""
if ft == 0:
return None
timestamp = (ft - 116444736000000000) / 10000000
try:
return datetime.utcfromtimestamp(timestamp).strftime('%Y-%m-%d %H:%M:%S UTC')
except (OSError, ValueError):
return None
# すべてのプリフェッチファイルを処理
prefetch_dir = '/cases/case-2024-001/prefetch/'
results = []
for filename in sorted(os.listdir(prefetch_dir)):
if filename.lower().endswith('.pf'):
filepath = os.path.join(prefetch_dir, filename)
print(f"\n=== {filename} ===")
result = parse_prefetch(filepath)
if result:
print(f" 実行ファイル: {result['executable']}")
print(f" 実行回数: {result['run_count']}")
if 'last_run' in result:
print(f" 最終実行: {result['last_run']}")
elif 'last_run_times' in result:
for i, ts in enumerate(result['last_run_times']):
print(f" 実行時刻 {i+1}: {ts}")
results.append(result)
# 結果を保存
with open('/cases/case-2024-001/analysis/prefetch_analysis.json', 'w') as f:
json.dump(results, f, indent=2)
PYEOF
ステップ4:不審な実行証跡を特定
# 既知の悪意あるツール名をプリフェッチから検索
ls /cases/case-2024-001/prefetch/ | grep -iE \
'(MIMIKATZ|PSEXEC|WMIC|COBALT|BEACON|PWDUMP|PROCDUMP|LAZAGNE|RUBEUS|BLOODHOUND|SHARPHOUND|CERTUTIL|BITSADMIN)'
# スクリプトインタープリタを検索(悪意のある実行の可能性)
ls /cases/case-2024-001/prefetch/ | grep -iE \
'(POWERSHELL|CMD\.EXE|WSCRIPT|CSCRIPT|MSHTA|REGSVR32|RUNDLL32|MSIEXEC)'
# リモートアクセスツールを検索
ls /cases/case-2024-001/prefetch/ | grep -iE \
'(TEAMVIEWER|ANYDESK|LOGMEIN|VNC|SPLASHTOP|SCREENCONNECT|AMMYY)'
# データ流出ツールを検索
ls /cases/case-2024-001/prefetch/ | grep -iE \
'(RAR|7Z|ZIP|RCLONE|MEGA|DROPBOX|ONEDRIVE|GDRIVE|FTP|CURL|WGET)'
# 最近作成されたプリフェッチファイル(最も新しい実行ファイル)を検索
ls -lt /cases/case-2024-001/prefetch/ | head -20
# ShimcacheやAmcacheと相互参照して確認
# プリフェッチが存在する = プログラムが少なくとも1回実行された
ステップ5:実行タイムラインの構築
# プリフェッチデータからタイムラインを作成
python3 << 'PYEOF'
import json
import csv
with open('/cases/case-2024-001/analysis/prefetch_analysis.json') as f:
data = json.load(f)
timeline = []
for entry in data:
if 'last_run_times' in entry:
for ts in entry['last_run_times']:
if ts:
timeline.append({
'timestamp': ts,
'executable': entry['executable'],
'run_count': entry['run_count'],
'source': 'Prefetch'
})
elif 'last_run' in entry and entry['last_run']:
timeline.append({
'timestamp': entry['last_run'],
'executable': entry['executable'],
'run_count': entry['run_count'],
'source': 'Prefetch'
})
# 時系列順に並べ替え
timeline.sort(key=lambda x: x['timestamp'])
# タイムラインCSVを書き出し
with open('/cases/case-2024-001/analysis/execution_timeline.csv', 'w', newline='') as f:
writer = csv.DictWriter(f, fieldnames=['timestamp', 'executable', 'run_count', 'source'])
writer.writeheader()
writer.writerows(timeline)
# 不審な時間帯のエントリを出力
for entry in timeline:
if '2024-01-15' in entry['timestamp'] or '2024-01-16' in entry['timestamp']:
print(f" {entry['timestamp']} | {entry['executable']} (x{entry['run_count']})")
PYEOF
主要な概念
| 概念 | 説明 |
|---|---|
| Prefetch | Windowsのパフォーマンス最適化機能。アプリケーションデータのプリロードと実行追跡を行う |
| SCCAシグネチャ | 有効なプリフェッチファイルを示すマジックバイト |
| パスハッシュ | 実行可能ファイルパスのCRCベースのハッシュで、.pfファイル名の一部を構成 |
| 実行回数 | 実行可能ファイルが起動された回数(ラップアラウンドする可能性あり) |
| 最終実行タイムスタンプ | Windows 8+では最大8つの最近の実行タイムスタンプを保存 |
| 参照ファイル | 実行開始から最初の10秒間にアクセスされたファイルとディレクトリのリスト |
| ボリューム情報 | ソースボリュームを識別するドライブのシリアル番号と作成日 |
| MAM圧縮 | Windows 10のプリフェッチファイルはMAM4圧縮を使用。解析前に解凍が必要 |
ツールとシステム
| ツール | 目的 |
|---|---|
| PECmd | Eric Zimmerman製のプリフェッチパーサー。CSV/JSON出力対応 |
| WinPrefetchView | NirSoft製のGUIツール。プリフェッチファイルを表示 |
| python-prefetch | プリフェッチファイル解析のためのPythonライブラリ |
| Prefetch Hash Calculator | 実行可能パスから期待されるハッシュを計算するツール |
| KAPE | プリフェッチを含む自動フォレンジック証拠収集ツール |
| Autopsy | プリフェッチ分析モジュールを備えたフォレンジックプラットフォーム |
| Plaso/log2timeline | プリフェッチパーサーを含むスーパータイムラインツール |
| Velociraptor | プリフェッチ収集・分析アーティファクトを持つエンドポイントエージェント |
よくあるシナリオ
シナリオ1:マルウェア実行の確認 プリフェッチディレクトリでマルウェアの実行ファイル名を検索し、プリフェッチの存在で実行を確認。実行回数と最終実行時刻を抽出。参照されたDLLを特定してマルウェアの動作を理解。レジストリの自動起動エントリと関連付け。
シナリオ2:攻撃者ツールの使用タイムライン PsExec、Mimikatz、BloodHoundなど攻撃者ツールのプリフェッチファイルを特定。時系列のツール実行タイムラインを構築。攻撃の順序(偵察、認証情報窃取、横方向移動)を特定。タイムスタンプをネットワーク接続ログと照合。
シナリオ3:データのステージングと持ち出し 圧縮ツール(7z、WinRAR、zip)のプリフェッチエントリを確認。ファイル転送ユーティリティ(rclone、FTPクライアント)の実行を特定。クラウドストレージクライアントの実行を確認。データのステージングと転送が行われた時間を特定。
シナリオ4:アンチフォレンジックの検出 既知のアンチフォレンジックツール(CCleaner、Eraser、SDelete)の実行を確認。プリフェッチディレクトリが最近クリアされたかどうかを確認(アクティブなシステムで想定されるよりもファイル数が少ない)。アンチフォレンジックツールの実行タイムスタンプを他の証拠と比較。
出力形式
PreFetch分析サマリ:
システム: Windows 10 Pro (Build 19041)
プリフェッチファイル数: 234
分析期間: 利用可能な全実行履歴
実行統計:
一意の実行ファイル総数: 234
最初の実行: 2023-06-15 (システムインストール時)
最新の実行: 2024-01-18 23:45 UTC
不審な実行:
MIMIKATZ.EXE-5F2A3B1C.pf
実行回数: 3 | 最終実行: 2024-01-16 02:30:15 UTC
PSEXEC.EXE-AD70946C.pf
実行回数: 7 | 最終実行: 2024-01-16 02:45:30 UTC
RCLONE.EXE-1F3E5A2B.pf
実行回数: 2 | 最終実行: 2024-01-17 03:15:00 UTC
POWERSHELL.EXE-022A1004.pf
実行回数: 145 | 最終実行: 2024-01-18 14:00:00 UTC
攻撃タイムライン(Prefetchから):
2024-01-15 14:32 - POWERSHELL.EXE (初期アクセス)
2024-01-16 02:30 - MIMIKATZ.EXE (認証情報窃取)
2024-01-16 02:45 - PSEXEC.EXE (横方向移動)
2024-01-17 03:15 - RCLONE.EXE (データ流出)
レポート: /cases/case-2024-001/analysis/execution_timeline.csv