python-registry
Introduction
python-registry was originally written by Willi Ballenthin, a forensicator who wanted to access the contents of the Windows Registry from his Linux laptop. python-registry currently provides read-only access to Windows Registry files, such as NTUSER.DAT, userdiff, and SOFTWARE. The interface is two-fold: a high-level interface suitable for most tasks, and a low level set of parsing objects and methods which may be used for advanced study of the Windows Registry. python-registry is written in pure Python, making it portable across all major platforms.Download
python-registry can be downloaded at GitHub here: Download.Documentation
Static API documentation for python-registry can be found here: Documentation.Usage
Most users will find theRegistry.Registry module most
appropriate. The module exposes three classes: the Registry,
the RegistryKey, and the RegistryValue. The Registry organizes
parsing and access to the Windows Registry file. The
RegistryKey is a convenient interface into the tree-like
structure of the Windows Registry. A RegistryKey may have
children RegistryKeys, and may also have values associated
with it. A RegistryValue can be thought of as the tuple
(name, datatype, value) associated with a RegistryKey.
python-registry supports all major datatypes, such as RegSZ,
RegDWord, and RegBin.
Open a Windows Registry file
Its this easy:import sys from Registry import Registry reg = Registry.Registry(sys.argv[1])
Print all keys in a Registry
def rec(key, depth=0):
print "\t" * depth + key.path()
for subkey in key.subkeys():
rec(subkey, depth + 1)
rec(reg.root())
Find a key and print all string values
try:
key = reg.open("SOFTWARE\\Microsoft\\Windows\\Current Version\\Run")
except Registry.RegistryKeyNotFoundException:
print "Couldn't find Run key. Exiting..."
sys.exit(-1)
for value in [v for v key.values() \
if v.value_type() == Registry.RegSZ or \
v.value_type() == Registry.RegExpandSZ]:
print "%s: %s" % (value.name(), value.value())
Advanced users who wish to study the structure of the
Windows Registry may find the Registry.RegistryParse
module useful. This module implements all known structures
of the Windows Registry.
Testing
python-registry was developed using Python 2.6.5 on Ubuntu Linux. More importantly, the package was tested against a small set of Windows XP SP3 Registry files acquired from one of the author's virtual machines. The script testing/RegTester.py will parse the .reg files exported by Microsoft Regedit and compare the values parsed by python-registry. This tool can be used to identify regressions and deficiencies in the development of python-registry.Wanted
python-registry was originally developed to scratch one of the author's itches. Now he hopes it can be of use to someone outside of his lonely NYC apartment.
License
python-registry is released under the Apache v2.0 license.Sources
Nearly all structure definitions used in python-registry came from one of two sources:- WinReg.txt, by B.H., which may be accessed at: http://pogostick.net/~pnh/ntpasswd/WinReg.txt
- The Windows NT Registry File Format version 0.4, by Timothy D. Morgan, which may be accessed at: http://sentinelchicken.com/data/TheWindowsNTRegistryFileFormat.pdf
Sample
The source directory for python-registry contains a sample/ subdirectory that contains small programs that use python-registry. For example,regview.py is a read-only clone of Microsoft Window's
Regedit, implemented in a few hundred lines.
regview.py source code that are relevant to
python-registry are included below to highlight how the
module may be used. The full source code may be viewed at Github:
here.
import sys
import wx
from Registry import Registry
class DataPanel(wx.Panel):
"""Displays the value of a RegistryValue humanely."""
def __init__(self, *args, **kwargs):
...
def _format_hex(self, data):
...
def display_value(self, value):
self._sizer.Clear()
data_type = value.value_type()
if data_type == Registry.RegSZ or \ # we can manipulate
data_type == Registry.RegExpandSZ or \ # string and integer
data_type == Registry.RegDWord or \ # types as expected
data_type == Registry.RegQWord:
view = wx.TextCtrl(self, style=wx.TE_MULTILINE)
view.SetValue(unicode(value.value()))
elif data_type == Registry.RegMultiSZ: # RegMultiSZ is simply
view = wx.ListCtrl(self, style=wx.LC_LIST) # a list of strings
for string in value.value():
view.InsertStringItem(view.GetItemCount(), string)
elif data_type == Registry.RegBin or \ # binary data is supported
data_type == Registry.RegNone: # and formatted nicely here
view = wx.TextCtrl(self, style=wx.TE_MULTILINE)
font = wx.Font(8, wx.SWISS, wx.NORMAL, wx.NORMAL, False, u'Courier')
view.SetFont(font)
view.SetValue(self._format_hex(value.value()))
self._sizer.Add(view, 1, wx.EXPAND)
self._sizer.Layout()
def clear_value(self):
...
class ValuesListCtrl(wx.ListCtrl):
def __init__(self, *args, **kwargs):
...
def clear_values(self):
...
def add_value(self, value):
n = self.GetItemCount()
self.InsertStringItem(n, value.name()) # column 1: name (string)
self.SetStringItem(n, 1, value.value_type_str()) # column 2: type (string)
self.values[value.name()] = value
def get_value(self, valuename):
"""This is merely a cache of the Registry model."""
return self.values[valuename]
class RegistryTreeCtrl(wx.TreeCtrl):
def __init__(self, *args, **kwargs):
...
def add_registry(self, registry):
root_key = registry.root() # .root() is the first key
root_item = self.AddRoot(root_key.name() + "(%s)" % (sys.argv[1]))
self.SetPyData(root_item, {"key": root_key,
"has_expanded": False})
if len(root_key.subkeys()) > 0: # we can easily get children
self.SetItemHasChildren(root_item) # by asking for subkeys
def _extend(self, item):
"""Lazily build the tree as the user requests nodes"""
key = self.GetPyData(item)["key"]
for subkey in key.subkeys():
subkey_item = self.AppendItem(item, subkey.name())
self.SetPyData(subkey_item, {"key": subkey,
"has_expanded": False})
if len(subkey.subkeys()) > 0:
self.SetItemHasChildren(subkey_item)
self.GetPyData(item)["has_expanded"] = True
def OnExpandKey(self, event):
item = event.GetItem()
...
if not self.GetPyData(item)["has_expanded"]:
self._extend(item)
def _expand_into(dest, src):
...
class RegView(wx.Frame):
def __init__(self, parent, registry):
...
self._tree.add_registry(registry)
def OnKeySelected(self, event):
item = event.GetItem()
...
key = self._tree.GetPyData(item)["key"]
...
for value in key.values(): # values are easily accessed
self._value_list_view.add_value(value) # as lists, or can be retrieved
# with .value(name) by name
def OnValueSelected(self, event):
...
if __name__ == '__main__':
...
registry = Registry.Registry(sys.argv[1])
app = wx.App(False) # standard wxPython app
frame = RegView(None, registry=registry) # nothing to see here, except
frame.Show() # easy construction by filename
app.MainLoop()