Detecting RecentFileCache tampering
How attackers suppress, poison, or wipe RecentFileCache.bcf — and the event-log, scheduled-task, and filesystem signals that catch them doing it.
If RecentFileCache.bcf is useful for triage, it is also worth suppressing for an attacker who wants to stay quiet. This post walks the four realistic ways to tamper with the artifact and the signals each one leaves.
The four suppression strategies
- Disable the Application Experience service.
sc stop AeLookupSvcthensc config AeLookupSvc start= disabled. New executions stop being recorded. - Disable the ProgramDataUpdater scheduled task. Stops the periodic rewrite. Existing entries stay; new ones may accumulate in memory but never get flushed.
- Delete the file.
del C:\Windows\AppCompat\Programs\RecentFileCache.bcf(requires elevation). Until the nextMicrosoft\Windows\Application Experience\ProgramDataUpdaterrun, the artifact is just gone. - In-memory execution. Do not suppress the artifact at all. Make sure the loader never sees you. Reflective DLL injection, process hollowing, fileless PowerShell, signed-LOLBin abuse.
Each leaves a different fingerprint.
Signal: service control events
Stopping or disabling AeLookupSvc emits Service Control Manager events in the System log.
| Event ID | Source | What it indicates |
|---|---|---|
| 7036 | Service Control Manager | Service state change (e.g., "stopped") |
| 7040 | Service Control Manager | Start type changed (e.g., auto -> disabled) |
| 7045 | Service Control Manager | New service installed (rare for AppCompat) |
Hunt for AeLookupSvc in event payload XML. On a healthy machine the service starts at boot and stays running. A 7036-stopped event during business hours, with no corresponding restart, is loud.
Get-WinEvent -LogName System -FilterXPath "*[System[(EventID=7036 or EventID=7040)]]" |
Where-Object { $_.Message -like "*AeLookup*" } |
Select-Object TimeCreated, Id, Message
Pull these from EVTX on an image, or live with Get-WinEvent. Either works.
Signal: scheduled-task history
Disabling \Microsoft\Windows\Application Experience\ProgramDataUpdater writes to the Microsoft-Windows-TaskScheduler/Operational log.
| Event ID | Meaning |
|---|---|
| 141 | Task deleted |
| 142 | Task disabled |
| 200 | Action started |
| 201 | Action completed |
Look for 141/142 referencing the ProgramDataUpdater task path, or a long gap between 200/201 events on a machine that has been powered on continuously.
Signal: filesystem state
The file itself betrays tampering when you read it carefully.
LastWriteTimefar in the past on a daily-used machine. Healthy systems see a write roughly every 24 hours. A BCF last written six weeks ago on a workstation logged into daily is a flag.- File missing entirely on a Win7 endpoint where logs show ProgramDataUpdater previously ran. The USN journal and
$LogFilerecord the deletion. CheckUSN_REASON_FILE_DELETErecords for the BCF. LastWriteTimeexactly matching an attacker-time event (incident-window correlation). Possible deliberate flush.- Zero or near-zero entries on a machine that has been running months of normal activity. Either the file was just cleared, or
AeLookupSvchas been off since the last reset.
Pull MFT metadata with the MFT parser and compare $STANDARD_INFORMATION against $FILE_NAME for the BCF itself. Timestomping the BCF is rare in practice, but I have seen it once. Worth checking.
Signal: USN journal and $LogFile
If the BCF was deleted or renamed, NTFS records it. Parse with the USN journal parser or usn-parser:
TIMESTAMP REASON FILE
2026-05-23T14:09:11Z FILE_DELETE | CLOSE RecentFileCache.bcf
2026-05-23T14:09:12Z FILE_CREATE | CLOSE RecentFileCache.bcf
A close-paired delete and create on the same file is the classic clear-by-replacement move. The created file will often be empty or hold only the 20-byte header.
$LogFile (parsed with LogFileParser or MFTECmd's $LogFile mode) captures finer-grained MFT operations and survives shorter windows than the USN journal in some cases.
Signal: cross-artifact contradictions
The richest signal is cross-artifact disagreement.
- Prefetch shows execution; the BCF shows no corresponding path. Either the binary bypassed the loader (in-memory), or the BCF was tampered with. Check the BCF's
LastWriteTimeagainst the Prefetch's last-run time. The Prefetch parser gives you the timestamps. - Amcache has entries for executables not in the BCF. Normal if ProgramDataUpdater already promoted them. Suspicious if the timestamps suggest promotion should not have happened yet. The Amcache parser gives you registry-key
LastWrittento compare. - BCF is exactly the 20-byte header with no records. A clean state that occurs naturally right after ProgramDataUpdater rewrote and nothing has run since. Verify against the file's mtime and the System log before calling it suspicious.
What in-memory execution looks like (when there is nothing to see)
The point of in-memory tradecraft is that no file ever touches disk in a way the loader's AppCompat hook can catch. RecentFileCache will look completely normal. Do not read its silence as exoneration. Pair with:
- EDR telemetry on
CreateRemoteThread,WriteProcessMemory, unbacked executable regions. - PowerShell
4104script-block logging (if enabled). - Sysmon event ID 1 (process create) with command line, parent, and image-loaded fields. The EVTX parser reads these.
- RAM acquisition with Volatility's
malfind,dlllist,ldrmodules. - Pagefile carving when memory is no longer available.
A short hunt query
Daily-cadence detection rule, pseudo-XQL:
service = "AeLookupSvc" AND
event_id IN (7036, 7040) AND
NOT (event_id = 7036 AND state = "running")
| stats count by host, event_id, _time
| where count > 0
Combined with a scheduled check that RecentFileCache.bcf exists and has been modified within the last 48 hours on every Win7 endpoint, you catch the loud half of suppression attempts. The quiet half (in-memory execution) needs the other half of your stack: EDR, memory, command-line logging.
End of the series
That closes the primer. You now have the format, the lifecycle, the comparison context, the acquisition workflow, the triage heuristics, the validation chain, and the tampering signals. The parser on this site is the front end for the BCF itself. Everything else lives in your usual DFIR toolchain.
Further reading
- Validating RecentFileCache findings
- Triage: spotting suspicious entries in RecentFileCache
- USN journal, MFT, and Registry for cross-artifact corroboration