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
20 WIN_UNIX_DIFF_MSECS = 11644473600
21
22
23
24
25
26 KEY_READ = 0x20019
27
28
29
30
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
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]
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
91
92 - def __exit__(self, exc_type=None, exc_val=None, exc_tb=None):
93 self.Close()
94 return False
95
97 if not self.handle or not self._close:
98 return
99 if RegCloseKey is None:
100 return
101 rc = RegCloseKey(self.handle)
102 self.handle = ctypes.c_void_p()
103 if rc != ERROR_SUCCESS:
104 raise ctypes.WinError(2)
105
108
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
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
131
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
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
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
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
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
378
379
380
381 common.FILE_SPEC_DISPATCHER["Reg"] = RegistryKeyInformation
382