예제 #1
0
    def test_getRef(self):
        model.keepRef(1, int, 0xcafecafe)
        model.keepRef(2, float, 0xcafecafe)

        self.assertEquals(model.getRef(int, 0xcafecafe), 1)
        self.assertEquals(model.getRef(float, 0xcafecafe), 2)
        self.assertIsNone(model.getRef(str, 0xcafecafe))
        self.assertIsNone(model.getRef(str, 0xdeadbeef))
        self.assertIsNone(model.getRef(int, 0xdeadbeef))
예제 #2
0
  def test_getRef(self):
    model.keepRef(1, int, 0xcafecafe)
    model.keepRef(2, float, 0xcafecafe)

    self.assertEquals( model.getRef(int,0xcafecafe), 1)
    self.assertEquals( model.getRef(float,0xcafecafe), 2)
    self.assertIsNone( model.getRef(str,0xcafecafe))
    self.assertIsNone( model.getRef(str,0xdeadbeef))
    self.assertIsNone( model.getRef(int,0xdeadbeef))
예제 #3
0
  def iterateListField(self, mappings, fieldname, sentinels=[]):
    ''' 
    start from the field  and iterate a list. 
    does not return self.'''
    
    structType, offset = self._getListFieldInfo(fieldname)

    # @ of the field
    headAddr = self._orig_address_ + utils.offsetof( type(self), fieldname)
    #log.info('Ignore headAddress self.%s at 0x%0.8x'%(fieldname, headAddr))
    head = getattr(self, fieldname)

    if not hasattr(head, '_iterateList'):
      raise ValueError('Not an iterable field. Probably not declared as a list.')

    from haystack import model # need my cache
    done = [s for s in sentinels]+[headAddr]
    for entry in head._iterateList(mappings):
      # DO NOT think HEAD is a valid entry - FIXME
      if entry in done:
        continue
      # save it
      done.append(entry)
      # @ of the struct, entry is not null, head._iterateList garantizes it.
      link = entry + offset
      #log.info('Read %s at 0x%0.8x instead of 0x%0.8x'%(fieldname, link, entry))
      # use cache if possible, avoid loops.
      st = model.getRef( structType, link)
      #st._orig_addr_ = link
      if st: 
        yield st
      else:
        raise ValueError('the structure has not been loaded, please use loadMembers.')

    raise StopIteration
예제 #4
0
 def loadMembers(self, mappings, maxDepth):
   if not LoadableMembersStructure.loadMembers(self, mappings, maxDepth):
     return False
   #log.debug('evp    app_data    attr_obj_address=0x%lx'%(self.evp.app_data) )
   #log.debug('evp    cipher_data attr_obj_address=0x%lx'%(self.evp.cipher_data) )  ##none
   cipher = model.getRef( Cipher, getaddress(self.cipher) )
   ciphername = cipher.name.toString() 
   # cast evp.app_data into a valid struct
   if ciphername in self.cipherContexts:
     # evp.cipher.nid should be 0
     struct = self.cipherContexts[ciphername]
     if (struct is None):
       log.warning("Unsupported cipher %s"%(ciphername))
       return True
     attr_obj_address = self.evp.app_data
     memoryMap = is_valid_address_value( attr_obj_address, mappings, struct)
     log.debug( "CipherContext CAST app_data into : %s "%( struct) )
     if not memoryMap:
       log.warning('On second toughts, app_data seems to be at an invalid address. That should not happen (often).')
       log.warning('%s addr:0x%lx size:0x%lx addr+size:0x%lx '%(is_valid_address_value( attr_obj_address, mappings), 
                                   attr_obj_address, ctypes.sizeof(struct), attr_obj_address+ctypes.sizeof(struct)))
       return False # DEBUG kill it
     # read the void * and keep a ref
     st = memoryMap.readStruct(attr_obj_address, struct )
     model.keepRef(st, struct, attr_obj_address)
     # yeah... no. "self.evp.app_data = xx" means SEGFAULT.
     evp_app_data = ctypes.c_void_p(ctypes.addressof(st)) 
     
     log.debug('Copied 0x%lx into app_data (0x%lx)'%(attr_obj_address, evp_app_data.value) )
     log.debug('LOADED app_data as %s from 0x%lx (%s) into 0x%lx'%(struct, 
           attr_obj_address, is_valid_address_value(attr_obj_address,mappings,struct), evp_app_data.value))
     log.debug('\t\t---------\n%s\t\t---------'%(st.toString() ) )
   else:
     log.debug("Unknown cipher %s, can't load a data struct for the EVP_CIPHER_CTX->app_data"%(ciphername))
   return True
