Registry Parser
All articles

Stable, volatile and linked: the Windows registry hive layout

9 min read

The tree you see in regedit is a fiction. Useful, but a fiction. There is no single object on disk called "the registry," and several of the keys you can browse on a live machine have no backing file at all. Understanding the registry hive layout — which parts come from disk, which parts live only in RAM, and which parts are symbolic links pointing somewhere else entirely — is the difference between an analyst who knows what an offline hive set can and cannot contain, and one who keeps looking for keys that were never written down.

This post covers the logical assembly: how the kernel stitches loaded hives into one namespace, how the predefined HKEY_* handles map onto it, what a volatile hive is, and what volatile storage means for a dead-box investigation. For the byte-level mechanics of a single hive file, read the regf hive format piece first; this one sits a layer above it. For the broader map, see Windows registry internals.

The kernel namespace, not the regedit tree

Inside the kernel, the registry is a single namespace rooted at \Registry. Everything else is a mount. Under \Registry\Machine are the hives that regedit surfaces as HKEY_LOCAL_MACHINE; under \Registry\User, the per-user hives. A master hive — \Registry itself — holds the structure tying the others together. The kernel has no notion of "HKLM" or "HKCU"; those are strictly a user-mode convenience.

Each loaded hive contributes a subtree. The kernel knows where to splice it because the hive is mounted at a path in the namespace, the same way a filesystem is mounted at a directory. SYSTEM mounts at \Registry\Machine\SYSTEM, SOFTWARE at \Registry\Machine\SOFTWARE, a user's NTUSER.DAT at \Registry\User\<SID>, and so on. The composite tree you browse is the union of all of them.

This matters offline because each hive is a separate file. Loading a dead-box image means opening SYSTEM, SOFTWARE, SAM, SECURITY, DEFAULT, the per-user NTUSER.DAT and UsrClass.dat files (and possibly Amcache), then reconstructing the namespace by knowing where each one mounts. Miss a hive and you miss an entire subtree — silently, because nothing in the other files references it.

Root cell versus logical root key

Every hive file has exactly one root cell — the nk record whose offset is recorded in the base block, the top of that file's internal key tree. That is a property of the file. A logical root key like HKLM or HKU is something else: a label the system pins onto a mount point.

For HKLM the relationship is many-to-one. HKEY_LOCAL_MACHINE is not one hive; its children — SYSTEM, SOFTWARE, SAM, SECURITY, HARDWARE — are each the root cell of a different hive (except HARDWARE, below). HKLM itself is just a junction where those roots are gathered. Open a single SYSTEM hive in a parser and its root cell is what you'd see at HKLM\SYSTEM on the live box, with everything below it intact and everything beside it (SOFTWARE, SAM) absent — those are other files.

A path like HKLM\SOFTWARE\Microsoft\... therefore means "open the SOFTWARE hive file, start at its root cell, walk down." There is no SOFTWARE key inside the SOFTWARE hive; the hive's root cell is that key.

Predefined handles: HKEY_* are user-mode aliases

The HKEY_* constants are always-open predefined handles that user mode hands to the registry API as entry points. KernelBase.dll translates each one into a kernel namespace path before any syscall happens. The standard mappings:

  • HKEY_LOCAL_MACHINE\Registry\Machine
  • HKEY_USERS\Registry\User
  • HKEY_CURRENT_USER\Registry\User\<SID> for the calling user's SID
  • HKEY_CLASSES_ROOT → a merged view of HKLM\SOFTWARE\Classes and HKCU\Software\Classes, with the per-user entries taking precedence
  • HKEY_CURRENT_CONFIG → an alias for HKLM\SYSTEM\CurrentControlSet\Hardware Profiles\Current

Two of these — HKCR and HKCC — are not hives or even single keys. HKCR is a runtime merge of two locations; HKCC is an alias onto a deep path. Neither exists as a file. Offline you reconstruct HKCR yourself by reading both SOFTWARE\Classes and the user's Software\Classes (the latter physically lives in UsrClass.dat, not NTUSER.DAT) with the same precedence. A tool that "shows you HKCR" is computing it.

Stable and volatile storage inside a hive

Here is the part that trips up people who think of a hive as purely a file. A loaded hive has two storage areas: stable and volatile. Stable storage is the on-disk representation, continuously synchronized so the file stays consistent across a sudden power loss. Volatile storage exists only in memory for the current boot and is never written to the file. In a live debugger view of a loaded hive you can see both — each hive reports a Stable Length and a Volatile Length side by side.

