Author Topic: [Python] Query and Read Keys from Windows Registry  (Read 2065 times)

0 Members and 1 Guest are viewing this topic.

Offline Psycho_Coder

  • Knight
  • **
  • Posts: 166
  • Cookies: 84
  • Programmer, Forensic Analyst
    • View Profile
    • Code Hackers Blog
[Python] Query and Read Keys from Windows Registry
« on: March 17, 2015, 01:40:16 pm »
"Windows Registry is a hierarchical database that stores configuration settings and options on Microsoft Windows operating systems. It contains settings for low-level operating system components and for applications running on the platform that have opted to use the Registry."
------------Wikipedia

With Registry you can retrieve a lot of useful data which could be beneficial for different purposes like Security, Forensics, Tweaking Windows, adding new features etc. But manipulating Registry can have adverse effects if not done properly or taken care, so do it at your own risk.

What to expect from this  tutorial ?

In this article we will learn about how to use python scripting to query and read registry data. Python 2.x.x series provides an interface to windows registry and the module name being _winreg and the same for Python 3.x.x series is named as winreg. I know that _winreg is an odd name for a module and its nice that it was corrected in the Python 3 series. However we will write the script in a way that it is compatible with both Python Series.

Prerequisites

1. Basic Knowledge of Python Programming.
2. Experience with Windows

So lets begin.



Registry Basics.

Windows Registry has been divided into a number of groups based on the type of information they store. Using a tool Registry Editor you can see the content of windows registry. By Default this tool is present in all the windows variants OS including Windows Server series. We can open this tool by writing regedit on command or in the Run dialog box, the Registry can be seen as one unified file system. the left-hand pane, also known as the key pane contains an organized listing of what appear to be folders. The five most hierarchical folders are called "hives" and begin with HKEY (an abbreviation for "Handle to a Key"). Although five hives can be seen only two of these are actually "real", they are : HKEY_USERS (HKU) and HKEY_LOCAL_MACHINE (HKLM). The Other three are shortcuts or aliases to branches within one of the two hives. Each of these hives is composed of of keys, which contain values and subkeys. Values are the names of certain items within a key, which uniquely identify specific values pertaining to the operating system or to applications that depend upon that value.


Image taken from Google

So this is the very basic elements you should know about Registry. Details about the windows registry is beyond the scope of this article.




Now we will look into the Python winreg module. (Note I am primarily using Python 3 but all the codes will be compatible with Python 2 as well but instead of importing winreg you need to import _winreg).

Python winreg (Windows registry access) is an interface that exposes the Windows Registry API.

winreg (Python3) docs :- https://docs.python.org/3.4/library/winreg.html
winreg (Python2) docs :- https://docs.python.org/2/library/_winreg.html

Steps to use winreg to query or read values from registry.

Follow the steps as mentioned below to work with winreg.

importing winreg module

To import the module simple write "import winreg" or "import _winreg" in case of Python 2.7. To achieve an independent solution for both python versions we can use the platform module to get the python version and if the version is 2.7 then we import _winreg else import winreg. We can do that simple with the following code :-

Code: [Select]
import platform

if platform.python_version()[0] == "3":
    import winreg as wreg
elif platform.python_version()[0] == "2":
    import _winreg as wreg

In the above code we check that if the first character of the python version is 3 then its Python3 and we import winreg with wreg as an alias, and vice versa.

Here we are done with importing the module and we are now concerned with Connecting to the registry to query data.

Connecting to registry with winreg

winreg module provides a class ConnectRegistry to establishes a connection to a predefined registry handle on
 another computer or on the local computer. It takes two parameters :-

1. Computer name :- The computers whose registry will be connected. If None then local computer used.
2. Hive :- The Hive name to connect to. winreg modules provide constants for different Hives.

We can connect to registry as follows :-

Code: [Select]
try:
        regconn = wreg.ConnectRegistry( None, wreg.HKEY_CURRENT_USER )
       