예제 #5
0
 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
예제 #6
0
    def _loadListEntries(self, fieldname, mappings, maxDepth):
        ''' 
    we need to load the pointed entry as a valid struct at the right offset, 
    and parse it.
    
    When does it stop following FLink/BLink ?
      sentinel is headAddr only
    '''

        structType, offset = self._getListFieldInfo(fieldname)

        # DO NOT think HEAD is a valid entry.
        # if its a ListEntries, self has already been loaded anyway.
        headAddr = self._orig_address_ + utils.offsetof(type(self), fieldname)
        head = getattr(self, fieldname)

        for entry in head._iterateList(mappings):
            # DO NOT think HEAD is a valid entry
            if entry == headAddr:
                continue
            link = entry + offset
            log.debug('got a element of list at %s 0x%x/0x%x offset:%d' %
                      (fieldname, entry, link, offset))
            # use cache if possible, avoid loops.
            #XXX
            from haystack import model
            ref = model.getRef(structType, link)
            if ref:  # struct has already been loaded, bail out
                log.debug("%s loading from references cache %s/0x%lx" %
                          (fieldname, structType, link))
                continue  # do not reload
            else:
                #  OFFSET read, specific to a LIST ENTRY model
                memoryMap = utils.is_valid_address_value(
                    link, mappings, structType)
                if memoryMap is False:
                    log.error(
                        'error while validating address 0x%x type:%s @end:0x%x'
                        % (link, structType.__name__,
                           link + ctypes.sizeof(structType)))
                    log.error('self : %s , fieldname : %s' %
                              (self.__class__.__name__, fieldname))
                    raise ValueError(
                        'error while validating address 0x%x type:%s @end:0x%x'
                        % (link, structType.__name__,
                           link + ctypes.sizeof(structType)))
                st = memoryMap.readStruct(
                    link, structType)  # point at the right offset
                st._orig_addr_ = link
                model.keepRef(st, structType, link)
                log.debug("keepRef %s.%s @%x" % (structType, fieldname, link))
                # load the list entry structure members
                if not st.loadMembers(mappings, maxDepth - 1):
                    log.error('Error while loading members on %s' %
                              (self.__class__.__name__))
                    print st
                    raise ValueError('error while loading members')

        return True
예제 #7
0
 def getEvpAppData(self):
   cipher = model.getRef( Cipher, getaddress(self.cipher) )
   ciphername = cipher.name.toString() 
   if ciphername in self.cipherContexts:
     struct = self.cipherContexts[ciphername]
     if(struct is None):
       log.warning("Unsupported cipher %s"%(ciphername))
       log.warning("%s"%(cipher.toString()))
       return None
     log.debug('CAST evp.app_data Into %s'%(struct))
     attr_obj_address = self.evp.app_data
     st = model.getRef(struct, attr_obj_address)
     #st = struct.from_address(attr)
     log.debug('app_data value is : 0x%lx'%(attr_obj_address))
     log.debug(st.toString())
     return st
   return None
