Overview
Windows Prefetch is a performance optimization feature that monitors application loading behavior and creates .pf files in C:\Windows\Prefetch\ to speed up subsequent launches. For digital forensics, Prefetch files are goldmines of evidence because they record which executables ran on the system, how many times they ran, when they last ran (and up to 8 previous execution timestamps on Windows 8+), and which files and directories were accessed during the first 10 seconds of execution. Prefetch files persist even after the original executable is deleted, providing proof of execution that survives many anti-forensic techniques.
Prefetch files follow the naming convention EXECUTABLE_NAME-XXXXXXXX.pf where the hash is derived from the executable path and any command-line arguments (for hosting executables like svchost.exe and dllhost.exe). Windows 10/11 uses MAM (Memory Access Manager) compressed Prefetch format, while earlier versions use an uncompressed format. Each Prefetch file contains the executable name, run count, up to 8 last run timestamps, volume information (device path, serial number, creation time), and a list of files and directories referenced during loading. Tools like PECmd, WinPrefetchView, and python-prefetch parse these binary files for forensic analysis.
Installation
PECmd (Eric Zimmerman)
# Download PECmd
Invoke-WebRequest -Uri "https://f001.backblazeb2.com/file/EricZimmermanTools/net6/PECmd.zip" -OutFile PECmd.zip
Expand-Archive PECmd.zip -DestinationPath C:\Tools\PECmd
# Verify
C:\Tools\PECmd\PECmd.exe --help
WinPrefetchView (NirSoft)
# Download from NirSoft
# https://www.nirsoft.net/utils/win_prefetch_view.html
# GUI tool — no installation required
python-prefetch
# Install Python library
pip install prefetch
# Or install from source
git clone https://github.com/PoorBillionaire/Windows-Prefetch-Parser.git
cd Windows-Prefetch-Parser
pip install -e .
prefetchruncounts (Volatility Plugin)
# For memory forensics prefetch analysis
# Part of Volatility community plugins
pip install volatility3
Core Commands
PECmd
| Command | Description |
|---|
PECmd.exe -f <file> | Parse single Prefetch file |
PECmd.exe -d <directory> | Parse all Prefetch files in directory |
PECmd.exe --csv <outdir> | Output as CSV |
PECmd.exe --json <outdir> | Output as JSON |
PECmd.exe -k <keyword> | Filter by keyword in filename references |
PECmd.exe -q | Quiet mode |
# Parse single Prefetch file
PECmd.exe -f "C:\Windows\Prefetch\CMD.EXE-4A81B364.pf"
# Parse entire Prefetch directory
PECmd.exe -d "C:\Windows\Prefetch" --csv C:\Analysis\
# Parse with keyword filtering
PECmd.exe -d "C:\Windows\Prefetch" -k "password" --csv C:\Analysis\
# Parse from mounted forensic image
PECmd.exe -d "E:\Windows\Prefetch" --csv C:\Evidence\
# JSON output
PECmd.exe -d "C:\Windows\Prefetch" --json C:\Analysis\
# Parse specific timeframe
PECmd.exe -d "C:\Windows\Prefetch" --csv C:\Analysis\ -q
Python Prefetch Parser
#!/usr/bin/env python3
import prefetch
# Parse a single Prefetch file
pf = prefetch.Prefetch("CMD.EXE-4A81B364.pf")
# Display basic information
print(f"Executable: {pf.executableName}")
print(f"Run Count: {pf.runCount}")
print(f"Last Run: {pf.lastRunTime}")
# Display all 8 timestamps (Windows 8+)
for i, ts in enumerate(pf.timestamps):
print(f"Run {i+1}: {ts}")
# List files referenced during execution
print("\nFiles loaded:")
for filename in pf.filenames:
print(f" {filename}")
# Volume information
for volume in pf.volumeInformation:
print(f"Volume: {volume['Name']}")
print(f"Serial: {volume['Serial Number']}")
print(f"Created: {volume['Creation Time']}")
# List directories
print("\nDirectories:")
for directory in pf.directoryStrings:
print(f" {directory}")
WinPrefetchView (CLI Mode)
# Export all Prefetch data to CSV
WinPrefetchView.exe /scomma prefetch_output.csv
# Export specific columns
WinPrefetchView.exe /scomma prefetch_output.csv /PrefetchFolder "C:\Windows\Prefetch"
# Export as HTML report
WinPrefetchView.exe /shtml prefetch_report.html
File Structure
| Field | Description |
|---|
| Signature | MAM\x04 (compressed Win10+) or SCCA (legacy) |
| File Size | Size of the Prefetch file |
| Executable Name | Name of the executable (up to 29 chars) |
| Hash | Path hash in filename |
| Run Count | Number of times executed |
| Last Run Time(s) | Up to 8 FILETIME timestamps |
| Volume Info | Device path, serial number, creation time |
| File References | MFT references to files accessed |
| Directory Strings | Directory paths accessed |
Hash Calculation
# Prefetch filename hash is based on:
# - Full path to executable (case-insensitive)
# - For hosting executables (svchost, dllhost, rundll32):
# - Includes command-line arguments
# Examples:
# CMD.EXE-4A81B364.pf -> C:\Windows\System32\cmd.exe
# POWERSHELL.EXE-022A1004.pf -> C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
# SVCHOST.EXE-D78CA325.pf -> svchost.exe with specific -k parameter
Analysis Techniques
Execution Timeline
# Build execution timeline from PECmd CSV output
Import-Csv "C:\Analysis\PECmd_Output_Timeline.csv" |
Sort-Object RunTime -Descending |
Select-Object ExecutableName, RunTime, RunCount |
Format-Table
# Find recently executed programs (last 24 hours)
$yesterday = (Get-Date).AddDays(-1)
Import-Csv "C:\Analysis\PECmd_Output.csv" |
Where-Object { [DateTime]$_.LastRun -gt $yesterday } |
Sort-Object LastRun -Descending |
Select-Object ExecutableName, LastRun, RunCount |
Format-Table
Suspicious Execution Detection
# Find executables that ran from suspicious locations
Import-Csv "C:\Analysis\PECmd_Output.csv" |
Where-Object {
$_.SourceFilename -match '(TEMP|APPDATA|USERS.*DOWNLOADS|PUBLIC|RECYCLER)' -or
$_.SourceFilename -match '(PROGRAMDATA|RECYCLE\.BIN)'
} |
Select-Object ExecutableName, SourceFilename, LastRun, RunCount |
Format-Table
# Find executables with low run counts (potentially first-time malware)
Import-Csv "C:\Analysis\PECmd_Output.csv" |
Where-Object { [int]$_.RunCount -le 3 } |
Sort-Object LastRun -Descending |
Select-Object ExecutableName, LastRun, RunCount |
Format-Table
# Find renamed system tools (LOLBAS-style)
$systemTools = @("cmd.exe","powershell.exe","certutil.exe","bitsadmin.exe",
"mshta.exe","wscript.exe","cscript.exe","rundll32.exe")
Import-Csv "C:\Analysis\PECmd_Output.csv" |
Where-Object {
$name = $_.ExecutableName
$systemTools | Where-Object { $name -eq $_ } |
ForEach-Object { $_.SourceFilename -notmatch "Windows\\System32" }
}
DLL and File Reference Analysis
# Search for specific DLL references across all Prefetch files
Import-Csv "C:\Analysis\PECmd_Output_Timeline.csv" |
Where-Object { $_.FilesLoaded -match "suspicious.dll" } |
Select-Object ExecutableName, RunTime |
Format-Table
# Find executables that loaded files from USB drives
# (Look for volume paths that don't match C:\)
Import-Csv "C:\Analysis\PECmd_Output.csv" |
Where-Object { $_.VolumeInfo -notmatch "\\Device\\HarddiskVolume[12]" } |
Select-Object ExecutableName, VolumeInfo, LastRun |
Format-Table
Batch Processing for Incident Response
#!/usr/bin/env python3
"""Batch process Prefetch files for IR."""
import os
import json
import prefetch
from datetime import datetime
def process_prefetch_dir(pf_dir):
results = []
for filename in os.listdir(pf_dir):
if not filename.upper().endswith('.PF'):
continue
filepath = os.path.join(pf_dir, filename)
try:
pf = prefetch.Prefetch(filepath)
entry = {
'filename': filename,
'executable': pf.executableName,
'run_count': pf.runCount,
'last_run': str(pf.lastRunTime),
'timestamps': [str(ts) for ts in pf.timestamps],
'file_count': len(pf.filenames),
'directory_count': len(pf.directoryStrings),
}
# Flag suspicious patterns
if any(s in str(pf.filenames).lower() for s in ['temp', 'appdata', 'downloads']):
entry['suspicious'] = True
results.append(entry)
except Exception as e:
results.append({'filename': filename, 'error': str(e)})
return sorted(results, key=lambda x: x.get('last_run', ''), reverse=True)
results = process_prefetch_dir('/evidence/Windows/Prefetch/')
print(json.dumps(results, indent=2))
Configuration
Enabling/Disabling Prefetch
# Check Prefetch status
Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management\PrefetchParameters" -Name EnablePrefetcher
# Values:
# 0 = Disabled
# 1 = Application launch prefetching
# 2 = Boot prefetching
# 3 = Both application and boot (default)
# Note: Windows Server editions have Prefetch disabled by default
# To enable on server:
Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management\PrefetchParameters" -Name EnablePrefetcher -Value 3
# Superfetch/SysMain service must also be running
Get-Service SysMain
Troubleshooting
| Issue | Solution |
|---|
| No Prefetch files found | Prefetch may be disabled (common on servers); check registry EnablePrefetcher value |
| Cannot decompress Win10 .pf | Use PECmd or updated parser; Win10+ uses MAM compression |
| Timestamps show as epoch 0 | File may be corrupted or from an incompatible Windows version |
| Missing file references | File references use MFT numbers; full paths may not always resolve |
| Only 128 Prefetch files | Windows limits Prefetch to 1024 files (Win8+) or 128 (Win7); oldest are recycled |
| Hash doesn’t match path | Different paths or command-line arguments produce different hashes |
| Permission denied | Prefetch directory requires Admin access; copy files to writable location |
| Python parser fails | Ensure correct parser version for Windows version (Win10 format differs) |