Attackers know about Prefetch. Some of them try to defeat it. Most of them try and fail, because the things you have to do to suppress Prefetch leave their own marks, and the things you can suppress only matter if you also clean up everything that touched the binary, which nobody does completely.
This post is a walkthrough of the anti-forensics techniques I have seen actually used against Prefetch, in order of how much they cost the attacker and how much they hurt the investigation.
Disabling the Prefetcher service
The most thorough approach. Set HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management\PrefetchParameters\EnablePrefetcher to 0. Reboot. Prefetch stops writing new .pf files for any new processes.
Three problems for the attacker.
First, the registry change itself is loud. The LastWrite time of PrefetchParameters updates the moment the value is written. If you have registry transaction logs, VSC snapshots, or even just a baseline of the value from the same host taken before the engagement, the change is visible. The forensic value of "EnablePrefetcher was just changed two hours before the suspicious window started" is high.
Second, the change does not take effect immediately. The Prefetcher service caches state in memory. New Prefetch entries continue to be written for a period after the registry change, usually until the system is rebooted or the service is restarted. An attacker who flips the registry and runs their tooling thirty seconds later may still have produced .pf files. I have seen this case more than once.
Third, the existing Prefetch directory is not erased by the change. All the .pf files from before the disable are still there. If the attacker did not also delete them, you have a record of everything that ran on the host up to the moment of the change.
Detection: search the SYSTEM hive for the LastWrite time on PrefetchParameters and compare it to your timeline. If the value sits at 0 or 1 (when the host's policy says it should be 3), check VSC snapshots for when the change happened. If you find a change inside the suspicious window, that is itself an event worth investigating, regardless of what was done after.
Deleting individual .pf files
The most common technique, by a wide margin. After running a tool, the attacker simply deletes C:\Windows\Prefetch\TOOLNAME-XXXXXXXX.pf. This requires administrator rights (the Prefetch directory is protected) but anyone running attack tools usually has them.
The deletion succeeds. The .pf file is gone. So is the obvious evidence.
What survives:
- The MFT. Every deleted
.pffile leaves an MFT entry that lingers until the slot is re-used. The entry preserves the filename, the file size, the timestamps, and (if the entry is still resident or shortly after deletion) sometimes file content. A targeted deletion of one.pfwill sit visible in the MFT as "deleted file, name PREFETCH/EVIL-AABBCCDD.pf" until something else claims the entry. - The USN journal. The deletion produces a
FILE_DELETE|CLOSEUSN record with the filename of the.pf. On a busy host the journal rolls over but on most hosts you can see weeks of USN history. The deletion is in there. - The Prefetch directory's own NTFS timestamps. The directory's
Modifiedtime updates each time a file is added or removed. If you have a baseline, the deletion is visible. If you have VSCs, you can see the directory state from before. - The other artifacts that referenced the same binary. AmCache still has the hash. Shimcache still has the binary's name. The MFT still has the binary if it was not also wiped. The registry user-run-history still has the program in
UserAssistorRunMRU. Prefetch is one of many.
Detection: enumerate the Prefetch directory's deleted MFT entries. Any .pf filename in the deleted-entry list that does not exist in the live directory is a deletion. Pair with USN records. The filename usually gives you the executable name; from there you can pivot to AmCache, Shimcache, and the rest.
I have closed cases where the only direct artifact of a known attacker tool was the MFT entry for a deleted .pf file. The .pf itself was gone, but the deletion's residue named the tool plainly.
Wiping the entire Prefetch directory
A more aggressive version: delete everything in C:\Windows\Prefetch\. Some attackers do this routinely as part of their cleanup.
The same residues survive. The MFT now shows dozens or hundreds of deleted .pf filenames. The USN journal shows the deletes in sequence, often in seconds of each other. The directory's NTFS timestamps update to the time of the wipe.
A Prefetch directory that is empty (or contains only NTOSBOOT-XXXXXXXX.pf, which is regenerated on boot) on a workstation that has been running for months is a screaming red flag. The natural state of the directory on a long-running host is hundreds of files. Empty means somebody emptied it.
Detection: count entries in the live directory and compare to the expected count for the host's age and usage. Empty or near-empty Prefetch directories on aged hosts are an anomaly to be explained, not a finding to be accepted.
The "rename before run" trick
The clever attack. Copy your tool to disk, rename it to something innocuous, run it, then rename it back or delete it. The thinking: the .pf filename embeds the binary name from the executable, so a binary named update.exe produces a UPDATE.EXE-XXXXXXXX.pf file. If you mix in among the host's existing update.exe Prefetch entries, you hide in plain sight.
This is partially effective and very catchable.
What works for the attacker: the .pf filename is genuinely just the executable's filename at the time of execution. Rename mimikatz.exe to update.exe before running it and you get UPDATE.EXE-XXXXXXXX.pf, not MIMIKATZ.EXE-XXXXXXXX.pf. An analyst grepping for MIMI in the Prefetch directory listing will find nothing.
What does not work for the attacker:
- The hash in the filename still encodes the path. A renamed mimikatz at
C:\Users\Public\update.exeproduces a different hash from the legitimateupdate.exeatC:\Program Files\<vendor>\update.exe. You can spot the duplicate name with two different hashes. - The load list still gives the binary away. The renamed mimikatz still loads
sekurlsa.dll-flavored DLLs and touches LSASS-adjacent paths. The.pfSection C will show those paths regardless of what the executable is named. - The executable path Prefetch records is still the real path the binary ran from. Even renamed, the binary lives somewhere, and the
.pfknows where.C:\Users\Public\update.exeas a Prefetch path on a host whereupdate.exeshould live under Program Files is itself an anomaly.
Detection: never search by executable name alone. Search the Prefetch directory for any binary whose recorded path is outside the standard system or program directories, regardless of name. The set of "binaries with user-writable paths" on a normal host is small. The rename trick adds to that set; it does not blend in with it.
Modifying .pf files in place
The advanced approach. Some attackers have written tools that edit Prefetch files: reduce the run count, remove an execution timestamp, scrub a path from the load list. I have seen this attempted twice in seven years of practice.
It is very fragile. The Prefetch file format has internal offsets, section size fields, and checksums (on some versions). Editing the run count without rewriting the rest of the structure is doable. Editing the load list requires recomputing offsets through Section A and Section C and is rarely done correctly.
Detection: structural validation. Run the file through a strict parser that checks every offset and length against the file's declared sizes. Tools like PECmd flag inconsistent files, though they do not always refuse to parse them. A .pf file whose internal sizes do not add up to its on-disk size, or whose Section A references string offsets that fall outside Section C, is either corrupt or tampered.
I have not personally caught a successful in-place tamper in a real investigation. The attempts I have seen produced files that broke obvious invariants. That said, the technique is plausible for a sophisticated attacker, and I would not assume a Prefetch file is canonical just because it parses.
Why Prefetch survives more than Shimcache does
Shimcache only writes on shutdown. An attacker who knows what they are doing can blow away the Shimcache by terminating the system uncleanly, or by overwriting the AppCompatCache registry value before shutdown.
Prefetch writes continuously, as a side effect of normal operation. There is no "flush on shutdown" you can skip. To prevent a .pf file from being written, you have to stop the Prefetch service before the binary runs, which requires the registry change above, which is itself loud. To remove a .pf file after it has been written, you have to delete it, which leaves MFT and USN residue.
This is why I trust Prefetch more than Shimcache for execution claims. Not because Prefetch is more accurate (Shimcache covers more binaries in some ways) but because Prefetch is harder to suppress without leaving traces.
Defender countermeasures
If you run defense, the following make life harder for an attacker trying to clean Prefetch:
- Forward the USN journal to a SIEM. Even a sampled feed catches mass
.pfdeletions in seconds. - Audit registry writes to
PrefetchParametersvia the EVTX registry audit policy or Sysmon EID 13. Any change toEnablePrefetcherorEnableSuperfetchis alert-worthy. - Snapshot the Prefetch directory listing nightly. A diff of last-night-to-this-morning will catch mass deletions and bulk creations.
- Snapshot the SRUM and AmCache databases too. Defense in depth across execution artifacts means an attacker has to clean four things, not one.
- Block writes to
C:\Windows\Prefetch\from non-system contexts via WDAC or AppLocker rules. Most attackers will run with SYSTEM and bypass this, but raising the bar is rarely wasted.
What I tell clients
Prefetch is the artifact attackers most often think they have cleaned and most often have not. The technique that actually works (disable, run, re-enable) is the most operationally costly, requires reboot timing, and is the most detectable through registry change tracking. The technique that is most popular (delete the .pf after the run) leaves the residue you can pivot off in MFT, USN, and adjacent artifacts.
Treat an empty or freshly-pruned Prefetch directory not as the absence of evidence, but as evidence of intervention. Then find the intervention.
Further reading
- Eric Zimmerman, PECmd — handles malformed files reasonably well, useful for sanity checks.
- Microsoft Docs, Registry entries for Prefetch parameters — the canonical reference for the relevant registry keys.
- Harlan Carvey, Windows Registry Forensics — broader context for the registry side of anti-forensics detection.