예제 #8
0
def list_head_loadRealMembers(self, mappings, maxDepth, attrtype, listHeadName, addresses):
  '''
    Copy ->next and ->prev target structure's memeory space.
    attach prev and next correctly.
    @param attrtype the target structure type
    @param listHeadName the member name of the list_head in the target structure
    @param addresses original pointers for prev and next
  '''
  attrname = listHeadName
  addr_prev,addr_next = addresses
  null = list_head()
  for listWay, addr in [('prev',addr_prev),('next',addr_next)]:
    attr = getattr(self,listWay)
    if addr is None or not bool(attr):
      attr.contents = null
      continue # do not load unvalid address
    #print listHeadName,listWay, hex(addr)
    #elif not is_address_local(attr) :
    #  continue # coul
    cache = model.getRef(attrtype, addr ) # is the next/prev Item in cache
    if cache:
      # get the offset into the buffer and associate the .list_head->{next,prev} to it
      attr.contents = gen.list_head.from_address(ctypes.addressof( getattr(cache, attrname)) ) #loadMember is done
      log.debug("assigned &%s.%s in self "%(attrname,listWay ))
      # DO NOT recurse
      continue
    log.debug('re-loading %s.%s.%s from 0x%x'%(attrtype,attrname,listWay, addr))
    memoryMap = is_valid_address_value( addr, mappings, attrtype)
    if(not memoryMap):
      # big BUG Badaboum, why did pointer changed validity/value ?
      log.warning("%s.%s %s not loadable 0x%lx but VALID "%(attrname,listWay, attr, addr ))
      attr.contents = null
      continue
    else:
      log.debug("self.%s.%s -> 0x%lx (is_valid_address_value: %s)"%(attrname,listWay, addr, memoryMap ))
      # save the total struct to local memspace
      nextItem = memoryMap.readStruct(addr, attrtype )
      #if not nextItem.isValid(mappings):
      #  log.warning('%s.%s (%s) is INVALID'%(attrname,listWay, attrtype))
      #  return False
      log.debug("%s.%s is loaded: '%s'"%(attrname,listWay, nextItem ))
      # save the ref and load the task
      model.keepRef( nextItem, attrtype, addr)
      # get the offset into the buffer and associate the .tasks->next to it
      attr.contents = gen.list_head.from_address(ctypes.addressof( getattr(nextItem, attrname) )) #loadMember is done
      log.debug("assigned &%s.%s in self "%(attrname,listWay ))
      # recursive validation checks on new struct
      if not bool(attr):
        log.warning('Member %s.%s is null after copy: %s'%(attrname, listWay ,attr))
        attr.contents = null
      else:
        # recursive loading - model revalidation
        if not nextItem.loadMembers(mappings, maxDepth-1):
          return False
      continue
  return True
예제 #9
0
def task_struct_toPyObject(self):
  my_class=getattr(sys.modules[self.__class__.__module__],"%s_py"%(self.__class__.__name__) )
  #keep ref
  cache = model.getRef(my_class, ctypes.addressof(self) )
  if cache:
    return cache
  obj=model.LoadableMembers.toPyObject(self)
  # change list_head by task_struct
  obj.tasks.next = self.getTasksNext().toPyObject()
  obj.tasks.prev = self.getTasksPrev().toPyObject()
예제 #10
0
def EVP_CIPHER_CTX_toPyObject(self):
    d=super(EVP_CIPHER_CTX,self).toPyObject()
    log.debug('Cast a EVP_CIPHER_CTX into PyObj')
    # cast app_data or cipher_data to right struct
    if bool(self.cipher_data):
      cipher = model.getRef( evp_cipher_st, getaddress(self.cipher) )
      struct = getCipherDataType( cipher.nid)
      if struct is not None:
        # CAST c_void_p to struct
        d.cipher_data = struct.from_address(self.cipher_data).toPyObject()
    return d
예제 #11
0
def task_struct_toPyObject(self):
    my_class = getattr(sys.modules[self.__class__.__module__],
                       "%s_py" % (self.__class__.__name__))
    #keep ref
    cache = model.getRef(my_class, ctypes.addressof(self))
    if cache:
        return cache
    obj = model.LoadableMembers.toPyObject(self)
    # change list_head by task_struct
    obj.tasks.next = self.getTasksNext().toPyObject()
    obj.tasks.prev = self.getTasksPrev().toPyObject()
예제 #12
0
  def _loadListEntries(self, fieldname, mappings, maxDepth):
    ''' 
    we need to load the pointed entry as a valid struct at the right offset, 
    and parse it.
    
    When does it stop following FLink/BLink ?
      sentinel is headAddr only
    '''
    
    structType, offset = self._getListFieldInfo(fieldname)
    
    # DO NOT think HEAD is a valid entry.
    # if its a ListEntries, self has already been loaded anyway.
    headAddr = self._orig_address_ + utils.offsetof( type(self), fieldname)
    head = getattr(self, fieldname)
    
    for entry in head._iterateList(mappings):
      # DO NOT think HEAD is a valid entry
      if entry == headAddr:
        continue
      link = entry + offset
      log.debug('got a element of list at %s 0x%x/0x%x offset:%d'%(fieldname, entry, link, offset))
      # use cache if possible, avoid loops.
      #XXX 
      from haystack import model
      ref = model.getRef( structType, link)
      if ref: # struct has already been loaded, bail out
        log.debug("%s loading from references cache %s/0x%lx"%(fieldname, structType, link ))
        continue # do not reload
      else:
        #  OFFSET read, specific to a LIST ENTRY model
        memoryMap = utils.is_valid_address_value( link, mappings, structType)
        if memoryMap is False:
          log.error('error while validating address 0x%x type:%s @end:0x%x'%(link, 
                  structType.__name__, link+ctypes.sizeof(structType)) )
          log.error('self : %s , fieldname : %s'%(self.__class__.__name__, fieldname))
          raise ValueError('error while validating address 0x%x type:%s @end:0x%x'%(link, 
                  structType.__name__, link+ctypes.sizeof(structType)) )
        st = memoryMap.readStruct( link, structType) # point at the right offset
        st._orig_addr_ = link
        model.keepRef(st, structType, link)
        log.debug("keepRef %s.%s @%x"%(structType, fieldname, link  ))
        # load the list entry structure members
        if not st.loadMembers(mappings, maxDepth-1):
          log.error('Error while loading members on %s'%(self.__class__.__name__))
          print st
          raise ValueError('error while loading members')

    return True
