def loadMembers(self, mappings, maxDepth): if not LoadableMembersStructure.loadMembers(self, mappings, maxDepth): return False # Load and memcopy key and iv log.debug('Enc Memcopying a Key with %d bytes'%self.key_len) attr_obj_address = getaddress(self.key) log.debug('got key @%x '%(attr_obj_address)) memoryMap = is_valid_address_value( attr_obj_address, mappings) # DEBUG - I do question the buffer_copy. log.debug('memoryMap is %s - \nmake array '%(memoryMap)) array=(ctypes.c_ubyte*self.key_len).from_buffer_copy(memoryMap.readArray(attr_obj_address, ctypes.c_ubyte, self.key_len)) # save key as bitstream ##key_contents = ctypes.c_ubyte.from_buffer(array) key_contents = array log.debug('keep ref ') model.keepRef(key_contents, model.get_subtype(self.key), attr_obj_address) log.debug('Enc Memcopying a IV with %d bytes'%( self.block_size) ) attr_obj_address=getaddress(self.iv) memoryMap = is_valid_address_value( attr_obj_address, mappings) log.debug('make array ') array=(ctypes.c_ubyte*self.block_size).from_buffer_copy(memoryMap.readArray(attr_obj_address, ctypes.c_ubyte,self.block_size)) # save iv contents as bitstream ##iv_contents = ctypes.c_ubyte.from_buffer(array) iv_contents = array log.debug('keep ref') model.keepRef(iv_contents, model.get_subtype(self.iv), attr_obj_address) log.debug('ENC KEY(%d bytes) and IV(%d bytes) acquired'%(self.key_len,self.block_size)) return True
def test_keepRef(self): self.assertNotEqual(self.mappings, None) for fname, ftype in self.heap_obj.getFields(): attr = getattr(self.heap_obj, fname) if isCStringPointer(ftype): # ignore that - attr_addr = getaddress(attr.ptr) continue elif isPointerType(ftype): attr_addr = getaddress(attr) else: continue if attr_addr == 0: continue self.assertTrue( utils.is_valid_address_value(attr_addr, self.mappings), '%s: 0x%x is not valid' % (fname, attr_addr)) # the book should register struct type, not pointer to strut type attr_type = model.get_subtype(ftype) # look in the books saved = model.getRefByAddr(attr_addr) _class, _addr, _obj = saved[0] self.assertEquals(attr_addr, _addr) self.assertEquals(attr_type, _class, '%s != %s' % (type(ftype), type(_class))) self.assertTrue(model.hasRef(model.get_subtype(ftype), attr_addr)) return
def test_keepRef(self): self.assertNotEqual( self.mappings, None ) for fname, ftype in self.heap_obj.getFields(): attr = getattr(self.heap_obj, fname) if isCStringPointer(ftype): # ignore that - attr_addr = getaddress(attr.ptr) continue elif isPointerType(ftype): attr_addr = getaddress(attr) else: continue if attr_addr == 0: continue self.assertTrue( utils.is_valid_address_value(attr_addr, self.mappings), '%s: 0x%x is not valid'%(fname, attr_addr)) # the book should register struct type, not pointer to strut type attr_type = model.get_subtype(ftype) # look in the books saved = model.getRefByAddr( attr_addr ) _class, _addr, _obj = saved[0] self.assertEquals( attr_addr, _addr) self.assertEquals( attr_type, _class, '%s != %s' %(type(ftype), type(_class))) self.assertTrue( model.hasRef( model.get_subtype(ftype), attr_addr)) return
def loadMembers(self, mappings, maxDepth): if not LoadableMembersStructure.loadMembers(self, mappings, maxDepth): return False # Load and memcopy key log.debug('Memcopying a Key with %d bytes'%self.key_len) attr_obj_address=getaddress(self.key) memoryMap = is_valid_address_value( attr_obj_address, mappings) array=(ctypes.c_ubyte*self.key_len).from_buffer_copy(memoryMap.readArray(attr_obj_address, ctypes.c_ubyte, self.key_len)) model.keepRef(array, model.get_subtype(self.key), attr_obj_address) log.debug('unmac_ctx has been nulled and ignored. its not often used by any ssh impl. Not useful for us anyway.') log.debug('MAC KEY(%d bytes) acquired'%(self.key_len)) return True
def check_varname_for_type(varname, structType): done = [] st = structType from haystack import model for v in varname: if not hasattr(st, v): fields = ["%s: %s"%(n,t) for n,t in st.getFields()] log.error('(%s.)%s does not exists in type %s\n\t%s'%('.'.join(done), v, st, '\n\t'.join(fields)) ) return False st = st.getFieldType(v) if utils.isPointerType(st): # accept pointers st = model.get_subtype(st) done.append(v) return True
def check_varname_for_type(varname, structType): done = [] st = structType from haystack import model for v in varname: if not hasattr(st, v): fields = ["%s: %s" % (n, t) for n, t in st.getFields()] log.error('(%s.)%s does not exists in type %s\n\t%s' % ('.'.join(done), v, st, '\n\t'.join(fields))) return False st = st.getFieldType(v) if utils.isPointerType(st): # accept pointers st = model.get_subtype(st) done.append(v) return True
def _attrToString(self,attr,field,attrtype,prefix, depth=-1): s='' if isStructType(attrtype): s=prefix+'"%s": {\t%s%s},\n'%(field, attr.toString(prefix+'\t', depth-1),prefix ) elif isFunctionType(attrtype): s=prefix+'"%s": 0x%lx, #(FIELD NOT LOADED: function type)\n'%(field, getaddress(attr) ) # only print address in target space elif isBasicTypeArray(attr): ## array of something else than int s=prefix+'"%s": b%s,\n'%(field, repr(array2bytes(attr)) ) elif isArrayType(attrtype): ## array of something else than int/byte # go through each elements, we hardly can make a array out of that... s=prefix+'"%s" :{'%(field) eltyp=type(attr[0]) for i in range(0,len(attr)): s+=self._attrToString( attr[i], i, eltyp, '') s+='},\n' elif isPointerType(attrtype): if not bool(attr) : s=prefix+'"%s": 0x%lx,\n'%(field, getaddress(attr) ) # only print address/null elif isVoidPointerType(attrtype) : s=prefix+'"%s": 0x%lx, #(FELD NOT LOADED: void pointer) \n'%(field, attr ) # only print address/null elif not is_address_local(attr) : s=prefix+'"%s": 0x%lx, #(FIELD NOT LOADED)\n'%(field, getaddress(attr) ) # only print address in target space else: # we can read the pointers contents # if isBasicType(attr.contents): ? # if isArrayType(attr.contents): ? _attrType = get_subtype(attrtype) contents = getRef(_attrType, getaddress(attr)) if type(self) == type(contents): s=prefix+'"%s": { #(0x%lx) -> %s\n%s},\n'%(field, getaddress(attr), _attrType, prefix) # use struct printer elif isStructType(type(contents)): # do not enter in lists s=prefix+'"%s": { #(0x%lx) -> %s%s},\n'%(field, getaddress(attr), contents.toString(prefix+'\t', depth-1),prefix) # use struct printer elif isPointerType(type(contents)): s=prefix+'"%s": { #(0x%lx) -> %s%s},\n'%(field, getaddress(attr), self._attrToString(contents, None, None, prefix+'\t'), prefix ) # use struct printer else: s=prefix+'"%s": { #(0x%lx) -> %s\n%s},\n'%(field, getaddress(attr), contents, prefix) # use struct printer elif isCStringPointer(attrtype): s=prefix+'"%s": "%s" , #(CString)\n'%(field, getRef(CString, getaddress(attr.ptr)) ) elif isBasicType(attrtype): # basic, ctypes.* !Structure/pointer % CFunctionPointer? s=prefix+'"%s": %s, \n'%(field, repr(attr) ) elif isUnionType(attrtype): # UNION s=prefix+'"%s": { # UNION DEFAULT repr\t%s%s},\n'%(field, attr.toString(prefix+'\t', depth-1),prefix ) else: # wtf ? s=prefix+'"%s": %s, # Unknown/bug DEFAULT repr\n'%(field, repr(attr) ) return s
def _HEAP_SEGMENT_loadMember(self, attr, attrname, attrtype, mappings, maxDepth): #log.debug('_loadMember attrname : %s'%(attrname)) if attrname == 'LastValidEntry': # isPointerType code. _attrType = model.get_subtype(attrtype) attr_obj_address = utils.getaddress(attr) #### memoryMap = utils.is_valid_address(attr, mappings, _attrType) if (not memoryMap): log.debug("LastValidEntry out of mapping - 0x%lx - ignore " % (attr_obj_address)) return True from haystack.model import getRef, keepRef, delRef # TODO CLEAN ref = getRef(_attrType, attr_obj_address) if ref: #log.debug("%s %s loading from references cache %s/0x%lx"%(attrname,attr,_attrType,attr_obj_address )) #DO NOT CHANGE STUFF SOUPID attr.contents = ref return True #log.debug("%s %s loading from 0x%lx (is_valid_address: %s)"%(attrname,attr,attr_obj_address, memoryMap )) ##### Read the struct in memory and make a copy to play with. ### ERRROR attr.contents=_attrType.from_buffer_copy(memoryMap.readStruct(attr_obj_address, _attrType )) contents = memoryMap.readStruct(attr_obj_address, _attrType) # save that validated and loaded ref and original addr so we dont need to recopy it later keepRef(contents, _attrType, attr_obj_address) #log.debug("%s %s loaded memcopy from 0x%lx to 0x%lx"%(attrname, attr, attr_obj_address, (utils.getaddress(attr)) )) # recursive validation checks on new struct if not bool(attr): log.warning('Member %s is null after copy: %s' % (attrname, attr)) return True # go and load the pointed struct members recursively if not contents.loadMembers(mappings, maxDepth): log.debug('member %s was not loaded' % (attrname)) #invalidate the cache ref. delRef(_attrType, attr_obj_address) return False return True else: return super(_HEAP_SEGMENT, self)._loadMember(attr, attrname, attrtype, mappings, maxDepth)
def _HEAP_SEGMENT_loadMember(self, attr, attrname, attrtype, mappings, maxDepth): # log.debug('_loadMember attrname : %s'%(attrname)) if attrname == "LastValidEntry": # isPointerType code. _attrType = model.get_subtype(attrtype) attr_obj_address = utils.getaddress(attr) #### memoryMap = utils.is_valid_address(attr, mappings, _attrType) if not memoryMap: log.debug("LastValidEntry out of mapping - 0x%lx - ignore " % (attr_obj_address)) return True from haystack.model import getRef, keepRef, delRef # TODO CLEAN ref = getRef(_attrType, attr_obj_address) if ref: # log.debug("%s %s loading from references cache %s/0x%lx"%(attrname,attr,_attrType,attr_obj_address )) # DO NOT CHANGE STUFF SOUPID attr.contents = ref return True # log.debug("%s %s loading from 0x%lx (is_valid_address: %s)"%(attrname,attr,attr_obj_address, memoryMap )) ##### Read the struct in memory and make a copy to play with. ### ERRROR attr.contents=_attrType.from_buffer_copy(memoryMap.readStruct(attr_obj_address, _attrType )) contents = memoryMap.readStruct(attr_obj_address, _attrType) # save that validated and loaded ref and original addr so we dont need to recopy it later keepRef(contents, _attrType, attr_obj_address) # log.debug("%s %s loaded memcopy from 0x%lx to 0x%lx"%(attrname, attr, attr_obj_address, (utils.getaddress(attr)) )) # recursive validation checks on new struct if not bool(attr): log.warning("Member %s is null after copy: %s" % (attrname, attr)) return True # go and load the pointed struct members recursively if not contents.loadMembers(mappings, maxDepth): log.debug("member %s was not loaded" % (attrname)) # invalidate the cache ref. delRef(_attrType, attr_obj_address) return False return True else: return super(_HEAP_SEGMENT, self)._loadMember(attr, attrname, attrtype, mappings, maxDepth)
def getKey(self): #return pointer2bytes(self.key,self.key_len) return model.array2bytes( model.getRef( model.get_subtype(self.key), getaddress(self.key)) )
def getIV(self): #return pointer2bytes(model.getRef(ctypes.Array, getaddress(self.iv)), self.block_size) return model.array2bytes(model.getRef( model.get_subtype(self.iv), getaddress(self.iv)) )
def _attrToPyObject(self,attr,field,attrtype): if isStructType(attrtype): obj=attr.toPyObject() elif isUnionType(attrtype): obj=attr.toPyObject() elif isBasicTypeArray(attr): ## array of basic types obj=array2bytes(attr) elif isArrayType(attrtype): ## array of something else than int/byte obj=[] eltyp=type(attr[0]) for i in range(0,len(attr)): obj.append(self._attrToPyObject( attr[i], i, eltyp) ) elif isFunctionType(attrtype): obj = repr(attr) elif isCStringPointer(attrtype): #obj = getRef(CString, getaddress(attr)).toString() obj = attr.toString() elif isPointerType(attrtype): if isVoidPointerType(attrtype): log.error('Void pointer - %s'%(field)) obj='Void Pointer' elif isBasicTypeArray(attr): log.error('basic Type array - %s'%(field)) obj='BasicType array' elif not bool(attr) : obj=(None,None) else: # get the cached Value of the LP. _subtype = get_subtype(attrtype) cache = getRef(_subtype, getaddress(attr) ) if cache is not None: obj = self._attrToPyObject(cache, field, _subtype ) elif isPointerBasicType(attrtype): log.error('Pointer to Basic type - %s'%(field)) obj = 'Pointer to Basic type' else: log.error('LP structure for field:%s %s/%s not in cache %x'%(field, attrtype, get_subtype(attrtype), getaddress(attr) ) ) #raise ValueError('LP structure for %s not in cache %s,%x'%(field, get_subtype(attrtype), getaddress(attr) ) ) return (None,None) # ####### any pointer should be in cache # contents=attr.contents # will SEGFAULT # if isStructType(type(contents)) : # attr_py_class = getattr(sys.modules[contents.__class__.__module__],"%s_py"%(contents.__class__.__name__) ) # cache = getRef(attr_py_class, getaddress(attr) ) # if cache: # return cache # #else: # # log.error('any LP struct should be in cache.') # # raise ValueError('LP structure not in cache %s'%(attr_py_class)) # obj=contents.toPyObject() # elif isPointerType(type(contents)): # obj=self._attrToPyObject(contents,None,None) # else: # pointer vers autre chose, le repr() est le seul choix. # #obj=repr(contents) # obj=contents elif isBasicType(attrtype) and isCTypes(attr): obj = attr.value elif isinstance(attr, numbers.Number): obj = attr else: log.error('toPyObj default to return attr %s'%( type(attr) )) obj = attr return obj
def _loadMember(self,attr,attrname,attrtype,mappings, maxDepth): # skip static basic data members if not self._isLoadableMember(attr, attrname, attrtype): log.debug("%s %s not loadable bool(attr) = %s"%(attrname,attrtype, bool(attr)) ) return True # load it, fields are valid elif isStructType(attrtype) or isUnionType(attrtype): # DEBUG TEST offset = offsetof(type(self),attrname) log.debug('st: %s %s is STRUCT at @%x'%(attrname,attrtype, self._orig_address_ + offset) ) # TODO pydoc for impl. attr._orig_address_ = self._orig_address_ + offset if not attr.loadMembers(mappings, maxDepth+1): log.debug("st: %s %s not valid, erreur while loading inner struct "%(attrname,attrtype) ) return False log.debug("st: %s %s inner struct LOADED "%(attrname,attrtype) ) return True elif isBasicTypeArray(attr): return True if isArrayType(attrtype): log.debug('a: %s is arraytype %s recurse load'%(attrname,repr(attr)) )# attrLen=len(attr) if attrLen == 0: return True elType=type(attr[0]) for i in range(0,attrLen): # FIXME BUG DOES NOT WORK - offsetof("%s[%d]") is called, and %s exists, not %s[%d] #if not self._loadMember(attr[i], "%s[%d]"%(attrname,i), elType, mappings, maxDepth): if not self._loadMember(attr[i], attrname, elType, mappings, maxDepth): return False return True # we have PointerType here . Basic or complex # exception cases if isCStringPointer(attrtype) : # can't use basic c_char_p because we can't load in foreign memory attr_obj_address = getaddress(attr.ptr) if not bool(attr_obj_address): log.debug('%s %s is a CString, the pointer is null (validation must have occurred earlier) '%(attrname, attr)) return True memoryMap = is_valid_address_value(attr_obj_address, mappings) if not memoryMap : log.warning('Error on addr while fetching a CString. should not happen') return False MAX_SIZE=255 ref = getRef(CString,attr_obj_address) if ref: log.debug("%s %s loading from references cache %s/0x%lx"%(attrname,attr,CString,attr_obj_address )) return True log.debug("%s %s is defined as a CString, loading from 0x%lx is_valid_address %s"%( attrname,attr,attr_obj_address, is_valid_address(attr,mappings) )) txt,full = memoryMap.readCString(attr_obj_address, MAX_SIZE ) if not full: log.warning('buffer size was too small for this CString') # that will SEGFAULT attr.string = txt - instead keepRef to String keepRef( txt, CString, attr_obj_address) log.debug('kept CString ref for "%s" at @%x'%(txt, attr_obj_address)) return True elif isPointerType(attrtype): # not functionType, it's not loadable _attrType = get_subtype(attrtype) attr_obj_address=getaddress(attr) #### # memcpy and save objet ref + pointer in attr # we know the field is considered valid, so if it's not in memory_space, we can ignore it memoryMap = is_valid_address( attr, mappings, _attrType) if(not memoryMap): # big BUG Badaboum, why did pointer changed validity/value ? log.warning("%s %s not loadable 0x%lx but VALID "%(attrname, attr,attr_obj_address )) return True ref = getRef(_attrType,attr_obj_address) if ref: log.debug("%s %s loading from references cache %s/0x%lx"%(attrname,attr,_attrType,attr_obj_address )) #DO NOT CHANGE STUFF SOUPID attr.contents = ref. attr.contents will SEGFAULT return True log.debug("%s %s loading from 0x%lx (is_valid_address: %s)"%(attrname,attr,attr_obj_address, memoryMap )) ##### Read the struct in memory and make a copy to play with. #### DO NOT COPY THE STRUCT, we have a working readStruct for that... ### ERRROR attr.contents=_attrType.from_buffer_copy(memoryMap.readStruct(attr_obj_address, _attrType )) contents=memoryMap.readStruct(attr_obj_address, _attrType ) # save that validated and loaded ref and original addr so we dont need to recopy it later keepRef( contents, _attrType, attr_obj_address) log.debug("keepRef %s.%s @%x"%(_attrType, attrname, attr_obj_address )) log.debug("%s %s loaded memcopy from 0x%lx to 0x%lx"%(attrname, attr, attr_obj_address, (getaddress(attr)) )) # recursive validation checks on new struct if not bool(attr): log.warning('Member %s is null after copy: %s'%(attrname,attr)) return True # go and load the pointed struct members recursively if not contents.loadMembers(mappings, maxDepth): log.debug('member %s was not loaded'%(attrname)) #invalidate the cache ref. delRef( _attrType, attr_obj_address) return False return True #TATAFN return True
def _isValidAttr(self,attr,attrname,attrtype,mappings): ''' Validation of a single member ''' # a) log.debug('valid: %s, %s'%(attrname, attrtype)) if isBasicType(attrtype): if attrname in self.expectedValues: if attr not in self.expectedValues[attrname]: log.debug('basicType: %s %s %s bad value not in self.expectedValues[attrname]:'%(attrname,attrtype,repr(attr) )) return False log.debug('basicType: %s %s %s ok'%(attrname,attrtype,repr(attr) )) return True # b) elif isStructType(attrtype) or isUnionType(attrtype): ### do i need to load it first ? becaus it should be memcopied with the super().. if not attr.isValid(mappings): log.debug('structType: %s %s %s isValid FALSE'%(attrname,attrtype,repr(attr) )) return False log.debug('structType: %s %s %s isValid TRUE'%(attrname,attrtype,repr(attr) )) return True # c) elif isBasicTypeArray(attr): if attrname in self.expectedValues: if attr not in self.expectedValues[attrname]: log.debug('basicArray: %s %s %s bad value not in self.expectedValues[attrname]:'%(attrname,attrtype,repr(attr) )) return False log.debug('basicArray: %s is arraytype %s we decided it was valid',attrname,repr(attr))# return True elif isArrayType(attrtype): log.debug('array: %s is arraytype %s recurse validate'%(attrname,repr(attr)) )# attrLen=len(attr) if attrLen == 0: return True elType=type(attr[0]) for i in range(0,attrLen): # FIXME BUG DOES NOT WORK - offsetof("%s[%d]") is called, and %s exists, not %s[%d] if not self._isValidAttr(attr[i], "%s[%d]"%(attrname,i), elType, mappings ): return False return True # d) elif isCStringPointer(attrtype): myaddress=getaddress(attr.ptr) if attrname in self.expectedValues: # test if NULL is an option if not bool(myaddress) : if not ( (None in self.expectedValues[attrname]) or (0 in self.expectedValues[attrname]) ): log.debug('str: %s %s %s isNULL and that is NOT EXPECTED'%(attrname,attrtype,repr(attr) )) return False log.debug('str: %s %s %s isNULL and that is OK'%(attrname,attrtype,repr(attr) )) return True if (myaddress != 0) and ( not is_valid_address_value( myaddress, mappings) ) : log.debug('str: %s %s %s 0x%lx INVALID'%(attrname,attrtype, repr(attr) ,myaddress)) return False log.debug('str: %s %s %s is at 0x%lx OK'%(attrname,attrtype,repr(attr),myaddress )) return True # e) elif isPointerType(attrtype): if attrname in self.expectedValues: # test if NULL is an option log.debug('isPointerType: bool(attr):%s attr:%s'%(bool(attr), attr)) if not bool(attr): if not ( (None in self.expectedValues[attrname]) or (0 in self.expectedValues[attrname]) ): log.debug('ptr: %s %s %s isNULL and that is NOT EXPECTED'%(attrname,attrtype,repr(attr) )) return False log.debug('ptr: %s %s %s isNULL and that is OK'%(attrname,attrtype,repr(attr) )) return True # all case, _attrType=None if isVoidPointerType(attrtype) or isFunctionType(attrtype): log.debug('Its a simple type. Checking mappings only. attr=%s'%(attr)) if getaddress(attr) != 0 and not is_valid_address_value( attr, mappings): # NULL can be accepted log.debug('voidptr: %s %s %s 0x%lx INVALID simple pointer'%(attrname,attrtype, repr(attr) ,getaddress(attr))) return False else: # test valid address mapping _attrType = get_subtype(attrtype) if ( not is_valid_address( attr, mappings, _attrType) ) and (getaddress(attr) != 0): # why ? print 'wordsize',Config.WORDSIZE print 'is_valid_address( %s, mappings, %s) = %s'%( attrname, _attrType ,is_valid_address( attr, mappings, _attrType)) print 'attr',attr.value print 'attr in mappings', int(attr.value) in mappings log.debug('ptr: %s %s %s 0x%lx INVALID'%(attrname,attrtype, repr(attr) ,getaddress(attr))) return False # null is accepted by default log.debug('ptr: name:%s repr:%s getaddress:0x%lx OK'%(attrname,repr(attr) ,getaddress(attr))) return True log.error('What type are You ?: %s/%s'%(attrname,attrtype)) return True
s+='%s (@0x%lx) :['%(field, ctypes.addressof(attr),)+','.join(["%s"%(val) for val in attr ])+'],\n' continue elif isCStringPointer(attrtype): if not bool(attr) : s+='%s (@0x%lx) : 0x%lx\n'%(field,ctypes.addressof(attr), getaddress(attr.ptr) ) # only print address/null elif not is_address_local(attr) : s=prefix+'"%s": 0x%lx, #(FIELD NOT LOADED)\n'%(field, getaddress(attr) ) # only print address in target space else: s+='%s (@0x%lx) : %s (CString) \n'%(field,ctypes.addressof(attr), getRef(CString, getaddress(attr.ptr))) elif isPointerType(attrtype) and not isVoidPointerType(attrtype): # bug with CString if not bool(attr) : s+='%s (@0x%lx) : 0x%lx\n'%(field, ctypes.addressof(attr), getaddress(attr) ) # only print address/null elif not is_address_local(attr) : s+='%s (@0x%lx) : 0x%lx (FIELD NOT LOADED)\n'%(field, ctypes.addressof(attr), getaddress(attr) ) # only print address in target space else: _attrType=get_subtype(attrtype) contents = getRef(_attrType, getaddress(attr)) if type(self) == type(contents): # do not recurse in lists s+='%s (@0x%lx) : (0x%lx) -> {%s}\n'%(field, ctypes.addressof(attr), getaddress(attr), repr(contents) ) # use struct printer else: s+='%s (@0x%lx) : (0x%lx) -> {%s}\n'%(field, ctypes.addressof(attr), getaddress(attr), contents) # use struct printer elif type(attr) is long or type(attr) is int: s+='%s : %s\n'%(field, hex(attr) ) else: s+='%s : %s\n'%(field, repr(attr) ) return s def __repr__(self): if hasattr(self, '_orig_address_'): return "# <%s at @%x>\n"%(self.__class__.__name__, self._orig_address_) else: