Пример #1
0
def get_pointee_address(obj):
    """
    Returns the address of the struct pointed by the obj, or null if invalid.

    :param obj: a pointer.
    """
    import ctypes
    # check for homebrew POINTER
    if hasattr(obj, '_sub_addr_'):
        # print 'obj._sub_addr_', hex(obj._sub_addr_)
        return obj._sub_addr_
    elif isinstance(obj, int) or isinstance(obj, long):
        # basictype pointers are created as int.
        return obj
    elif not bool(obj):
        return 0
    elif ctypes.is_function_type(type(obj)):
        return ctypes.cast(obj, ctypes.c_void_p).value
    elif ctypes.is_pointer_type(type(obj)):
        return ctypes.cast(obj, ctypes.c_void_p).value
        # check for null pointers
        # if bool(obj):
        if not hasattr(obj, 'contents'):
            return 0
        # print '** NOT MY HAYSTACK POINTER'
        return ctypes.addressof(obj.contents)
    else:
        return 0
Пример #2
0
 def __str__(self):
     """Print the direct members values. Never tries to recurse."""
     import ctypes
     if hasattr(self, '_orig_address_'):
         s = "# <%s at @%x>\n" % (
             self.__class__.__name__, self._orig_address_)
     else:
         s = "# <%s at @???>\n" % (self.__class__.__name__)
     # we need to ensure _mappings_ is defined in all children.
     for field, attrtype in self.getFields():
         attr = getattr(self, field)
         if ctypes.is_basic_type(attrtype):
             # basic type, ctypes or python
             s += '%s : %s, \n' % (field, repr(attr))
         elif (ctypes.is_struct_type(attrtype) or
               ctypes.is_union_type(attrtype)):
             # you can print a inner struct content
             s += '%s (@0x%lx) : {\t%s}\n' % (field,
                                              ctypes.addressof(attr),
                                              attr)
         elif ctypes.is_function_type(attrtype):
             # only print address in target space
             s += '%s (@0x%lx) : 0x%lx (FIELD NOT LOADED: function type)\n' % (
                 field, ctypes.addressof(attr),
                 utils.get_pointee_address(attr))
         elif ctypes.is_array_of_basic_type(attrtype):
             try:
                 s += '%s (@0x%lx) : %s\n' % (field, ctypes.addressof(attr),
                                              repr(utils.array2bytes(attr)))
             except IndexError as e:
                 log.error('error while reading %s %s' % (repr(attr),
                                                          type(attr)))
                 # FIXME
         elif ctypes.is_array_type(attrtype):
             # array of something else than int
             s += '%s (@0x%lx)    :[' % (field, ctypes.addressof(attr))
             s += ','.join(["%s" % (val) for val in attr])
             s += '],\n'
         elif ctypes.is_cstring_type(attrtype):
             # only print address/null
             s += '%s (@0x%lx) : 0x%lx\n' % (field, ctypes.addressof(attr),
                                             utils.get_pointee_address(attr.ptr))
         elif ctypes.is_pointer_type(attrtype):  # and
             # not ctypes.is_pointer_to_void_type(attrtype)):
             # do not recurse.
             if attr is None:
                 attr = 0
                 s += '%s (@????) : 0x0\n' % (field)
             else:
                 s += '%s (@0x%lx) : 0x%lx\n' % (field, ctypes.addressof(attr),
                                             utils.get_pointee_address(attr))
         elif (isinstance(attr, long)) or (isinstance(attr, int)):
             s += '%s : %s\n' % (field, hex(attr))
         else:
             s += '%s : %s\n' % (field, repr(attr))
     return s
Пример #3
0
def check_varname_for_type(varname, structType):
    done = []
    st = structType
    from haystack import model
    import ctypes
    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 ctypes.is_pointer_type(st):  # accept pointers
            st = model.get_subtype(st)
        done.append(v)
    return True
