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:

KeyLastWriteTimestamp is 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 KeyLastWriteTimestamp is 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, KeyLastWriteTimestamp is 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 InventoryApplicationFile rows share the same FullPath but have different Hash values and different KeyLastWriteTimestamp values, 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.CreationTime in the MFT). KeyLastWriteTimestamp is 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 TimeDateStamp they want at link time, and it is sometimes set to 0 deliberately (for reproducible builds) or to a date in the past (to make the binary look old/established). Trusting LinkDate as a host-presence pivot produces wrong findings.
  • Cryptographic identity. LinkDate alone 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 KeyLastWriteTimestamp on the file records. If a file's KeyLastWriteTimestamp is significantly older than its parent application's InstallDate, 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 InstallDate near 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:

  1. Identify a suspicious row in *_UnassociatedFileEntries.csv (typically via "unsigned PE in user-writable path").
  2. Take its KeyLastWriteTimestamp.
  3. Define a one-hour window centred on that timestamp.
  4. 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), and 11 (file create) events.
    • All file-system creates from the MFT and USN journal.
  5. 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:

  • LinkDate is identical. That's the TimeDateStamp in 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.
  • Hash differs. Different file content was at the path at the two KeyLastWriteTimestamp moments.
  • KeyLastWriteTimestamp differs. 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#

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

Back to all posts