source: trunk/python/pyregfi/__init__.py@ 209

Last change on this file since 209 was 209, checked in by tim, 15 years ago

worked on pyregfi value data interface

added initial scons target for API/devel documentation

File size: 13.5 KB
Line 
1#!/usr/bin/env python
2
3import sys
4from pyregfi.structures import *
5
6import ctypes
7import ctypes.util
8from ctypes import c_char,c_char_p,c_int,c_uint16,c_uint32,c_bool,POINTER
9
10regfi = ctypes.CDLL(ctypes.util.find_library('regfi'), use_errno=True)
11
12
13regfi.regfi_alloc.argtypes = [c_int]
14regfi.regfi_alloc.restype = POINTER(REGFI_FILE)
15
16regfi.regfi_alloc_cb.argtypes = [POINTER(REGFI_RAW_FILE)]
17regfi.regfi_alloc_cb.restype = POINTER(REGFI_FILE)
18
19regfi.regfi_free.argtypes = [POINTER(REGFI_FILE)]
20regfi.regfi_free.restype = None
21
22regfi.regfi_log_get_str.argtypes = []
23regfi.regfi_log_get_str.restype = c_char_p
24
25regfi.regfi_log_set_mask.argtypes = [c_uint16]
26regfi.regfi_log_set_mask.restype = c_bool
27
28regfi.regfi_free_record.argtypes = [c_void_p]
29regfi.regfi_free_record.restype = None
30
31regfi.regfi_fetch_num_subkeys.argtypes = [POINTER(REGFI_NK)]
32regfi.regfi_fetch_num_subkeys.restype = c_uint32
33
34regfi.regfi_fetch_num_values.argtypes = [POINTER(REGFI_NK)]
35regfi.regfi_fetch_num_values.restype = c_uint32
36
37regfi.regfi_fetch_classname.argtypes = [POINTER(REGFI_FILE), POINTER(REGFI_NK)]
38regfi.regfi_fetch_classname.restype = POINTER(REGFI_CLASSNAME)
39
40regfi.regfi_fetch_sk.argtypes = [POINTER(REGFI_FILE), POINTER(REGFI_NK)]
41regfi.regfi_fetch_sk.restype = POINTER(REGFI_SK)
42
43regfi.regfi_fetch_data.argtypes = [POINTER(REGFI_FILE), POINTER(REGFI_VK)]
44regfi.regfi_fetch_data.restype = POINTER(REGFI_DATA)
45
46regfi.regfi_find_subkey.argtypes = [POINTER(REGFI_FILE), POINTER(REGFI_NK),
47 c_char_p, POINTER(c_uint32)]
48regfi.regfi_find_subkey.restype = c_bool
49
50regfi.regfi_find_value.argtypes = [POINTER(REGFI_FILE), POINTER(REGFI_NK),
51 c_char_p, POINTER(c_uint32)]
52regfi.regfi_find_value.restype = c_bool
53
54regfi.regfi_get_subkey.argtypes = [POINTER(REGFI_FILE), POINTER(REGFI_NK),
55 c_uint32]
56regfi.regfi_get_subkey.restype = POINTER(REGFI_NK)
57
58regfi.regfi_get_value.argtypes = [POINTER(REGFI_FILE), POINTER(REGFI_NK),
59 c_uint32]
60regfi.regfi_get_value.restype = POINTER(REGFI_VK)
61
62regfi.regfi_iterator_new.argtypes = [POINTER(REGFI_FILE), REGFI_ENCODING]
63regfi.regfi_iterator_new.restype = POINTER(REGFI_ITERATOR)
64
65regfi.regfi_iterator_free.argtypes = [POINTER(REGFI_ITERATOR)]
66regfi.regfi_iterator_free.restype = None
67
68regfi.regfi_iterator_down.argtypes = [POINTER(REGFI_ITERATOR)]
69regfi.regfi_iterator_down.restype = c_bool
70
71regfi.regfi_iterator_up.argtypes = [POINTER(REGFI_ITERATOR)]
72regfi.regfi_iterator_up.restype = c_bool
73
74regfi.regfi_iterator_to_root.argtypes = [POINTER(REGFI_ITERATOR)]
75regfi.regfi_iterator_to_root.restype = c_bool
76
77regfi.regfi_iterator_walk_path.argtypes = [POINTER(REGFI_ITERATOR)]
78regfi.regfi_iterator_walk_path.restype = c_bool
79
80regfi.regfi_iterator_cur_key.argtypes = [POINTER(REGFI_ITERATOR)]
81regfi.regfi_iterator_cur_key.restype = POINTER(REGFI_NK)
82
83regfi.regfi_iterator_first_subkey.argtypes = [POINTER(REGFI_ITERATOR)]
84regfi.regfi_iterator_first_subkey.restype = c_bool
85
86regfi.regfi_iterator_cur_subkey.argtypes = [POINTER(REGFI_ITERATOR)]
87regfi.regfi_iterator_cur_subkey.restype = POINTER(REGFI_NK)
88
89regfi.regfi_iterator_next_subkey.argtypes = [POINTER(REGFI_ITERATOR)]
90regfi.regfi_iterator_next_subkey.restype = c_bool
91
92regfi.regfi_iterator_find_subkey.argtypes = [POINTER(REGFI_ITERATOR), c_char_p]
93regfi.regfi_iterator_find_subkey.restype = c_bool
94
95regfi.regfi_iterator_first_value.argtypes = [POINTER(REGFI_ITERATOR)]
96regfi.regfi_iterator_first_value.restype = c_bool
97
98regfi.regfi_iterator_cur_value.argtypes = [POINTER(REGFI_ITERATOR)]
99regfi.regfi_iterator_cur_value.restype = POINTER(REGFI_VK)
100
101regfi.regfi_iterator_next_value.argtypes = [POINTER(REGFI_ITERATOR)]
102regfi.regfi_iterator_next_value.restype = c_bool
103
104regfi.regfi_iterator_find_value.argtypes = [POINTER(REGFI_ITERATOR), c_char_p]
105regfi.regfi_iterator_find_value.restype = c_bool
106
107
108
109regfi.regfi_get_value
110
111regfi.regfi_init.argtypes = []
112regfi.regfi_init.restype = None
113regfi.regfi_init()
114
115
116def GetLogMessages():
117 msgs = regfi.regfi_log_get_str()
118 if msgs == None:
119 return ''
120 return msgs.decode('ascii')
121
122
123def _buffer2bytearray(char_pointer, length):
124 if length == 0 or char_pointer == None:
125 return None
126
127 ret_val = bytearray(length)
128 for i in range(0,length):
129 ret_val[i] = char_pointer[i][0]
130
131 return ret_val
132
133
134def _charss2strlist(chars_pointer):
135 ret_val = []
136 i = 0
137 s = chars_pointer[i]
138 while s != None:
139 ret_val.append(s.decode('utf-8'))
140 i += 1
141 s = chars_pointer[i]
142
143 return ret_val
144
145
146class _StructureWrapper():
147 "Handles memory management and proxies attribute access to base structures"
148 hive = None
149 base = None
150
151 def __init__(self, hive, base):
152 self.hive = hive
153 # XXX: check for NULL here, throw an exception if so.
154 self.base = base
155
156 def __del__(self):
157 regfi.regfi_free_record(self.base)
158
159 def __getattr__(self, name):
160 return getattr(self.base.contents, name)
161
162 def __eq__(self, other):
163 return (type(self) == type(other)) and (self.offset == other.offset)
164
165 def __ne__(self, other):
166 return (not self.__eq__(other))
167
168
169class Key(_StructureWrapper):
170 pass
171
172class Value(_StructureWrapper):
173 pass
174
175class Data(_StructureWrapper):
176 pass
177
178class Security(_StructureWrapper):
179 pass
180
181
182class _GenericList():
183 hive = None
184 key = None
185 length = None
186 current = None
187
188 # implementation-specific functions
189 fetch_num = None
190 find_element = None
191 get_element = None
192 constructor = None
193
194 def __init__(self, key):
195 self.hive = key.hive
196 # XXX: check for NULL here, throw an exception if so.
197 self.key = key
198 self.length = self.fetch_num(key.base)
199
200 def __len__(self):
201 return self.length
202
203 def __getitem__(self, name):
204 index = c_uint32()
205 if isinstance(name, str):
206 name = name.encode('utf-8')
207
208 if name != None:
209 name = create_string_buffer(bytes(name))
210
211 if self.find_element(self.hive.file, self.key.base, name, byref(index)):
212 return self.constructor(self.hive, self.get_element(self.hive.file,
213 self.key.base,
214 index))
215 raise KeyError('')
216
217 def get(self, name, default):
218 try:
219 return self[name]
220 except KeyError:
221 return default
222
223 def __iter__(self):
224 self.current = 0
225 return self
226
227 def __next__(self):
228 if self.current >= self.length:
229 raise StopIteration('')
230
231 elem = self.get_element(self.hive.file, self.key.base,
232 c_uint32(self.current))
233 self.current += 1
234 return self.constructor(self.hive, elem)
235
236
237class _SubkeyList(_GenericList):
238 fetch_num = regfi.regfi_fetch_num_subkeys
239 find_element = regfi.regfi_find_subkey
240 get_element = regfi.regfi_get_subkey
241
242
243class _ValueList(_GenericList):
244 fetch_num = regfi.regfi_fetch_num_values
245 find_element = regfi.regfi_find_value
246 get_element = regfi.regfi_get_value
247
248
249class Key(_StructureWrapper):
250 values = None
251 subkeys = None
252
253 def __init__(self, hive, base):
254 super(Key, self).__init__(hive, base)
255 self.values = _ValueList(self)
256 self.subkeys = _SubkeyList(self)
257
258 def __getattr__(self, name):
259 ret_val = super(Key, self).__getattr__(name)
260
261 if name == "name":
262 if ret_val == None:
263 ret_val = self.name_raw
264 else:
265 ret_val = ret_val.decode('utf-8')
266
267 elif name == "name_raw":
268 length = super(Key, self).__getattr__('name_length')
269 ret_val = _buffer2bytearray(ret_val, length)
270
271 return ret_val
272
273
274 def fetch_security(self):
275 return Security(self.hive,
276 regfi.regfi_fetch_sk(self.hive.file, self.base))
277
278
279class Value(_StructureWrapper):
280 def __getattr__(self, name):
281 ret_val = None
282 if name == "data":
283 data_p = regfi.regfi_fetch_data(self.hive.file, self.base)
284 try:
285 data_struct = data_p.contents
286 except Exception:
287 return None
288
289 if data_struct.interpreted_size == 0:
290 ret_val = None
291 elif data_struct.type in (REG_SZ, REG_EXPAND_SZ, REG_LINK):
292 # Unicode strings
293 ret_val = data_struct.interpreted.string.decode('utf-8')
294 elif data_struct.type in (REG_DWORD, REG_DWORD_BE):
295 # 32 bit integers
296 ret_val = data_struct.interpreted.dword
297 elif data_struct.type == REG_QWORD:
298 # 64 bit integers
299 ret_val = data_struct.interpreted.qword
300 elif data_struct.type == REG_MULTI_SZ:
301 ret_val = _charss2strlist(data_struct.interpreted.multiple_string)
302 elif data_struct.type in (REG_NONE, REG_RESOURCE_LIST,
303 REG_FULL_RESOURCE_DESCRIPTOR,
304 REG_RESOURCE_REQUIREMENTS_LIST,
305 REG_BINARY):
306 ret_val = _buffer2bytearray(data_struct.interpreted.none,
307 data_struct.interpreted_size)
308
309 regfi.regfi_free_record(data_p)
310
311 elif name == "data_raw":
312 # XXX: should we load the data without interpretation instead?
313 data_p = regfi.regfi_fetch_data(self.hive.file, self.base)
314 try:
315 data_struct = data_p.contents
316 except Exception:
317 return None
318
319 ret_val = _buffer2bytearray(data_struct.raw,
320 data_struct.size)
321 regfi.regfi_free_record(data_p)
322
323 else:
324 ret_val = super(Value, self).__getattr__(name)
325 if name == "name":
326 if ret_val == None:
327 ret_val = self.name_raw
328 else:
329 ret_val = ret_val.decode('utf-8')
330
331 elif name == "name_raw":
332 length = super(Value, self).__getattr__('name_length')
333 ret_val = _buffer2bytearray(ret_val, length)
334
335 return ret_val
336
337
338# Avoids chicken/egg class definitions.
339# Also makes for convenient code reuse in these lists' parent classes.
340_SubkeyList.constructor = Key
341_ValueList.constructor = Value
342
343
344
345class Hive():
346 file = None
347 raw_file = None
348
349 def __init__(self, fh):
350 # The fileno method may not exist, or it may throw an exception
351 # when called if the file isn't backed with a descriptor.
352 try:
353 if hasattr(fh, 'fileno'):
354 self.file = regfi.regfi_alloc(fh.fileno())
355 return
356 except:
357 pass
358
359 self.raw_file = structures.REGFI_RAW_FILE()
360 self.raw_file.fh = fh
361 self.raw_file.seek = seek_cb_type(self.raw_file.cb_seek)
362 self.raw_file.read = read_cb_type(self.raw_file.cb_read)
363 self.file = regfi.regfi_alloc_cb(self.raw_file)
364
365 def __getattr__(self, name):
366 return getattr(self.file.contents, name)
367
368 def __del__(self):
369 regfi.regfi_free(self.file)
370 if self.raw_file != None:
371 regfi.regfi_free(self.file)
372
373
374 def __iter__(self):
375 return HiveIterator(self)
376
377 def subtree(self, path):
378 hi = HiveIterator(self)
379 hi.descend(path)
380 return hi
381
382
383class HiveIterator():
384 hive = None
385 iter = None
386 iteration_root = None
387
388 def __init__(self, hive):
389 # REGFI_ENCODING_UTF8==1
390 self.iter = regfi.regfi_iterator_new(hive.file, 1)
391 if self.iter == None:
392 raise Exception("Could not create iterator. Current log:\n"
393 + GetLogMessages())
394 self.hive = hive
395
396 def __getattr__(self, name):
397 return getattr(self.file.contents, name)
398
399 def __del__(self):
400 regfi.regfi_iterator_free(self.iter)
401
402 def __iter__(self):
403 self.iteration_root = None
404 return self
405
406 def __next__(self):
407 if self.iteration_root == None:
408 self.iteration_root = self.current_key()
409 elif not regfi.regfi_iterator_down(self.iter):
410 up_ret = regfi.regfi_iterator_up(self.iter)
411 while (up_ret and
412 not regfi.regfi_iterator_next_subkey(self.iter)):
413 if self.iteration_root == self.current_key():
414 self.iteration_root = None
415 raise StopIteration('')
416 up_ret = regfi.regfi_iterator_up(self.iter)
417
418 if not up_ret:
419 raise StopIteration('')
420
421 if not regfi.regfi_iterator_down(self.iter):
422 raise Exception('Error traversing iterator downward.'+
423 ' Current log:\n'+ GetLogMessages())
424
425 regfi.regfi_iterator_first_subkey(self.iter)
426 return self.current_key()
427
428 def down(self):
429 pass
430
431 def up(self):
432 pass
433
434 def descend(self, path):
435 #set up generator
436 cpath = (bytes(p,'ascii') for p in path)
437
438 # evaluate generator and create char* array
439 apath = (c_char_p*len(path))(*cpath)
440
441 if not regfi.regfi_iterator_walk_path(self.iter,apath):
442 raise Exception('Could not locate path.\n'+GetLogMessages())
443
444 def current_key(self):
445 return Key(self.hive, regfi.regfi_iterator_cur_key(self.iter))
Note: See TracBrowser for help on using the repository browser.