except ( WindowsError, EnvironmentError ):
        print( "Unable to Connect to the Window Registry and read keys"

As evident from the above code I am trying to connect to the HKEY_CURRENT_USER hive.


After this we need to decide what kind of operation we wanna perform. In this tutorial I will cover reading keys or values of subkeys only. In another article I will cover creating keys or deleting keys.

To read any key we need to Open the key first and we can do so using the OpenKey class under winreg.

Opening a Key using OpenKey

We can open a key or subkey of registry in the following way :-

Code: [Select]
key = wreg.OpenKey( regconn, ""AppEvents\\EventLabels"", wreg.KEY_READ )
regconn is the connection object we created earlier. We can even open a key with creating first an object of ConnectRegistry in the following manner :-

Code: [Select]
key = wreg.OpenKey( wreg.HKEY_CURRENT_USER, ""AppEvents\\EventLabels"", wreg.KEY_READ )
So what we are doing is we pass the first parameter as regconn or hive constant defined in winreg winreg.HKEY_CURRENT_USER. The second parameter is the Subkey for which we want to read the subkeys or values. The third parameter is the access or permission for what kind of operation you wanna do. The default being KEY_READ which states that we want to read the keys. There are several other constants for permissions in winreg like KEY_WRITE or KEY_ACCESS_ALL. KEY_ACCESS_ALL is a collective value for a number of other permissions. For more details about the descriptions of the parameters follow the docs.

Now in the second param we have sent an argument called ""AppEvents\\EventLabels"". Now this subkey stores different other subkeys which stores sounds or music relative to different events (Window Close, Open, System exit etc.) of your windows OS. This Key is same in Windows 8 64 bit, Windows 7 (32 bit) and Windows XP (32 bit) (Not checked with Vista or Windows Server but it should be same).


Therefore the above code means that we want to read all the subkeys under "HKEY_CURRENT_USER\AppEvents\EventLabels"

Get list of all Subkeys

To get the list of all subkeys under a key we can enumerate the list using EnumKey defined in winreg. It takes two parameters :- a) The OpenKey instance which in our case is stored in 'key' and b) the index of the subkey which we want to get.

Now we can get them in two ways :- 1.) The Bad way and 2.) The Better way. We will discuss both.

The Bad way

In this case we run an infinite loop and iterate over all the subkeys unless an exception is thrown (WindowsError, an alias of OSError.) We catch the exception and neglect it. The following snippet does so :-

Code: [Select]
try:
        regconn = wreg.ConnectRegistry( None, wreg.HKEY_CURRENT_USER )
        key = wreg.OpenKey( regconn, "AppEvents\\EventLabels", wreg.KEY_READ )
        i = 0
        while True:
            print( wreg.EnumKey( key, i ) )
            i += 1
except:
        pass

The Better way or The Proper method

This method is better way to do the things and more like written by a programmer. In this method we first query how many subkeys are present and then iterate to that range rather than a blind infinite loop. To get the number of subkeys under a key we use "QueryInfoKey", this takes a single parameter and that is the instance of OpenKey for a key which we want to query. This returns a tuple of three values, namely (NO_OF_SUBKEYS, NO_OF_VALUES, LAST_MODIFIED_TIME). When we get this we will simply take the first value.

We can do this as follows :-

Code: [Select]
subkeys_count = wreg.QueryInfoKey( key )[0]

When we have the no of subkeys we will simply iterate through the subkeys_count and using EnumKey get the names of the Subkeys. The following code is a complete example for the concept :-

Code: [Select]
'''
Created on 01-Jan-2015

@author: Psycho_Coder
'''

import platform

if platform.python_version()[0] == "3":
        import winreg as wreg
elif platform.python_version()[0] == "2":
    import _winreg as wreg


def main():
    try:
        regconn = wreg.ConnectRegistry( None, wreg.HKEY_CURRENT_USER )
        key = wreg.OpenKey( regconn, "AppEvents\\EventLabels", wreg.KEY_READ )
        subkeys_count = wreg.QueryInfoKey( key )[0]

        subkeys_list = []

        for i in range( subkeys_count ):
            subkeys_list.append( wreg.EnumKey( key, i ) )
    except ( WindowsError, EnvironmentError ):
        print( "Unable to Connect to the Window Registry and read keys" )
    finally:
        key.Close()

    for subkey in iter( subkeys_list ):
        print( subkey )


if __name__ == '__main__':
    main()


Output