Пример #4
0
    def toString(cls):
        import ctypes

        fieldsStrings = []
        for attrname, attrtyp in cls.getFields():  # model
            if ctypes.is_pointer_type(attrtyp) and not ctypes.is_pointer_to_void_type(attrtyp):
                fieldsStrings.append("(%s, ctypes.POINTER(%s) ),\n" % (attrname, attrtyp._type_.__name__))
            else:  # pointers not in the heap.
                fieldsStrings.append("(%s, %s ),\n" % (attrname, attrtyp.__name__))
        fieldsString = "[ \n%s ]" % ("".join(fieldsStrings))

        info = "size:%d" % (ctypes.sizeof(cls))
        ctypes_def = """
class %s(ctypes.Structure):  # %s
  _fields_ = %s

""" % (
            cls.__name__,
            info,
            fieldsString,
        )
        return ctypes_def
Пример #5
0
def declare_double_linked_list_type(structType, forward, backward):
    """Declares a list iterator on structType, as used by ListModel.

    declare_double_linked_list_type(struct_A, 'next', 'previous')

    C code example:
    struct Entry {
        struct Entry * next;
        struct Entry * previous;
    }

    The effect will be the current structType will NOT be validated, or loaded
    by basicmodel. No member, pointers members will be loaded.
    But next and previous elements can be iterated upon with _iterateList,
    at what point, address validation of both forward and backward pointer
    occurs before loading of pointee.
    """
    import ctypes

    # test existence
    flinkType = getattr(structType, forward)
    blinkType = getattr(structType, backward)
    d = dict(structType.getFields())
    flinkType = d[forward]
    blinkType = d[backward]
    if not ctypes.is_pointer_type(flinkType):
        raise TypeError("The %s field is not a pointer." % (forward))
    if not ctypes.is_pointer_type(blinkType):
        raise TypeError("The %s field is not a pointer." % (backward))

    def iterateList(self, mappings):
        """ iterate forward, then backward, until null or duplicate """
        done = [0]
        obj = self
        # print 'going forward '
        for fieldname in [forward, backward]:
            link = getattr(obj, fieldname)
            addr = utils.get_pointee_address(link)
            # print fieldname,addr,hex(addr)
            log.debug("iterateList got a <%s>/0x%x" % (link.__class__.__name__, addr))
            nb = 0
            while addr not in done:
                # print '%x %s'%(addr, addr in done)
                done.append(addr)
                memoryMap = mappings.is_valid_address_value(addr, structType)
                if memoryMap == False:
                    log.error("ValueError: 'the link of this linked list has a bad value'")
                    raise StopIteration
                st = memoryMap.readStruct(addr, structType)
                st._orig_address_ = addr
                mappings.keepRef(st, structType, addr)
                log.debug("keepRefx2 %s.%s: @%x" % (structType.__name__, fieldname, addr))
                yield addr
                # next
                link = getattr(st, fieldname)
                addr = utils.get_pointee_address(link)
            # print 'going backward after %x'%(addr)
        raise StopIteration

    def loadMembers(self, mappings, depth):
        # voluntary blockade of loadMembers.
        # we do not want to validate members or pointees of this struct.
        log.debug("- <%s> loadMembers return TRUE" % (structType.__name__))
        return True

    def attrToPyObject(self, attr, field, attrtype):
        if field in [forward, backward]:
            # TODO we could maybe put a pointer to parent struct ?
            # or add a hidden field in list struct representation so that the
            # python user can get the parent python object easily.
            return "# double_linked_list_type - contents not loaded"
        else:
            return self._attrToPyObject2(attr, field, attrtype)

    # set iterator on the list structure
    structType._iterateList = iterateList
    # structType.loadMembers = loadMembers # FIXME DEBUG WHY?
    # be nicer on printouts
    # structType._attrToPyObject2 = structType._attrToPyObject
    # structType._attrToPyObject = attrToPyObject

    log.debug("%s has been fitted with a list iterator self._iterateList(mappings)" % (structType))
    return
