-
Notifications
You must be signed in to change notification settings - Fork 33
Expand file tree
/
Copy pathutils.py
More file actions
357 lines (301 loc) · 10.2 KB
/
utils.py
File metadata and controls
357 lines (301 loc) · 10.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2011 Loic Jaquemet loic.jaquemet+python@gmail.com
#
'''
This module holds some basic constraint class for the Haystack model.
Several useful function validation are also here, like pointer validation.
'''
__author__ = "Loic Jaquemet loic.jaquemet+python@gmail.com"
import ctypes, os
from struct import pack,unpack
import logging
log = logging.getLogger('utils')
class Dummy(object):
pass
def is_valid_address(obj, mappings, structType=None):
'''
@param obj: the obj to evaluate.
@param mappings: the memory mappings in a list.
@param structType: the object's type, so the size could be taken in consideration.
Returns False if the object address is NULL.
Returns False if the object address is not in a mapping.
Returns False if the object overflows the mapping.
Returns the mapping in which the object stands otherwise.
'''
# check for null pointers
addr = getaddress(obj)
if addr == 0:
return False
return is_valid_address_value(addr, mappings, structType)
def is_valid_address_value(addr, mappings, structType=None):
'''
@param addr: the address to evaluate.
@param mappings: the memory mappings in a list.
@param structType: the object's type, so the size could be taken in consideration.
Returns False if the object address is NULL.
Returns False if the object address is not in a mapping.
Returns False if the object overflows the mapping.
Returns the mapping in which the address stands otherwise.
'''
m = mappings.getMmapForAddr(addr)
if m:
if (structType is not None):
s = ctypes.sizeof(structType)
if (addr+s) not in m:
return False
return m
return False
def is_address_local(obj, structType=None):
'''
Costly , checks if obj is mapped to local memory space.
Returns the memory mapping if found.
False, otherwise.
'''
addr=getaddress(obj)
if addr == 0:
return False
class P:
pid=os.getpid()
from memory_mapping import readProcessMappings # loading dependencies
mappings = readProcessMappings(P()) # memory_mapping
return is_valid_address(obj, mappings, structType)
def getaddress(obj):
'''
Returns the address of the struct pointed by the obj, or null if invalid.
@param obj: a pointer.
'''
# check for null pointers
if bool(obj):
if not hasattr(obj,'contents'):
return 0
return ctypes.addressof(obj.contents)
else:
return 0
def container_of(memberaddr, typ, membername):
'''
Returns the instance of typ(), in which the member "membername' is really.
@param memberadd: the address of membername.
@param typ: the type of the containing structure.
@param membername: the membername.
Stolen from linux kernel headers.
const typeof( ((typ *)0)->member ) *__mptr = (ptr);
(type *)( (char *)__mptr - offsetof(type,member) );})
'''
return typ.from_address( memberaddr - offsetof(typ, membername) )
def offsetof(typ, membername):
'''
Returns the offset of a member in a structure.
@param typ: the structure type.
@param membername: the membername in that structure.
'''
T=typ()
return ctypes.addressof( getattr(T,membername) ) - ctypes.addressof(T)
''' MISSING
d double float 8 (4)
p char[] string
'''
bytestr_fmt={
'c_bool': '?',
'c_char': 'c',
'c_byte': 'b',
'c_ubyte': 'B',
'c_short': 'h',
'c_ushort': 'H',
'c_int': 'i', #c_int is c_long
'c_uint': 'I',
'int': 'i',
'c_long': 'l', #c_int is c_long
'c_ulong': 'L',
'long': 'q',
'c_longlong': 'q',
'c_ulonglong': 'Q',
'c_float': 'f', ## and double float ?
'c_char_p': 's',
'c_void_p': 'P',
'c_void': 'P', ## void in array is void_p ##DEBUG
}
def array2bytes_(array, typ):
''' Convert an array of typ() to a byte string.'''
arrayLen = len(array)
if arrayLen == 0:
return b''
if typ not in bytestr_fmt:
log.warning('Unknown ctypes to pack: %s %s'%(typ,array))
return None
if typ == 'c_void':
return b'' # void array cant be extracted
fmt=bytestr_fmt[typ]
sb=b''
try:
for el in array:
sb+=pack(fmt, el)
except Exception ,e:
log.warning('%s %s'%(fmt,el))
#raise e
return sb
def array2bytes(array):
''' Convert an array of undetermined Basic Ctypes class to a byte string,
by guessing it's type from it's class name.
This is a bad example of introspection.
'''
if not isBasicTypeArray(array):
return b'NOT-AN-BasicType-ARRAY'
# BEURK
#log.info(type(array).__name__.split('_'))
typ='_'.join(type(array).__name__.split('_')[:2])
return array2bytes_(array,typ)
def bytes2array(bytes, typ):
''' Converts a bytestring in a ctypes array of typ() elements.'''
typLen=ctypes.sizeof(typ)
if len(bytes)%typLen != 0:
raise ValueError('thoses bytes are not an array of %s'%(typ))
arrayLen=len(bytes)/typLen
array=(typ*arrayLen)()
if arrayLen == 0:
return array
if typ.__name__ not in bytestr_fmt:
log.warning('Unknown ctypes to pack: %s'%(typ))
return None
fmt=bytestr_fmt[typ.__name__]
sb=b''
import struct
try:
for i in range(0,arrayLen):
array[i]=unpack(fmt, bytes[typLen*i:typLen*(i+1)])[0]
except struct.error,e:
log.error('format:%s typLen*i:typLen*(i+1) = %d:%d'%(fmt, typLen*i,typLen*(i+1)))
raise e
return array
def pointer2bytes(attr,nbElement):
'''
Returns an array from a ctypes POINTER, geiven the number of elements.
@param attr: the structure member.
@param nbElement: the number of element in the array.
'''
# attr is a pointer and we want to read elementSize of type(attr.contents))
if not is_address_local(attr):
return 'POINTER NOT LOCAL'
firstElementAddr=getaddress(attr)
array=(type(attr.contents)*nbElement).from_address(firstElementAddr)
# we have an array type starting at attr.contents[0]
return array2bytes(array)
def isCTypes(obj):
''' Checks if an object is a ctypes type object'''
return issubclass(type(obj), ctypes.Structure) #or (type(obj).__module__ in ['ctypes','_ctypes'])
def isBasicType(objtype):
''' Checks if an object is a ctypes basic type, or a python basic type.'''
return (isinstance(objtype, type) and not isPointerType(objtype) and not isFunctionType(objtype)
and (objtype.__module__ in ['ctypes','_ctypes','__builtin__']) )
#return not isPointerType(obj) and not isFunctionType(obj) and (type(obj).__module__ in ['ctypes','_ctypes','__builtin__'])
def isStructType(objtype):
''' Checks if an object is a ctypes Structure.'''
return issubclass(objtype, ctypes.Structure)
#return isinstance(obj, ctypes.Structure)
__ptrt = type(ctypes.POINTER(ctypes.c_int))
def isPointerType(objtype):
''' Checks if an object is a ctypes pointer.m CTypesPointer or CSimpleTypePointer'''
return __ptrt == type(objtype) or isVoidPointerType(objtype) or isFunctionType(objtype)
#return __ptrt == type(type(obj)) or type(type(obj)) == type(ctypes.c_void_p) or isFunctionType(obj)
def isVoidPointerType(objtype):
''' Checks if an object is a ctypes pointer.m CTypesPointer or CSimpleTypePointer'''
return objtype in [ctypes.original_c_char_p, ctypes.c_wchar_p, ctypes.c_void_p]
def isBasicTypeArray(obj):
''' Checks if an object is a array of basic types.
It checks the type of the first element.
The array should not be null :).
'''
if isArrayType(type(obj)):
if len(obj) == 0:
return False # no len is no BasicType
if isPointerType(type(obj[0])):
return False
if isBasicType(type(obj[0])):
return True
return False
__arrayt = type(ctypes.c_int*1)
def isArrayType(objtype):
''' Checks if an object is a ctype array.'''
return __arrayt == type(objtype)
__cfuncptrt = type(type(ctypes.memmove))
def isFunctionType(objtype):
''' Checks if an object is a function pointer.'''
return __cfuncptrt == type(objtype)
def isCStringPointer(objtype):
''' Checks if an object is our CString.'''
#return isinstance(obj, haystack.model.CString)
#return obj.__class__.__name__ == 'CString'
import haystack
return issubclass(objtype, haystack.model.CString)
def isUnionType(objtype):
''' Checks if an object is a Union type.'''
return issubclass(objtype,ctypes.Union) and not isCStringPointer(objtype)
class IgnoreMember:
'''
Constraint class for the Haystack model.
If this constraints is applied on a Structure member,
the member will be ignored by the validation engine.
'''
def __contains__(self,obj):
return True
class RangeValue:
'''
Constraint class for the Haystack model.
If this constraints is applied on a Structure member,
the member has to be between 'low' and 'high' values to be
considered as Valid.
'''
def __init__(self,low,high):
self.low=low
self.high=high
def __contains__(self,obj):
return self.low <= obj <= self.high
def __eq__(self,obj):
return self.low <= obj <= self.high
class NotNullComparable:
'''
Constraint class for the Haystack model.
If this constraints is applied on a Structure member,
the member should not be null to be considered valid by the validation engine.
'''
def __contains__(self,obj):
return bool(obj)
def __eq__(self,obj):
return bool(obj)
'''
Constraint class for the Haystack model.
If this constraints is applied on a Structure member,
the member should not be null to be considered valid by the validation engine.
'''
NotNull=NotNullComparable()
class BytesComparable:
'''
Constraint class for the Haystack model.
If this constraints is applied on a Structure member,
the member should have the same bytes value and length.
'''
def __init__(self, seq):
self.seq = seq
def __contains__(self,obj):
if cmp(self,obj) == 0:
return True
return False
def __cmp__(self,obj):
if isinstance(obj, type(ctypes.c_void_p)):
if ctypes.sizeof(obj) != len(seq):
return -1
bytes = ctypes.string_at(ctypes.addressof(obj), ctypes.sizeof(obj) )
if bytes == self.seq:
return 0
else:
return -1
return cmp(self.seq, ctypes.string_at(ctypes.addressof(obj), ctypes.sizeof(obj) ) )
PerfectMatch=BytesComparable
py_xrange=xrange
def xrange(start, end, step=1):
''' stoupid xrange can't handle long ints... '''
end=end-start
for val in py_xrange(0, end, step):
yield start+val
return