Tip: Updating the Windows registry using libguestfs and hivex

virt-win-reg is a high level tool for merging Registry changes into a Windows virtual machine, and it’s relatively simple to use. You can also do the same thing using the libguestfs and hivex APIs directly, but it’s a little bit more complicated. This posting explains how to do it the low-level way.

First understand how the Windows Registry is stored in a VM: Although in Windows it appears as a single tree with top level nodes called things like HKEY_LOCAL_MACHINE and HKEY_USERS, this is not how Windows actually stores it. The Registry is split across several files called hives. Hivex is a C library for editing this proprietary file format.

A hive file contains a part of the Registry tree. The main hives of interest are called SOFTWARE, SYSTEM, SECURITY and SAM (without any file extension) and they live in the %systemroot%\System32\Config directory. These hives correspond to HKEY_LOCAL_MACHINE\SOFTWARE, HKEY_LOCAL_MACHINE\SYSTEM etc. There are also per-user hives stored in a location that depends on the version of Windows.

Another thing to understand about the Registry is that when Windows is running it synthesizes “symbolic keys” which don’t really exist in the hive file itself. The most important example is CurrentControlSet which is really a link to ControlSetXXX as explained in more detail here.

The plan for modifying a Windows Registry in an offline guest is therefore:

  1. Locate the hive file containing the key we want to modify.
  2. Download it to a local temporary directory.
  3. Modify it with hivex.
  4. Upload it back to the Windows VM.

(This is essentially what virt-win-reg does).

Below is a Python program which demonstrates how to change the hostname of a Windows VM using the APIs directly. The hostname is stored in HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\Tcpip\Parameters in the key Hostname. Notice from the name that this is located in the SYSTEM hive file, and in this case I’m going to assume that CurrentControlSet is a link to ControlSet001 but in reality you’d probably want to read this and do it right.

A final note: Although this changes the Hostname registry key correctly, Windows doesn’t use this key for very much (in particular, this is not the name of the machine), and also it appears that Windows will overwrite this key with whatever name it gets from a DHCP server. It’s only an example though …

#!/usr/bin/python

import guestfs
import hivex

windows_domain = "Win7x32"

# Windows strings stored in the registry have a trailing NUL
new_hostname = "win7x32\0"

# Use libguestfs to download the HKEY_LOCAL_MACHINE\SYSTEM hive.
g = guestfs.GuestFS ()
g.add_domain (windows_domain)
g.launch ()

roots = g.inspect_os ()
root = roots[0]
g.mount_options ("", root, "/")

systemroot = g.inspect_get_windows_systemroot (root)
path = "%s/system32/config/system" % systemroot
path = g.case_sensitive_path (path)
g.download (path, "/tmp/system")

# Open the hive file for writing.
h = hivex.Hivex ("/tmp/system", write=True)

# Navigate down to the TCP/IP parameters.
key = h.root ()
key = h.node_get_child (key, "ControlSet001")
key = h.node_get_child (key, "Services")
key = h.node_get_child (key, "Tcpip")
key = h.node_get_child (key, "Parameters")

# Get the old hostname.
val = h.node_get_value (key, "Hostname")
old_hostname = h.value_value (val)

# Keep the old type (probably 1 = string)
type = old_hostname[0]

# The registry key is encoded as UTF-16LE.
old_hostname = old_hostname[1].decode ('utf-16le').encode ('utf-8')

print "old hostname = %s" % old_hostname

# Change the hostname.
new_hostname = new_hostname.encode ('utf-16le')
new_value = { 'key': "Hostname", 't': type,
              'value': new_hostname }
h.node_set_value (key, new_value)

# Commit the changes to the hive.
h.commit (None)

# Upload the hive back to the guest.
g.upload ("/tmp/system", path)

# This is only needed for libguestfs < 1.5.24, but
# it won't hurt for newer versions.
g.sync ()

Leave a comment

Filed under Uncategorized

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s