分析 Prefetch 檔案以取得執行歷程 是做什麼的?
使用時機
- 需要判斷 Windows 系統執行過哪些程式及執行時間
- 惡意軟體調查中,確認可疑的二進位檔是否真正執行
- 建立事件期間應用程式使用的時間線
- 將程式執行證據與其他鑑識痕跡相互關聯
- 識別曾執行過的反鑑識工具或未經授權的軟體
先決條件
- 可存取鑑識映像中的 Windows Prefetch 目錄 (
C:\Windows\Prefetch\) - PECmd (Eric Zimmerman)、WinPrefetchView 或 python-prefetch 剖析器
- 了解 Prefetch 檔案格式(版本 17、23、26、30)
- Windows 系統已啟用 Prefetch(用戶端 OS 預設啟用,伺服器停用)
- 了解 Prefetch 命名規則 (
APPNAME-HASH.pf)
工作流程
步驟 1:從鑑識映像擷取 Prefetch 檔案
# 掛載鑑識映像
mount -o ro,loop,offset=$((2048*512)) /cases/case-2024-001/images/evidence.dd /mnt/evidence
# 複製所有 prefetch 檔案
mkdir -p /cases/case-2024-001/prefetch/
cp /mnt/evidence/Windows/Prefetch/*.pf /cases/case-2024-001/prefetch/
# 計數及列出 prefetch 檔案
ls -la /cases/case-2024-001/prefetch/ | wc -l
ls -la /cases/case-2024-001/prefetch/ | head -30
# 計算所有 prefetch 檔案的雜湊值以確保完整性
sha256sum /cases/case-2024-001/prefetch/*.pf > /cases/case-2024-001/prefetch/pf_hashes.txt
# 注意:Prefetch 檔名格式為 EXECUTABLE_NAME-XXXXXXXX.pf
# 雜湊值 (XXXXXXXX) 是根據執行檔路徑計算而得
# 同一執行檔從不同路徑執行會產生不同的 prefetch 檔案
步驟 2:使用 PECmd 剖析 Prefetch 檔案
# 使用 Eric Zimmerman 的 PECmd(Windows 或透過 Mono/Wine 在 Linux 執行)
# 從 https://ericzimmerman.github.io/ 下載
# 剖析單一 prefetch 檔案
PECmd.exe -f "C:\cases\prefetch\POWERSHELL.EXE-A]B2C3D4.pf"
# 剖析所有 prefetch 檔案並輸出為 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 個時間戳記)
# - 執行期間參照的檔案與目錄
# - 磁碟區資訊(序號、建立日期)
# - Prefetch 檔案的建立時間
步驟 3:在 Linux 中使用 Python 進行剖析
pip install prefetch
python3 << 'PYEOF'
import os
import json
from datetime import datetime
# 使用 python 剖析 prefetch 檔案
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 prefetch 檔案是壓縮的
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" 無效的 prefetch 簽章")
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 檔案
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:識別可疑的執行證據
# 在 prefetch 中搜尋已知惡意工具名稱
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)'
# 尋找最近建立的 prefetch 檔案(最新執行的執行檔)
ls -lt /cases/case-2024-001/prefetch/ | head -20
# 與 Shimcache 及 Amcache 交叉比對以確認
# Prefetch 存在 = 程式至少執行過一次
步驟 5:建立執行時間線
# 從 prefetch 資料建立時間線
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 簽章 | 標示有效 Prefetch 檔案的魔術位元組 |
| 路徑雜湊 | 以 CRC 為基礎的執行檔路徑雜湊,構成 .pf 檔名的一部分 |
| 執行次數 | 執行檔被啟動的次數(可能迴繞) |
| 最後執行時間戳記 | Windows 8+ 最多儲存 8 個最近的執行時間戳記 |
| 參照檔案 | 執行前 10 秒內存取的檔案與目錄清單 |
| 磁碟區資訊 | 識別來源磁碟區的磁碟序號與建立日期 |
| MAM 壓縮 | Windows 10 Prefetch 檔案使用 MAM4 壓縮,需先解壓縮才能剖析 |
工具與系統
| 工具 | 用途 |
|---|---|
| PECmd | Eric Zimmerman 的 Prefetch 剖析器,支援 CSV/JSON 輸出 |
| WinPrefetchView | NirSoft 的 GUI 工具,用於檢視 Prefetch 檔案 |
| python-prefetch | 用於剖析 Prefetch 檔案的 Python 函式庫 |
| Prefetch Hash Calculator | 根據執行檔路徑計算預期雜湊值的工具 |
| KAPE | 自動化鑑識收集工具,包含 Prefetch |
| Autopsy | 鑑識平台,內含 Prefetch 分析模組 |
| Plaso/log2timeline | 超級時間線工具,包含 Prefetch 剖析器 |
| Velociraptor | 端點代理程式,具備 Prefetch 收集與分析功能 |
常見情境
情境 1:確認惡意軟體執行 在 Prefetch 目錄中搜尋惡意軟體執行檔名稱,透過 Prefetch 是否存在來確認執行,擷取執行次數與最後執行時間,識別參照的 DLL 以了解惡意軟體行為,並與登錄檔自動啟動項目關聯。
情境 2:攻擊者工具使用時間線 找出 PsExec、Mimikatz、BloodHound 及其他攻擊者工具的 Prefetch 檔案,建立工具執行的時間順序時間線,判斷攻擊的序列(偵察、憑證竊取、橫向移動),並比對時間戳記與網路連線日誌。
情境 3:資料暫存與外洩 尋找壓縮工具(7z、WinRAR、zip)的 Prefetch 項目,識別檔案傳輸工具(rclone、FTP 用戶端)的執行,檢查雲端儲存用戶端的執行情況,建立資料暫存及傳輸發生的時間線。
情境 4:反鑑識偵測 檢查已知反鑑識工具(CCleaner、Eraser、SDelete)的執行,判斷 Prefetch 目錄是否近期被清除(活躍系統中檔案數量少於預期),記錄反鑑識工具執行時間戳記與其他證據的相對關係。
輸出格式
Prefetch 分析摘要:
系統:Windows 10 Pro(組建 19041)
Prefetch 檔案數量: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