Registry Forensics
The Windows Registry is both a persistence playground for attackers and a rich evidence source for investigators. This chapter covers registry hive structure, the forensically important keys for each attack phase, and how to extract and analyze registry artifacts from both live systems and disk images.
An attacker gained access via a phishing email, ran a PowerShell implant, and established persistence via three different registry locations — a Run key, a service, and an Image File Execution Options debugger hijack. They also modified the LSA protection settings to allow credential dumping. Six days later, you're investigating. The live system is still running. The registry has all of this recorded — the attacker's persistence mechanisms, modified security settings, and evidence of their tooling. This chapter shows how to find it, with and without the live system available.
Registry Hive Files on Disk
The registry is stored as binary hive files on disk. During a forensic investigation, you work with these files directly — either from a live system or from a disk image.
| Hive name | File location | Key contents |
|---|---|---|
| SYSTEM | C:\Windows\System32\config\SYSTEM | Services, drivers, network config, timezone, control sets. Critical for services-based persistence and LSA settings. |
| SOFTWARE | C:\Windows\System32\config\SOFTWARE | HKLM\SOFTWARE — installed programs, startup programs, OS configuration. ShimCache lives here. |
| SAM | C:\Windows\System32\config\SAM | Local user accounts and password hashes (NTLM). Requires SYSTEM key to decrypt. |
| SECURITY | C:\Windows\System32\config\SECURITY | LSA secrets, cached credentials, security policy. Contains the DPAPI system key. |
| NTUSER.DAT | C:\Users\<username>\NTUSER.DAT | Per-user HKCU hive: user's Run keys, recent documents, TypedPaths, UserAssist, MUICache, user-specific settings. |
| UsrClass.dat | C:\Users\<username>\AppData\Local\Microsoft\Windows\UsrClass.dat | Shellbags (directory browsing history). OpenSaveMRU, FileOpenMRU per-application. |
| Amcache.hve | C:\Windows\AppCompat\Programs\Amcache.hve | Execution evidence with SHA-1 hashes. Separate chapter (Ch08). |
HKLM (HKEY_LOCAL_MACHINE) requires admin/SYSTEM privileges to write — persistence there means the attacker elevated privileges. HKCU (HKEY_CURRENT_USER = NTUSER.DAT) can be written by any standard user — persistence there reveals what the attacker did at user-level privilege. An attacker who lands in a standard user context but establishes HKLM persistence has elevated privileges at some point. An attacker with only HKCU persistence may still be at user level — or may have established HKLM persistence elsewhere too. Check both.
Key Registry Locations for Persistence
# Hunt for persistence across common registry locations
# Run on live system or against offline hive with RECmd
# === Run / RunOnce keys ===
$runKeys = @(
"HKLM:\Software\Microsoft\Windows\CurrentVersion\Run",
"HKLM:\Software\Microsoft\Windows\CurrentVersion\RunOnce",
"HKCU:\Software\Microsoft\Windows\CurrentVersion\Run",
"HKCU:\Software\Microsoft\Windows\CurrentVersion\RunOnce",
"HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Run",
"HKCU:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Run"
)
foreach ($key in $runKeys) {
try {
$vals = Get-ItemProperty -Path $key -ErrorAction Stop
$vals.PSObject.Properties |
Where-Object { $_.Name -notmatch "^PS" } |
ForEach-Object {
[PSCustomObject]@{
Key = $key
Name = $_.Name
Value = $_.Value
}
}
} catch {}
} | Format-Table -AutoSize
# === Image File Execution Options debugger hijack ===
# Attacker sets IFEO debugger for a legitimate binary to intercept its launch
Get-ChildItem "HKLM:\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options" |
Get-ItemProperty |
Where-Object { $_.Debugger } |
Select-Object PSChildName, Debugger
# === AppInit_DLLs — DLL loaded into every GUI process ===
Get-ItemProperty "HKLM:\Software\Microsoft\Windows NT\CurrentVersion\Windows" |
Select-Object AppInit_DLLs, LoadAppInit_DLLs
# === Winlogon persistence ===
Get-ItemProperty "HKLM:\Software\Microsoft\Windows NT\CurrentVersion\Winlogon" |
Select-Object Userinit, Shell # Should be: userinit.exe, explorer.exe
# === COM hijacking via user CLSID override ===
# Attackers register a CLSID in HKCU that shadows a legitimate HKLM entry
Get-ChildItem "HKCU:\Software\Classes\CLSID" |
Select-Object -ExpandProperty PSChildName
LSA and Credential Protection Settings
# Check LSA security settings — attackers modify these to enable credential dumping
$lsa = Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa"
# RunAsPPL: 1 = LSA Protected Process enabled (prevents LSASS dump)
Write-Host "RunAsPPL: $($lsa.RunAsPPL)"
# DisableRestrictedAdmin: if 1, Pass-the-Hash via mstsc/RDP is possible
Write-Host "DisableRestrictedAdmin: $($lsa.DisableRestrictedAdmin)"
# wdigest UseLogonCredential: if 1, cleartext creds stored in memory
$wdigest = Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\WDigest" -ErrorAction SilentlyContinue
Write-Host "WDigest UseLogonCredential: $($wdigest.UseLogonCredential)"
# Attackers set this to 1 then wait for a user to log in — cleartext in LSASS
# CachedLogonsCount: how many domain creds are cached locally
Write-Host "CachedLogonsCount: $($lsa.cachedlogonscount)"
UserAssist — GUI Execution Evidence
UserAssist records every program executed through Windows Explorer GUI, including the run count and last execution time. The data is ROT-13 encoded (not encrypted — just obfuscated).
# Parse UserAssist from NTUSER.DAT hive (live system)
# For offline: use RegRipper plugin "userassist" or RECmd
$uaPath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\UserAssist"
Get-ChildItem $uaPath | ForEach-Object {
$guid = $_.PSChildName
$countPath = "$uaPath\$guid\Count"
Get-ItemProperty -Path $countPath -ErrorAction SilentlyContinue |
Select-Object -Property * -ExcludeProperty PS* |
ForEach-Object {
$props = $_
$props.PSObject.Properties | ForEach-Object {
# Decode ROT-13 program name
$decoded = $_.Name -replace '[A-Za-z]', {
$c = [int][char]$_
if ($c -ge 65 -and $c -le 90) { [char](($c - 65 + 13) % 26 + 65) }
elseif ($c -ge 97 -and $c -le 122) { [char](($c - 97 + 13) % 26 + 97) }
else { [char]$c }
}
[PSCustomObject]@{
Program = $decoded
RawName = $_.Name
}
}
}
}
RegRipper for Forensic Analysis
RegRipper is a Perl-based registry analysis tool with plugins for every forensically relevant registry key. It's the fastest way to extract a comprehensive set of forensic artifacts from an offline hive.
# RegRipper — forensic registry analysis
# Available in SIFT Workstation as 'rip'
# Run all plugins against a hive
rip -r /cases/CASE001/triage/C/Windows/System32/config/SOFTWARE \
-f software > /cases/CASE001/parsed/reg-software.txt
rip -r /cases/CASE001/triage/C/Windows/System32/config/SYSTEM \
-f system > /cases/CASE001/parsed/reg-system.txt
# For NTUSER.DAT (per-user) — run against each user's hive
for hive in /cases/CASE001/triage/C/Users/*/NTUSER.DAT; do
username=$(echo $hive | cut -d'/' -f8)
rip -r "$hive" -f ntuser > "/cases/CASE001/parsed/reg-ntuser-${username}.txt"
done
# Run a specific plugin
rip -r SYSTEM -p services # List all services + binpaths
rip -r SYSTEM -p shimcache # AppCompatCache (Shimcache)
rip -r SOFTWARE -p run # All Run keys
rip -r SOFTWARE -p uninstall # Installed programs list
rip -r NTUSER.DAT -p userassist # UserAssist decoded
rip -r NTUSER.DAT -p recentdocs # Recent documents opened
rip -r NTUSER.DAT -p muicache # Programs that appeared in UI (execution evidence)
rip -r NTUSER.DAT -p typedpaths # URLs/paths typed into Explorer address bar
Quick Reference: Forensically Important Registry Keys
| Key | Forensic value |
|---|---|
| HKLM\SYSTEM\CurrentControlSet\Services\<name> | All services including malicious ones — ImagePath shows the executable path. Attacker services often have generic names or paths in unusual locations. |
| HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\InstalledSDB | Shim databases — attackers use custom SDB files to inject DLLs into processes without touching disk. |
| HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\BootExecute | Programs that run at boot before Windows fully loads. Should only contain "autocheck autochk *". Any addition is highly suspicious. |
| HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\TypedPaths | Paths the user typed directly into Explorer address bar — evidence of manual file browsing to specific locations. |
| HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\RecentDocs | Recently opened files per extension — shows what the attacker or user accessed. |
| HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList | All user profiles that have ever logged on to this system — user SIDs and profile paths. |
| HKLM\SYSTEM\CurrentControlSet\Control\Lsa | LSA settings — see credential protection section above. |
Q & A
Q: You have registry hives from a KAPE collection but can't load them into regedit on your analysis workstation because they conflict with the live registry. How do you access offline hives?
Use RegRipper or RECmd (Eric Zimmermann) for scripted analysis — they parse hives as files without loading them into the live registry. For interactive browsing: on Windows, you can load a foreign hive into a temporary key: regedit → HKLM → File → Load Hive → select the file → give it a temporary name. After analysis, unload it from the same menu. This is non-destructive — the original hive file is read-only if you're working from a copy. Alternatively, on Linux with SIFT, hivexsh and hivexget (hivex toolkit) allow shell-style navigation of any hive file. For large-scale analysis across many hives, RECmd batch mode is the most efficient: it runs all configured plugins against all hives in a directory and produces CSV output for each.
Q: Registry timestamps — do registry keys have timestamps and can attackers modify them?
Yes — each registry key has a LastWriteTime timestamp (similar to directory modification time in NTFS). This records when a key or any of its values was last modified. This is valuable forensic evidence: a Run key's LastWriteTime tells you when the attacker added their persistence value. RegRipper reports LastWriteTime for keys in its output. Attackers can modify key timestamps using tools like SetRegTime — so apply the same timestomping suspicion as with file timestamps. If a Run key's timestamp predates the OS install date, or if the timestamp is implausibly round, investigate further. Unlike NTFS, registry key timestamps only exist on keys — individual values within a key don't have their own timestamps, so you know the key changed but can't tell which specific value within it changed or when.