A key created with REG_OPTION_VOLATILE lands in the volatile storage area of its hive. Per Microsoft's documentation, such a key "is stored in memory and is not preserved when the corresponding registry hive is unloaded" — and for HKLM that unload happens only at a full system shutdown. So volatile keys can survive reboots-that-aren't (fast startup is a partial shutdown by default and muddies this), but they do not survive a real shutdown, and RegSaveKey deliberately skips them. Volatile subkeys can also hang off otherwise-stable parents: the hive file on disk holds the stable parent and none of its volatile children.

Volatile hives: HKLM\HARDWARE has no file

The volatile concept scales up to entire hives. Some hives are file-backed: they exist on disk and in memory and are synchronized. Others are volatile hives: they live only in memory, get built during boot, and vanish at shutdown with no backing file ever created.

The canonical example is HKLM\HARDWARE. It is reconstructed every boot from firmware and hardware enumeration — detected processors, firmware tables, the device map. There is no HARDWARE file in C:\Windows\System32\config\ to acquire (the master hive \Registry is likewise volatile). So when you browse HKLM on a live machine and see HARDWARE populated with DESCRIPTION\System\CentralProcessor and ACPI tables, you are looking at memory that exists nowhere on the disk you are about to image.

What this means for a dead-box image

State the implication plainly, because it is the whole point of knowing the layout:

An offline hive set cannot contain anything that lived in volatile storage. Pull the hives from a powered-off machine (or a forensic image of its disk) and you get exactly the stable storage of each file-backed hive, replayed against its transaction logs. You do not get:

  • HKLM\HARDWARE in any form. No CPU enumeration, no firmware tables, no live device map. If your question depends on what hardware the machine saw at last boot, the disk image will not answer it. Memory forensics will.
  • Any REG_OPTION_VOLATILE key, anywhere. Malware and legitimate software both use volatile keys precisely because they evaporate. A volatile key holding a decryption parameter, a runtime flag, or an IPC handle is gone the moment the machine powered down, and it was never in the file to begin with.
  • The merged HKCR or the HKCC alias as such — though here you can rebuild them, since the underlying stable data (SOFTWARE\Classes, UsrClass.dat, the Hardware Profiles path) is on disk.

Conversely, everything stable is recoverable: the full SYSTEM/SOFTWARE/SAM/SECURITY trees, every per-user hive, and — crucially — deleted stable cells sitting in free space, because those were written to the file before deletion. The stable/volatile split is also why live acquisition or a memory capture sometimes beats a clean disk image: it is the only way to see the volatile half.

Symbolic links: REG_LINK ties the tree together

The composite tree is not just unions and mounts. Parts of it are stitched together with registry symbolic links — keys of type REG_LINK carrying a SymbolicLinkValue that names a target path. Resolving a path through such a key transparently redirects to the target. (User code opts into seeing the link itself with REG_OPTION_OPEN_LINK; Microsoft's guidance is that symbolic links "should only be used when absolutely necessary.")

Two links you must know:

  • HKEY_CURRENT_USER → \Registry\User\<SID>. HKCU is not a separate hive. It is a link (resolved per the calling token's SID) into HKU. The data physically lives in that user's NTUSER.DAT, mounted under \Registry\User\<SID>. Offline, "HKCU" simply is the NTUSER.DAT you loaded; there is no separate artifact to find.
  • CurrentControlSetControlSet001 (or ControlSet002, etc.). Inside the SYSTEM hive, CurrentControlSet is a volatile link created at boot pointing at whichever numbered control set the kernel selected. The on-disk SYSTEM hive contains ControlSet001, possibly ControlSet002, and a Select key telling you which is Current — but no CurrentControlSet key, because that link is volatile and built at boot. This is the single most common offline gotcha: analysts grep an offline SYSTEM hive for CurrentControlSet\Services\... and find nothing, because the path that exists on disk is ControlSet001\Services\.... Read the Select\Current value to learn which set was live, then walk the numbered set. The mechanics of that selection are their own subject — see control sets and Select.

A running system holds more REG_LINK keys (class redirections, the HKCC alias), but HKCU and CurrentControlSet are the two that change how you navigate an offline hive.

Putting it together

The live registry is an assembled view: file-backed hives mounted into the \Registry namespace, plus volatile hives like HARDWARE built fresh at boot, plus volatile keys scattered through otherwise-stable hives, all knitted together with REG_LINK symbolic links and surfaced to user mode through a handful of always-open HKEY_* predefined keys. A dead-box image gives you the stable storage of the file-backed hives and nothing else. Knowing the registry hive layout tells you, before you waste an hour looking, that HARDWARE will be empty, that CurrentControlSet won't exist by that name, and that any volatile key is a question for memory, not disk.

Explore it hands-on: drop a SYSTEM or NTUSER.DAT hive into Registry Parser to parse a hive in your browser — nothing leaves your machine — and watch how the root cell of one file corresponds to one subtree of the live namespace.

Further reading