예제 #13
0
def EVP_CIPHER_CTX_loadMembers(self, mappings, maxDepth):
  if not super(EVP_CIPHER_CTX,self).loadMembers(mappings, maxDepth):
    return False
  log.debug('trying to load cipher_data Structs.')
  '''
  if bool(cipher) and bool(self.cipher.nid) and is_valid_address(cipher_data):
    memcopy( self.cipher_data, cipher_data_addr, self.cipher.ctx_size)
    # cast possible on cipher.nid -> cipherType
  '''
  cipher = model.getRef( evp_cipher_st, getaddress(self.cipher) )
  if cipher.nid == 0: # NID_undef, not openssl doing
    log.info('The cipher is home made - the cipher context data should be application dependant (app_data)')
    return True
    
  struct = getCipherDataType( cipher.nid) 
  log.debug('cipher type is %s - loading %s'%( getCipherName(cipher.nid), struct ))
  if(struct is None):
    log.warning("Unsupported cipher %s"%(cipher.nid))
    return True
  
  # c_void_p is a basic type.
  attr_obj_address = self.cipher_data
  memoryMap = is_valid_address_value( attr_obj_address, mappings, struct)
  log.debug( "cipher_data CAST into : %s "%(struct) )
  if not memoryMap:
    log.warning('in CTX On second toughts, cipher_data seems to be at an invalid address. That should not happen (often).')
    log.warning('%s addr:0x%lx size:0x%lx addr+size:0x%lx '%(is_valid_address_value( attr_obj_address, mappings), 
                                attr_obj_address, ctypes.sizeof(struct), attr_obj_address+ctypes.sizeof(struct)))
    return True
  #ok
  st = memoryMap.readStruct(attr_obj_address, struct )
  model.keepRef(st, struct, attr_obj_address)
  self.cipher_data = ctypes.c_void_p(ctypes.addressof(st)) 
  ###print 'self.cipher_data in loadmembers',self.cipher_data
  # check debug
  attr=getattr(self, 'cipher_data')      
  log.debug('Copied 0x%lx into %s (0x%lx)'%(ctypes.addressof(st), 'cipher_data', attr))      
  log.debug('LOADED cipher_data as %s from 0x%lx (%s) into 0x%lx'%(struct, 
        attr_obj_address, is_valid_address_value(attr_obj_address, mappings, struct), attr ))
  log.debug('\t\t---------\n%s\t\t---------'%st.toString())
  return True
예제 #14
0
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)
예제 #15
0
 def toPyObject(self):
   ''' 
   Returns a Plain Old python object as a perfect copy of this ctypes object.
   array would be lists, pointers, inner structures, and circular 
   reference should be handled nicely.
   '''
   # get self class.
   #log.debug("%s %s %s_py"%(self.__class__.__module__, sys.modules[self.__class__.__module__], self.__class__.__name__) )
   my_class = getattr(sys.modules[self.__class__.__module__],"%s_py"%(self.__class__.__name__) )
   my_self = my_class()
   #keep ref
   if hasRef(my_class, ctypes.addressof(self) ):
     return getRef(my_class, ctypes.addressof(self) )
   # we are saving us in a partially resolved state, to keep from loops.
   keepRef(my_self, my_class, ctypes.addressof(self) )
   for field,typ in self.getFields():
     attr = getattr(self,field)
     member = self._attrToPyObject(attr,field,typ)
     setattr(my_self, field, member)
   # save the original type (me) and the field
   setattr(my_self, '_ctype_', type(self))
   return my_self