Code: [Select]
.Default
ActivatingDocument
AppGPFault
BlockedPopup
CCSelect
ChangeTheme
Close
CriticalBatteryAlarm
DeviceConnect
DeviceDisconnect
DeviceFail
DisNumbersSound
EmptyRecycleBin
FaxBeep
FeedDiscovered
HubOffSound
HubOnSound
HubSleepSound
LowBatteryAlarm
MailBeep
Maximize
MenuCommand
MenuPopup
MessageNudge
Minimize
MisrecoSound
MoveMenuItem
Navigating
Notification.Default
Notification.IM
Notification.Looping.Alarm
Notification.Looping.Alarm10
Notification.Looping.Alarm2
Notification.Looping.Alarm3
Notification.Looping.Alarm4
Notification.Looping.Alarm5
Notification.Looping.Alarm6
Notification.Looping.Alarm7
Notification.Looping.Alarm8
Notification.Looping.Alarm9
Notification.Looping.Call
Notification.Looping.Call10
Notification.Looping.Call2
Notification.Looping.Call3
Notification.Looping.Call4
Notification.Looping.Call5
Notification.Looping.Call6
Notification.Looping.Call7
Notification.Looping.Call8
Notification.Looping.Call9
Notification.Mail
Notification.Proximity
Notification.Reminder
Notification.SMS
Open
PanelSound
PrintComplete
ProximityConnection
RestoreDown
RestoreUp
SearchProviderDiscovered
SecurityBand
ShowBand
SystemAsterisk
SystemExclamation
SystemExit
SystemHand
SystemNotification
SystemQuestion
VS_BreakpointHit
VS_BuildCanceled
VS_BuildFailed
VS_BuildSucceeded
WindowsLogoff
WindowsLogon
WindowsUAC
WindowsUnlock


So, its pretty simple. Right ?

Get all Values of a Key

Now we will see another example code. In this we print some system details stored under HKEY_CURRENT_USER\Volatile Environment


To get the Values of a Subkey we follow a similar approach as above with changes at some steps. In the previous example we had seen that using QueryInfoKey we got the number of Subkeys. If you remember properly I said that the second parameter returns the number of values in the key. So we get the values_count as follows :-

Code: [Select]
values_count = wreg.QueryInfoKey( key )[1]


Again, using EnumKey in the previous example we enumerate the subkeys but in this example we want to get the list of all the values and for that we use EnumValue under winreg. The rest is same as EnumKey. So main function code is :-

Code: [Select]
def main():
    try:
        regconn = wreg.ConnectRegistry( None, wreg.HKEY_CURRENT_USER )
        key = wreg.OpenKey( regconn, "Volatile Environment", wreg.KEY_READ )
        values_count = wreg.QueryInfoKey( key )[1]
        values_list = []

        for i in range( values_count ):
            values_list.append( wreg.EnumValue( key, i ) )
    except ( WindowsError, EnvironmentError ):
        print( "Unable to Connect to the Window Registry and read keys" )
    finally:
        key.Close()
    return values_list


I made a more complete example where I printed the data properly in a format. The complete code for that is :-

Code: [Select]
'''
Created on 02-Jan-2015

@author: Psycho_Coder
'''


import platform

if platform.python_version()[0] == "3":
    import winreg as wreg
elif platform.python_version()[0] == "2":
    import _winreg as wreg

DataType = {
        0 : "REG_NONE",
        1 : "REG_SZ",
        2 : "REG_EXPAND_SZ",
        3 : "REG_BINARY",
        4 : "REG_DWORD",
        4 : "REG_DWORD_LITTLE_ENDIAN",
        5 : "REG_DWORD_BIG_ENDIAN",
        6 : "REG_LINK",
        7 : "REG_MULTI_SZ",
        8 : "REG_RESOURCE_LIST",
        9 : "REG_FULL_RESOURCE_DESCRIPTOR",
        10: "REG_RESOURCE_REQUIREMENTS_LIST",
        11: "REG_QWORD | ",
        11: "REG_QWORD_LITTLE_ENDIAN"
}

def main():
    try:
        regconn = wreg.ConnectRegistry( None, wreg.HKEY_CURRENT_USER )
        key = wreg.OpenKey( regconn, "Volatile Environment", wreg.KEY_READ )
        values_count = wreg.QueryInfoKey( key )[1]
        values_list = []

        for i in range( values_count ):
            values_list.append( wreg.EnumValue( key, i ) )
    except ( WindowsError, EnvironmentError ):
        print( "Unable to Connect to the Window Registry and read keys" )
    finally:
        key.Close()
    return values_list


def display_data( values_list ):
    for subkey in iter( values_list ):
        print( "Name : " + subkey[0] )
        print( "Data : " + subkey[1] )
        print( "Type : " + DataType[subkey[2]] )
        print( "-" * 40 )


if __name__ == '__main__':
    display_data( main() )



Output

Code: [Select]
Name : LOGONSERVER
Data : \\PSYCHO-WORK-PC
Type : REG_SZ
----------------------------------------
Name : USERDOMAIN
Data : Psycho-Work-PC
Type : REG_SZ
----------------------------------------
Name : USERNAME
Data : Psycho_Coder
Type : REG_SZ
----------------------------------------
Name : USERPROFILE
Data : C:\Users\Psycho
Type : REG_SZ
----------------------------------------
Name : HOMEPATH
Data : \Users\Psycho
Type : REG_SZ
----------------------------------------
Name : HOMEDRIVE
Data : C:
Type : REG_SZ
----------------------------------------
Name : APPDATA
Data : C:\Users\Psycho\AppData\Roaming
Type : REG_SZ
----------------------------------------
Name : LOCALAPPDATA
Data : C:\Users\Psycho\AppData\Local
Type : REG_SZ
----------------------------------------
Name : USERDOMAIN_ROAMINGPROFILE
Data : Psycho-Work-PC
Type : REG_SZ
----------------------------------------

