The definitive Amcache.hve forensic reference: every key, every value, every timestamp
Amcache.hve is the single richest execution-artifact source on a
modern Windows host. It is also one of the most misunderstood. This
post is the reference I wish existed when I first started pulling
hives off compromised machines: every subkey, every value, every
timestamp, what the schema looked like in each Windows release, and —
just as importantly — the claims about Amcache that are not
actually true.
If you are looking for tool-level documentation rather than the artifact itself, see the AmcacheParser complete guide and the output columns reference.
1. What Amcache.hve actually is#
Amcache.hve is a registry hive written by Windows' Application
Compatibility / Program Compatibility Assistant subsystem. It is
not a security artifact by design. Microsoft uses it to feed
compatibility telemetry into the Customer Experience Improvement
Program and the Compatibility Appraiser, both of which decide which
installed software might break on upgrade.
The reason it matters to DFIR is a side effect of that purpose: in
order to assess whether a program is safe to upgrade, Windows needs
to enumerate programs, drivers, devices, and files on the machine.
That enumeration is dumped — with hashes, paths, publishers, sizes,
and timestamps — into Amcache.hve.
Path#
C:\Windows\AppCompat\Programs\Amcache.hve
A .LOG1 / .LOG2 transaction-log pair sits alongside it. Both
logs must be replayed into the hive before parsing if the hive was
not cleanly unmounted. Most modern tools (AmcacheParser, the
browser parser, RegRipper) do this for you, but never delete the
.LOG files before triage — they may contain the writes that hold
your evidence.
Who writes it#
compatTelRunner.exe— driven by the scheduled task\Microsoft\Windows\Application Experience\Microsoft Compatibility Appraiser.- Also touched by
aeinv.dll(Application Experience Inventory) and the broader CompatTelemetry stack.
By default the appraiser runs daily and on logon, but the cadence
varies by Windows build and group policy. Do not assume Amcache
data is real-time. A binary executed five minutes before a
shutdown may not appear at all; one executed an hour before may
appear with a KeyLastWriteTimestamp reflecting the appraiser run,
not the execution.
Acquisition#
The hive is held open by the OS at runtime. To grab a live copy you need raw-NTFS access:
- KAPE with the
Amcachetarget - Velociraptor
Windows.Registry.Amcache - FTK Imager → File System →
C:\Windows\AppCompat\Programs - RawCopy64.exe / CopyRawFiles.ps1
- From an
E01/AFF4/VHDXimage, just read the file normally
A shadow-copy snapshot (vssadmin list shadows) often gives you an
earlier hive that contains evidence the current one has rolled off.
2. Schema evolution: Windows 7 through Windows 11#
Amcache's schema has changed substantially. If you walk into a case expecting Windows 10 1607 keys on a Windows 7 hive, you will think the artefact is empty. It is not — it just looks different.
| Windows version | Amcache present? | Dominant schema |
|---|---|---|
| Windows 7 RTM / SP1 (pre-KB2952664) | No (uses RecentFileCache.bcf) |
n/a |
| Windows 7 SP1 + KB2952664 (2015) | Yes | Root\File\{VolumeGUID}\{FileRef} + Root\Programs |
| Windows 8 / 8.1 | Yes | Root\File + Root\Programs |
| Windows 10 1507 – 1511 | Yes | Root\File + Root\Programs (transitional) |
| Windows 10 1607 (Anniversary) | Yes | Root\InventoryApplicationFile and the wider Inventory* family introduced |
| Windows 10 1703 – 1809 | Yes | Inventory schema stable; minor field additions |
| Windows 10 1903 – 22H2 | Yes | Inventory schema, LongPathHash, additional driver fields |
| Windows 11 21H2 / 22H2 / 23H2 / 24H2 | Yes | Inventory schema, expanded device records, more PnP detail |
The 1607 jump is the biggest. Pre-1607 hives have a handful of keys
with maybe a dozen values each. Post-1607 hives have ten-plus
top-level Inventory* containers, each with rich nested data.
Legacy schema (Win7 → Win10 1511)#
Root\
File\
{Volume GUID, e.g. "{abcd1234-...}"}\
{NTFS File Reference, e.g. "0000abcd00000001"}\
... values ...
Programs\
{ProgramId}\
... values ...
Orphan\
Generic\
The interesting values under each File\{Vol}\{FileRef} subkey were
numbered (0, 1, 2, ... 101, ...). The mapping is well
documented in
Willi Ballenthin's original 2013/2015 research and reproduced in the
Mandiant blog. Highlights:
| Value | Meaning |
|---|---|
0 |
Product name |
1 |
Company name |
2 |
PE FileVersion |
3 |
Language code (LCID) |
5 |
BinaryFileVersion |
6 |
BinaryProductVersion |
c |
FileDescription |
f |
PE LinkDate (FILETIME) |
11 |
Last modified (FILETIME) |
12 |
Created (FILETIME) |
15 |
Full path |
17 |
Last modified (alternative FILETIME slot) |
100 |
ProgramId |
101 |
FileId (SHA-1 with 0000 prefix) |
Modern schema (Win10 1607+)#
Root\
InventoryApplication\
{ProgramId}\ ← installed-program record
InventoryApplicationFile\
{Name|FileId}\ ← per-file record
InventoryApplicationShortcut\
InventoryApplicationFramework\
InventoryApplicationDriver\
InventoryDeviceContainer\
InventoryDevicePnp\
InventoryDeviceInterface\
InventoryDriverBinary\
InventoryDriverPackage\
InventoryMiscellaneousUUPInfo\
Programs\ ← legacy, often still present
File\ ← legacy, often empty on modern OS
Orphan\
Generic\
Each modern subkey carries named values (not numeric), which makes them much easier to read. The rest of this post is the field-by-field reference for those modern values.
3. Root\InventoryApplicationFile — the workhorse#
One subkey per file Windows has inventoried. This is where attacker binaries, side-loaded DLLs, and ad-hoc tooling tend to appear.
| Value | Type | Meaning | Forensic note |
|---|---|---|---|
Name |
string | File name | e.g. mimikatz.exe |
LowerCaseLongPath |
string | Full path (lower-cased) | The single most useful pivot. |
LongPathHash |
string | Hash Windows uses internally for path dedup | Useful for joining records across reboots. |
FileId |
string | "0000" + SHA-1(first 31 MiB) |
Strip the 0000 prefix for VT / TI lookups. |
Publisher |
string | X.509 CN or PE company resource | Empty = unsigned. |
Version |
string | PE FileVersion |
|
BinFileVersion |
string | PE VS_FIXEDFILEINFO.dwFileVersion |
|
BinProductVersion |
string | PE VS_FIXEDFILEINFO.dwProductVersion |
|
ProductName |
string | PE resource ProductName |
|
ProductVersion |
string | PE resource ProductVersion |
|
LinkDate |
string or FILETIME | PE TimeDateStamp |
Attacker-controlled. Group by, do not date by. |
BinaryType |
string | pe32, pe64, pe32_arm64, pe32_managed, ... |
Filter for native PE when threat hunting. |
Size |
dword/qword | File size in bytes | |
Language |
dword | PE resource LCID | |
IsPeFile |
dword (0/1) | Is this a PE? | Almost always 1 here. |
IsOsComponent |
dword (0/1) | Windows-shipped binary | Filter to 0 to cut noise. |
ProgramId |
string | 44-char identity hash of parent app | Empty/zero = "unassociated" file. |
Usn |
qword | USN journal sequence number at inventory | |
AppxPackageFullName |
string | UWP package full name | Populated for store apps. |
AppxPackageRelativeId |
string | UWP package-relative ID |
Two FileId formats#
Two formats coexist in the wild:
0000+ 40 hex chars — SHA-1 of the first 31 MiB of the file. This is the dominant format from Windows 8 onward.0001+ 32 hex chars — MD5; rare and mostly historical.
When pivoting to threat-intel feeds, always check the prefix and
strip it. Submitting the raw FileId to VirusTotal will return
zero hits and waste a meaningful amount of triage time.
"Unassociated" vs "associated"#
A file with a non-empty ProgramId that points at an existing
InventoryApplication subkey is "associated" — Windows linked it to
an installed product. A file with a blank or zero ProgramId is
"unassociated" and could not be tied to any registered application.
Attacker tooling is almost always unassociated. Filtering
InventoryApplicationFile to unassociated entries with a
LowerCaseLongPath under \Users\, \AppData\, \ProgramData\,
\Temp\, or \PerfLogs\ is the cheapest, most productive triage
filter on a typical commodity-malware case.
4. Root\InventoryApplication — installed-program records#
One subkey per registered application (MSI installs, Add/Remove Programs entries, Store apps, etc.).
| Value | Meaning |
|---|---|
Name |
Display name |
Version |
Application version |
Publisher |
Publisher string |
RootDirPath |
Install directory |
Source |
MSI, AddRemoveProgram, WindowsUpdate, ... |
InstallDate |
Install date (string or FILETIME) |
Type |
Application, OptionalFeature, ... |
Language |
LCID |
MsiPackageCode |
MSI package GUID |
MsiProductCode |
MSI product GUID |
RegistryKeyPath |
Uninstall key (SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\...) |
UninstallString |
Command-line to uninstall |
OSVersionAtInstallTime |
Windows version when installed |
InstallDateArpLastModified |
Add/Remove last-modified date |
PackageFullName |
UWP full name (if applicable) |
InstallDateArpLastModified is underused. If a row's InstallDate
and its ARP-last-modified value diverge by months, you may be
looking at a replaced binary (think DLL side-load via a legitimate
installer left behind by IT).
5. Root\InventoryDriverBinary — kernel-mode artefacts#
The single best source for BYOVD (bring-your-own-vulnerable-driver) hunts.
| Value | Meaning |
|---|---|
DriverName |
Driver file name |
DriverInBox |
True if shipped with Windows |
DriverIsKernelMode |
True for ring-0 drivers |
DriverSigned |
Signed-flag claim (do not trust blindly — check the cert separately) |
DriverType |
Bit flags: legacy / PnP / service / file-system / ... |
DriverVersion |
Driver version string |
DriverCompany |
Company string |
Product |
Product name |
ProductVersion |
Product version |
WdfVersion |
Windows Driver Framework version, if applicable |
Service |
Backing service name |
Inf |
.inf filename |
DriverPackageStrongName |
Strong name |
DriverTimeStamp |
PE link date of the driver |
ImageSize |
Image size in bytes |
Hash |
SHA-1 of the driver |
For BYOVD: sort by DriverTimeStamp ascending, filter DriverSigned
to true, then look at the KeyLastWriteTimestamp of each record.
Old, signed, recently-inventoried drivers are the high-signal set.
Cross-reference against
loldrivers.io for known-abused names
and hashes.
6. Root\InventoryDeviceContainer and Root\InventoryDevicePnp#
InventoryDeviceContainer is the user-facing device list:
"Brother HL-L2350DW", "Logitech BRIO", "Samsung Galaxy S22". One
subkey per logical device. Notable values: Categories,
DiscoveryMethod, FriendlyName, Manufacturer, ModelName,
ModelNumber, IsConnected, IsPaired, Icon.
InventoryDevicePnp is the technical enumeration: one subkey per
device interface, with BusReportedDescription, DeviceClass,
DeviceId, InstanceId, Manufacturer, Service, DriverName.
Pair the two on InstanceId to get both the marketing name and the
PnP hardware IDs. This is often the cheapest answer to "did device X
ever attach to this host?" without wading through Setup logs.
7. Root\InventoryApplicationShortcut and other minor keys#
InventoryApplicationShortcut— one subkey per.lnkthat Windows knows about. CarriesShortcutPath,TargetPath, and the parentProgramId. Useful for "what was pinned to the taskbar on $DATE."InventoryApplicationFramework— .NET / runtime framework records.InventoryApplicationDriver— bridge between an installed application and the driver it shipped.InventoryDriverPackage— INF-level package records.InventoryMiscellaneousUUPInfo— Unified Update Platform staging info; rarely relevant.
8. Timestamps: the part everyone gets wrong#
Amcache exposes at least five distinct kinds of "when," and they mean different things. Misreading them is the most common error in Amcache findings.
| Timestamp | Source | What it actually says |
|---|---|---|
KeyLastWriteTimestamp |
Registry last-write of the subkey | Closest thing to "when Amcache observed this." This is your authoritative pivot. |
LinkDate |
PE header TimeDateStamp |
When the compiler/linker stamped the binary. Attacker-controlled, frequently faked. |
InstallDate (InventoryApplication) |
Whatever the installer wrote | Best-effort; reflects installer behavior, not necessarily ground truth. |
InstallDateArpLastModified |
Add/Remove Programs key last-modified | Useful for detecting replacement of an existing app. |
DriverTimeStamp |
PE link date of a driver | Same caveats as LinkDate. |
The KeyLastWriteTimestamp gotcha#
KeyLastWriteTimestamp is the last time the registry key was
written, which is the last time the appraiser touched the record.
If Windows re-evaluated the file last Tuesday because of a metadata
change, the timestamp will say Tuesday — not the date the file was
first observed.
That means:
- You cannot assume
KeyLastWriteTimestampis "first seen." - You can assume it is "last touched by the appraiser."
- For "first seen," correlate against shadow copies of prior
Amcache hives, or against the USN journal entry referenced by
Usn.
The "Amcache = execution" myth#
You will read in many older blog posts that "Amcache proves execution." This is not safe to claim. Maxim Suhanov's research (2018, "Windows ShellBag and Amcache forensics: just stop relying on single-source signals") demonstrated that the Compatibility Appraiser will inventory files that have not been executed — for example, executables present in directories the appraiser scanned.
What Amcache reliably proves:
- The file existed on the system at the inventory time.
- Its hash, path, publisher, and PE metadata at that moment.
What Amcache does not prove on its own:
- That the file was executed.
- When the file was first placed on disk.
- That the user (rather than the system) is responsible.
For execution evidence, corroborate with Prefetch, Sysmon
EventID 1, Security 4688, ShimCache, BAM/DAM, UserAssist, or
SRUM. Amcache is a fantastic triage artefact and a strong
supporting artefact, but it is a weak sole-source execution
witness.
9. ProgramId and FileId: how the identifiers work#
ProgramId (44 characters)#
A hash derived from the application's name, version, publisher, and language. The exact algorithm has not been formally documented by Microsoft, but the practical consequences are:
- The same product installed on two machines will (usually) have
the same
ProgramId. - A point-release upgrade will (usually) change it.
- It is not a content hash — two different binaries from the
same product share a
ProgramId.
Use ProgramId to pivot, never to identify a file.
FileId (44 characters with 0000 prefix)#
This is a content hash:
FileId = "0000" + SHA1(first 31 MiB of file content)
For files smaller than 31 MiB, FileId[4:] is a full SHA-1 of the
file and will match the SHA-1 reported by any other tool. For files
larger than 31 MiB, FileId[4:] is a SHA-1 of the first 31 MiB
only — it will not match a full-file SHA-1.
This matters: a 200 MB packed installer will have a FileId that
does not match its full-file SHA-1, and a VT lookup keyed on the
full hash may miss while a lookup keyed on the Amcache value would
hit (and vice versa). When in doubt, search both.
10. Anti-forensics and tampering#
Amcache can be tampered with. The hive lives on disk and can be modified offline. Known patterns:
- Selective key deletion by a SYSTEM-level actor between appraiser runs.
Set-ItemPropertystyle writes to plant misleadingLinkDateorPublishervalues for a binary the attacker wants to look benign.- Hive replacement with a hive harvested from a clean machine.
- Disabling the appraiser scheduled task (visible in Task
Scheduler history and
Microsoft-Windows-Application-Experienceevent logs).
Defensive corroborations:
- The
.LOG1/.LOG2files often contain pre-tamper state. - Volume Shadow Copies of
Amcache.hvefrom prior days give you a before/after. - The USN journal records writes to the hive file itself.
Microsoft-Windows-Application-Experience/Program-Telemetryevent log records appraiser runs.
If a hive looks too tidy — sparse InventoryApplicationFile
entries, no unassociated rows, perfect publisher coverage — be
suspicious. A normal Windows desktop accumulates thousands of file
records over its lifetime.
11. Cross-artefact corroboration#
Amcache is at its strongest when joined to its neighbors. The joins that pay off most often:
| Question | Join Amcache against |
|---|---|
| Was this binary actually executed? | Prefetch .pf files, Sysmon 1, BAM/DAM, ShimCache, UserAssist |
| When was it placed on disk? | $MFT $STANDARD_INFORMATION and $FILE_NAME timestamps, USN journal |
| Where did it come from? | InstallSource in Programs, Zone.Identifier ADS, browser history, email gateway logs |
| Did it phone home? | DNS logs, Sysmon 3, firewall logs |
| What user ran it? | Security 4688, BAM/DAM (per-SID), UserAssist (per-NTUSER) |
| Earlier state of this hive? | Shadow Copies, prior backups, KAPE Triage collections |
A finding sourced from Amcache plus Prefetch plus a Security
4688 is reportable. A finding sourced from Amcache alone is a
lead.
12. Tools that read Amcache#
No single tool is best for every situation. A working DFIR shop keeps several around.
| Tool | Strengths | When to reach for it |
|---|---|---|
| AmcacheParser (Eric Zimmerman) | Canonical, well-tested, KAPE-integrated, CSV output | Bulk processing, KAPE pipelines, court-ready output |
RegRipper (amcache.pl plugin) |
Text reports, great for narrative timelines | When you want a human-readable summary |
| This browser parser | Zero install, runs entirely client-side via WebAssembly, no upload | Quick triage, classroom demos, third-party laptops where you cannot install software |
Velociraptor Windows.Registry.Amcache |
Fleet-wide collection and parsing | EDR-style sweep across hundreds of hosts |
| Magnet AXIOM / EnCase | GUI + integrated case management | Commercial-tool shops |
Python python-registry / Rust nt-hive |
Programmatic access | Custom pipelines, research |
If you want to skip installs entirely, drop a hive on the home page and you will see every key and value in a few seconds. Nothing leaves the browser.
13. Further reading (the sources that actually move the field forward)#
Most of what is "known" about Amcache comes from a small number of researchers. If you only have time to read four things, read these:
- Willi Ballenthin (Mandiant) — the original Amcache field mapping for the legacy schema. Still the canonical reference for pre-1607 hives.
- Andrea Fortuna — multiple posts walking through the
Inventory*schema as it evolved through Windows 10. - Maxim Suhanov — registry-internals work, and the most rigorous treatment of what Amcache does and does not prove. His work is what killed the "Amcache = execution" myth.
- Eric Zimmerman's tool notes — read the release notes for AmcacheParser; they are how new schema fields get publicly documented first.
Then read your own hives. The schema in the wild contains fields no single blog post covers, and the only reliable way to know what your build of Windows is recording is to look.
See also#
- AmcacheParser complete guide — the canonical reference for Eric Zimmerman's CLI.
- AmcacheParser CLI cheatsheet — every flag with worked examples.
- AmcacheParser output columns explained — field-by-field for the CSV output.
- AmcacheParser download guide — official sources, mirrors, and verification.
- Understanding Amcache for Windows forensics — the short, friendly intro.
Have a hive you want to look at right now? Drop it on the parser home page — it parses in your browser, locally, in a couple of seconds.
Related posts
- AmcacheParser output columns explained: every CSV field decoded
A field-by-field reference for AmcacheParser's CSV output — FileId, PathHash, ProgramId, LinkDate, BinFileVersion, IsPeFile, and every other column, with the pivots that matter in DFIR.
- Volatility and Amcache: extracting the hive from memory images
A practical guide to recovering Amcache from a Windows memory image using Volatility — when memory-side recovery is the only option, which plugins to use, and how to hand off to AmcacheParser.
- RegRipper amcache plugin: what it does and when to use it
A practical guide to RegRipper's amcache plugin — what it parses, how its text output differs from AmcacheParser's CSV, and when to reach for it instead of (or alongside) the Zimmerman tool.
- AmcacheParser download guide: official sources, mirrors, and verification
Every way to download Eric Zimmerman's AmcacheParser — Get-ZimmermanTools, direct download, KAPE, Velociraptor — with checksum verification and air-gapped install patterns.