Chapter 7

Prefetch Analysis

Windows Prefetch records every executable that runs on the system — filename, path, run count, run timestamps, and the DLLs and files it accessed. For forensics, it's a chronological execution log that survives file deletion.

Scenario

An attacker ran Mimikatz from a temp directory as svchost32.exe (renamed to blend in), deleted it immediately after execution, and cleaned up the temp folder. Three days later, you're investigating. The file is gone. The MFT record shows the deleted entry but the attacker also timestomped it. But Prefetch doesn't lie: SVCHOST32.EXE-A3F2B819.pf exists in C:\Windows\Prefetch\. PECmd parses it: run count 1, last run 2026-09-17 03:42:11, file path \TEMP\SVCHOST32.EXE, DLLs loaded include WDIGEST.DLL (cleartext credential extraction). The attacker can delete their tool but they can't easily delete its Prefetch entry.

What Prefetch Records

The Windows Prefetch service monitors program startup to speed up future launches. As a side effect, it creates a forensic execution log for every program that runs.

Data recorded in each .pf fileForensic value
Executable name and hash of the pathIdentifies what ran — the hash means two executables with the same name but different paths get different .pf files
Last run time (up to 8 most recent)Windows 8+: stores up to 8 run timestamps. Shows exactly when the program ran.
Run countTotal number of times the program ran
Volume informationDrive serial number and volume path — helps correlate to specific disks
Files and directories accessed on first runWhich DLLs were loaded, which config files read, which directories accessed — evidence of what the program did
File pathFull path the executable ran from — reveals suspicious locations (temp dir, user profile, AppData)

