Amcache timestamps explained: KeyLastWriteTimestamp vs LinkDate vs the rest

Amcache exposes multiple distinct timestamps, and confusing them is the single most common mistake new analysts make. Date a finding wrong and the entire timeline collapses. This page is the full reference. Every timestamp, what it actually represents, which one to pivot on for any given question.

For broader 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) Last-modified marker, present in some schema versions.
LastWriteTimestamp (legacy Programs) Registry key metadata Same idea as KeyLastWriteTimestamp, 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#

The registry-level last-write time of the key containing the entry. Hive metadata. 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:

  • 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 when 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 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. Up to ~24h 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.
  • 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's a filesystem question. $STANDARD_INFORMATION.CreationTime in the MFT. KeyLastWriteTimestamp is at best an upper bound: the file existed on disk no later than the timestamp, probably earlier.
  • "When did this binary execute?" Amcache records presence, not execution. Use Prefetch.
  • Sub-second precision. Don't draw conclusions from 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. Sort unassociated PEs on a host by LinkDate and 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 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. The attacker can set any TimeDateStamp they want at link time, sometimes set to 0 deliberately (reproducible builds) or to a past date (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 filesystem last-modified time as the appraiser saw it at inventory - not authoritative. The MFT's $STANDARD_INFORMATION is authoritative.

LastWriteTimestamp on legacy Programs#

The legacy Root\Programs schema exposes a per-entry LastWriteTimestamp 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 filesystem creates from the MFT and USN journal.
  1. 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#

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:

  • 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 content 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 ± 1h for the new binary's drop event. Pivot on March 12 ± 1h for the original drop. Two intrusion events. One path. One Amcache entry to find both.

Further reading#

  • Maxim Suhanov on registry key write-time semantics.
  • Yogesh Khatri's deep dive on Amcache, including the timestamp gotchas.

Related posts

Back to all posts