Пример #6
0
 def _attrToPyObject(self, attr, field, attrtype):
     import ctypes
     if ctypes.is_basic_type(attrtype):
         if ctypes.is_basic_ctype(type(attr)):
             obj = attr.value
         else:
             obj = attr
     elif ctypes.is_struct_type(attrtype) or ctypes.is_union_type(attrtype):
         attr._mappings_ = self.mappings
         obj = self.parse(attr)
     elif ctypes.is_array_of_basic_type(attrtype):
         # return a list of int, float, or a char[] to str
         obj = utils.ctypes_to_python_array(attr)
     elif ctypes.is_array_type(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 ctypes.is_cstring_type(attrtype):
         obj = self.mappings.getRef(
             ctypes.CString,
             utils.get_pointee_address(
                 attr.ptr))
     elif ctypes.is_function_type(attrtype):
         obj = repr(attr)
     elif ctypes.is_pointer_type(attrtype):
         # get the cached Value of the LP.
         _subtype = get_subtype(attrtype)
         _address = utils.get_pointee_address(attr)
         if _address == 0:
             # Null pointer
             obj = None
         elif ctypes.is_pointer_to_void_type(attrtype):
             # TODO: make a prototype for c_void_p loading
             # void types a rereturned as None
             obj = None
         elif ctypes.is_array_of_basic_type(attrtype):
             log.error('basic Type array - %s' % (field))
             obj = 'BasicType array'
         else:
             # get the cached Value of the LP.
             _subtype = get_subtype(attrtype)
             cache = self.mappings.getRef(_subtype, _address)
             if cache is not None:  # struct, union...
                 obj = self._attrToPyObject(cache, field, _subtype)
             else:
                 # you got here because your pointer is not loaded:
                 #  did you ignore it in expectedValues ?
                 #  is it in the middle of a struct ?
                 #  is that a linked list ?
                 #  is it a invalid instance ?
                 log.debug('Pointer for field:%s %s/%s not in cache '
                           '0x%x' % (field, attrtype, get_subtype(attrtype),
                                     _address))
                 return (None, None)
     elif isinstance(attr, numbers.Number):
         # case for int, long. But needs to be after c_void_p pointers case
         obj = attr
     else:
         log.error('toPyObj default to return attr %s' % (type(attr)))
         obj = attr
     return obj
Пример #7
0
    def _loadMember(self, attr, attrname, attrtype, mappings, maxDepth):
        ctypes = self._mappings_.config.ctypes
        # skip static void_p 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 ctypes.is_struct_type(attrtype) or ctypes.is_union_type(attrtype):
            # its an embedded record. Bytes are already loaded.
            offset = utils.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
            attr._mappings = mappings
            if not attr.loadMembers(mappings, maxDepth - 1):
                log.debug(
                    "st: %s %s not valid, error while loading inner struct" %
                    (attrname, attrtype))
                return False
            log.debug("st: %s %s inner struct LOADED " % (attrname, attrtype))
            return True
        elif ctypes.is_array_of_basic_type(attrtype):
            return True
        elif ctypes.is_array_type(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
        elif ctypes.is_function_type(attrtype):
            pass
            # FIXME
        elif ctypes.is_cstring_type(attrtype):
            # can't use basic c_char_p because we can't load in foreign memory
            # FIXME, you need to keep a ref to this ctring if
            # your want _mappings_ to exists
            # or just mandate mappings in toString
            attr_obj_address = utils.get_pointee_address(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 = mappings.is_valid_address_value(attr_obj_address)
            if not memoryMap:
                log.warning('Error on addr while fetching a CString.'
                            'should not happen')
                return False
            ref = mappings.getRef(ctypes.CString, attr_obj_address)
            if ref:
                log.debug("%s %s loading from references cache %s/0x%lx" % (attrname,
                                                                            attr, ctypes.CString, attr_obj_address))
                return True
            max_size = min(
                self.MAX_CSTRING_SIZE,
                memoryMap.end -
                attr_obj_address)
            log.debug('%s %s is defined as a CString, loading %d bytes from 0x%lx '
                      'is_valid_address %s' % (attrname, attr, max_size, attr_obj_address,
                                               mappings.is_valid_address_value(attr_obj_address)))
            txt, truncated = memoryMap.readCString(attr_obj_address, max_size)
            if truncated:
                log.warning(
                    'buffer size was too small for this CString: %d' %
                    (max_size))

            # that will SEGFAULT attr.string = txt - instead keepRef to String
            mappings.keepRef(txt, ctypes.CString, attr_obj_address)
            log.debug(
                'kept CString ref for "%s" at @%x' %
                (txt, attr_obj_address))
            return True
        # not functionType, it's not loadable
        elif ctypes.is_pointer_type(attrtype):
            _attrType = get_subtype(attrtype)
            attr_obj_address = utils.get_pointee_address(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 = mappings.is_valid_address(attr, _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 = mappings.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
            mappings.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,
                 (utils.get_pointee_address(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
            subtype = utils.get_subtype(attrtype)
            if (ctypes.is_basic_type(subtype) or
                    ctypes.is_array_of_basic_type(subtype)):
                # do nothing
                return True
            elif (ctypes.is_array_type(subtype) or
                  ctypes.is_pointer_type(subtype)):
                return self._loadMember(
                    contents, 'pointee', subtype, mappings, maxDepth - 1)

            if not contents.loadMembers(mappings, maxDepth - 1):
                log.debug('member %s was not loaded' % (attrname))
                # invalidate the cache ref.
                mappings.delRef(_attrType, attr_obj_address)
                return False
            return True
        # TATAFN
        return True
Пример #8
0
 def _isValidAttr(self, attr, attrname, attrtype, mappings):
     """ Validation of a single member """
     import ctypes
     # a)
     log.debug('valid: %s, %s' % (attrname, attrtype))
     if ctypes.is_basic_type(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 ctypes.is_struct_type(attrtype) or ctypes.is_union_type(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 ctypes.is_array_of_basic_type(attrtype):
         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, type(attr)))
                 return False
         log.debug(
             'basicArray: %s is arraytype %s we decided it was valid',
             attrname,
             type(attr))
         return True
     # d)
     elif ctypes.is_array_type(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
     # e)
     elif ctypes.is_cstring_type(attrtype):
         myaddress = utils.get_pointee_address(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 - NOT EXPECTED' % (
                         attrname, attrtype, repr(attr)))
                     return False
                 log.debug('str: %s %s %s isNULL - OK' % (attrname, attrtype,
                                                          repr(attr)))
                 # e.1)
                 return True
         if (myaddress != 0 and
                 not mappings.is_valid_address_value(myaddress)):
             log.debug('str: %s %s %s 0x%lx INVALID' % (attrname, attrtype,
                                                        repr(attr), myaddress))
             # e.2)
             return False
         log.debug('str: %s %s %s is at 0x%lx OK' % (attrname, attrtype,
                                                     repr(attr), myaddress))
         # e.3)
         return True
     # f)
     elif ctypes.is_pointer_type(attrtype):
         myaddress = utils.get_pointee_address(attr)
         if attrname in self.expectedValues:
             # test if NULL is an option
             log.debug('ctypes.is_pointer_type: bool(attr):%s attr:%s' % (
                 bool(attr), attr))
             if not bool(myaddress):
                 if not ((None in self.expectedValues[attrname]) or
                         (0 in self.expectedValues[attrname])):
                     log.debug('ptr: %s %s %s isNULL - NOT EXPECTED' % (
                         attrname, attrtype, repr(attr)))
                     # f.1) expectedValues specifies NULL to be invalid
                     return False
                 log.debug('ptr: %s %s %s isNULL - OK' % (attrname, attrtype,
                                                          repr(attr)))
                 # f.2) expectedValues specifies NULL to be valid
                 return True
         _attrType = None
         if (ctypes.is_pointer_to_void_type(attrtype) or
                 ctypes.is_function_type(attrtype)):
             log.debug(
                 'Its a simple type. Checking mappings only. attr=%s' %
                 (attr))
             if (myaddress != 0 and
                     not mappings.is_valid_address_value(myaddress)):
                 log.debug('voidptr: %s %s %s 0x%lx INVALID simple pointer' % (
                     attrname, attrtype, repr(attr), myaddress))
                 # f.3) address must be valid, no type requirement
                 return False
         else:
             # test valid address mapping
             _attrType = get_subtype(attrtype)
         if (myaddress != 0 and
                 not mappings.is_valid_address(attr, _attrType)):
             log.debug('ptr: %s %s %s 0x%lx INVALID' % (attrname, attrtype,
                                                        repr(attr), utils.get_pointee_address(attr)))
             # f.4) its a pointer, but not valid in our mappings for this
             # pointee type.
             return False
         log.debug('ptr: name:%s repr:%s address:0x%lx OK' % (attrname,
                                                              repr(attr), utils.get_pointee_address(attr)))
         # f.5) null is accepted by default
         return True
     # g)
     log.error('What type are You ?: %s/%s' % (attrname, attrtype))
     return True