Windows on iSCSI - Part 3/3

March 26 2018

by Markus Partheymueller

As an important step towards automating the creation of Windows disk assets/images, we will take a closer look at the Critical Device Database (CDDB) inside the Windows registry. The goal is to transform any locally installed instance to be bootable from iSCSI without having to run a full installation onto an iSCSI disk before.

In the second part of the iSCSI mini-series, we identified the necessary changes to a normal Windows installation to make it network-bootable. We relied on a previously completed installation to obtain the corresponding registry entries. In this article, we will take it one step further and construct these entries from information we collected using Windows PE.

The CDDB dissected

If you recall this screenshot from the previous article, the CDDB entry was located under the PCI#VEN_xxxx&DEV_yyyy subtree.

CDDB entry for the network adapter
CDDB entry for the network adapter

We will now go through this entry piece by piece to find the essential parts we need for constructing our own CDDB entry.

Generic driver information

Generic driver information
Generic driver information

Right at the top of the entry, we find information about the driver that belongs to this critical device. The important ones are ClassGUID and Service. This tells Windows that the device is a network adapter, and the corresponding driver service is called E1G60. These two values are the essential ones we have to keep in mind. The only variable here is the service name, and this is very easy to determine from either the driver’s .inf file or the registry of a running Windows PE with the driver installed.

The device location (a.k.a. DevicePaths)

The device path describes the location of the device within the PCI tree. In our case, it is PCIROOT(0)#PCI(1E00)#(0100)#PCI(0100). This corresponds to the following lspci -vt output:

lspci output within Windows PE shell
lspci output within Windows PE shell

lspci is not included in Windows PE by default. You can obtain it by downloading the pciutils package.

In order to understand the mapping of this output to the identifier used by Windows, we have to lay some basic PCI knowledge foundations. Windows takes into account the tree property of PCI. Branching off the root bridge (bus 0), there can be additional bridge devices, providing more buses. Devices can provide multiple functions, which essentially translates into unique identifiers for PCI devices (bus, device, function, or BDF). Executing lspci without the tree switch -t yields a representation of the PCI bus using those identifiers. For more detail on PCI, you can check out dedicated articles, e.g. on osdev.

We can now analyze how the device path is constructed: Every section describes a node within the PCI tree (either a bridge or the actual device). In our example, there is a PCI bridge attached to the root bus PCIROOT(0) with device number 1e and function 0. The remaining path sections are of the form PCI(DDFF), where DD stands for the device part, and FF for the function part. For the first bridge, this results in PCI(1E00), the second becomes PCI(0100). Finally, the device itself is listed as device number 1, function 0, which also becomes PCI(0100).

Now that we found our first two important puzzle pieces, we can move on to examine the actual contents of this entry.

Hardware Key

Usually, this part does not contain a lot of essential information, but it has a striking similarity to the Enum section of the registry, which can be found under HKLM\SYSTEM\CurrentControlSet\Enum\PCI. In there, you will find a similar VEN_xxxx&DEV_yyyy key, which in turn contains a subkey called Device Parameters. This subkey directly corresponds to the HardwareKey section of the CDDB entry.

Enum entry of a running Windows instance
Enum entry of a running Windows instance

The Enum section lists all devices that Windows has enumerated in a running system. That means it is possible to extract this from Windows PE as well, as long as the hardware is present.

One noteworthy quirk is that there are elements in there that interfere with the boot process and have to be removed before importing them to the CDDB. At the time of writing, these are InstanceIndex, Routing Info, and Affinity Policy - Temporal. Furthermore, a value named PreInstalled=1 is added.

Software Key

The Software Key subkey contains far more values. From the looks of it, this is basically the entire driver configuration, plus some settings for how Windows handles this driver. It is difficult to tell which values are absolutely essential, because they appear to be somewhat interdependent. Luckily, this section again has a striking similarity to another spot in the registry, this time under HKLM\SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}.

Class entry of a running Windows instance
Class entry of a running Windows instance

This subtree contains a list of network devices Windows has configured. Most of them are internal devices like Miniports, but there will be one that contains a field called DeviceInstanceID that matches the device and vendor ID of the network adapter. The subkeys of this entry need to be copied to the SoftwareKey section, with some modifications.

First of all, values that do not correspond to driver parameters (listed under Ndi\Params) should be removed, except for NetCfgInstanceId, *IfType, *MediaType, and *PhysicalMediaType.

Furthermore, four additional values need to be added:

  • PreInstalled=1
  • BootNIC=1
  • Characteristics=dword:00000084
  • BusType="5"

The Service Entry

The last missing piece is the service entry that describes the actual driver. The essential value here is the ImagePath, which contains the location of the driver binary. This entry can be found in a running Windows instance under HKLM\SYSTEM\CurrentControlSet\services\<service_name>.

Service entry of a running Windows instance
Service entry of a running Windows instance

This entry can also be copied to the same location in the new image. The only modification that might be necessary is to remove the subkeys Enum and Parameters, if present.

Putting it all together

With all those puzzle pieces together, we can summarize the steps to transform a local disk installation:

  • Boot Windows PE (in our case, based on Windows 7) on target machine
  • Retrieve lspci output and determine device path
  • If necessary, load network driver (drvload <driver.inf>)
  • Export class, enum, and service entry
  • Determine PCI vendor/device id
  • Construct CDDB and service entries from the obtained information and registry values
  • Apply the registry changes to the installed OS (either offline or by booting it from disk)

Caveats

The biggest drawback is of course that a machine with the respective hardware is still needed. Unfortunately, any attempt to forge the CDDB entry just from driver files has failed so far. The CDDB mechanism has proven to be fairly sensitive to missing or incorrect information. But the method we discussed in this article is definitely a significant improvement to the previous approach of installing to an iSCSI disk to retrieve the entries.

What next

Given this method, it is possible to incorporate necessary registry modifications in an automated deployment process. Creating or duplicating golden images is very simple, as well as customizing installations during deployment.

For example, given a golden image of a stock Windows 7 installation, customizations can include different sets of software, drivers, or even updates. As an example of this use case, we will discuss deploying an updated Windows 7 image using the Microsoft Deployment Toolkit in an upcoming article.


Share this article: