Registry Parser
All articles

Loading and mounting registry hives: from boot to RegLoadKey

8 min read

The registry you browse in regedit is not a file. It is a runtime view assembled from a set of separate hive files, each one loaded and mounted into a single namespace by the kernel. To load a registry hive is to splice a regf file into a live tree at a chosen mount point; to unmount it is to detach that subtree without touching the file on disk. Understanding when each hive is loaded, who loads it, and where it lands — including the case where someone calls RegLoadKey to mount a hive that has no business being there — is the difference between trusting a live registry snapshot and knowing exactly what it is missing.

This is part of an ongoing look at registry internals; for the structure of the files themselves, see the regf hive file format in practice and the hive layout overview.

What loads at boot, and in what order

The visible top-level keys — HKLM, HKU, HKCU, HKCR, HKCC — are not all hives. HKCU, HKCR, and HKCC are links and merged views layered over the real backing hives. The hives that actually get loaded from disk during boot live under \Registry\Machine and \Registry\User in the kernel's object namespace.

The kernel cannot bootstrap itself without configuration, so there is a chicken-and-egg problem at the very start. The boot loader (winload) reads the SYSTEM hive off disk before the kernel is even running and hands it to the kernel as part of the boot block. SYSTEM has to come first because it contains CurrentControlSet, which lists the boot-start drivers and services the kernel needs to get any further. Without SYSTEM there is no boot.

Once the kernel is up, it brings the rest of the machine hives online from %SystemRoot%\System32\config:

  • SOFTWARE — application and OS configuration, mounted at HKLM\SOFTWARE.
  • SAM — local account database, at HKLM\SAM.
  • SECURITY — the LSA secrets and local security policy, at HKLM\SECURITY.
  • DEFAULT — mounted at HKU\.DEFAULT; this is the profile hive of the local system context, not a template for new users, despite the name implying otherwise.

Alongside these there are volatile hives that never touch disk: the HARDWARE hive (HKLM\HARDWARE), rebuilt from scratch on every boot by the Plug and Play manager, and the per-boot pieces of HKLM\SYSTEM. A volatile hive has no regf file, which is precisely why you will never find one in an offline acquisition — there is nothing to find. If you want the hardware enumeration that was live at acquisition time, you need a memory image, not a disk image.

User hives: mounted at logon, gone at logoff

None of the per-user data is loaded at boot. When a user authenticates, the profile service mounts that user's hives under HKU\<SID>, where the SID is the account's security identifier:

  • NTUSER.DAT, from the root of the user's profile directory, mounted at HKU\<SID>. This is the hive behind HKCU for the interactively logged-on user — HKCU is just a link to the HKU\<SID> subtree of whoever owns the current process token.
  • UsrClass.dat, from AppData\Local\Microsoft\Windows, mounted at HKU\<SID>_Classes. This holds per-user COM registrations and file associations and is the user-specific half of the merged HKCR view.

At logoff these subtrees are unmounted and the files are flushed back to disk. The operational consequence is blunt: a user who is not logged on has no hive in the live registry. On a multi-user box you will see HKU\<SID> entries only for the SIDs with an active session plus a handful of service accounts. Everyone else's NTUSER.DAT is sitting on disk, untouched, waiting for a logon that may not happen during your acquisition window. For deciding which files you actually need, see which registry hive to grab.

RegLoadKey: mounting an arbitrary hive

Boot and logon are the automatic paths. The manual path is RegLoadKey. It creates a subkey under HKEY_LOCAL_MACHINE or HKEY_USERS and loads a hive file into that subkey — those are the only two permitted roots, because every other predefined handle (HKEY_CLASSES_ROOT, HKEY_CURRENT_USER) is itself a view over one of them. The signature is straightforward:

LSTATUS RegLoadKey(
  HKEY    hKey,      // HKEY_LOCAL_MACHINE or HKEY_USERS
  LPCWSTR lpSubKey,  // the mount-point name to create
  LPCWSTR lpFile     // the hive file on disk
);

