The Windows registry keys that pay back the time in DFIR
8 min read
The Windows registry is one of those artifacts where the documentation is exhaustive and the prioritization is missing. There are tens of thousands of keys on a default install. You will look at maybe twenty of them on most investigations. The trick is knowing which twenty, and knowing what each one is actually telling you when it lights up.
This post is the short list I keep coming back to. Not an exhaustive reference. A working set.
Which hives to grab, in what order
If somebody hands you a host and tells you they think it is compromised, you want five files plus their transaction logs:
C:\Windows\System32\config\SYSTEM— services, drivers, the liveControlSet, the Shimcache.C:\Windows\System32\config\SOFTWARE— installed applications, theRunkeys, the network list service.C:\Windows\System32\config\SECURITY— local security policy, audit configuration, cached domain credentials (DCC2 hashes).C:\Windows\System32\config\SAM— local accounts and password hashes. Paired withSYSTEMto decrypt.C:\Users\<user>\NTUSER.DAT— per-user settings, includingUserAssist,RecentDocs, and the per-userRunkeys.
Each of those has a transaction log pair (.LOG1, .LOG2). Always acquire those alongside the main hive. Replaying the logs recovers in-flight writes and occasionally surfaces records that never reached the main file. This single habit has rescued more investigations than any other.
If you suspect deletion of registry data, also pull every NTUSER.DAT from C:\Users\ (including any profile that has not logged in recently — the deleted-but-not-cleaned-up profiles), and look for UsrClass.dat next to each one.
Volume Shadow Copies are gold. Most well-instrumented Windows installs keep at least a week of VSS snapshots, and comparing hives across VSS snapshots is how you catch attackers who edited a key and put it back.
The persistence keys, in priority order
There are roughly a hundred persistence locations in the registry, but a handful catch most actual incidents:
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run and RunOnce — boot-time execution. The first place to look. HKCU\Software\Microsoft\Windows\CurrentVersion\Run is its per-user equivalent. Both pay back the time.
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon — Userinit, Shell, and Notify keys. Modified Userinit values are an old technique that still works on improperly hardened hosts. Defaults are well known; deviation is interesting.
HKLM\SYSTEM\CurrentControlSet\Services\ — every Windows service. Look at ImagePath and ServiceDll for binaries in user-writable directories. Services running from \AppData\Local\Temp\ or \Users\Public\ are almost always malicious.
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\ — the IFEO key. A legitimate debugger redirection mechanism that is abused for persistence and process hijacking. Any Debugger value pointing at an unusual binary is worth investigating. The classic is \sethc.exe or \osk.exe with a debugger pointing at cmd.exe (sticky-keys backdoor on RDP login screens).
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders and User Shell Folders — startup folder redirection. Attackers occasionally point Common Startup at a writable directory and drop a payload there.
HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\BootExecute — applications to run during boot. Defaults are autocheck autochk *. Anything else is interesting.
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tasks — scheduled tasks (the registry-backed half; the XML half is in C:\Windows\System32\Tasks\). Comparing the two often surfaces tasks that have been hidden by editing one half but not the other.
HKCU\Software\Microsoft\Windows NT\CurrentVersion\Windows\Load — per-user load value. Rare in legitimate use; almost always malicious when set.
If you are doing a quick pass, run autoruns from Sysinternals against a mounted hive. It checks all of these and many more. The output is verbose but the column-sort makes triage tractable.
UserAssist: the ROT13 oddity that still works
HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\UserAssist\{GUID}\Count\ records every program a user has launched from the Start menu, Explorer or the Run dialog. The key names are ROT13-encoded (yes, in 2026, ROT13). The values include a run count and the FILETIME of the last run.
This is one of the best per-user execution artifacts on the system. Better than Prefetch for the "who ran it" question, because UserAssist lives in the user's NTUSER.DAT and is therefore unambiguous about attribution.
Edge cases worth knowing:
- Programs launched via the command line, scheduled task, or service do not show up. UserAssist only tracks GUI-driven launches.
- The
LastRuntimestamps update on every launch, which makes them useful but volatile. Pull the value at acquisition time; do not assume it will be the same an hour later. - The two GUIDs that matter are
CEBFF5CD-ACE2-4F4F-9178-9926F41749EA(executable runs) andF4E57C4B-2036-45F0-A9AB-443BCFE33D9F(shortcuts). Tools sometimes only display one.
ShellBags: messy, contested, useful
HKCU\Software\Microsoft\Windows\Shell\BagMRU\ and the parallel keys under UsrClass.dat record which directories a user has navigated to in Explorer, including directories on removable media and network shares. The keys are nested and reference each other through a separate Bags\ tree, which is why every analyst has at some point cursed at ShellBags.
When the question is "did this user open this folder", ShellBags answer it. When the folder is on a USB stick that has since been removed, ShellBags may be the only artifact that survives.
The catch: ShellBag parsing is harder than the format suggests, because the structure has changed across Windows versions and because Explorer writes the bags lazily. Three tools that do it correctly are Eric Zimmerman's ShellBagsExplorer, RegRipper with the shellbags plugin, and the parser on this site. Most ad-hoc Python implementations get a subset of the records right.
Pair ShellBag hits with LNK files and jump lists for the strongest claim about user file activity.
Recently used: the small keys that close cases
A few per-user keys that punch above their weight:
HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\RecentDocs — files the user opened, by extension. ROT13-free this time.
HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\TypedPaths — every path typed into Explorer's address bar. Includes UNC paths.
HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\RunMRU — every command typed into Win+R. People type things into Run that they would never put in their command history.
HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\ComDlg32\OpenSavePidlMRU — files opened or saved through standard Win32 dialogs. Includes file picker history for Office, browsers, and most native apps.
HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\ComDlg32\LastVisitedPidlMRU — the application most recently used to open a given file extension.
If you are reconstructing what a user did during the suspected window, those five keys plus UserAssist will get you 70% of the picture.
The keys that mislead you
HKLM\SYSTEM\Setup\Status\SysprepStatus and the related sysprep keys carry timestamps that look authoritative and sometimes are not. On systems imaged from a master image, the sysprep timestamps reflect when the image was sealed, not when the host was built or first booted. Cross-validate with HKLM\SYSTEM\Setup\Source OS (Updated on YYYY-MM-DD) keys and the MFT timestamps on the SYSTEM hive itself.
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\InstallDate is a Unix epoch in a registry. It is the install date as Windows knows it. After certain in-place upgrades it gets rewritten, so it is not always the first install.
The LastWrite time of a key is the time the key (not its values) was last modified. If you see a LastWrite near the suspected incident time on a persistence key, that is interesting. If you see it on a key Windows updates routinely (Software\Microsoft\Windows\CurrentVersion\Explorer\StreamMRU and friends), it is noise.
Anti-forensics: what attackers do, and what survives
The registry is writable by anything with sufficient privilege. Attackers who know what they are doing:
- Edit and revert. Set a
Runkey, drop the payload, run it, delete the value. TheRunkey'sLastWritewill reflect the deletion, but the previous value is sometimes recoverable from the transaction logs and almost always from VSS snapshots. - Hide via permissions. Take ownership of a key, set permissions so SYSTEM can read but Administrators cannot, and write persistence there. Tools like
nirsoft RegScannerandRegRipperrunning in SYSTEM context (or against an offline hive) bypass the trick. - Hide via null-character names. Registry key names containing embedded null bytes are invalid via the Win32 API but legal at the NT level. The Windows regedit UI cannot see them; offline parsers can. This is an old trick that still works against unsophisticated checks.
- Clear MUICache and UserAssist. Possible, but the registry is a copy-on-write tree, so unallocated cells in the hive still contain the cleared values. Parsers like RegRipper's
delplugin and yarp recover them.
The hive transaction logs are the most overlooked safety net. Replay them. Acquire VSS snapshots. Run a recovery mode on every hive before you start the real analysis.
A working order of operations
For a standard "is this host compromised" pass:
- Acquire
SYSTEM,SOFTWARE,SECURITY,SAM, and everyNTUSER.DATplus their.LOG1/.LOG2andUsrClass.datfiles. - Run a recovery pass on each hive. Some parsers do this automatically.
- Dump the persistence keys above. The Sysinternals
autorunsoutput is the fastest way. - Pull UserAssist, RecentDocs, RunMRU and TypedPaths from each user hive.
- Diff against VSS snapshots if available. Persistence that appears in the live hive but not in yesterday's snapshot is suspicious.
- For any persistence value pointing at a binary, pivot to AmCache, Prefetch, and the MFT for the file itself.
The diff step is what separates passable from good registry forensics. Anyone can dump a Run key. Knowing that the Run key was empty in the snapshot from two days ago is what makes the finding defensible.
Reading hives in the browser
The parser on this site reads regf hives entirely client-side, with transaction-log replay. Drop a hive in and you get the keys-and-values tree, the LastWrite timestamps, and the standard plugins covering the persistence locations above. No upload, which matters when the SAM or SECURITY hive is in scope.
Further reading
- Harlan Carvey, RegRipper — the canonical offline plugin-based parser. Read the plugin source; it is the best living reference for what each key actually contains.
- Maxim Suhanov, yarp — the lowest-level library, good for understanding the hive format.
- Microsoft, Registry Hives — vendor reference. Less useful than RegRipper's plugins, but officially canonical.
- The SANS DFIR poster on Windows Registry Forensics — single-sheet cheat sheet, worth printing.
The registry is one of those artifacts where ten minutes of reading the right keys beats two hours of reading the wrong ones. The list above is mine; build your own from it.