Package rekall :: Package plugins :: Package response :: Module registry
[frames] | no frames]

Source Code for Module rekall.plugins.response.registry

  1  """Support the windows registry. 
  2   
  3  This code is borrowed from GRR. 
  4  """ 
  5   
  6  import ctypes 
  7  import ctypes.wintypes 
  8  import exceptions 
  9  import stat 
 10  import StringIO 
 11  import _winreg 
 12   
 13  from rekall import obj 
 14  from rekall_lib import utils 
 15  from rekall.plugins.overlays import basic 
 16  from rekall.plugins.response import common 
 17   
 18   
 19  # Difference between 1 Jan 1601 and 1 Jan 1970. 
 20  WIN_UNIX_DIFF_MSECS = 11644473600 
 21   
 22  # KEY_READ = STANDARD_RIGHTS_READ | KEY_QUERY_VALUE | 
 23  #            KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY 
 24  # Also see: http://msdn.microsoft.com/en-us/library/windows/desktop/ 
 25  # ms724878(v=vs.85).aspx 
 26  KEY_READ = 0x20019 
 27   
 28   
 29  # _winreg is broken on Python 2.x and doesn't support unicode registry values. 
 30  # We provide some replacement functions here. 
 31   
 32  advapi32 = ctypes.windll.advapi32 
 33   
 34  LPDWORD = ctypes.POINTER(ctypes.wintypes.DWORD) 
 35  LPBYTE = ctypes.POINTER(ctypes.wintypes.BYTE) 
 36   
 37  ERROR_SUCCESS = 0 
 38  ERROR_MORE_DATA = 234 
