Amcache forensics: how to find evidence of execution
The question that puts Amcache on the table is almost always some version of "prove this thing ran on this host" — a tool the attacker deleted, a binary an EDR alert named but the analyst can't find on disk, a piece of malware that wiped itself after staging. Amcache.hve is the cheapest place on a Windows system to answer that question, because the Compatibility Appraiser inventories portable executables whether or not they still exist, and it records the one field that survives everything else: the SHA-1 hash.
This is the end-to-end walkthrough: acquire the hive, parse it, cut the noise, find the entries that matter, pivot on them, and — the part most guides skip — understand exactly what an Amcache hit does and does not prove. If you want the artefact reference rather than the workflow, start with the Amcache complete reference; this page is about using it to find evidence.
What an Amcache entry actually proves#
Get this right first, because every conclusion downstream depends on it.
Amcache's headline key, Root\InventoryApplicationFile, holds one entry per PE the appraiser saw. An entry means: this executable was present on the filesystem when the appraiser ran, and here is its metadata. That is presence, not execution. For the overwhelming majority of real cases the distinction is academic — an attacker's mimikatz.exe sitting in C:\ProgramData\ got there to be run — but in a courtroom or a report you state it precisely:
- Strong claim, well supported: the binary with this SHA-1 and this path existed on this host at or before the appraiser run that wrote this entry.
- Weaker claim, needs corroboration: the binary was executed. Confirm with Prefetch, ShimCache, Sysmon Event ID 1, or Security 4688.
The honest framing — presence first, execution by corroboration — is what separates a finding that survives review from one that gets torn apart. See what the Amcache tells you for the full treatment of this boundary.
Step 1: acquire the hive#
The file lives at a fixed path on every Windows version from 8 onward:
C:\Windows\AppCompat\Programs\Amcache.hve
C:\Windows\AppCompat\Programs\Amcache.hve.LOG1
C:\Windows\AppCompat\Programs\Amcache.hve.LOG2
On a live host the hive is held open, so you cannot just copy it with Explorer. Use a raw-handle copy (KAPE, FTK Imager, RawCopy, or the Velociraptor artefact) and take the two .LOG transaction logs with it — they carry writes not yet flushed into the hive, and a good parser replays them. The full acquisition options are in acquiring the Amcache.hve; the short version is: copy all three files, never trust a hot copy without the logs.
# KAPE, the standard triage path
kape.exe --tsource C: --target Amcache --tdest C:\triage\
Step 2: parse with AmcacheParser#
Eric Zimmerman's AmcacheParser is the de facto tool. The flags that matter:
AmcacheParser.exe -f Amcache.hve --csv .\out\ --mp -i
-f— the hive to parse.--csv— output directory for the CSV set.--mp— include the\Microsoft\paths (don't pre-filter at parse time; filter later, where you can see what you dropped).-i— include entries even where the appraiser data is partial.
It replays the transaction logs automatically and emits a set of CSVs — UnassociatedFileEntries.csv and AssociatedFileEntries.csv are the two you live in. (No Windows box handy? Drop the hive on the browser parser — it reads the hive client-side via WebAssembly and never uploads it, which also clears the "no third-party uploads" rule that regulated environments impose.) For what every column means, keep AmcacheParser output columns open in a tab.
Step 3: read the fields that carry evidence#
Per file-entry, these are the ones you build findings on:
| Field | What it gives you | Evidentiary weight |
|---|---|---|
FileId (SHA-1) |
Hash of the file. The pivot key across hosts and into threat intel. | Highest. Survives deletion and rename. |
LowerCaseLongPath |
Full path the binary lived at. | High. Location is intent (\Temp\, \ProgramData\ vs \Program Files\). |
Name / OriginalFileName |
On-disk name vs PE-internal name. A mismatch is a flag. | High when they disagree. |
Publisher / IsPeSigned |
Signing identity. Blank/unsigned in user paths is suspicious. | Medium. |
LinkDate |
PE compile timestamp. | Medium, spoofable. |
Size |
File size in bytes. | Medium, corroborating. |
KeyLastWriteTimestamp |
When the appraiser last wrote this entry. | Medium — a bound, not an execution time. |
IsOsComponent |
Whether Windows considers it an OS file. | Filter signal, not evidence. |
The FileId deserves special attention: AmcacheParser strips the leading 0000 zero-padding for you, so the remaining 40 hex characters are the file's true SHA-1 — paste it straight into VirusTotal. The full mechanics are in Amcache FileId explained and the hunting workflow in SHA-1 hashes for malware hunting.
Step 4: filter the noise#
UnassociatedFileEntries.csv on a normal workstation runs to tens of thousands of rows. You cannot read that. The filtering order I apply every time, identical to what seasoned analysts converge on:
- Drop OS plumbing by path. Everything under
c:\windows\winsxs\,c:\windows\servicing\,c:\program files\microsoft\. - Drop
IsOsComponent = True. More OS noise the path filter missed. - Keep the interesting neighbourhoods. Paths in
\users\,\programdata\,\windows\temp\,\perflogs\, or anything containing\appdata\. Attackers stage where they can write. - Keep blank or
Unknownpublishers. Signed software with a real publisher is rarely the first lead. - Sort by
KeyLastWriteTimestampdescending. Work the window you care about first.
In PowerShell, against the parsed CSV:
Import-Csv .\out\*_UnassociatedFileEntries.csv |
Where-Object {
$_.IsOsComponent -ne 'True' -and
$_.LowerCaseLongPath -notmatch '\\winsxs\\|\\servicing\\|\\program files\\microsoft\\' -and
$_.LowerCaseLongPath -match '\\users\\|\\programdata\\|\\windows\\temp\\|\\appdata\\|\\perflogs\\'
} |
Sort-Object KeyLastWriteTimestamp -Descending |
Select-Object KeyLastWriteTimestamp, LowerCaseLongPath, Name, Publisher, FileId |
Format-Table -AutoSizeTwenty-thousand rows become a few dozen. That is the set you actually read.
Step 5: a worked example — the deleted binary#
Here is the pattern that makes Amcache worth reaching for first. The filtered set surfaces a row like this:
KeyLastWriteTimestamp: 2026-06-09 23:51:07 UTC
LowerCaseLongPath: c:\programdata\intel\drivers\igfxsvc.exe
Name: igfxsvc.exe
OriginalFileName: rundll32.exe
Publisher: (empty)
IsPeSigned: False
FileId: 0000a1b2c3d4e5f60718293a4b5c6d7e8f90a1b2
Size: 1264640
Three things make this entry shout:
- Name/OriginalFileName mismatch. The file calls itself
igfxsvc.exeon disk but its PE header saysrundll32.exe. Legitimate Intel graphics software does not do this. Renamed system tooling — or something masquerading as it. - Wrong neighbourhood. Real Intel drivers do not live under
c:\programdata\intel\drivers\. That path is attacker-chosen camouflage. - Unsigned, no publisher, in a writable directory. Three weak signals that compound into a strong one.
Now the binary itself is gone from disk — the attacker deleted it. You still have everything you need:
- Pivot the SHA-1. Take
a1b2c3d4e5f60718293a4b5c6d7e8f90a1b2(drop the0000) to VirusTotal / your intel platform. A hit names the tool. No hit means run it across every other host's Amcache to see where else this exact file landed. - Establish a time bound.
KeyLastWriteTimestampof2026-06-09 23:51tells you the file was present by that moment. Pair it with the timestamps reference so you do not over-claim — this is the appraiser's write time, not the execution time. - Confirm execution. Cross to Prefetch for
IGFXSVC.EXE-<hash>.pf(run count + last-run times), to ShimCache, and to Sysmon EID 1 / Security 4688 for the actual process create. Amcache says it was here; those say it ran, this many times, at these moments.
That chain — surface, pivot, bound, confirm — is the spine of investigating a real incident with the Amcache and the malware investigation guide.
Beyond executables: device and driver evidence#
Program execution is the headline, but the same hive answers two more evidentiary questions analysts under-use:
- What hardware touched this host?
Root\InventoryDeviceContainerandRoot\InventoryDevicePnpgive the cleanest tabular USB / peripheral history Windows exposes — friendly names, vendor/model, connect state. This is the basis of every USB-exfiltration triage; the full method is in USB and device history from Amcache. It is also, per search data, the question people most often arrive at Amcache asking — theDeviceContainers/KeyLastWriteTimestamppairing. - What drivers were loaded?
Root\InventoryDriverBinaryrecords driver binaries with their own hashes — the artefact you check for BYOVD (bring-your-own-vulnerable-driver) attacks, where a signed-but-vulnerable driver is dropped to gain kernel access.
The limits that catch analysts out#
The it-connect-style walkthroughs are right to dwell here, and so will I. An Amcache finding is only as good as your awareness of what the hive cannot tell you.
Scripts are invisible#
.ps1, .cmd, .bat, .vbs — none of them have a PE header, so the appraiser does not inventory them as file entries. A PowerShell-only intrusion can leave no Amcache execution trace for the malicious logic itself (though powershell.exe and any compiled tools it dropped will appear). For script execution you need Prefetch, ScriptBlock logging (EID 4104), and the command-line in 4688/Sysmon. This is the single most common reason an analyst wrongly concludes "nothing ran."
OS components are filtered out by design#
Entries flagged IsOsComponent = True — and many living-off-the-land binaries that ship with Windows — may be absent or de-emphasised. An attacker using only certutil.exe, bitsadmin.exe, wmic.exe leaves a thin Amcache trail precisely because those are OS components. LOLBins evade the inventory the same way they evade everything else.
It is an inventory, not a log#
There is no per-execution record and no run count — that is Prefetch's job. One Amcache entry per file, updated in place. If a binary ran fifty times you see one row, and KeyLastWriteTimestamp reflects the appraiser's last write, not the last run.
The appraiser lag is real#
The Microsoft Compatibility Appraiser runs roughly daily, throttled by idle and power state. A binary that ran two hours before you pulled the hive may simply not be inventoried yet. Absence of an Amcache entry is never proof a binary did not run — see why is my Amcache empty and how often Amcache updates.
Timestamps are bounds, not events#
KeyLastWriteTimestamp is the appraiser's write time. LinkDate is a compile timestamp the author controls and can forge. Neither is "the time the program ran." The disciplined reading is in Amcache timestamps decoded.
Correlation: where Amcache fits in the picture#
Amcache earns its keep as the fast first look and the survivor of deletion. It is at its strongest when triangulated:
| Question | Amcache | Corroborate with |
|---|---|---|
| Was this binary on the host? | Yes — primary source | $MFT, $J for filesystem timeline |
| Did it execute? | Implies presence | Prefetch, ShimCache, Sysmon 1, Security 4688 |
| How many times / when exactly? | No | Prefetch (run count + 8 last-run times) |
| What is this file, exactly? | SHA-1 — primary | VirusTotal / threat intel |
| What hardware connected? | Device keys — primary | setupapi.dev.log, USBSTOR |
| Did a script run? | No | EID 4104, 4688, Prefetch |
For the artefact-by-artefact comparisons, see Amcache vs Prefetch, Amcache vs ShimCache, and Amcache vs SRUM.
The workflow in one screen#
- Acquire
Amcache.hve+ both.LOGfiles (raw copy). AmcacheParser.exe -f Amcache.hve --csv .\out\ --mp -i.- Filter: drop OS paths and
IsOsComponent, keep writable user paths and blank publishers, sort byKeyLastWriteTimestampdesc. - Read the surviving rows for path/name mismatches and odd neighbourhoods.
- Pivot each candidate's SHA-1 to intel and across hosts.
- Bound the time with
KeyLastWriteTimestamp; never call it the execution time. - Confirm execution in Prefetch / ShimCache / EVTX.
- State presence as fact, execution as corroborated — and name what the hive could not see.
That is how you turn Amcache.hve into evidence rather than a hunch.
Related#
Related posts
- Volatility and Amcache: extracting the hive from memory images
When you only have a RAM dump, Volatility extracts the in-memory copy of Amcache.hve. Hand off to AmcacheParser. The cases where this is the only option.
- RegRipper amcache plugin: what it does and when to use it
RegRipper's amcache plugin produces a plain-text Amcache report. Useful when you're already running RegRipper across other hives or need narrative output. Use AmcacheParser when you need CSV.
- AmcacheParser output columns explained: every CSV field decoded
Field-by-field reference for AmcacheParser's CSV output. FileId, PathHash, ProgramId, LinkDate, BinFileVersion, IsPeFile, and every other column, with the pivots that matter.
- AmcacheParser download guide: official sources, mirrors, and verification
Where to get AmcacheParser. Get-ZimmermanTools, direct download, KAPE, Velociraptor. Plus checksum verification and the air-gapped install pattern.