예제 #16
0
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)
예제 #17
0
    def iterateListField(self, mappings, fieldname, sentinels=[]):
        ''' 
    start from the field  and iterate a list. 
    does not return self.'''

        structType, offset = self._getListFieldInfo(fieldname)

        # @ of the field
        headAddr = self._orig_address_ + utils.offsetof(type(self), fieldname)
        #log.info('Ignore headAddress self.%s at 0x%0.8x'%(fieldname, headAddr))
        head = getattr(self, fieldname)

        if not hasattr(head, '_iterateList'):
            raise ValueError(
                'Not an iterable field. Probably not declared as a list.')

        from haystack import model  # need my cache
        done = [s for s in sentinels] + [headAddr]
        for entry in head._iterateList(mappings):
            # DO NOT think HEAD is a valid entry - FIXME
            if entry in done:
                continue
            # save it
            done.append(entry)
            # @ of the struct, entry is not null, head._iterateList garantizes it.
            link = entry + offset
            #log.info('Read %s at 0x%0.8x instead of 0x%0.8x'%(fieldname, link, entry))
            # use cache if possible, avoid loops.
            st = model.getRef(structType, link)
            #st._orig_addr_ = link
            if st:
                yield st
            else:
                raise ValueError(
                    'the structure has not been loaded, please use loadMembers.'
                )

        raise StopIteration
예제 #18
0
 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
예제 #19
0
def list_head_loadRealMembers(self, mappings, maxDepth, attrtype, listHeadName,
                              addresses):
    '''
    Copy ->next and ->prev target structure's memeory space.
    attach prev and next correctly.
    @param attrtype the target structure type
    @param listHeadName the member name of the list_head in the target structure
    @param addresses original pointers for prev and next
  '''
    attrname = listHeadName
    addr_prev, addr_next = addresses
    null = list_head()
    for listWay, addr in [('prev', addr_prev), ('next', addr_next)]:
        attr = getattr(self, listWay)
        if addr is None or not bool(attr):
            attr.contents = null
            continue  # do not load unvalid address
        #print listHeadName,listWay, hex(addr)
        #elif not is_address_local(attr) :
        #  continue # coul
        cache = model.getRef(attrtype, addr)  # is the next/prev Item in cache
        if cache:
            # get the offset into the buffer and associate the .list_head->{next,prev} to it
            attr.contents = gen.list_head.from_address(
                ctypes.addressof(getattr(cache,
                                         attrname)))  #loadMember is done
            log.debug("assigned &%s.%s in self " % (attrname, listWay))
            # DO NOT recurse
            continue
        log.debug('re-loading %s.%s.%s from 0x%x' %
                  (attrtype, attrname, listWay, addr))
        memoryMap = is_valid_address_value(addr, mappings, attrtype)
        if (not memoryMap):
            # big BUG Badaboum, why did pointer changed validity/value ?
            log.warning("%s.%s %s not loadable 0x%lx but VALID " %
                        (attrname, listWay, attr, addr))
            attr.contents = null
            continue
        else:
            log.debug("self.%s.%s -> 0x%lx (is_valid_address_value: %s)" %
                      (attrname, listWay, addr, memoryMap))
            # save the total struct to local memspace
            nextItem = memoryMap.readStruct(addr, attrtype)
            #if not nextItem.isValid(mappings):
            #  log.warning('%s.%s (%s) is INVALID'%(attrname,listWay, attrtype))
            #  return False
            log.debug("%s.%s is loaded: '%s'" % (attrname, listWay, nextItem))
            # save the ref and load the task
            model.keepRef(nextItem, attrtype, addr)
            # get the offset into the buffer and associate the .tasks->next to it
            attr.contents = gen.list_head.from_address(
                ctypes.addressof(getattr(nextItem,
                                         attrname)))  #loadMember is done
            log.debug("assigned &%s.%s in self " % (attrname, listWay))
            # recursive validation checks on new struct
            if not bool(attr):
                log.warning('Member %s.%s is null after copy: %s' %
                            (attrname, listWay, attr))
                attr.contents = null
            else:
                # recursive loading - model revalidation
                if not nextItem.loadMembers(mappings, maxDepth - 1):
                    return False
            continue
    return True