Prefetch Location and Limitations

  Prefetch Facts
  ═══════════════════════════════════════════════════════════════════

  Location:  C:\Windows\Prefetch\
  Format:    EXECUTABLENAME-PATHHASH.pf
  Max files: ~1024 (older entries overwritten when limit reached)
  Retention: Survives reboot; entries persist until limit or deletion

  Enabled by default:
    Workstations: YES (Superfetch/SysMain service)
    Servers:      NO  — Prefetch disabled by default on Server OS
                  Check: HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\
                         Memory Management\PrefetchParameters → EnablePrefetcher

  Windows versions and timestamps stored:
    Windows 7/8:    1 run timestamp per .pf file
    Windows 10/11:  Up to 8 run timestamps per .pf file (huge forensic value)

  Attackers delete Prefetch? Yes — requires SYSTEM or admin rights.
    Indicator: gap in Prefetch sequence numbers (they're not sequential
    but mass deletion leaves the directory unusually sparse).
    More often attackers leave Prefetch alone (don't know about it)
    or rename the executable before running (gets its own .pf file).

Using PECmd to Parse Prefetch

Batchpecmd-parse.bat
:: Parse all Prefetch files in a directory
:: PECmd.exe from Eric Zimmermann Tools

:: Parse all .pf files, output CSV
PECmd.exe -d "D:\evidence\C\Windows\Prefetch" --csv "D:\analysis\prefetch" --csvf prefetch.csv -q

:: CSV output columns:
::   SourceFilename    — the .pf filename
::   SourceCreated     — when the .pf file was created (not execution time)
::   SourceModified    — when the .pf was last updated (correlates to last run)
::   ExecutableName    — name of the executable
::   Hash              — path hash (used to disambiguate same-name executables)
::   Size              — prefetch file size
::   Version           — Windows version
::   RunCount          — total times run
::   LastRun           — most recent execution timestamp
::   PreviousRun0..6   — up to 7 prior run timestamps (Windows 10+)
::   Directories       — directories accessed on first run
::   FilesLoaded       — files (DLLs etc) accessed on first run

:: Parse a single .pf file with full detail (loaded files list)
PECmd.exe -f "D:\evidence\C\Windows\Prefetch\MIMIKATZ.EXE-A1B2C3D4.pf" -q
PowerShellhunt-suspicious-prefetch.ps1
# Hunt for suspicious executables in Prefetch CSV output
$pf = Import-Csv "D:\analysis\prefetch\prefetch.csv"

# Executables that ran from suspicious locations
$suspiciousLocations = @(
    "\\TEMP\\",
    "\\APPDATA\\LOCAL\\TEMP\\",
    "\\USERS\\PUBLIC\\",
    "\\PROGRAMDATA\\",
    "\\RECYCLE",
    "\\WINDOWS\\TASKS\\"  # scripts in Tasks dir
)

foreach ($loc in $suspiciousLocations) {
    $pf | Where-Object { $_.ExecutableName -match [regex]::Escape($loc) } |
        Select-Object ExecutableName, RunCount, LastRun |
        ForEach-Object {
            Write-Host "SUSPICIOUS LOCATION: $($_.ExecutableName)"
            Write-Host "  Runs: $($_.RunCount), Last: $($_.LastRun)"
        }
}

# Known attacker tool names
$toolNames = @(
    "MIMIKATZ", "MIMI", "PROCDUMP", "PWDUMP",
    "PSEXEC", "PSEXESVC", "COBALT", "COBALTSTRIKE",
    "METERPRETER", "BEACON", "RUBEUS", "BLOODHOUND",
    "SHARPHOUND", "LAZAGNE", "WCEWIN", "FGDUMP",
    "GSECDUMP", "GETSYSTEM", "GETPASS"
)

foreach ($tool in $toolNames) {
    $pf | Where-Object { $_.ExecutableName -match $tool } |
        Select-Object ExecutableName, RunCount, LastRun
}

# Executables with unusual names — single char names, numeric names
$pf | Where-Object {
    $name = ($_.ExecutableName -split "\\")[-1] -replace "\.EXE$",""
    $name -match "^[a-z0-9]{1,3}$"  # 1-3 char names are unusual
} | Select-Object ExecutableName, RunCount, LastRun

Building an Execution Timeline from Prefetch

PowerShellprefetch-timeline.ps1
# Build a chronological execution timeline from Prefetch data
# Combines all run timestamps (up to 8 per entry) into a flat timeline

$pf = Import-Csv "D:\analysis\prefetch\prefetch.csv"

$timeline = @()

foreach ($entry in $pf) {
    # Add LastRun
    if ($entry.LastRun -and $entry.LastRun -ne "") {
        $timeline += [PSCustomObject]@{
            Timestamp  = [datetime]$entry.LastRun
            Executable = ($entry.ExecutableName -split "\\")[-1]
            FullPath   = $entry.ExecutableName
            RunCount   = $entry.RunCount
        }
    }

    # Add PreviousRun0 through PreviousRun6 if they exist
    for ($i = 0; $i -le 6; $i++) {
        $col = "PreviousRun$i"
        if ($entry.$col -and $entry.$col -ne "") {
            $timeline += [PSCustomObject]@{
                Timestamp  = [datetime]$entry.$col
                Executable = ($entry.ExecutableName -split "\\")[-1]
                FullPath   = $entry.ExecutableName
                RunCount   = "(prior run $i)"
            }
        }
    }
}

# Sort by time and filter to incident window
$incidentStart = [datetime]"2026-09-15 00:00:00"
$incidentEnd   = [datetime]"2026-09-20 23:59:59"

$timeline |
    Where-Object { $_.Timestamp -ge $incidentStart -and $_.Timestamp -le $incidentEnd } |
    Sort-Object Timestamp |
    Format-Table Timestamp, Executable, FullPath -AutoSize

Using Loaded Files to Identify Tool Capabilities

The list of files accessed by an executable on its first run is recorded in Prefetch. This tells you what DLLs the tool loaded — which reveals its capabilities even if you don't have the binary.

DLL in loaded files listCapability it suggests
WDIGEST.DLLWDigest authentication — may be credential-related tool (Mimikatz, LaZagne)
SAMLIB.DLLSAM database access — account enumeration or credential extraction
VAULTCLI.DLLWindows Credential Manager access
DPAPI DLLs (CRYPTDPAPI, etc)DPAPI decryption — browser credential extraction, credential vault decryption
RASAPI32.DLLVPN/dial-up credentials access
WININET.DLL + WS2_32.DLLHTTP networking — download/upload capability (C2, exfil)
PSAPI.DLL / DBGHELP.DLLProcess inspection, memory reading — typical for credential dumpers
Why Prefetch is one of the most reliable execution artifacts

Prefetch is reliable for two reasons: attackers rarely think to clean it up, and it records execution even when the file has been deleted. An EDR that gets deployed after a compromise won't have process creation logs for activity before its deployment — but Prefetch records execution history that predates EDR deployment. It's also useful when EDR telemetry is unavailable (host wasn't EDR-covered, telemetry was deleted). The combination of execution timestamp, file path, and loaded DLLs makes Prefetch one of the most information-dense artifacts in a Windows forensic investigation. Always parse it on every host you're investigating.

Q & A

Q: The server you're investigating has Prefetch disabled. How do you prove execution?

On Windows Server, Prefetch is off by default. Your execution evidence comes from alternative sources: (1) Shimcache (AppCompatCache in the registry) — records every executable that exists on the system, with a "has been executed" flag on some versions (ch08 covers this). (2) Amcache.hve — records SHA-1 hashes of executables and first execution time; more reliable for servers than Shimcache. (3) PowerShell Script Block Logs (Event 4104) — if the attacker used PowerShell, every script block executed is logged. (4) Windows Event Log process creation (Event 4688 with command line auditing enabled) — direct evidence of every process that started, with full command line. (5) EDR telemetry — if EDR was deployed, it has process creation records regardless of Prefetch state. The absence of Prefetch on servers is a known limitation — the other artifacts compensate for it adequately for most investigations.