39 40 41 -class FileTime(ctypes.Structure):
42 _fields_ = [("dwLowDateTime", ctypes.wintypes.DWORD), 43 ("dwHighDateTime", ctypes.wintypes.DWORD)]
44 45 46 RegCloseKey = advapi32.RegCloseKey 47 RegCloseKey.restype = ctypes.c_long 48 RegCloseKey.argtypes = [ctypes.c_void_p] 49 50 RegEnumKeyEx = advapi32.RegEnumKeyExW 51 RegEnumKeyEx.restype = ctypes.c_long 52 RegEnumKeyEx.argtypes = [ctypes.c_void_p, ctypes.wintypes.DWORD, 53 ctypes.c_wchar_p, LPDWORD, LPDWORD, ctypes.c_wchar_p, 54 LPDWORD, ctypes.POINTER(FileTime)] 55 56 RegEnumValue = advapi32.RegEnumValueW 57 RegEnumValue.restype = ctypes.c_long 58 RegEnumValue.argtypes = [ctypes.c_void_p, ctypes.wintypes.DWORD, 59 ctypes.c_wchar_p, LPDWORD, LPDWORD, LPDWORD, LPBYTE, 60 LPDWORD] 61 62 RegOpenKeyEx = advapi32.RegOpenKeyExW 63 RegOpenKeyEx.restype = ctypes.c_long 64 RegOpenKeyEx.argtypes = [ctypes.c_void_p, ctypes.c_wchar_p, ctypes.c_ulong, 65 ctypes.c_ulong, ctypes.POINTER(ctypes.c_void_p)] 66 67 RegQueryInfoKey = advapi32.RegQueryInfoKeyW 68 RegQueryInfoKey.restype = ctypes.c_long 69 RegQueryInfoKey.argtypes = [ctypes.c_void_p, ctypes.c_wchar_p, LPDWORD, LPDWORD, 70 LPDWORD, LPDWORD, LPDWORD, LPDWORD, LPDWORD, 71 LPDWORD, LPDWORD, ctypes.POINTER(FileTime)] 72 73 RegQueryValueEx = advapi32.RegQueryValueExW 74 RegQueryValueEx.restype = ctypes.c_long 75 RegQueryValueEx.argtypes = [ctypes.c_void_p, ctypes.c_wchar_p, LPDWORD, LPDWORD, 76 LPBYTE, LPDWORD]
77 78 79 -class KeyHandle(object):
80 """A wrapper class for a registry key handle.""" 81
82 - def __init__(self, value=0, close=True):
83 if value: 84 self.handle = ctypes.c_void_p(value) 85 else: 86 self.handle = ctypes.c_void_p() 87 self._close = close
88
89 - def __enter__(self):
90 return self
91
92 - def __exit__(self, exc_type=None, exc_val=None, exc_tb=None):
93 self.Close() 94 return False
95
96 - def Close(self):
97 if not self.handle or not self._close: 98 return 99 if RegCloseKey is None: 100 return # Globals become None during exit. 101 rc = RegCloseKey(self.handle) 102 self.handle = ctypes.c_void_p() 103 if rc != ERROR_SUCCESS: 104 raise ctypes.WinError(2)
105
106 - def __del__(self):
107 self.Close()
108
109 110 -def OpenKey(key, sub_key):
111 """This calls the Windows OpenKeyEx function in a Unicode safe way.""" 112 if not sub_key: 113 result = KeyHandle(close=False) 114 result.handle = key.handle 115 return result 116 117 new_key = KeyHandle() 118 # Don't use KEY_WOW64_64KEY (0x100) since it breaks on Windows 2000 119 rc = RegOpenKeyEx(key.handle, sub_key, 0, KEY_READ, ctypes.cast( 120 ctypes.byref(new_key.handle), ctypes.POINTER(ctypes.c_void_p))) 121 if rc != ERROR_SUCCESS: 122 raise ctypes.WinError(2) 123 124 return new_key
125
126 127 -def CloseKey(key):
128 rc = RegCloseKey(key) 129 if rc != ERROR_SUCCESS: 130 raise ctypes.WinError(2)
131
132 133 -def QueryInfoKey(key):
134 """This calls the Windows RegQueryInfoKey function in a Unicode safe way.""" 135 null = LPDWORD() 136 num_sub_keys = ctypes.wintypes.DWORD() 137 num_values = ctypes.wintypes.DWORD() 138 ft = FileTime() 139 rc = RegQueryInfoKey(key.handle, ctypes.c_wchar_p(), null, null, 140 ctypes.byref(num_sub_keys), null, null, 141 ctypes.byref(num_values), null, null, null, 142 ctypes.byref(ft)) 143 if rc != ERROR_SUCCESS: 144 raise ctypes.WinError(2) 145 146 return (num_sub_keys.value, num_values.value, ft.dwLowDateTime 147 | (ft.dwHighDateTime << 32))
148
149 150 -def QueryValueEx(key, value_name):
151 """This calls the Windows QueryValueEx function in a Unicode safe way.""" 152 size = 256 153 data_type = ctypes.wintypes.DWORD() 154 while True: 155 tmp_size = ctypes.wintypes.DWORD(size) 156 buf = ctypes.create_string_buffer(size) 157 rc = RegQueryValueEx(key.handle, value_name, LPDWORD(), 158 ctypes.byref(data_type), ctypes.cast(buf, LPBYTE), 159 ctypes.byref(tmp_size)) 160 if rc != ERROR_MORE_DATA: 161 break 162 163 # We limit the size here to ~10 MB so the response doesn't get too big. 164 if size > 10 * 1024 * 1024: 165 raise exceptions.WindowsError("Value too big to be read.") 166 167 size *= 2 168 169 if rc != ERROR_SUCCESS: 170 raise ctypes.WinError(2) 171 172 return (Reg2Py(buf, tmp_size.value, data_type.value), data_type.value)
173
174 175 -def EnumKey(key, index):
176 """This calls the Windows RegEnumKeyEx function in a Unicode safe way.""" 177 buf = ctypes.create_unicode_buffer(257) 178 length = ctypes.wintypes.DWORD(257) 179 rc = RegEnumKeyEx(key.handle, index, ctypes.cast(buf, ctypes.c_wchar_p), 180 ctypes.byref(length), LPDWORD(), ctypes.c_wchar_p(), 181 LPDWORD(), ctypes.POINTER(FileTime)()) 182 if rc != 0: 183 raise ctypes.WinError(2) 184 185 return ctypes.wstring_at(buf, length.value).rstrip(u"\x00")
186
187 188 -def EnumValue(key, index):
189 """This calls the Windows RegEnumValue function in a Unicode safe way.""" 190 null = ctypes.POINTER(ctypes.wintypes.DWORD)() 191 value_size = ctypes.wintypes.DWORD() 192 data_size = ctypes.wintypes.DWORD() 193 rc = RegQueryInfoKey(key.handle, ctypes.c_wchar_p(), null, null, null, null, 194 null, null, ctypes.byref(value_size), 195 ctypes.byref(data_size), null, 196 ctypes.POINTER(FileTime)()) 197 if rc != ERROR_SUCCESS: 198 raise ctypes.WinError(2) 199 200 value_size.value += 1 201 data_size.value += 1 202 203 value = ctypes.create_unicode_buffer(value_size.value) 204 205 while True: 206 data = ctypes.create_string_buffer(data_size.value) 207 208 tmp_value_size = ctypes.wintypes.DWORD(value_size.value) 209 tmp_data_size = ctypes.wintypes.DWORD(data_size.value) 210 data_type = ctypes.wintypes.DWORD() 211 rc = RegEnumValue(key.handle, index, ctypes.cast( 212 value, ctypes.c_wchar_p), 213 ctypes.byref(tmp_value_size), null, 214 ctypes.byref(data_type), ctypes.cast(data, LPBYTE), 215 ctypes.byref(tmp_data_size)) 216 217 if rc != ERROR_MORE_DATA: 218 break 219 220 data_size.value *= 2 221 222 if rc != ERROR_SUCCESS: 223 raise ctypes.WinError(2) 224 225 return (value.value, Reg2Py(data, tmp_data_size.value, data_type.value), 226 data_type.value)
227
228 229 -def Reg2Py(data, size, data_type):
230 if data_type == _winreg.REG_DWORD: 231 if size == 0: 232 return 0 233 return ctypes.cast(data, ctypes.POINTER(ctypes.c_int)).contents.value 234 elif data_type == _winreg.REG_SZ or data_type == _winreg.REG_EXPAND_SZ: 235 return ctypes.wstring_at(data, size // 2).rstrip(u"\x00") 236 elif data_type == _winreg.REG_MULTI_SZ: 237 return ctypes.wstring_at(data, size // 2).rstrip(u"\x00").split(u"\x00") 238 else: 239 if size == 0: 240 return None 241 return ctypes.string_at(data, size)
242
243 244 -class RegistryKeyInformation(common.FileInformation):
245 """Represent a key or value.""" 246 247 _hive_handle = None 248 249 # Maps the registry types to names 250 registry_map = { 251 _winreg.REG_NONE: "REG_NONE", 252 _winreg.REG_SZ: "REG_SZ", 253 _winreg.REG_EXPAND_SZ: "REG_EXPAND_SZ", 254 _winreg.REG_BINARY: "REG_BINARY", 255 _winreg.REG_DWORD: "REG_DWORD", 256 _winreg.REG_DWORD_LITTLE_ENDIAN: "REG_DWORD_LITTLE_ENDIAN", 257 _winreg.REG_DWORD_BIG_ENDIAN: "REG_DWORD_BIG_ENDIAN", 258 _winreg.REG_LINK: "REG_LINK", 259 _winreg.REG_MULTI_SZ: "REG_MULTI_SZ", 260 } 261
262 - def __init__(self, filename=None, **kwargs):
263 filename = common.FileSpec(filename, filesystem="Reg", path_sep="\\") 264 super(RegistryKeyInformation, self).__init__( 265 filename=filename, **kwargs) 266 self.hive = self.key_name = self.value_name = self.value = "" 267 self.value_type = "REG_NONE" 268 self.st_mode = stat.S_IFDIR 269 270 path_components = self.filename.components() 271 if not path_components: 272 return 273 274 # The first component MUST be a hive 275 self.hive = path_components[0] 276 self._hive_handle = KeyHandle(getattr(_winreg, self.hive, None)) 277 if self._hive_handle is None: 278 raise IOError("Unknown hive name %s" % self.hive) 279 280 # Maybe its a key. 281 try: 282 self._read_key(path_components) 283 except exceptions.WindowsError: 284 # Nop - maybe its a value then. 285 self._read_value(path_components)
286
287 - def _read_value(self, path_components):
288 self.key_name = "\\".join(path_components[1:-1]) 289 self.value_name = path_components[-1] 290 with OpenKey(self._hive_handle, self.key_name) as key: 291 # We are a value - we can be read but we can not be listed. 292 self.value, value_type = QueryValueEx(key, self.value_name) 293 self.st_mode = stat.S_IFREG 294 self.value_type = self.registry_map[value_type] 295 self.st_size = len(utils.SmartStr(self.value))
296
297 - def _read_key(self, path_components):
298 # The path is just the hive name. 299 if len(path_components) == 1: 300 return 301 302 # Its probably a key 303 self.key_name = "\\".join(path_components[1:]) 304 self.value_name = "" 305 # Try to get the default value for this key 306 with OpenKey(self._hive_handle, self.key_name) as key: 307 # Check for default value. 308 try: 309 self.value, value_type = QueryValueEx(key, self.value_name) 310 self.value_type = self.registry_map[value_type] 311 self.st_size = len(utils.SmartStr(self.value)) 312 except exceptions.WindowsError: 313 pass
314 315 @classmethod
316 - def from_stat(cls, filespec, session=None):
318
319 - def open(self):
320 if self.value_type != "REG_NONE": 321 return StringIO.StringIO(self.value) 322 323 return obj.NoneObject("No data")
324
325 - def list(self):
326 if self.st_mode == stat.S_IFREG: 327 return 328 329 # We represent the virtual root of all hives. 330 if self._hive_handle is None: 331 for name in dir(_winreg): 332 if name.startswith("HKEY_"): 333 yield RegistryKeyInformation( 334 filename=name, session=self.session) 335 336 return 337 338 try: 339 with OpenKey(self._hive_handle, self.key_name) as key: 340 (number_of_keys, 341 number_of_values, 342 last_modified) = QueryInfoKey(key) 343 344 st_mtime = basic.UnixTimeStamp( 345 name="st_mtime", value=( 346 last_modified / 10000000 - WIN_UNIX_DIFF_MSECS), 347 session=self.session) 348 349 # First keys - These will look like directories. 350 for i in xrange(number_of_keys): 351 name = EnumKey(key, i) 352 key_name = "\\".join((self.hive, self.key_name, name)) 353 try: 354 subkey = RegistryKeyInformation( 355 filename=key_name, session=self.session) 356 subkey.st_mtime = st_mtime 357 358 yield subkey 359 except exceptions.WindowsError: 360 pass 361 362 # Now Values - These will look like files. 363 for i in xrange(number_of_values): 364 name, _, _ = EnumValue(key, i) 365 key_name = "\\".join((self.hive, self.key_name, name)) 366 try: 367 subkey = RegistryKeyInformation( 368 filename=key_name, session=self.session) 369 subkey.st_mtime = st_mtime 370 371 yield subkey 372 except exceptions.WindowsError: 373 pass 374 375 except exceptions.WindowsError as e: 376 raise IOError("Unable to list key %s: %s" % ( 377 self.key_name, e))
378 379 380 # Register Reg as a filesystem: 381 common.FILE_SPEC_DISPATCHER["Reg"] = RegistryKeyInformation 382