Registry Marriage

“The Registry” is something most, if not all Windows users have heard of – but I would guess that only a fraction understand what it is or does, so I shall give a high-level overview here to enlighten those people…

The registry is essentially a hierarchical database – at the top level we see a collection of HKEY objects, for example from my W2K8R2 server the Registry Editor tool show:
> HKEY_CLASSES_ROOT
> HKEY_CURRENT_USER
> HKEY_LOCAL_MACHINE
> HKEY_USERS
> HKEY_CURRENT_CONFIG

Clicking on the marker to the left of any of these items will expand it and show the keys underneath – much like browsing a folder structure through Explorer.

 

A common mistake when discussing the registry is to incorrectly call those things we assign data to as “keys”.

If a key is analogous to a FOLDER on disk, then a value is a FILE (and actually holds data).

The keys are just containers, forming part of the path to one or more values.

Keys have no type, they just “are”, whereas values can be of the following types:
String Value (REG_SZ)
Binary Value (REG_BINARY)
DWORD (32-bit) Value (REG_DWORD)
QWORD (64-bit) Value (REG_QWORD, 64-bit Windows only)
Multi-String Value (REG_MULTI_SZ)
Expandable String Value (REG_EXPAND_SZ)

NOTE: When querying the registry, the type of the value must match or we get no result, so when you see the summary of details to manually add a value, make sure you get it correct.

Each key has an unnamed REG_SZ value when it is created, which cannot be renamed or deleted – this is displayed as “(Default)” in the Registry Editor but is referenced with a null name.
(If you look at an exported .reg file of a key where the “(Default)” value has been given “xyz”, you will see under the key: @=”xyz” .)

 

If you have ever used Process Monitor to log registry I/O for troubleshooting, there are a few things to be aware of regarding the Result field…

“NAME NOT FOUND” is not always an error – code often probes for the existence of a value in order to make a decision about how it will behave next, but if there is no such value (resulting in the return result which looks like an error) then we assume the default behaviour, whatever it may be.

“BUFFER OVERFLOW” is also not an error, despite the prevalence of “buffer overflow exploits” by malware.  In this context we are querying the registry for the data held in a value which does not have a fixed length, so the first query we make we say our buffer is zero characters long – the registry API will report “you don’t have enough space to hold this data” (buffer overflow), and how many characters you are short… now the call can be made again with a buffer exactly the right size to hold the data – thus avoiding potential for overflowing the buffer.
Ref: MSDN ZwQueryValueKey API

 

There are some special cases to be aware of when browsing the registry online…

HKEY_CURRENT_USER is a pointer to the user profile hive user HKEY_USERS which is used by the processes running in that particular session – if you consider a Remote Desktop Server with 10 users logged on, each of them has their own concept of “current user” but would like to be independent of each others’ sessions whilst using a standard path.
For my user account, it is easier to refer to HKEY_CURRENT_USER than to HKEY_USERS\S-1-5-21-1721254763-462695806-1538882281-2548689.

[ NOTE: HKEY_CURRENT_USER is abbreviated to HKCU ]

 

Under HKEY_USERS you will also see an extra key per (non-BUILTIN) user that is (or has been) logged onto the server, that ends with _Classes – this is the part of the user profile that never roams as it is machine-specific.
This is mounted as HKCU\SOFTWARE\Classes, and also merged with HKEY_LOCAL_MACHINE\SOFTWARE\Classes to be presented as HKEY_CLASSES_ROOT – the per-user definitions overriding the system default ones where a collision occurs.

[ NOTE: HKEY_LOCAL_MACHINE is abbreviated to HKLM, whilst HKEY_CLASSES_ROOT is abbreviated to HKCR ]

For this reason, HKCR is really only useful to read the “effective setting” of a particular object, and a decision needs to be made when wanting to update a value as to whether it should be per-machine (HKLM\SOFTWARE\Classes) or per-user (HKCU\SOFTWARE\Classes) – the result is seen instantly under HKCR.

 

Under HKLM\SYSTEM there are a number of ControlSetxxx keys, and one CurrentControlSet key – the latter is just a reparse point to one of the other keys… but how to know which one?
If you look at the value Current under the key HKLM\SYSTEM\Select then you can see which is being used (you can also see from the other values which was the last control set that failed and which was the last known good).

Traditionally we had just ControlSet001 and ControlSet002 to toggle between – but from Vista onwards we can go beyond this whenever a system is restored.

As with HKCU, we only care about “effective” settings under HKLM\SYSTEM\CurrentControlSet, and any changes here will be reflected in the corresponding ControlSetxxx key only – so if you have a problem that occurs “every other boot” then here is where you want to take a look (identify which is the bad control set and rename the key when it is not in use).

 

HKEY_CURRENT_CONFIG is a pointer to HKLM\SYSTEM\CurrentControlSet\Hardware Profiles\Current, and is an indicator to the hardware profile in use.

 

HKLM\HARDWARE is a key that is dynamically built when the system starts up, an enumeration of the buses and devices that comprise the system – it would make little sense to have this stored as non-volatile data as this way we know the key should reflect the underlying hardware more reliably.

 

There is a SOFTWARE\Policies sub-key under both HKCU and HKLM – this is where group and local policy settings are applied in order to have an effect whilst they are active, per-user and per-machine respectively.

This is also why you will see a lot of queries for non-existent keys and values under these 2 locations when running Process Monitor when doing certain activities – the process is checking to see if there is a setting defined by a system administrator which will take preference over any locally-defined setting.
Given that there are thousands of potential settings for many component parts of Windows, there is a lot of this kind of checking going on all the time, most getting “not found” as a result, but as explained this is not an error.

 

Note that I said “online” above – if you mount a raw registry hive from the %systemroot%\SYSTEM32\CONFIG folder of a system that is not currently booted, you will not see the merged, dynamic or reparsed registry keys.

It is useful to be aware of this path in case you end up with an unbootable system due to registry corruption – there is a RegBack sub-folder which contains a backup of the hives from the time the system was installed, should it be needed in an emergency.

The files on disk that comprise the registry:
DEFAULT
SAM
SECURITY
SOFTWARE
SYSTEM

Note that there are no file extensions, they are memory-mapped at system startup and are not accessed other than through the APIs.

 

For more information, check out TechNet (covers up to Windows Server 2003 R2, but the principle is the same) or the book Windows Internals Fifth Edition.