RegUnLoadKey reverses it, detaching the subtree without modifying the file. Both operations require the calling process to hold SE_RESTORE_NAME and SE_BACKUP_NAME — administrative privileges, in practice — which is why this is normally the province of backup software, installers, and analysts. The command-line front end is reg load HKLM\TempHive C:\path\to\hive and reg unload HKLM\TempHive.

This is exactly what offline analysis does, one file at a time. To inspect a dead box's NTUSER.DAT on a running Windows machine, you reg load HKU\victim C:\evidence\NTUSER.DAT, read what you need, and reg unload. The hive is mounted into a live registry that has its own SYSTEM, SOFTWARE, and so on, so any class-resolution or SID-translation you do is happening against the analysis host's context, not the evidence host's — a subtle trap when resolving SIDs to names or following symbolic links.

App hives: RegLoadKey without the privilege

RegLoadKey's privilege requirement was a real obstacle for modern app packaging, where a sandboxed application wants its own private settings store without administrative rights. The answer is RegLoadAppKey, available since Vista and used heavily by UWP/MSIX-style packaged apps.

An application hive is different in three ways that matter forensically. First, it loads under \Registry\A, a special root that cannot be enumerated or traversed. You cannot walk to it through the namespace; an attempt to open a key by absolute path under \Registry\A returns STATUS_ACCESS_DENIED. The only way to touch the hive is through the handle that RegLoadAppKey returned. Second, there is no per-key security — the whole hive is governed by the hive file's security descriptor, so anyone who can open the file can load and modify all of it, and you cannot set an ACL on an individual key inside it. Third, the hive auto-unloads when the last handle to it closes, with no explicit unload call. On Windows 8 and later a single process can hold multiple app hives open at once; on Windows 7 it was one at a time.

For an investigator, the takeaway is that app-hive data is real registry state that does not appear in any enumeration of the live tree. You find these hives the same way you find anything else: as .dat files on disk, which you load explicitly.

Differencing and virtualization, briefly

Two more mechanisms layer hives rather than simply mounting them. Registry virtualization is the legacy-compatibility shim that silently redirects writes to protected HKLM\SOFTWARE locations into a per-user virtual store under the user's UsrClass.dat, so a non-elevated legacy app that thinks it is writing machine-wide config is actually writing per-user. Differencing hives are the container primitive behind Windows containers and some app-isolation features: a base hive plus an overlay where the overlay records only the deltas, presented as a single merged view. Both mean that what an application sees and what is physically stored in any one hive file can diverge. Offline, you read each backing file as it is; you do not get the merged runtime illusion unless you reconstruct it yourself.

Why this matters at acquisition time

Pull all of the above together and the forensic rule is simple: at acquisition time, only the currently-loaded hives are reflected in the live registry's memory. A live reg export or an in-memory snapshot captures the machine hives, the logged-on users' NTUSER.DAT and UsrClass.dat, plus whatever app hives and RegLoadKey-mounted hives happen to be open at that instant. Logged-off users, unmounted hives, and the on-disk regf files in their last-flushed state are simply absent.

That same transience is an offensive primitive. An attacker with the necessary privilege can RegLoadKey a hive crafted to point a run key, service, or shell extension at a payload, trigger execution, and RegUnLoadKey it — leaving the live registry clean for any tool that only enumerates currently-mounted keys. The RegLoadAppKey path is stealthier still, since \Registry\A is not enumerable at all. Defensively, the answer is not to trust a point-in-time view of the mounted registry. Hive-load and hive-unload are auditable operations (and SeRestorePrivilege/SeBackupPrivilege use is itself a signal); collect those events, and treat every regf file on disk — and in Volume Shadow Copies — as a separate piece of evidence regardless of whether it was mounted when you arrived.

This is exactly why a tool like Registry Parser loads each hive file you give it explicitly, rather than reading "the registry." There is no single registry to read offline. There are hive files, each one a self-contained regf document, and you mount the ones you care about — NTUSER.DAT for one user, then SYSTEM, then SOFTWARE — exactly as the kernel would, but under your control and with nothing hidden behind a non-enumerable root. You can parse a hive in your browser and load each file deliberately, which is the only way to be sure you have seen what was actually on disk.

Further reading