analyzing-prefetch-files-for-execution-history

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Analyzing Prefetch Files for Execution History

分析Prefetch文件以获取执行历史

When to Use

使用场景

  • When determining which programs were executed on a Windows system and when
  • During malware investigations to confirm execution of suspicious binaries
  • For establishing a timeline of application usage during an incident
  • When correlating program execution with other forensic artifacts
  • To identify anti-forensic tools or unauthorized software that was run
  • 确定Windows系统上曾执行过哪些程序及执行时间时
  • 恶意软件调查中确认可疑二进制文件的执行情况时
  • 事件响应期间构建应用程序使用时间线时
  • 将程序执行记录与其他取证工件关联时
  • 识别曾运行过的反取证工具或未授权软件时

Prerequisites

前提条件

  • Access to Windows Prefetch directory (C:\Windows\Prefetch) from forensic image
  • PECmd (Eric Zimmerman), WinPrefetchView, or python-prefetch parser
  • Understanding of Prefetch file format (versions 17, 23, 26, 30)
  • Windows system with Prefetch enabled (default on client OS, disabled on servers)
  • Knowledge of Prefetch naming conventions (APPNAME-HASH.pf)
  • 可从取证镜像访问Windows Prefetch目录(C:\Windows\Prefetch\)
  • 具备PECmd(Eric Zimmerman开发)、WinPrefetchView或python-prefetch解析器
  • 了解Prefetch文件格式(版本17、23、26、30)
  • 已启用Prefetch的Windows系统(客户端系统默认启用,服务器系统默认禁用)
  • 了解Prefetch命名规则(APPNAME-HASH.pf)

Workflow

工作流程

Step 1: Extract Prefetch Files from Forensic Image

步骤1:从取证镜像提取Prefetch文件

bash
undefined
bash
undefined

Mount the forensic image

Mount the forensic image

mount -o ro,loop,offset=$((2048*512)) /cases/case-2024-001/images/evidence.dd /mnt/evidence
mount -o ro,loop,offset=$((2048*512)) /cases/case-2024-001/images/evidence.dd /mnt/evidence

Copy all prefetch files

Copy all prefetch files