As you can can see I have printed the type of data that is REG_SZ in his example (Null Terminated String) using the integer value returned by EnumValue for the subkey "Volatile Environment".



Conclusion


winreg is really helpful when collecting different types of information from a host computer in a large scale. I didn't find good tutorials on the web for this module and so made a very detailed tutorial. If you have any suggestions then feel free to reply and I will answer them. I will post more about winreg and post different examples which shows how we can use winreg to collect information. I hope you enjoyed the tutorial.

Note :- All the codes were tested on :- Windows 8 (64 bit) Windows 7 Ultimate (32 bit) and Windows XP (32 bit). Code were tested using PyPy on Win 7 and XP, and using CPython and IronPython on Windows 8. The code successfully ran on all the interpreters.


Thank you,
Sincerely,
Psycho_Coder.
"Don't do anything by half. If you love someone, love them with all your soul. When you hate someone, hate them until it hurts."--- Henry Rollins

Offline Deque

  • P.I.N.N.
  • Global Moderator
  • Overlord
  • *
  • Posts: 1203
  • Cookies: 518
  • Programmer, Malware Analyst
    • View Profile
Re: [Python] Query and Read Keys from Windows Registry
« Reply #1 on: March 18, 2015, 08:26:37 am »
Great tutorial.  :D


Offline Nightf0x

  • NULL
  • Posts: 1
  • Cookies: 0
    • View Profile
Re: [Python] Query and Read Keys from Windows Registry
« Reply #2 on: September 05, 2015, 02:08:41 am »
Awesome thanks a lot!

Offline proxx

  • Avatarception
  • Global Moderator
  • Titan
  • *
  • Posts: 2803
  • Cookies: 256
  • ФФФ
    • View Profile
Re: [Python] Query and Read Keys from Windows Registry
« Reply #3 on: September 05, 2015, 02:20:18 am »
Yes, these are the contributions I like, thank you bro , I will read the entire thing tomorrow, it is late.
:)
Wtf where you thinking with that signature? - Phage.
This was another little experiment *evillaughter - Proxx.
Evilception... - Phage

Offline kenjoe41

  • Symphorophiliac Programmer
  • Administrator
  • Baron
  • *
  • Posts: 990
  • Cookies: 224
    • View Profile
Re: [Python] Query and Read Keys from Windows Registry
« Reply #4 on: September 05, 2015, 02:24:43 am »
I saw this tutorial way back and i thought that this was some other boring technical windows stuff.
But now reading through it, it explains everything to great detail that anybody can enjoy it. We need more of them tutorials like this. Where did the spirit go?
If you can't explain it to a 6 year old, you don't understand it yourself.
http://upload.alpha.evilzone.org/index.php?page=img&img=GwkGGneGR7Pl222zVGmNTjerkhkYNGtBuiYXkpyNv4ScOAWQu0-Y8[<NgGw/hsq]>EvbQrOrousk[/img]

Offline Psycho_Coder

  • Knight
  • **
  • Posts: 166
  • Cookies: 84
  • Programmer, Forensic Analyst
    • View Profile
    • Code Hackers Blog
Re: [Python] Query and Read Keys from Windows Registry
« Reply #5 on: September 05, 2015, 07:52:45 pm »
I saw this tutorial way back and i thought that this was some other boring technical windows stuff.
But now reading through it, it explains everything to great detail that anybody can enjoy it. We need more of them tutorials like this. Where did the spirit go?

I am glad that people like this tutorial :)

Unfortunately, since I have started working in an organization I have got less time for the virtual community world that I have always cared and loved. I am currently employed as a Digital Forensic Analyst (though I am a trainee but still that's my domain), the stuff is pretty awesome and requires keen observation and hard work, I have got a lot to read and there are people I have always idealized and dreamed to reach upto them, hence I put more effort which consumes a lot of time.

I have almost no time to write tutorials now, moreover I am also stuck with my steganography research. But I will try to post better articles soon though :)

Thank you,
Sincerely,
Psycho_Coder
"Don't do anything by half. If you love someone, love them with all your soul. When you hate someone, hate them until it hurts."--- Henry Rollins