Amcache.hve and the Shimcache are Windows compatibility subsystem artefacts that consistently surface attacker tool execution during investigations. Attackers rarely think to clear them because they are not obviously security-relevant, and most automated cleanup scripts only target the locations that are written about in red team playbooks. These artefacts can place an attacker tool at a specific location at a specific time even after the file itself has been deleted.
Understanding what each artefact records
The Shimcache (AppCompatCache) and Amcache serve different purposes and have different forensic value. Understanding the distinction is important because confusing them leads to incorrect conclusions in investigations.
// SHIMCACHE:
// Registry location: HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\AppCompatCache
// What it records: file PRESENCE (not execution, from Vista onwards)
// Why it exists: application compatibility layer caching
// Key fields: file path, last modified timestamp
// Coverage: every executable touched by the filesystem, even if not run
// Forensic value: proves a file existed on this system at this path
// even if the file was deleted
// DOES NOT prove the file executed (Vista and later)
// AMCACHE:
// Registry location (as a hive): C:\Windows\AppCompat\Programs\Amcache.hve
// What it records: file EXECUTION (actual program runs)
// Why it exists: application compatibility and telemetry
// Key fields: file path, SHA1 hash, compile timestamp, publisher, first execution time
// Coverage: programs that actually ran on the system
// Forensic value: proves a file executed + provides hash for identification
// even if the file was deleted
// SHA1 hash survives renaming and can identify malware
Shimcache: parsing and analysis
// Extract the SYSTEM hive from a live system
reg save HKLM\SYSTEM C:\ir\SYSTEM.hive /y
// Extract from a forensic image
// Mount the image first, then copy:
cp /mnt/image/Windows/System32/config/SYSTEM /tmp/SYSTEM.hive
// Parse with AppCompatCacheParser (Eric Zimmermann toolkit)
// Download: https://ericzimmerman.github.io/
AppCompatCacheParser.exe -f SYSTEM.hive --csv C:\ir\ --csvf shimcache.csv
// Sample output fields:
// ControlSet, CacheEntryPosition, Path, LastModifiedTimeUTC, Executed, Duplicate
// Key analysis: find executables in unusual locations
python3 << EOF
import csv
from datetime import datetime
suspicious_paths = []
with open("shimcache.csv") as f:
for row in csv.DictReader(f):
path = row.get("Path", "")
# Flag executables outside of standard Windows locations
if path and not any(path.startswith(p) for p in [
"C:\\Windows\\", "C:\\Program Files", "C:\\Program Files (x86)"
]):
suspicious_paths.append({
"path": path,
"modified": row.get("LastModifiedTimeUTC", ""),
"position": row.get("CacheEntryPosition", "")
})
suspicious_paths.sort(key=lambda x: x["modified"], reverse=True)
for entry in suspicious_paths[:50]:
print(f"[{entry['position']:4s}] {entry['modified']} {entry['path']}")
EOF
Amcache: parsing and analysis
// The Amcache hive cannot be copied while the system is running
// Option 1: Copy via reg save (may not work for Amcache specifically)
// Option 2: Use a shadow copy or VSS snapshot
// Option 3: Extract from a forensic image
// Parse with AmcacheParser (Eric Zimmermann toolkit)
AmcacheParser.exe -f Amcache.hve --csv C:\ir\ --csvf amcache.csv
// This produces multiple CSV files:
// amcache_UnassociatedFileEntries.csv - programs that ran without being installed
// amcache_ProgramEntries.csv - installed applications
// amcache_DriverBinaries.csv - driver files
// The UnassociatedFileEntries is most interesting for IR
// It contains executables that ran but were never formally installed
python3 << EOF
import csv, hashlib, subprocess
print("Checking Amcache SHA1 hashes against VirusTotal...")
print("(Rate limit: 4 requests/minute for free tier)")
print()
with open("amcache_UnassociatedFileEntries.csv") as f:
for row in csv.DictReader(f):
sha1 = row.get("SHA1", "")
path = row.get("FullPath", "")
first_run = row.get("FileKeyLastWriteTimestamp", "")
if not sha1:
continue
# Flag executables from unusual locations
if not any(path.startswith(p) for p in [
"c:\\windows\\", "c:\\program files"
]):
print(f"UNUSUAL PATH: {path}")
print(f" First execution: {first_run}")
print(f" SHA1: {sha1}")
print(f" VT check: https://www.virustotal.com/gui/file/{sha1}")
print()
EOF
Timeline correlation between both artefacts
// Build a unified execution timeline from both sources
python3 << EOF
import csv
from datetime import datetime
events = []
# Load Shimcache entries
try:
with open("shimcache.csv") as f:
for row in csv.DictReader(f):
path = row.get("Path", "")
ts_str = row.get("LastModifiedTimeUTC", "")
if path and ts_str:
try:
ts = datetime.strptime(ts_str, "%Y-%m-%d %H:%M:%S")
events.append({
"source": "SHIMCACHE",
"time": ts,
"path": path,
"detail": f"File modified/touched"
})
except:
pass
except FileNotFoundError:
print("shimcache.csv not found")
# Load Amcache entries
try:
with open("amcache_UnassociatedFileEntries.csv") as f:
for row in csv.DictReader(f):
path = row.get("FullPath", "")
ts_str = row.get("FileKeyLastWriteTimestamp", "")
sha1 = row.get("SHA1", "")
if path and ts_str:
try:
ts = datetime.strptime(ts_str, "%Y-%m-%d %H:%M:%S")
events.append({
"source": "AMCACHE",
"time": ts,
"path": path,
"detail": f"SHA1={sha1}"
})
except:
pass
except FileNotFoundError:
print("amcache_UnassociatedFileEntries.csv not found")
# Define incident window
incident_start = datetime(2023, 9, 18, 22, 0, 0)
incident_end = datetime(2023, 9, 19, 2, 0, 0)
# Filter and sort by time
window_events = [e for e in events if incident_start <= e["time"] <= incident_end]
window_events.sort(key=lambda x: x["time"])
print(f"Events in incident window ({incident_start} to {incident_end}):")
print()
for e in window_events:
# Highlight executables from suspicious locations
suspicious = not any(e["path"].startswith(p) for p in [
"C:\\Windows\\", "c:\\windows\\",
"C:\\Program Files", "c:\\program files"
])
flag = " <<< SUSPICIOUS LOCATION" if suspicious else ""
print(f"[{e['source']:10s}] {e['time']} {e['path']}{flag}")
if e["detail"]:
print(f" {e['detail']}")
EOF
Practical investigation example
// Scenario: Attacker ran Mimikatz from C:\Users\Public\ and deleted it
// How to find it:
// 1. Shimcache shows the file existed (even if deleted)
grep -i "mimikatz\|mimi" shimcache.csv
// Returns: C:\Users\Public\m.exe (possibly renamed, check the hash)
// 2. Amcache shows the file ran and provides the hash
grep -i "Users\\\\Public" amcache_UnassociatedFileEntries.csv
// Returns: C:\Users\Public\m.exe SHA1=abc123...
// Check SHA1 on VirusTotal: "Win64/Mimikatz.A detected by 68/72 vendors"
// 3. Prefetch confirms the exact run times
Get-ChildItem C:\Windows\Prefetch\*.pf | Where-Object {$_.Name -match "^M\.EXE"}
// M.EXE-3A27C2B8.pf LastWriteTime: 2023-09-18 23:28:44
// The attacker deleted m.exe but the trail is still there across three artefacts
// Shimcache proves it existed at that path
// Amcache proves it ran and provides the hash that identifies it
// Prefetch gives the exact execution timestamp and referenced files