The create_dictionary() function prepares the UserAssist data for processing. This function pulls all values within each UserAssist GUID key. It creates a dictionary where the keys are the ROT-13 decoded executable name, and the values are the respective binary data. This binary data is extracted now, so we can process it in a later function:
085 def create_dictionary(registry):
086 """
087 The create_dictionary function creates a list of dictionaries
088 where keys are the ROT-13 decoded app names and values are
089 the raw hex data of said app.
090 :param registry: Registry Hive to process
091 :return: apps_list, A list containing dictionaries for
092 each app
093 """
On line 97, we try to open the registry file provided by the user. If there is an error accessing the input file, we catch the error, log it, and exit gracefully with an error code of 2:
094 try:
095 # Open the registry file to be parsed
096 registry_file = open(registry, "rb")
097 reg = Registry.RegistryHive(registry_file)
098 except (IOError, UnicodeDecodeError) as e:
099 msg = 'Invalid NTUSER.DAT path or Registry ID.'
100 print('[-]', msg)
101 logging.error(msg)
102 sys.exit(2)
If we can open the registry file, we then try to navigate to the UserAssist key. We use a conditional to catch the scenario where the UserAssist key is not found in the supplied registry file. Note that, for this error, we use the integer, 3, to differentiate from our previous exit scenario:
104 # Navigate to the UserAssist key
105 ua_key = reg.find_key(
106 ('SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer'
107 '\\UserAssist'))
108 if ua_key is None:
109 msg = 'UserAssist Key not found in Registry file.'
110 print('[-]', msg)
111 logging.error(msg)
112 sys.exit(3)
On line 113, we create a list named apps_list, which will store UserAssist dictionaries. If we were able to find the UserAssist key, we loop through each ua_subkey, a GUID, and check their count subkey. This is an important step; as Windows has evolved, more GUIDs have been added to the UserAssist key. Rather than hardcoding these values, which could miss new GUIDs added in future versions of Windows, we opted for a more dynamic process that will discover and handle new GUIDs across many versions of Windows:
113 apps_list = []
114 # Loop through each subkey in the UserAssist key
115 for ua_subkey in ua_key.subkeys():
116 # For each subkey in the UserAssist key, detect a subkey
117 # called Count that has more than 0 values to parse.
This process involves checking each GUIDs that has a subkey named Count, which stores the actual UserAssist application values. On line 118, we determine if the GUID has a subkey named Count with one or more values. This ensures that we find all the UserAssist values present on the system:
118 if(ua_subkey.subkey('Count') and
119 ua_subkey.subkey('Count').values_count() > 0):
We create an apps dictionary on line 120 and begin to loop through each value under the Count subkey. For each value, we add the ROT-13-decoded name as the key, and associate it with its raw_data as the value. Once all the values in the GUID have been added to the dictionary, it is appended to apps_list and the cycle repeats. Once all of the GUIDs have been processed, our list is returned to the main() function:
120 apps = {}
121 for v in ua_subkey.subkey('Count').values():
122 if sys.version_info[0] == 2:
123 apps[v.name().encode('utf-8').decode(
124 'rot-13')] = v.data_raw()
125 elif sys.version_info[0] == 3:
126 import codecs
127 enc = codecs.getencoder('rot-13')
128 apps[enc(str(v.name()))[0]] = v.data_raw()
129
130 apps_list.append(apps)
131 return apps_list