예제 #20
0
def _HEAP_getSegmentList(self, mappings):
    """ list all heap entries attached to one Heap structure. 
  
  Heap.SegmentList points to the _LIST_ENTRY of Heap.Segment. +0x10
  Iteration on SegmentList should return Segment.
  Offset is needed and provided through _listHead_.
  FIXME: offset could/should be automated by declaring child _LIST_ENTRY fieldname (SegmentListEntry)
    listmodel.py:164
  
  BUT iteration should stop on sentinel values.
    Internal algoritm of iterateListField will not use the root LIST_Entry address as a valid object.
    It will use it as a sentinel.
    If there is another sentinel... bad luck....
  
  Heap.Segment.Entry is a valid Heap_entry, addr+size*8 should point to FirstValidEntry.
  """
    allocated = list()
    free = list()
    # log.debug('%s'%(self))
    for segment in self.iterateListField(mappings, "SegmentList"):
        # for segment_addr in self.SegmentList._iterateList( mappings):
        segment_addr = segment._orig_addr_
        first_addr = utils.getaddress(segment.FirstEntry)
        last_addr = utils.getaddress(segment.LastValidEntry)

        log.debug(
            "Heap.Segment: 0x%0.8x FirstEntry: 0x%0.8x LastValidEntry: 0x%0.8x" % (segment_addr, first_addr, last_addr)
        )

        skiplist = dict()
        for ucr in segment.iterateListField(mappings, "UCRSegmentList"):
            ucr_addr = ucr._orig_addr_
            if ucr_addr is None:
                log.error("None in _orig_addr_")
            seg_addr = utils.getaddress(ucr.SegmentEntry.FLink)
            if ucr.Address is None:
                log.error("None in ucr.Address")
            try:
                log.debug(
                    "Heap.Segment.UCRSegmentList: 0x%0.8x addr: 0x%0.8x size: 0x%0.5x"
                    % (ucr_addr, ucr.Address, ucr.Size * 8)
                )
            except TypeError, e:
                import code

                code.interact(local=locals())
            # log.debug("%s"%(ucr.SegmentEntry)) # TODO - CHECK FOR CONSISTENCY ? more heapdebug than haystack debug
            skiplist[ucr.Address] = ucr.Size * 8

        # # obviously not usable, first entry sits on heap header.
        # chunk_header = segment.Entry
        # if self.EncodeFlagMask: #heap.EncodeFlagMask
        #  log.debug('EncodeFlagMask is set on the HEAP. decoding is needed.')
        #  chunk_header = _HEAP_ENTRY_decode(chunk_header, self)
        # chunk_addr = segment._orig_addr_ + utils.offsetof(_HEAP_SEGMENT, 'Entry')
        # log.debug('Heap.Segment.Entry: 0x%0.8x\n%s'%( chunk_addr, chunk_header))

        # print segment

        from haystack.model import getRef  # TODO CLEAN

        chunk_addr = first_addr
        while chunk_addr < last_addr:
            if chunk_addr in skiplist:
                size = skiplist[chunk_addr]
                log.debug("Skipping 0x%0.8x - skip %0.5x bytes to 0x%0.8x" % (chunk_addr, size, chunk_addr + size))
                chunk_addr += size
                continue
            chunk_header = getRef(_HEAP_ENTRY, chunk_addr)
            if chunk_header is None:  # force read it
                chunk_header = _get_chunk(mappings, self, chunk_addr)
            if self.EncodeFlagMask:  # heap.EncodeFlagMask
                chunk_header = _HEAP_ENTRY_decode(chunk_header, self)
            # log.debug('\t\tEntry: 0x%0.8x\n%s'%( chunk_addr, chunk_header))

            if (chunk_header.Flags & 1) == 1:
                log.debug("Chunk 0x%0.8x is in use size: %0.5x" % (chunk_addr, chunk_header.Size * 8))
                allocated.append((chunk_addr, chunk_header.Size * 8))
            else:
                log.debug("Chunk 0x%0.8x is FREE" % (chunk_addr))
                free.append((chunk_addr, chunk_header.Size * 8))
                pass
            chunk_addr += chunk_header.Size * 8
예제 #21
0
  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
예제 #22
0
 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)) )