mkdir -p /cases/case-2024-001/prefetch/ cp /mnt/evidence/Windows/Prefetch/*.pf /cases/case-2024-001/prefetch/
mkdir -p /cases/case-2024-001/prefetch/ cp /mnt/evidence/Windows/Prefetch/*.pf /cases/case-2024-001/prefetch/

Count and list prefetch files

Count and list prefetch files

ls -la /cases/case-2024-001/prefetch/ | wc -l ls -la /cases/case-2024-001/prefetch/ | head -30
ls -la /cases/case-2024-001/prefetch/ | wc -l ls -la /cases/case-2024-001/prefetch/ | head -30

Hash all prefetch files for integrity

Hash all prefetch files for integrity

sha256sum /cases/case-2024-001/prefetch/*.pf > /cases/case-2024-001/prefetch/pf_hashes.txt
sha256sum /cases/case-2024-001/prefetch/*.pf > /cases/case-2024-001/prefetch/pf_hashes.txt

Note: Prefetch filename format is EXECUTABLE_NAME-XXXXXXXX.pf

Note: Prefetch filename format is EXECUTABLE_NAME-XXXXXXXX.pf

The hash (XXXXXXXX) is based on the executable path

The hash (XXXXXXXX) is based on the executable path

Same executable from different paths creates different prefetch files

Same executable from different paths creates different prefetch files

undefined
undefined

Step 2: Parse Prefetch Files with PECmd

步骤2:使用PECmd解析Prefetch文件

bash
undefined
bash
undefined

Using Eric Zimmerman's PECmd (Windows or via Mono/Wine on Linux)

Using Eric Zimmerman's PECmd (Windows or via Mono/Wine on Linux)

Parse a single prefetch file

Parse a single prefetch file

PECmd.exe -f "C:\cases\prefetch\POWERSHELL.EXE-A]B2C3D4.pf"
PECmd.exe -f "C:\cases\prefetch\POWERSHELL.EXE-A]B2C3D4.pf"

Parse all prefetch files and output to CSV

Parse all prefetch files and output to CSV

PECmd.exe -d "C:\cases\prefetch" --csv "C:\cases\analysis" --csvf prefetch_results.csv
PECmd.exe -d "C:\cases\prefetch" --csv "C:\cases\analysis" --csvf prefetch_results.csv

Parse with JSON output

Parse with JSON output

PECmd.exe -d "C:\cases\prefetch" --json "C:\cases\analysis" --jsonf prefetch_results.json
PECmd.exe -d "C:\cases\prefetch" --json "C:\cases\analysis" --jsonf prefetch_results.json

Output includes for each file:

Output includes for each file:

- Executable name and path

- Executable name and path

- Run count

- Run count

- Last run time (up to 8 timestamps in Windows 10)

- Last run time (up to 8 timestamps in Windows 10)

- Files and directories referenced during execution

- Files and directories referenced during execution

- Volume information (serial number, creation date)

- Volume information (serial number, creation date)

- Prefetch file creation time

- Prefetch file creation time

undefined
undefined

Step 3: Parse with Python for Linux-Based Analysis

步骤3:使用Python进行基于Linux的分析

bash
pip install prefetch

python3 << 'PYEOF'
import os
import json
from datetime import datetime
bash
pip install prefetch

python3 << 'PYEOF'
import os
import json
from datetime import datetime

Parse prefetch files using python

Parse prefetch files using python

import struct
def parse_prefetch(filepath): """Parse a Windows Prefetch file.""" with open(filepath, 'rb') as f: data = f.read()
# Check for MAM compressed format (Windows 10)
if data[:4] == b'MAM\x04':
    import lznt1  # or use DecompressBuffer
    # Windows 10 prefetch files are compressed
    print(f"  [Compressed Win10 format - use PECmd for full parsing]")
    return None

# Version 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"  Invalid prefetch signature")
    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,
}

# Extract last execution timestamps
if version == 23:  # Vista/7 - 1 timestamp
    ts = struct.unpack('<Q', data[128:136])[0]
    result['last_run'] = filetime_to_datetime(ts)
elif version >= 26:  # Win8+ - up to 8 timestamps
    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): """Convert Windows FILETIME to datetime string.""" 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
import struct
def parse_prefetch(filepath): """Parse a Windows Prefetch file.""" with open(filepath, 'rb') as f: data = f.read()
# Check for MAM compressed format (Windows 10)
if data[:4] == b'MAM\x04':
    import lznt1  # or use DecompressBuffer
    # Windows 10 prefetch files are compressed
    print(f"  [Compressed Win10 format - use PECmd for full parsing]")
    return None

# Version 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"  Invalid prefetch signature")
    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,
}

# Extract last execution timestamps
if version == 23:  # Vista/7 - 1 timestamp
    ts = struct.unpack('<Q', data[128:136])[0]
    result['last_run'] = filetime_to_datetime(ts)
elif version >= 26:  # Win8+ - up to 8 timestamps
    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): """Convert Windows FILETIME to datetime string.""" 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

Process all prefetch files

Process all prefetch files

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" Executable: {result['executable']}") print(f" Run Count: {result['run_count']}") if 'last_run' in result: print(f" Last Run: {result['last_run']}") elif 'last_run_times' in result: for i, ts in enumerate(result['last_run_times']): print(f" Run Time {i+1}: {ts}") results.append(result)
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" Executable: {result['executable']}") print(f" Run Count: {result['run_count']}") if 'last_run' in result: print(f" Last Run: {result['last_run']}") elif 'last_run_times' in result: for i, ts in enumerate(result['last_run_times']): print(f" Run Time {i+1}: {ts}") results.append(result)

Save results

Save results

with open('/cases/case-2024-001/analysis/prefetch_analysis.json', 'w') as f: json.dump(results, f, indent=2) PYEOF
undefined
with open('/cases/case-2024-001/analysis/prefetch_analysis.json', 'w') as f: json.dump(results, f, indent=2) PYEOF
undefined

Step 4: Identify Suspicious Execution Evidence

步骤4:识别可疑执行证据

bash
undefined
bash
undefined

Search for known malicious tool names in prefetch

Search for known malicious tool names in 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
'(MIMIKATZ|PSEXEC|WMIC|COBALT|BEACON|PWDUMP|PROCDUMP|LAZAGNE|RUBEUS|BLOODHOUND|SHARPHOUND|CERTUTIL|BITSADMIN)'

Search for script interpreters (potential malicious execution)

Search for script interpreters (potential malicious execution)

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
'(POWERSHELL|CMD.EXE|WSCRIPT|CSCRIPT|MSHTA|REGSVR32|RUNDLL32|MSIEXEC)'

Search for remote access tools

Search for remote access tools

ls /cases/case-2024-001/prefetch/ | grep -iE
'(TEAMVIEWER|ANYDESK|LOGMEIN|VNC|SPLASHTOP|SCREENCONNECT|AMMYY)'
ls /cases/case-2024-001/prefetch/ | grep -iE
'(TEAMVIEWER|ANYDESK|LOGMEIN|VNC|SPLASHTOP|SCREENCONNECT|AMMYY)'

Search for data exfiltration tools

Search for data exfiltration tools

ls /cases/case-2024-001/prefetch/ | grep -iE
'(RAR|7Z|ZIP|RCLONE|MEGA|DROPBOX|ONEDRIVE|GDRIVE|FTP|CURL|WGET)'
ls /cases/case-2024-001/prefetch/ | grep -iE
'(RAR|7Z|ZIP|RCLONE|MEGA|DROPBOX|ONEDRIVE|GDRIVE|FTP|CURL|WGET)'

Find recently created prefetch files (newest executables run)

Find recently created prefetch files (newest executables run)

ls -lt /cases/case-2024-001/prefetch/ | head -20
ls -lt /cases/case-2024-001/prefetch/ | head -20

Cross-reference with Shimcache and Amcache for confirmation

Cross-reference with Shimcache and Amcache for confirmation

Prefetch existence = program was executed at least once

Prefetch existence = program was executed at least once

undefined
undefined

Step 5: Build Execution Timeline

步骤5:构建执行时间线

bash
undefined
bash
undefined

Create timeline from prefetch data

Create timeline from prefetch data

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' })
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' })

Sort chronologically

Sort chronologically

timeline.sort(key=lambda x: x['timestamp'])
timeline.sort(key=lambda x: x['timestamp'])

Write timeline CSV

Write timeline 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)
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)

Print suspicious time window

Print suspicious time window

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
undefined
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
undefined

Key Concepts

核心概念

ConceptDescription
PrefetchWindows performance optimization that pre-loads application data and tracks execution
SCCA signatureMagic bytes identifying a valid Prefetch file
Path hashCRC-based hash of the executable path forming part of the .pf filename
Run countNumber of times the executable has been launched (may wrap around)
Last run timestampsWindows 8+ stores up to 8 most recent execution timestamps
Referenced filesList of files and directories accessed during the first 10 seconds of execution
Volume informationDrive serial number and creation date identifying the source volume
MAM compressionWindows 10 Prefetch files use MAM4 compression requiring decompression before parsing
概念描述
PrefetchWindows性能优化机制,预加载应用数据并追踪执行记录
SCCA签名标识有效Prefetch文件的魔术字节
路径哈希基于可执行文件路径生成的CRC哈希,构成.pf文件名的一部分
运行次数可执行文件的启动次数(可能会溢出)
最后执行时间戳Windows 8及以上系统存储最多8条最近的执行时间戳
关联文件执行前10秒内访问的文件和目录列表
卷信息驱动器序列号和创建日期,用于识别源卷
MAM压缩Windows 10的Prefetch文件采用MAM4压缩,解析前需先解压

Tools & Systems

工具与系统

ToolPurpose
PECmdEric Zimmerman's Prefetch parser with CSV/JSON output
WinPrefetchViewNirSoft GUI tool for viewing Prefetch files
python-prefetchPython library for parsing Prefetch files
Prefetch Hash CalculatorTool to calculate expected hash from executable paths
KAPEAutomated artifact collection including Prefetch
AutopsyForensic platform with Prefetch analysis module
Plaso/log2timelineSuper-timeline tool that includes Prefetch parser
VelociraptorEndpoint agent with Prefetch collection and analysis artifacts
工具用途
PECmdEric Zimmerman开发的Prefetch解析器,支持CSV/JSON输出
WinPrefetchViewNirSoft开发的GUI工具,用于查看Prefetch文件
python-prefetch用于解析Prefetch文件的Python库
Prefetch Hash Calculator根据可执行文件路径计算预期哈希值的工具
KAPE自动化取证工件收集工具,包含Prefetch收集功能
Autopsy具备Prefetch分析模块的取证平台
Plaso/log2timeline超级时间线工具,内置Prefetch解析器
Velociraptor端点代理工具,支持Prefetch收集与分析

Common Scenarios

常见场景

Scenario 1: Confirming Malware Execution Search Prefetch directory for the malware executable name, confirm execution via Prefetch existence, extract run count and last run time, identify referenced DLLs to understand malware behavior, correlate with registry autorun entries.
Scenario 2: Attacker Tool Usage Timeline Identify Prefetch files for PsExec, Mimikatz, BloodHound, and other attacker tools, build chronological timeline of tool execution, determine the sequence of the attack (reconnaissance, credential theft, lateral movement), match timestamps with network connection logs.
Scenario 3: Data Staging and Exfiltration Look for Prefetch entries of compression tools (7z, WinRAR, zip), identify execution of file transfer utilities (rclone, FTP clients), check for cloud storage client execution, timeline when data staging and transfer occurred.
Scenario 4: Anti-Forensics Detection Check for execution of known anti-forensic tools (CCleaner, Eraser, SDelete), identify if Prefetch directory was recently cleared (fewer files than expected for active system), note timestamps of anti-forensic tool execution relative to other evidence.
场景1:确认恶意软件执行 在Prefetch目录中搜索恶意软件可执行文件名,通过Prefetch文件的存在确认执行情况,提取运行次数和最后执行时间,识别关联的DLL以了解恶意软件行为,并与注册表自启动项关联验证。
场景2:攻击者工具使用时间线 识别PsExec、Mimikatz、BloodHound等攻击者工具对应的Prefetch文件,构建工具执行的 chronological时间线,确定攻击序列(侦察、凭证窃取、横向移动),并将时间戳与网络连接日志匹配。
场景3:数据暂存与泄露 查找压缩工具(7z、WinRAR、zip)的Prefetch条目,识别文件传输工具(rclone、FTP客户端)的执行记录,检查云存储客户端的执行情况,确定数据暂存和传输的时间线。
场景4:反取证行为检测 检查已知反取证工具(CCleaner、Eraser、SDelete)的执行记录,识别Prefetch目录是否被近期清空(活跃系统的文件数量少于预期),记录反取证工具执行时间戳与其他证据的关联关系。

Output Format

输出格式

Prefetch Analysis Summary:
  System: Windows 10 Pro (Build 19041)
  Prefetch Files: 234
  Analysis Period: All available execution history

  Execution Statistics:
    Total unique executables: 234
    First execution: 2023-06-15 (system install)
    Latest execution: 2024-01-18 23:45 UTC

  Suspicious Executions:
    MIMIKATZ.EXE-5F2A3B1C.pf
      Run Count: 3 | Last: 2024-01-16 02:30:15 UTC
    PSEXEC.EXE-AD70946C.pf
      Run Count: 7 | Last: 2024-01-16 02:45:30 UTC
    RCLONE.EXE-1F3E5A2B.pf
      Run Count: 2 | Last: 2024-01-17 03:15:00 UTC
    POWERSHELL.EXE-022A1004.pf
      Run Count: 145 | Last: 2024-01-18 14:00:00 UTC

  Attack Timeline (from Prefetch):
    2024-01-15 14:32 - POWERSHELL.EXE (initial access)
    2024-01-16 02:30 - MIMIKATZ.EXE (credential theft)
    2024-01-16 02:45 - PSEXEC.EXE (lateral movement)
    2024-01-17 03:15 - RCLONE.EXE (data exfiltration)

  Report: /cases/case-2024-001/analysis/execution_timeline.csv
Prefetch Analysis Summary:
  System: Windows 10 Pro (Build 19041)
  Prefetch Files: 234
  Analysis Period: All available execution history

  Execution Statistics:
    Total unique executables: 234
    First execution: 2023-06-15 (system install)
    Latest execution: 2024-01-18 23:45 UTC

  Suspicious Executions:
    MIMIKATZ.EXE-5F2A3B1C.pf
      Run Count: 3 | Last: 2024-01-16 02:30:15 UTC
    PSEXEC.EXE-AD70946C.pf
      Run Count: 7 | Last: 2024-01-16 02:45:30 UTC
    RCLONE.EXE-1F3E5A2B.pf
      Run Count: 2 | Last: 2024-01-17 03:15:00 UTC
    POWERSHELL.EXE-022A1004.pf
      Run Count: 145 | Last: 2024-01-18 14:00:00 UTC

  Attack Timeline (from Prefetch):
    2024-01-15 14:32 - POWERSHELL.EXE (initial access)
    2024-01-16 02:30 - MIMIKATZ.EXE (credential theft)
    2024-01-16 02:45 - PSEXEC.EXE (lateral movement)
    2024-01-17 03:15 - RCLONE.EXE (data exfiltration)

  Report: /cases/case-2024-001/analysis/execution_timeline.csv