SHA-1 in the Amcache: pivoting from disk to threat intel

The single most valuable byte sequence in Amcache.hve is the FileId value under InventoryApplicationFile. It is a SHA-1 of the file contents, prefixed with four zeros (0000) for historical reasons that no longer matter. Strip the prefix, and you have a hash you can throw at any threat-intel feed on the planet.

This is what makes the Amcache different from almost every other Windows artifact. The shimcache gives you a path and a timestamp. The Prefetch gives you a run count and a hash of the path. The MFT gives you metadata about the file at a moment in time. The Amcache gives you the file's actual content fingerprint, computed by Windows itself, persisted in a registry hive that survives the file being deleted.

That last clause is the one that closes cases.

Why hashes survive deletion and paths do not#

When Appraiser walks the filesystem on its schedule (Microsoft\Windows\Application Experience\Microsoft Compatibility Appraiser), it computes SHA-1 over the file content and writes the result into the hive. That value sits there until somebody specifically deletes the subkey. If the operator drops loader.exe, runs it, and removes it, the file is gone from the MFT after a few writes, gone from the USN journal once the journal rolls, gone from Prefetch the next time the cache is trimmed. The Amcache row, with its SHA-1, persists indefinitely. I have pulled FileIds from hosts where the original binary was deleted six months earlier.

There are limits, and you should know them before you write the sentence in your report:

  • If the Compatibility Appraiser task was disabled, the binary was never hashed. No row, no FileId, no pivot.
  • If the attacker dropped, executed and deleted the binary inside a single Appraiser scan window, the file was never hashed. Same outcome.
  • If the attacker explicitly deleted the subkey under InventoryApplicationFile, the live hive has nothing. The transaction logs (Amcache.hve.LOG1 / Amcache.hve.LOG2) often still do. Grab them and replay.

The hashing is SHA-1, which is cryptographically broken for collision attacks but completely fine as a content identifier for DFIR. Nobody is engineering chosen-prefix collisions against your registry hive. If anyone tells you SHA-1 in the Amcache is "not trustworthy", they are confusing two different threat models.

The pivot, end to end#

A real workflow on a host I suspect of compromise:

  1. Acquire the hive and its logs. Replay. Parse.
  2. Dump every (FileId, OriginalFileName, LowerCaseLongPath, KeyLastWrite) tuple from InventoryApplicationFile. That is the working set, typically a few thousand rows on a workstation, tens of thousands on a long-lived server.
  3. Strip the 0000 prefix from each FileId. The remaining 40 hex characters are a normal SHA-1.
  4. Triage by path. Filter to user-writable directories first (\Users\*\AppData\, \ProgramData\ outside vendor subdirs, C:\Windows\Temp\, C:\PerfLogs\, C:\$Recycle.Bin\). Anything in C:\Windows\System32\ from a signed Microsoft binary is rarely the start of an investigation, even if you should still hash-check the outliers later.
  5. Submit the surviving hashes in batch to VirusTotal, your in-house sandbox, MalwareBazaar, your EDR vendor's reputation API, and whichever commercial feed you trust. The two free public services I use most are VirusTotal and abuse.ch's MalwareBazaar; both accept SHA-1.
  6. Bucket the responses. Known-bad goes straight into the IOC list. Unknown-but-suspicious paths get pulled forward for sandbox detonation, if you can still find the binary on a peer host or in a backup. Known-good signed binaries get noted and dropped.
  7. Anything that hit on threat intel becomes a sweep across the rest of the estate. The FileId is the IOC. Search every other Amcache you can get hands on for the same SHA-1.

Step 7 is the one most people undersell. The Amcache is per-host, but the FileIds are universal. If e3b0c44... showed up on the patient-zero host, it will show up wherever the operator dropped it next, and the Amcache often catches that even when the binary is no longer present. Bulk Amcache collection across an enterprise (KAPE collection target, Velociraptor hunt, your favourite EDR's file-collection capability) followed by a SHA-1 search is a workflow that scales.

The false positives that will waste your day#

Commodity offensive tooling pollutes hash-based pivots. Two specific patterns to recognise:

The first is shared infrastructure across red teams. PsExec is the canonical example: psexec.exe and psexesvc.exe SHA-1s light up on VirusTotal because every detection vendor has tagged them as "hacktool", "remote admin tool" or similar, but they are also signed Sysinternals binaries used by half the IT departments in the world. The hash is real malware-adjacent, but the host context decides whether it matters. Same story for procdump.exe, nircmd.exe, 7za.exe, and most of the LOLBAS / GTFOBins catalogue.

The second is shared loaders. Cobalt Strike's default beacon stagers, Sliver implants without recompilation, and Metasploit shellcode runners get reused across thousands of engagements. A hit on a Cobalt Strike default-config beacon hash means "someone deployed an off-the-shelf C2", not "you are facing the same threat actor as the FireEye report". Be careful about attribution from a hash alone.

The defensive workflow is to treat every threat-intel hit on a commodity tool as a yellow flag, not a red one. Look at LowerCaseLongPath. A signed PsExec under C:\Program Files\Sysinternals\ is different from a renamed PsExec called chrome_helper.exe under \AppData\Local\Temp\. The hash is the same; the context is everything.

Attacker-controlled fields are not the hash#

LinkDate is the PE header's IMAGE_FILE_HEADER.TimeDateStamp. It is whatever the compiler stamped, which is whatever the attacker told the compiler. Set to 1970-01-01 in half of commodity malware, set to a plausible-looking 2019 value in better samples, set to match a Microsoft binary in the polished ones. Do not build timelines on it.

OriginalFileName and ProductName come from the PE version resource. Also attacker-controlled. Less commonly tampered with than LinkDate, because messing with version resources can break code signing and breaks installer logic, but I have seen OriginalFileName = svchost.exe on cleartext Mimikatz droppers more than once.

FileId is computed by the operating system after the file landed on disk. The attacker cannot influence it without re-engineering the binary, at which point the new file is a different file with a different hash, which is exactly what you want for tracking.

Size is filesystem-truthful. Mismatches between Size and what a known-good copy of the supposedly-same binary should be is a cheap way to flag patched or trojanised system files.

Hash-pivoting at scale, briefly#

If you are doing this across thousands of hosts:

  • Collect Amcache hives via Velociraptor (Windows.Forensics.Amcache), KAPE (Amcache target), or your EDR's file-collection. All three handle the file lock correctly. Do not use xcopy against a live hive.
  • Normalise to a single hash column. Sometimes parsers preserve the 0000 prefix, sometimes they strip it. Pick one form and enforce it.
  • Bulk-submit to VirusTotal's v3 /files/{hash} endpoint, respecting rate limits. Cache responses. A SHA-1 you have seen this week does not need re-querying.
  • Maintain an internal allowlist of signed-Microsoft hashes you have already triaged. The Amcache returns the same OS binaries on every host; you do not want to look at cmd.exe ten thousand times.
  • Cross-correlate hits to Prefetch, Sysmon EventID 1 (ProcessCreate, includes the binary hash), and EDR telemetry. The Amcache says the file was there. The other artifacts say what it did.

The parser on this site is built around this workflow. Drop the hive, get a table of SHA-1s and paths, copy-paste into VirusTotal's batch lookup. No upload, which matters when the hive came from a regulated environment that does not want hashes leaving the perimeter.

Further reading#

Related posts

Back to all posts