예제 #23
0
def _HEAP_getSegmentList(self, mappings):
    ''' list all heap entries attached to one Heap structure. 
  
  Heap.SegmentList points to the _LIST_ENTRY of Heap.Segment. +0x10
  Iteration on SegmentList should return Segment.
  Offset is needed and provided through _listHead_.
  FIXME: offset could/should be automated by declaring child _LIST_ENTRY fieldname (SegmentListEntry)
    listmodel.py:164
  
  BUT iteration should stop on sentinel values.
    Internal algoritm of iterateListField will not use the root LIST_Entry address as a valid object.
    It will use it as a sentinel.
    If there is another sentinel... bad luck....
  
  Heap.Segment.Entry is a valid Heap_entry, addr+size*8 should point to FirstValidEntry.
  '''
    allocated = list()
    free = list()
    #log.debug('%s'%(self))
    for segment in self.iterateListField(mappings, 'SegmentList'):
        #for segment_addr in self.SegmentList._iterateList( mappings):
        segment_addr = segment._orig_addr_
        first_addr = utils.getaddress(segment.FirstEntry)
        last_addr = utils.getaddress(segment.LastValidEntry)

        log.debug(
            'Heap.Segment: 0x%0.8x FirstEntry: 0x%0.8x LastValidEntry: 0x%0.8x'
            % (segment_addr, first_addr, last_addr))

        skiplist = dict()
        for ucr in segment.iterateListField(mappings, 'UCRSegmentList'):
            ucr_addr = ucr._orig_addr_
            if ucr_addr is None:
                log.error('None in _orig_addr_')
            seg_addr = utils.getaddress(ucr.SegmentEntry.FLink)
            if ucr.Address is None:
                log.error('None in ucr.Address')
            try:
                log.debug(
                    "Heap.Segment.UCRSegmentList: 0x%0.8x addr: 0x%0.8x size: 0x%0.5x"
                    % (ucr_addr, ucr.Address, ucr.Size * 8))
            except TypeError, e:
                import code
                code.interact(local=locals())
            #log.debug("%s"%(ucr.SegmentEntry)) # TODO - CHECK FOR CONSISTENCY ? more heapdebug than haystack debug
            skiplist[ucr.Address] = ucr.Size * 8

        # # obviously not usable, first entry sits on heap header.
        #chunk_header = segment.Entry
        #if self.EncodeFlagMask: #heap.EncodeFlagMask
        #  log.debug('EncodeFlagMask is set on the HEAP. decoding is needed.')
        #  chunk_header = _HEAP_ENTRY_decode(chunk_header, self)
        #chunk_addr = segment._orig_addr_ + utils.offsetof(_HEAP_SEGMENT, 'Entry')
        #log.debug('Heap.Segment.Entry: 0x%0.8x\n%s'%( chunk_addr, chunk_header))

        #print segment

        from haystack.model import getRef  # TODO CLEAN
        chunk_addr = first_addr
        while (chunk_addr < last_addr):
            if chunk_addr in skiplist:
                size = skiplist[chunk_addr]
                log.debug('Skipping 0x%0.8x - skip %0.5x bytes to 0x%0.8x' %
                          (chunk_addr, size, chunk_addr + size))
                chunk_addr += size
                continue
            chunk_header = getRef(_HEAP_ENTRY, chunk_addr)
            if chunk_header is None:  # force read it
                chunk_header = _get_chunk(mappings, self, chunk_addr)
            if self.EncodeFlagMask:  #heap.EncodeFlagMask
                chunk_header = _HEAP_ENTRY_decode(chunk_header, self)
            #log.debug('\t\tEntry: 0x%0.8x\n%s'%( chunk_addr, chunk_header))

            if ((chunk_header.Flags & 1) == 1):
                log.debug('Chunk 0x%0.8x is in use size: %0.5x' %
                          (chunk_addr, chunk_header.Size * 8))
                allocated.append((chunk_addr, chunk_header.Size * 8))
            else:
                log.debug('Chunk 0x%0.8x is FREE' % (chunk_addr))
                free.append((chunk_addr, chunk_header.Size * 8))
                pass
            chunk_addr += chunk_header.Size * 8
예제 #24
0
 def getKey(self):
   #return pointer2bytes(self.key,self.key_len)
   return model.array2bytes( model.getRef( model.get_subtype(self.key), getaddress(self.key)) )
예제 #25
0
 elif isBasicTypeArray(attr):
   try:
     s+='%s (@0x%lx) : %s\n'%(field,ctypes.addressof(attr), repr(array2bytes(attr)) )  
   except IndexError,e:
     log.error( 'error while reading %s %s'%(repr(attr),type(attr)) )
     
 elif isArrayType(attrtype): ## array of something else than int
   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: