Amcache timestamps explained: KeyLastWriteTimestamp vs LinkDate vs the rest
Amcache exposes multiple different timestamps, and confusing them is the single most common mistake new Amcache analysts make. Date a finding wrong and the entire timeline collapses. This page is the full reference: every timestamp Amcache exposes, what it actually represents, and which one you should pivot on for any given question.
For the broader Amcache context, see the Amcache complete reference; for the surrounding registry structure, see Amcache registry structure.
The timestamps at a glance#
| Timestamp | Source | Represents |
|---|---|---|
KeyLastWriteTimestamp |
Registry key metadata | When the appraiser last wrote this entry. The closest thing to "when Amcache recorded this". |
LinkDate |
PE IMAGE_FILE_HEADER.TimeDateStamp |
When the binary was compiled / linked. Attacker-controllable. |
InstallDate |
InventoryApplication value |
When the application was installed. |
MsiInstallDate |
InventoryApplicationFile value |
When the parent MSI was installed (if any). |
LastModified |
Hive value (schema-dependent) | A last-modified marker, present in some schema versions. |
LastWriteTimestamp (legacy Programs) |
Registry key metadata | Same idea as KeyLastWriteTimestamp, but for the legacy Root\Programs schema. |
The single most important rule:
KeyLastWriteTimestampis the "when was this seen on this host" pivot. Everything else is a different question.
KeyLastWriteTimestamp#
This is the registry-level last-write time of the key containing the entry. It is metadata of the registry hive itself — Windows updates it every time the key's contents change.
For Root\InventoryApplicationFile\<entry>, the
KeyLastWriteTimestamp is updated whenever the appraiser writes or
updates that entry. In practice this means:
- The first time the appraiser inventories a file, the key is
created and its
KeyLastWriteTimestampis the inventory time. - If the file's metadata changes between inventories (size, hash, version), the key is rewritten and the timestamp advances.
- If nothing changes between inventories, the timestamp stays put — even if the appraiser ran again and confirmed the file is still present.
That last point matters: KeyLastWriteTimestamp is not "the most
recent time the appraiser saw this file." It is "the most recent
time the appraiser wrote about this file." For a stable,
unchanged file, the timestamp can be weeks or months old even though
the file has been present that entire time.
What KeyLastWriteTimestamp is good for#
- First-seen approximations. For a binary that the attacker
dropped new on a clean host,
KeyLastWriteTimestampis the appraiser-run time after the drop. Subject to:- the appraiser does not run instantly — there is up to ~24 h delay on workstations, longer on servers,
- the binary must still be present at appraiser time (transient binaries deleted before the next pass may never appear),
- the timestamp resolution is whatever the appraiser writes — typically second-precision.
- Time-window joins. Once you have a suspicious entry, take its
KeyLastWriteTimestamp± your chosen window (one hour is a common default) and join all other CSVs (Prefetch, Sysmon, Security 4688) on that window. You get the full story of what happened around the inventory event. - Detecting binary replacement. If two
InventoryApplicationFilerows share the sameFullPathbut have differentHashvalues and differentKeyLastWriteTimestampvalues, the binary at that path changed between those two times. Sort by timestamp to see the sequence.
What KeyLastWriteTimestamp is not good for#
- "When did this binary first exist on disk?" — that is a
file-system question (
$STANDARD_INFORMATION.CreationTimein the MFT).KeyLastWriteTimestampis at best an upper bound: the file existed on disk no later than the timestamp, but probably earlier. - "When did this binary execute?" — Amcache records presence, not execution. Use Prefetch.
- Sub-second precision. Don't draw conclusions from a few hundred milliseconds.
LinkDate#
The PE-header TimeDateStamp — the value the linker stamped into
the binary's IMAGE_FILE_HEADER at compile/link time. Every PE has
one.
What LinkDate is good for#
- Clustering binaries by build campaign. If you sort all
unassociated PEs on a host by
LinkDate, you frequently see tight clusters: 3–10 binaries all stamped within the same day or hour. That is often a single attacker compiling their full toolkit in one sitting. - Spotting suspiciously old or new builds. A driver compiled in 2014 that first shows up in your Amcache today is a flag for BYOVD. A binary compiled in the future is a flag for clock-skew shenanigans or sloppy tooling.
- Confirming a build belongs to the expected campaign. "Our internal tool builds always linkdate Mondays at 03:00 UTC; this one is Tuesday at 14:00 — investigate."
What LinkDate is not good for#
- "When did this binary appear on this host?" Attacker-controllable.
An attacker can set any
TimeDateStampthey want at link time, and it is sometimes set to0deliberately (for reproducible builds) or to a date in the past (to make the binary look old/established). TrustingLinkDateas a host-presence pivot produces wrong findings. - Cryptographic identity.
LinkDatealone is not unique; many binaries share the same link timestamp.
InstallDate (on InventoryApplication)#
When the application was installed, in registry FILETIME format. Useful for:
- Cross-checking with
KeyLastWriteTimestampon the file records. If a file'sKeyLastWriteTimestampis significantly older than its parent application'sInstallDate, something is unusual — the file appears to have been on disk before the application existed according to Windows. - Detecting silent installs. Applications installed without user
interaction sometimes leave
InstallDatenear 1601-01-01 (the FILETIME epoch) or at unrealistic future dates. Both are flags.
MsiInstallDate (on InventoryApplicationFile)#
The install date of the parent MSI for files that came from an MSI
installer. Same FILETIME format as InstallDate. Useful for
distinguishing files that arrived via a proper MSI install from files
that arrived via copy / drop.
LastModified (when present)#
Some Amcache schema versions expose a per-file LastModified value.
Not every hive has it. When present, treat it as the file-system
last-modified time as the appraiser saw it at inventory — not as
authoritative. The MFT's $STANDARD_INFORMATION is the authoritative
source.
LastWriteTimestamp on legacy Programs#
The legacy Root\Programs schema exposes a per-entry
LastWriteTimestamp that is conceptually identical to
KeyLastWriteTimestamp in the modern schema. Same caveats apply.
The standard time-bound pivot#
The investigation pattern most analysts standardise on:
- Identify a suspicious row in
*_UnassociatedFileEntries.csv(typically via "unsigned PE in user-writable path"). - Take its
KeyLastWriteTimestamp. - Define a one-hour window centred on that timestamp.
- Pull from that window:
- All other Amcache rows (cross-key — drivers, devices, shortcuts).
- All Prefetch entries (definitive execution).
- All Security 4688 process-creation events.
- All Sysmon
1(process create),7(image load), and11(file create) events. - All file-system creates from the MFT and USN journal.
- The resulting timeline is the full picture of what happened around that inventory event.
This is the canonical "what was the attacker doing in this minute?"
join, and KeyLastWriteTimestamp is the anchor that makes it
possible.
A worked example#
You see two Amcache rows for the same path:
FullPath: C:\Users\bob\AppData\Local\Temp\notepad.exe
Row A: KeyLastWriteTimestamp = 2026-03-12 14:23:11 UTC
Hash = aaaaaaaa...
LinkDate = 2018-04-03 09:00:00 UTC
Publisher = ""
Row B: KeyLastWriteTimestamp = 2026-04-19 02:14:55 UTC
Hash = bbbbbbbb...
LinkDate = 2018-04-03 09:00:00 UTC
Publisher = ""
Reading these:
LinkDateis identical. That's theTimeDateStampin the PE header — the attacker reused the same build identity, or used a template that linkstamps every build the same. Not evidence of build time.Hashdiffers. Different file content was at the path at the twoKeyLastWriteTimestampmoments.KeyLastWriteTimestampdiffers. Amcache saw the path twice, ~5 weeks apart, with different content each time.
Conclusion: a binary at this path was replaced between March 12 and April 19. Pivot on the April 19 timestamp ± 1 h for the new binary's drop event; pivot on March 12 ± 1 h for the original drop. Two intrusion events; one path; one Amcache entry to find both.
See also#
- Amcache complete reference — the high-level overview.
- Amcache registry structure — where each timestamp sits in the hive.
- Amcache FileId explained — the content-hash pivot that pairs with timestamps.
- Amcache ProgramId explained — the application-identity pivot.
- AmcacheParser output columns explained — every CSV field, in context.
To explore timestamps on your own hive without installing anything, drop a file on the parser home page — it parses entirely in your browser.
Related posts
- 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.
- What is LinkDate in Amcache? (glossary)
LinkDate is the PE header TimeDateStamp Amcache records — when the binary was compiled or linked, not when it appeared on the host.
- What is KeyLastWriteTimestamp in Amcache? (glossary)
KeyLastWriteTimestamp is the registry-level last-write time of an Amcache entry — the closest thing Amcache exposes to 'when the appraiser recorded this file'.