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

Last change on this file since 209 was 209, checked in by tim, 14 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.