Ejemplo n.º 1
0
class member(object):
    """
    This namespace allows one to interact with a member belonging
    to an enumeration once the enumeration's id has been determined.
    This allows one to modify the property of any one of an
    enumeration's members.

    Some examples of how to use this namespace can be::

        > eid = enum.by('example_enumeration')
        > mid = enum.members.by_value(eid, 0x1000)
        > oldname = enum.member.name(mid, 'somename')
        > oldvalue = enum.member.value(mid, 0x100)
        > oldcomment = enum.member.comment(mid, 'This is an example comment')
        > ok = enum.member.remove(mid)

    """
    @classmethod
    def parent(cls, mid):
        '''Return the id of the enumeration that owns the member `mid`.'''
        return idaapi.get_enum_member_enum(mid)

    owner = utils.alias(parent, 'member')

    @utils.multicase(mid=six.integer_types)
    @classmethod
    def remove(cls, mid):
        '''Remove the enumeration member with the given `mid`.'''
        eid, value = cls.parent(mid), cls.value(mid)
        # XXX: is a serial of 0 valid?
        res = idaapi.del_enum_member(eid, value, 0,
                                     idaapi.BADADDR & cls.mask(mid))
        if not res:
            raise E.DisassemblerError(
                u"{:s}.member.remove({:#x}) : Unable to remove member from enumeration."
                .format(__name__, mid))
        return res

    @utils.multicase()
    @classmethod
    def remove(cls, enum, member):
        '''Remove the specified `member` of the enumeration `enum`.'''
        eid = by(enum)
        mid = members.by(eid, member)
        return cls.remove(mid)

    ## properties
    @utils.multicase(mid=six.integer_types)
    @classmethod
    def name(cls, mid):
        '''Return the name of the enumeration member `mid`.'''
        if not interface.node.is_identifier(mid):
            raise E.MemberNotFoundError(
                u"{:s}.name({:#x}) : Unable to locate member by the specified identifier."
                .format('.'.join([__name__, cls.__name__]), mid))
        res = idaapi.get_enum_member_name(mid)
        return utils.string.of(res)

    @utils.multicase()
    @classmethod
    def name(cls, enum, member):
        '''Return the name of the enumeration `member` belonging to `enum`.'''
        eid = by(enum)
        mid = members.by(eid, member)
        return cls.name(mid)

    @utils.multicase(mid=six.integer_types, name=(six.string_types, tuple))
    @classmethod
    @utils.string.decorate_arguments('name')
    def name(cls, mid, name):
        '''Rename the enumeration member `mid` to `name`.'''
        res = interface.tuplename(*name) if isinstance(name, tuple) else name
        return idaapi.set_enum_member_name(mid, utils.string.to(res))

    @utils.multicase(name=six.string_types)
    @classmethod
    @utils.string.decorate_arguments('name', 'suffix')
    def name(cls, enum, member, name, *suffix):
        '''Rename the enumeration `member` belonging to `enum` to `name`.'''
        eid = by(enum)
        mid = members.by(eid, member)
        res = (name, ) + suffix
        return idaapi.set_enum_member_name(
            mid, utils.string.to(interface.tuplename(*res)))

    @utils.multicase(mid=six.integer_types)
    @classmethod
    def comment(cls, mid, **repeatable):
        """Return the comment for the enumeration member `mid`.

        If the bool `repeatable` is specified, then return the repeatable comment.
        """
        if not interface.node.is_identifier(mid):
            raise E.MemberNotFoundError(
                u"{:s}.comment({:#x}) : Unable to locate member by the specified identifier."
                .format('.'.join([__name__, cls.__name__]), mid))
        res = idaapi.get_enum_member_cmt(mid,
                                         repeatable.get('repeatable', True))
        return utils.string.of(res)

    @utils.multicase()
    @classmethod
    def comment(cls, enum, member, **repeatable):
        '''Return the comment for the enumeration `member` belonging to `enum`.'''
        eid = by(enum)
        mid = members.by(eid, member)
        return cls.comment(mid, **repeatable)

    @utils.multicase(mid=six.integer_types, comment=six.string_types)
    @classmethod
    @utils.string.decorate_arguments('comment')
    def comment(cls, mid, comment, **repeatable):
        """Set the comment for the enumeration member id `mid` to `comment`.

        If the bool `repeatable` is specified, then set the repeatable comment.
        """
        if not interface.node.is_identifier(mid):
            raise E.MemberNotFoundError(
                u"{:s}.comment({:#x}, {!r}) : Unable to locate member by the specified identifier."
                .format('.'.join([__name__, cls.__name__]), mid, comment))
        res = utils.string.to(comment)
        return idaapi.set_enum_member_cmt(mid, res,
                                          repeatable.get('repeatable', True))

    @utils.multicase(comment=six.string_types)
    @classmethod
    @utils.string.decorate_arguments('comment')
    def comment(cls, enum, member, comment, **repeatable):
        '''Set the comment for the enumeration `member` belonging to `enum` to the string `comment`.'''
        eid = by(enum)
        mid = members.by(eid, member)
        return cls.comment(mid, comment, **repeatable)

    @utils.multicase(mid=six.integer_types)
    @classmethod
    def value(cls, mid):
        '''Return the value of the enumeration member `mid`.'''
        if not interface.node.is_identifier(mid):
            raise E.MemberNotFoundError(
                u"{:s}.value({:#x}) : Unable to locate member by the specified identifier."
                .format('.'.join([__name__, cls.__name__]), mid))
        return idaapi.get_enum_member_value(mid)

    @utils.multicase()
    @classmethod
    def value(cls, enum, member):
        '''Return the value of the specified `member` belonging to the enumeration `enum`.'''
        eid = by(enum)
        mid = members.by(eid, member)
        return cls.value(mid)

    @utils.multicase(mid=six.integer_types, value=six.integer_types)
    @classmethod
    def value(cls, mid, value, **bitmask):
        """Set the `value` for the enumeration `member` belonging to `enum`.

        If the integer `bitmask` is specified, then use it as a bitmask. Otherwise assume all bits are set.
        """
        if not interface.node.is_identifier(mid):
            raise E.MemberNotFoundError(
                u"{:s}.value({:#x}, {:#x}) : Unable to locate member by the specified identifier."
                .format('.'.join([__name__, cls.__name__]), mid, value))
        bmask = bitmask.get('bitmask', idaapi.BADADDR & cls.mask(mid))
        return idaapi.set_enum_member_value(mid, value, bmask)

    @utils.multicase(value=six.integer_types)
    @classmethod
    def value(cls, enum, member, value, **bitmask):
        """Set the `value` for the enumeration `member` belonging to `enum`.

        If the integer `bitmask` is specified, then use it as a bitmask. Otherwise assume all bits are set.
        """
        eid = by(enum)
        mid = members.by(eid, member)
        return cls.value(mid, value, **bitmask)

    @utils.multicase(mid=six.integer_types)
    @classmethod
    def serial(cls, mid):
        '''Return the serial of the enumeration member `mid`.'''
        if not interface.node.is_identifier(mid):
            raise E.MemberNotFoundError(
                u"{:s}.serial({:#x}) : Unable to locate member by the specified identifier."
                .format('.'.join([__name__, cls.__name__]), mid))
        return idaapi.get_enum_member_serial(mid)

    @utils.multicase()
    @classmethod
    def serial(cls, enum, member):
        '''Return the serial of the enumeration `member` belonging to `enum`.'''
        eid = by(enum)
        mid = members.by(eid, member)
        return cls.serial(mid)

    @utils.multicase(mid=six.integer_types)
    @classmethod
    def mask(cls, mid):
        '''Return the bitmask for the enumeration member `mid`.'''
        if not interface.node.is_identifier(mid):
            raise E.MemberNotFoundError(
                u"{:s}.mask({:#x}) : Unable to locate member by the specified identifier."
                .format('.'.join([__name__, cls.__name__]), mid))
        return idaapi.get_enum_member_bmask(mid)

    @utils.multicase()
    @classmethod
    def mask(cls, enum, member):
        '''Return the bitmask for the enumeration `member` belonging to `enum`.'''
        eid = by(enum)
        mid = members.by(eid, member)
        return cls.mask(mid)

## searching
@utils.string.decorate_arguments('name')
def by_name(name):
    '''Return the segment with the given `name`.'''
    res = utils.string.to(name)
    seg = idaapi.get_segm_by_name(res)
    if seg is None:
        raise E.SegmentNotFoundError(
            u"{:s}.by_name({!r}) : Unable to locate the segment with the specified name."
            .format(__name__, name))
    return seg


byname = utils.alias(by_name)


def by_selector(selector):
    '''Return the segment associated with `selector`.'''
    seg = idaapi.get_segm_by_sel(selector)
    if seg is None:
        raise E.SegmentNotFoundError(
            u"{:s}.by_selector({:#x}) : Unable to locate the segment with the specified selector."
            .format(__name__, selector))
    return seg


byselector = utils.alias(by_selector)

Ejemplo n.º 3
0
    eid = by(enum)
    return idaapi.get_enum_flag(eid) & mask


@utils.string.decorate_arguments('name')
def by_name(name):
    '''Return the identifier for the enumeration with the given `name`.'''
    res = idaapi.get_enum(utils.string.to(name))
    if res == idaapi.BADADDR:
        raise E.EnumerationNotFoundError(
            u"{:s}.by_name({!r}) : Unable to locate enumeration by the name \"{:s}\"."
            .format(__name__, name, utils.string.escape(name, '"')))
    return res


byname = utils.alias(by_name)


def by_index(index):
    '''Return the identifier for the enumeration at the specified `index`.'''
    res = idaapi.getn_enum(index)
    if res == idaapi.BADADDR:
        raise E.EnumerationNotFoundError(
            u"{:s}.by_index({:#x}) : Unable to locate enumeration by the index {:d}."
            .format(__name__, index, index))
    return res


byindex = utils.alias(by_index)

Ejemplo n.º 4
0
class members(object):
    """
    This namespace allows one to interact with the members belonging
    to an enumeration once the enumeration's id has been determined.
    This allows one to iterate through all of its members or add
    and remove values to the enumeration.

    By default this namespace will yield the names of all of the
    members of an enumeration.

    Some examples of using this namespace are::

        > eid = enum.by('example_enumeration')
        > mid = enum.members.add(eid, 'name', 0x1000)
        > ok = enum.members.remove(eid, mid)
        > mid = enum.members.by_name(eid, 'name')
        > mid = enum.members.by_value(eid, 0x1000)
        > for mid in enum.members.iterate(eid): ...
        > enum.members.list(e)

    """
    def __new__(cls, enum):
        '''Yield the name of each member from the enumeration `enum`.'''
        eid = by(enum)
        for mid in cls.iterate(eid):
            yield member.name(mid)
        return

    ## scope
    @classmethod
    @utils.string.decorate_arguments('name')
    def add(cls, enum, name, value, **bitmask):
        """Add an enumeration member `name` with the specified `value` to the enumeration `enum`.

        If the int, `bitmask`, is specified then used it as the bitmask for the enumeration.
        """
        eid = by(enum)
        bmask = bitmask.get('bitmask', idaapi.BADADDR & mask(eid))

        res = interface.tuplename(name) if isinstance(name, tuple) else name
        ok = idaapi.add_enum_member(eid, utils.string.to(res), value, bmask)

        err = {
            getattr(idaapi, item): item
            for item in [
                'ENUM_MEMBER_ERROR_NAME', 'ENUM_MEMBER_ERROR_VALUE',
                'ENUM_MEMBER_ERROR_ENUM', 'ENUM_MEMBER_ERROR_MASK',
                'ENUM_MEMBER_ERROR_ILLV'
            ]
        }
        if ok in err.keys():
            raise E.DisassemblerError(
                u"{:s}.add({:#x}, {!r}, {:#x}{:s}) : Unable to add member to enumeration due to error {:s}({:d})."
                .format(
                    '.'.join([__name__, cls.__name__]), eid, name, value,
                    u", {:s}".format(utils.string.kwargs(bitmask))
                    if bitmask else '', err[ok], ok))
        return eid

    new = create = utils.alias(add, 'members')

    @classmethod
    def remove(cls, enum, member):
        '''Remove the specified `member` of the enumeration `enum`.'''
        eid = by(enum)
        mid = cls.by(eid, member)
        return member.remove(mid)

    delete = destroy = utils.alias(remove, 'members')

    ## aggregations
    @classmethod
    def names(cls, enum):
        '''Return a set of all the names belonging to the enumeration `enum`.'''
        eid = by(enum)
        return {member.name(mid) for mid in cls.iterate(eid)}

    @classmethod
    def values(cls, enum):
        '''Return a set of all the values belonging to the enumeration `enum`.'''
        eid = by(enum)
        return {member.value(mid) for mid in cls.iterate(eid)}

    @classmethod
    def mapping(cls, enum):
        '''Return a dictionary mapping all the values values to their names for the enumeration `enum`.'''
        eid = by(enum)
        return {
            member.value(mid): member.name(mid)
            for mid in cls.iterate(eid)
        }

    ## searching
    @classmethod
    def by_index(cls, enum, index):
        '''Return the member identifier for the member of the enumeration `enum` at the specified `index`.'''
        eid = by(enum)
        try:
            return next(mid for i, mid in enumerate(cls.iterate(eid))
                        if i == index)
        except StopIteration:
            pass
        raise E.MemberNotFoundError(
            u"{:s}.by_index({:#x}, {:d}) : Unable to locate member by index.".
            format('.'.join([__name__, cls.__name__]), eid, index))

    @classmethod
    def by_identifier(cls, enum, mid):
        '''Return the member of the enumeration specified by `enum` and its `mid`.'''
        eid = by(enum)
        if member.parent(mid) != eid:
            raise E.MemberNotFoundError(
                u"{:s}.by_identifier({:#x}, {:d}) : Unable to locate member by the specified identifier."
                .format('.'.join([__name__, cls.__name__]), eid, mid))
        return mid

    @classmethod
    def by_value(cls, enum, value):
        '''Return the member identifier for the member of the enumeration `enum` with the specified `value`.'''
        eid = by(enum)
        bmask = idaapi.BADADDR & mask(eid)
        res, _ = idaapi.get_first_serial_enum_member(eid, value, bmask)
        if res == idaapi.BADADDR:
            raise E.MemberNotFoundError(
                u"{:s}.by_value({:#x}, {:d}) : Unable to locate member by value."
                .format('.'.join([__name__, cls.__name__]), eid, value))
        return res

    byvalue = utils.alias(by_value, 'members')

    @classmethod
    @utils.string.decorate_arguments('name')
    def by_name(cls, enum, name):
        '''Return the member identifier for the member of the enumeration `enum` with the specified `name`.'''
        eid = by(enum)
        for mid in cls.iterate(eid):
            if name == member.name(mid):
                return mid
            continue
        return

    byname = utils.alias(by_name, 'members')

    @utils.multicase(n=six.integer_types)
    @classmethod
    def by(cls, enum, n):
        '''Return the member belonging to `enum` identified by its index or id in `n`.'''
        return cls.by_identifier(
            enum, n) if interface.node.is_identifier(n) else cls.by_index(
                enum, n)

    @utils.multicase(member=six.string_types)
    @classmethod
    @utils.string.decorate_arguments('member')
    def by(cls, enum, member):
        '''Return the member with the given `name` belonging to `enum`.'''
        return cls.by_name(enum, member)

    # FIXME: Implement a matcher class for enumeration members that can be used with .iterate and .list below.
    __member_matcher = utils.matcher()

    @classmethod
    def __iterate__(cls, eid):
        '''Iterate through all the members of the enumeration identified by `eid`.'''
        bmask = idaapi.BADADDR & mask(eid)

        res = idaapi.get_first_enum_member(eid, bmask)
        if res == idaapi.BADADDR: return

        yield res

        while res != idaapi.get_last_enum_member(eid, bmask):
            res = idaapi.get_next_enum_member(eid, res, bmask)
            yield res
        return

    @classmethod
    def iterate(cls, enum):
        '''Iterate through all ids of each member associated with the enumeration `enum`.'''
        eid = by(enum)
        bmask = idaapi.BADADDR & mask(eid)
        for value in cls.__iterate__(eid):
            res, _ = idaapi.get_first_serial_enum_member(eid, value, bmask)
            # XXX: what does get_next_serial_enum_member and the rest do?
            yield res
        return

    @classmethod
    def list(cls, enum):
        '''List all the members belonging to the enumeration identified by `enum`.'''
        # FIXME: make this consistent with every other .list using the matcher class
        eid = by(enum)
        listable = [item for item in cls.iterate(eid)]
        maxindex = max(
            builtins.map(utils.first, enumerate(listable)
                         ) if listable else [1])
        maxvalue = max(
            builtins.map(utils.fcompose(member.value, "{:#x}".format, len
                                        ), listable) if listable else [1])
        for i, mid in enumerate(listable):
            six.print_(u"[{:d}] 0x{:>0{:d}x} {:s}".format(
                i, member.value(mid), maxvalue, member.name(mid)))
        return
Ejemplo n.º 5
0
class members_t(object):
    """An abstraction around the members of a particular IDA structure

    This allows one to treat each member as a dict.
    """
    __slots__ = ('__owner', 'baseoffset')

    # members state
    @property
    def owner(self):
        '''Return the structure_t that owns this members_t.'''
        return self.__owner

    @property
    def ptr(self):
        '''Return the members' idaapi pointer.'''
        return self.__owner.ptr.members

    def __init__(self, owner, baseoffset=0):
        self.__owner = owner
        self.baseoffset = baseoffset

    def __getstate__(self):
        return (self.owner.name, self.baseoffset,
                map(self.__getitem__, range(len(self))))

    def __setstate__(self, state):
        ownername, baseoffset, _ = state
        identifier = idaapi.get_struc_id(ownername)
        if identifier == idaapi.BADADDR:
            raise LookupError(
                "{:s}.instance({:s}).members.__setstate__ : Failure creating a members_t for structure_t {!r}"
                .format(__name__, self.owner.name, ownername))
            logging.warn(
                "{:s}.instance({:s}).members.__setstate__ : Creating structure {:s} -- [{:+#x}] {:d} members"
                .format(__name__, self.owner.name, ownername, baseoffset,
                        len(members)))
            identifier = idaapi.add_struc(idaapi.BADADDR, ownername)
        self.baseoffset = baseoffset
        self.__owner = instance(identifier, offset=baseoffset)
        return

    # fetching members
    def __len__(self):
        '''Return the number of members within the structure.'''
        return 0 if self.owner.ptr is None else self.owner.ptr.memqty

    def __iter__(self):
        for idx in xrange(len(self)):
            yield member_t(self.owner, idx)
        return

    def __getitem__(self, index):
        '''Return the member at the specified ``index``.'''
        if isinstance(index, (int, long)):
            index = self.owner.ptr.memqty + index if index < 0 else index
            res = member_t(
                self.owner, index
            ) if index >= 0 and index < self.owner.ptr.memqty else None
        elif isinstance(index, str):
            res = self.byname(index)
        elif isinstance(index, slice):
            res = [self.__getitem__(i)
                   for i in range(self.owner.ptr.memqty)].__getitem__(index)
        else:
            raise TypeError, index

        if res is None:
            raise IndexError, index
        return res

    def index(self, member_t):
        '''Return the index of the member ``member_t``.'''
        for i in range(0, self.owner.ptr.memqty):
            if member_t.id == self[i].id:
                return i
            continue
        raise ValueError(
            "{:s}.instance({:s}).members.index : {!r} not in list".format(
                __name__, self.owner.name, member_t))

    __member_matcher = utils.matcher()
    __member_matcher.boolean('regex', re.search, 'name')
    __member_matcher.attribute('index', 'index')
    __member_matcher.attribute('identifier',
                               'id'), __matcher__.attribute('id', 'id')
    __member_matcher.attribute('offset', 'offset')
    __member_matcher.boolean('name', lambda v, n: fnmatch.fnmatch(n, v),
                             'name')
    __member_matcher.boolean('like', lambda v, n: fnmatch.fnmatch(n, v),
                             'name')
    __member_matcher.boolean('fullname', lambda v, n: fnmatch.fnmatch(n, v),
                             'fullname')
    __member_matcher.boolean('comment', lambda v, n: fnmatch.fnmatch(n, v),
                             'comment')
    __member_matcher.boolean(
        'greater', operator.le,
        lambda m: m.offset + m.size), __member_matcher.boolean(
            'gt', operator.lt, lambda m: m.offset + m.size)
    __member_matcher.boolean('less', operator.ge,
                             'offset'), __member_matcher.boolean(
                                 'lt', operator.gt, 'offset')
    __member_matcher.predicate('predicate'), __member_matcher.predicate('pred')

    # searching members
    @utils.multicase()
    def iterate(self, **type):
        if not type: type = {'predicate': lambda n: True}
        res = __builtin__.list(iter(self))
        for k, v in type.iteritems():
            res = __builtin__.list(self.__member_matcher.match(k, v, res))
        for n in res:
            yield n

    @utils.multicase(string=basestring)
    def list(self, string):
        '''List any members that match the glob in `string`.'''
        return self.list(like=string)

    @utils.multicase()
    def list(self, **type):
        """List all the members within the structure.

        Search type can be identified by providing a named argument.
        like = glob match
        regex = regular expression
        index = particular index
        identifier = particular id number
        predicate = function predicate
        """
        res = __builtin__.list(self.iterate(**type))

        escape = repr
        maxindex = max(
            __builtin__.map(
                utils.compose(operator.attrgetter('index'), "{:d}".format,
                              len), res) or [1])
        maxoffset = max(
            __builtin__.map(
                utils.compose(operator.attrgetter('offset'), "{:x}".format,
                              len), res) or [1])
        maxsize = max(
            __builtin__.map(
                utils.compose(operator.attrgetter('size'), "{:x}".format, len),
                res) or [1])
        maxname = max(
            __builtin__.map(
                utils.compose(operator.attrgetter('name'), escape, len), res)
            or [1])
        maxtype = max(
            __builtin__.map(
                utils.compose(operator.attrgetter('type'), repr, len), res)
            or [1])

        for m in res:
            print "[{:{:d}d}] {:>{:d}x}:+{:<{:d}x} {:<{:d}s} {:{:d}s} (flag={:x},dt_type={:x}{:s}){:s}".format(
                m.index, maxindex, m.offset, int(maxoffset), m.size, maxsize,
                escape(m.name), int(maxname), m.type, int(maxtype), m.flag,
                m.dt_type,
                '' if m.typeid is None else ",typeid={:x}".format(m.typeid),
                " // {:s}".format(m.comment) if m.comment else '')
        return

    @utils.multicase()
    def by(self, **type):
        '''Return the member with the specified ``name``.'''
        searchstring = ', '.join("{:s}={!r}".format(k, v)
                                 for k, v in type.iteritems())

        res = __builtin__.list(self.iterate(**type))
        if len(res) > 1:
            map(logging.info, (("[{:d}] {:x}:+{:x} '{:s}' {!r}".format(
                m.index, m.offset, m.size, m.name, m.type)) for m in res))
            logging.warn(
                "{:s}.instance({:s}).members.by({:s}) : Found {:d} matching results, returning the first one. : [{:d}] {:x}:+{:x} '{:s}' {!r}"
                .format(__name__, self.owner.name, searchstring, len(res),
                        res[0].index, res[0].offset, res[0].size,
                        res[0].fullname, res[0].type))

        res = next(iter(res), None)
        if res is None:
            raise LookupError(
                "{:s}.instance({:s}).members.by({:s}) : Found 0 matching results."
                .format(__name__, self.owner.name, searchstring))
        return res

    @utils.multicase(name=basestring)
    def by(self, name):
        '''Return the member with the specified ``name``.'''
        return self.by_name(name)

    @utils.multicase(offset=six.integer_types)
    def by(self, offset):
        '''Return the member at the specified ``offset``.'''
        return self.by_offset(offset)

    def by_name(self, name):
        '''Return the member with the specified ``name``.'''
        mem = idaapi.get_member_by_name(self.owner.ptr, str(name))
        if mem is None:
            raise KeyError(
                "{:s}.instance({:s}).members.by_name : Unable to find member with requested name : {!r}"
                .format(__name__, self.owner.name, name))
        index = self.index(mem)
        return self[index]

    byname = byName = utils.alias(by_name, 'members_t')

    def by_fullname(self, fullname):
        '''Return the member with the specified ``fullname``.'''
        mem = idaapi.get_member_by_fullname(self.owner.ptr, str(fullname))
        if mem is None:
            raise KeyError(
                "{:s}.instance({:s}).members.by_fullname : Unable to find member with full name : {!r}"
                .format(__name__, self.owner.name, fullname))
        index = self.index(mem)
        return self[index]

    byfullname = byFullname = utils.alias(by_fullname, 'members_t')

    def by_offset(self, offset):
        '''Return the member at the specified ``offset``.'''
        min, max = map(lambda sz: sz + self.baseoffset,
                       (idaapi.get_struc_first_offset(self.owner.ptr),
                        idaapi.get_struc_last_offset(self.owner.ptr)))

        mptr = idaapi.get_member(self.owner.ptr, max - self.baseoffset)
        msize = idaapi.get_member_size(mptr)
        if (offset < min) or (offset >= max + msize):
            raise LookupError(
                "{:s}.instance({:s}).members.by_offset : Requested offset {:+#x} not within bounds ({:#x},{:#x})"
                .format(__name__, self.owner.name, offset, min, max + msize))

        mem = idaapi.get_member(self.owner.ptr, offset - self.baseoffset)
        if mem is None:
            raise LookupError(
                "{:s}.instance({:s}).members.by_offset : Unable to find member at offset : {:+#x}"
                .format(__name__, self.owner.name, offset))

        index = self.index(mem)
        return self[index]

    byoffset = byOffset = utils.alias(by_offset, 'members_t')

    def near_offset(self, offset):
        '''Return the member near to the specified ``offset``.'''
        min, max = map(lambda sz: sz + self.baseoffset,
                       (idaapi.get_struc_first_offset(self.owner.ptr),
                        idaapi.get_struc_last_offset(self.owner.ptr)))
        if (offset < min) or (offset >= max):
            logging.warn(
                "{:s}.instance({:s}).members.near_offset : Requested offset {:+#x} not within bounds ({:#x},{:#x}). Trying anyways.."
                .format(__name__, self.owner.name, offset, min, max))

        res = offset - self.baseoffset
        mem = idaapi.get_member(self.owner.ptr, res)
        if mem is None:
            logging.info(
                "{:s}.instance({:s}).members.near_offset : Unable to locate member at offset {:+#x}. Trying get_best_fit_member instead."
                .format(__name__, self.owner.name, res))
            mem = idaapi.get_best_fit_member(self.owner.ptr, res)

        if mem is None:
            raise LookupError(
                "{:s}.instance({:s}).members.near_offset : Unable to find member near offset : {:+#x}"
                .format(__name__, self.owner.name, offset))

        index = self.index(mem)
        return self[index]

    near = nearoffset = nearOffset = utils.alias(near_offset, 'members_t')

    # adding/removing members
    @utils.multicase(name=(basestring, tuple))
    def add(self, name):
        '''Append the specified member ``name`` with the default type at the end of the structure.'''
        offset = self.owner.size + self.baseoffset
        return self.add(name, int, offset)

    @utils.multicase(name=(basestring, tuple))
    def add(self, name, type):
        '''Append the specified member ``name`` with the given ``type`` at the end of the structure.'''
        offset = self.owner.size + self.baseoffset
        return self.add(name, type, offset)

    @utils.multicase(name=(basestring, tuple), offset=six.integer_types)
    def add(self, name, type, offset):
        """Add a member at ``offset`` with the given ``name`` and ``type``.
        To specify a particular size, ``type`` can be a tuple with the second element referring to the size.
        """
        flag, typeid, nbytes = interface.typemap.resolve(type)

        # FIXME: handle .strtype (strings), .ec (enums), .cd (custom)
        opinfo = idaapi.opinfo_t()
        opinfo.tid = typeid
        realoffset = offset - self.baseoffset

        if name is None:
            logging.warn(
                "{:s}.instance({:s}).members.add : name is undefined, defaulting to offset {:+#x}"
                .format(__name__, self.owner.name, realoffset))
            name = 'v', realoffset
        if isinstance(name, tuple):
            name = interface.tuplename(*name)

        res = idaapi.add_struc_member(self.owner.ptr, name, realoffset, flag,
                                      opinfo, nbytes)
        if res == idaapi.STRUC_ERROR_MEMBER_OK:
            logging.info(
                "{:s}.instance({:s}).members.add : idaapi.add_struc_member(sptr={!r}, fieldname={:s}, offset={:+#x}, flag={:#x}, mt={:#x}, nbytes={:#x}) : Success"
                .format(__name__, self.owner.name, self.owner.name, name,
                        realoffset, flag, typeid, nbytes))
        else:
            error = {
                idaapi.STRUC_ERROR_MEMBER_NAME: 'Duplicate field name',
                idaapi.STRUC_ERROR_MEMBER_OFFSET: 'Invalid offset',
                idaapi.STRUC_ERROR_MEMBER_SIZE: 'Invalid size',
            }
            callee = "idaapi.add_struc_member(sptr={!r}, fieldname={:s}, offset={:+#x}, flag={:#x}, mt={:#x}, nbytes={:#x})".format(
                self.owner.name, name, realoffset, flag, typeid, nbytes)
            logging.fatal(' : '.join(
                ('members_t.add', callee,
                 error.get(res, "Error code {:#x}".format(res)))))
            return None

        res = idaapi.get_member(self.owner.ptr, realoffset)
        if res is None:
            logging.fatal(
                "{:s}.instance({:s}.members.add : Failed creating member {!r} {:s}:{:+#x}"
                .format(__name__, self.owner.name, name, realoffset, nbytes))

        # sloppily figure out what the correct index is
        idx = self.index(idaapi.get_member(self.owner.ptr, realoffset))
        return member_t(self.owner, idx)

    def pop(self, index):
        '''Remove the member at the specified ``index``.'''
        item = self[index]
        return self.remove(item.offset - self.baseoffset)

    def __delitem__(self, index):
        return self.pop(index)

    @utils.multicase()
    def remove(self, offset):
        '''Remove all the member from the structure at ``offset``.'''
        return idaapi.del_struc_member(self.owner.ptr,
                                       offset - self.baseoffset)

    @utils.multicase()
    def remove(self, offset, size):
        '''Remove all the members from the structure from ``offset`` up to ``size``.'''
        ofs = offset - self.baseoffset
        return idaapi.del_struc_members(self.owner.ptr, ofs, ofs + size)

    def __repr__(self):
        '''Display all the fields within the specified structure.'''
        result = []
        mn, ms = 0, 0
        for i in xrange(len(self)):
            m = self[i]
            name, t, ofs, size, comment = m.name, m.type, m.offset, m.size, m.comment
            result.append((i, name, t, ofs, size, comment))
            mn = max((mn, len(name)))
            ms = max((ms, len("{:x}".format(size))))
        mi = len(str(len(self)))
        mo = max(
            map(
                len,
                map("{:x}".format,
                    (self.baseoffset, self.baseoffset + self.owner.size))))
        return "{!r}\n{:s}".format(
            self.owner, '\n'.join(
                "[{:{:d}d}] {:>{:d}x}:+{:<{:d}x} {:<{:d}s} {!r} {:s}".format(
                    i, mi, o, mo, s, ms, "'{:s}'".format(n), mn +
                    2, t, " // {:s}".format(c) if c else '')
                for i, n, t, o, s, c in result))
Ejemplo n.º 6
0
    eid = by(enum)
    return idaapi.get_enum_flag(eid)
@utils.multicase(mask=six.integer_types)
def flags(enum, mask):
    '''Return the flags for the enumeration `enum` and masked with `mask`.'''
    eid = by(enum)
    return idaapi.get_enum_flag(eid) & mask

@utils.string.decorate_arguments('name')
def by_name(name):
    '''Return the identifier for the enumeration with the given `name`.'''
    res = idaapi.get_enum(utils.string.to(name))
    if res == idaapi.BADADDR:
        raise E.EnumerationNotFoundError(u"{:s}.by_name({!r}) : Unable to locate enumeration by the name \"{:s}\".".format(__name__, name, utils.string.escape(name, '"')))
    return res
byName = utils.alias(by_name)

def by_index(index):
    '''Return the identifier for the enumeration at the specified `index`.'''
    res = idaapi.getn_enum(index)
    if res == idaapi.BADADDR:
        raise E.EnumerationNotFoundError(u"{:s}.by_index({:#x}) : Unable to locate enumeration by the index {:d}.".format(__name__, index, index))
    return res
byIndex = utils.alias(by_index)

@utils.multicase(index=six.integer_types)
def by(index):
    '''Return the identifier for the enumeration at the specified `index`.'''
    bits = math.trunc(math.ceil(math.log(idaapi.BADADDR)/math.log(2.0)))
    highbyte = 0xff << (bits-8)
    if index & highbyte == highbyte:
Ejemplo n.º 7
0
def search(string):
    '''Search through all the structures using globbing.'''
    return by(like=string)


def by_name(name, **options):
    '''Return a structure by it's name.'''
    id = idaapi.get_struc_id(name)
    if id == idaapi.BADADDR:
        raise LookupError(
            "{:s}.by_name({!r}) : Unable to locate structure with given name.".
            format(__name__, name))
    return instance(id, **options)


byName = utils.alias(by_name)


def by_index(index, **options):
    '''Return a structure by it's index.'''
    id = idaapi.get_struc_by_idx(index)
    if id == idaapi.BADADDR:
        raise IndexError(
            "{:s}.by_index({:d}) : Unable to locate structure at given index.".
            format(__name__, index))
    return instance(id, **options)


byIndex = utils.alias(by_index)

Ejemplo n.º 8
0
    for seg in res:
        comment = idaapi.get_segment_cmt(seg, 0) or idaapi.get_segment_cmt(seg, 1)
        six.print_(u"[{:{:d}d}] {:#0{:d}x}<>{:#0{:d}x} : {:<+#{:d}x} : {:>{:d}s} : sel:{:04x} flags:{:02x}{:s}".format(seg.index, int(cindex), seg.startEA, 2+int(caddr), seg.endEA, 2+int(caddr), seg.size(), 3+int(csize), utils.string.of(idaapi.get_true_segm_name(seg)), maxname, seg.sel, seg.flags, u"// {:s}".format(utils.string.of(comment)) if comment else ''))
    return

## searching
@utils.string.decorate_arguments('name')
def by_name(name):
    '''Return the segment with the given `name`.'''
    res = utils.string.to(name)
    seg = idaapi.get_segm_by_name(res)
    if seg is None:
        raise E.SegmentNotFoundError(u"{:s}.by_name({!r}) : Unable to locate the segment with the specified name.".format(__name__, name))
    return seg
byName = utils.alias(by_name)
def by_selector(selector):
    '''Return the segment associated with `selector`.'''
    seg = idaapi.get_segm_by_sel(selector)
    if seg is None:
        raise E.SegmentNotFoundError(u"{:s}.by_selector({:#x}) : Unable to locate the segment with the specified selector.".format(__name__, selector))
    return seg
bySelector = utils.alias(by_selector)
def by_address(ea):
    '''Return the segment that contains the specified `ea`.'''
    seg = idaapi.getseg(interface.address.within(ea))
    if seg is None:
        raise E.SegmentNotFoundError(u"{:s}.by_address({:#x}) : Unable to locate segment containing the specified address.".format(__name__, ea))
    return seg
byAddress = utils.alias(by_address)
@utils.multicase(segment=idaapi.segment_t)
Ejemplo n.º 9
0
    caddr = math.ceil(math.log(maxaddr)/math.log(16))
    csize = math.ceil(math.log(maxsize)/math.log(16))

    for seg in res:
        comment = idaapi.get_segment_cmt(seg, 0) or idaapi.get_segment_cmt(seg, 1)
        print("[{:{:d}d}] {:0{:d}x}:{:0{:d}x} {:>{:d}s} {:<+#{:d}x} sel:{:04x} flags:{:02x}{:s}".format(seg.index, int(cindex), seg.startEA, int(caddr), seg.endEA, int(caddr), idaapi.get_true_segm_name(seg), maxname, seg.size(), int(csize), seg.sel, seg.flags, "// {:s}".format(comment) if comment else ''))
    return

## searching
def by_name(name):
    '''Return the segment with the given ``name``.'''
    s = idaapi.get_segm_by_name(name)
    if s is None:
        raise LookupError("{:s}.by_name({!r}) : Unable to locate segment".format(__name__, name))
    return s
byName = utils.alias(by_name)
def by_selector(selector):
    '''Return the segment associated with ``selector``.'''
    s = idaapi.get_segm_by_sel(selector)
    if s is None:
        raise LookupError("{:s}.by_selector({:x}) : Unable to locate segment".format(__name__, selector))
    return s
bySelector = utils.alias(by_selector)
def by_address(ea):
    '''Return the segment that contains the specified ``ea``.'''
    s = idaapi.getseg(interface.address.within(ea))
    if s is None:
        raise LookupError("{:s}.by_address({:x}) : Unable to locate segment".format(__name__, ea))
    return s
byAddress = utils.alias(by_address)
@utils.multicase(segment=idaapi.segment_t)
Ejemplo n.º 10
0
class member(object):
    '''This class allows one to interact with the members of a defined enumeration.

    Examples:
        e = enum.byName('example_enumeration')
        print enum.repr(e)

        enum.member.rename(e, 'oldname', 'newname')

        n = enum.member.add(e, 'name', 0x1000)
        enum.member.remove(n)

        n = enum.member.byName(e, 'name')
        n = enum.member.byValue(e, 0x1000)

        enum.member.name(n, 'somename')
        enum.member.value(n, 0x100)
        enum.member.comment(n, 'This is an test value')

        for n in enum.member.iterate(e):
            print enum.member.name(n)
            print enum.member.value(n)
            print enum.member.comment(n)
    '''
    @classmethod
    def parent(cls, mid):
        '''Return the enumeration id that owns the member ``mid``.'''
        return idaapi.get_enum_member_enum(mid)

    ## lifetime
    @classmethod
    def add(cls, enum, name, value, **bitmask):
        """Add an enumeration member ``name`` with the specified ``value`` to the enumeration identified by ``enum``.
        If the int, ``bitmask``, is specified then used it as the bitmask for the enumeration.
        """
        eid = by(enum)
        bmask = bitmask.get('bitmask', -1 & mask(eid))

        res = interface.tuplename(name) if isinstance(name, tuple) else name
        ok = idaapi.add_enum_member(eid, res, value, bmask)

        if ok in (idaapi.ENUM_MEMBER_ERROR_NAME,
                  idaapi.ENUM_MEMBER_ERROR_VALUE,
                  idaapi.ENUM_MEMBER_ERROR_ENUM, idaapi.ENUM_MEMBER_ERROR_MASK,
                  idaapi.ENUM_MEMBER_ERROR_ILLV):
            raise ValueError(
                "{:s}.add({:x}, {!r}, {:x}, bitmask={!r}) : Unable to add member to enumeration."
                .format('.'.join((__name__, cls.__name__)), eid, name, value,
                        bitmask))
        return cls.by_value(eid, value)

    new = create = utils.alias(add, 'member')

    @utils.multicase(mid=six.integer_types)
    @classmethod
    def remove(cls, mid):
        '''Remove the enumeration member with the given ``mid``.'''
        value = cls.value(mid)
        # XXX: is a serial of 0 valid?
        res = idaapi.del_enum_member(cls.parent(mid), value, 0,
                                     -1 & cls.mask(mid))
        if not res:
            raise LookupError(
                "{:s}.member._remove({:x}) : Unable to remove member from enumeration."
                .format(__name__, mid))
        return res

    @utils.multicase()
    @classmethod
    def remove(cls, enum, member):
        '''Remove the specified ``member`` of the enumeration ``enum``.'''
        eid = by(enum)
        mid = cls.by(eid, member)
        return cls.remove(mid)

    delete = destroy = utils.alias(remove, 'member')

    ## searching
    @classmethod
    def by_index(cls, enum, index):
        '''Return the member id for the member of the enumeration ``enum`` at the specified ``index``.'''
        eid = by(enum)
        try:
            return next(m for i, m in enumerate(cls.iterate(eid))
                        if i == index)
        except StopIteration:
            pass
        raise LookupError(
            "{:s}.by_index({:x}, {:d}) : Unable to locate member by index.".
            format('.'.join((__name__, cls.__name__)), eid, index))

    @classmethod
    def by_identifer(cls, enum, mid):
        eid = by(enum)
        if cls.parent(mid) != eid:
            raise LookupError(
                "{:s}.by_identifier({:x}, {:d}) : Unable to locate member by id."
                .format('.'.join((__name__, cls.__name__)), eid, index))
        return mid

    @classmethod
    def by_value(cls, enum, value):
        '''Return the member id for the member of the enumeration ``enum`` with the specified ``value``.'''
        eid = by(enum)
        bmask = -1 & mask(eid)
        res, _ = idaapi.get_first_serial_enum_member(eid, value, bmask)
        if res == idaapi.BADADDR:
            raise LookupError(
                "{:s}.by_value({:x}, {:d}) : Unable to locate member by value."
                .format('.'.join((__name__, cls.__name__)), eid, value))
        return res

    byValue = utils.alias(by_value, 'member')

    @classmethod
    def by_name(cls, enum, name):
        '''Return the member id for the member of the enumeration ``enum`` with the specified ``name``.'''
        eid = by(enum)
        for mid in cls.iterate(eid):
            if name == cls.name(mid):
                return mid
            continue
        return

    byName = utils.alias(by_name, 'member')

    @utils.multicase(n=six.integer_types)
    @classmethod
    def by(cls, enum, n):
        '''Return the member belonging to ``enum`` identified by it's index, or it's id.'''
        bits = int(math.ceil(math.log(idaapi.BADADDR) / math.log(2.0)))
        highbyte = 0xff << (bits - 8)
        if n & highbyte == highbyte:
            return cls.by_identifier(enum, n)
        return cls.by_index(enum, n)

    @utils.multicase(member=basestring)
    @classmethod
    def by(cls, enum, member):
        '''Return the member with the given ``name`` belonging to ``enum``.'''
        return cls.by_name(enum, member)

    ## properties
    @utils.multicase(mid=six.integer_types)
    @classmethod
    def name(cls, mid):
        '''Return the name of the enumeration member ``mid``.'''
        return idaapi.get_enum_member_name(mid)

    @utils.multicase()
    @classmethod
    def name(cls, enum, member):
        '''Return the name of the enumeration ``member`` belonging to ``enum``.'''
        eid = by(enum)
        mid = cls.by(eid, member)
        return cls.name(mid)

    @utils.multicase(mid=six.integer_types, name=(basestring, tuple))
    @classmethod
    def name(cls, mid, name):
        '''Rename the enumeration member ``mid`` to ``name``.'''
        res = interface.tuplename(*name) if isinstance(name, tuple) else name
        return idaapi.set_enum_member_name(mid, res)

    @utils.multicase(name=basestring)
    @classmethod
    def name(cls, enum, member, name, *suffix):
        '''Rename the enumeration ``member`` of ``enum`` to ``name```.'''
        eid = by(enum)
        mid = cls.by(eid, member)
        res = (name, ) + suffix
        return cls.name(eid, interface.tuplename(*res))

    rename = utils.alias(name, 'member')

    @utils.multicase(mid=six.integer_types)
    @classmethod
    def comment(cls, mid, **repeatable):
        """Return the comment for the enumeration member id ``mid``.
        If the bool ``repeatable`` is specified, then return the repeatable comment.
        """
        return idaapi.get_enum_member_cmt(mid,
                                          repeatable.get('repeatable', True))

    @utils.multicase(name=basestring)
    @classmethod
    def comment(cls, enum, member, **repeatable):
        '''Return the comment for the enumeration ``member`` belonging to ``enum``.'''
        eid = by(enum)
        mid = cls.by(eid, name)
        return cls.comment(mid, **repeatable)

    @utils.multicase(mid=six.integer_types, comment=basestring)
    @classmethod
    def comment(cls, mid, comment, **repeatable):
        """Set the comment for the enumeration member id ``mid`` to ``comment``.
        If the bool ``repeatable`` is specified, then set the repeatable comment.
        """
        return idaapi.set_enum_member_cmt(mid, comment,
                                          kwds.get('repeatable', True))

    @utils.multicase(comment=basestring)
    @classmethod
    def comment(cls, enum, member, comment, **repeatable):
        '''Set the comment for the enumeration ``member`` belonging to ``enum`` to the string ``comment``.'''
        eid = by(enum)
        mid = cls.by(eid, name)
        return cls.comment(mid, comment, **repeatable)

    @utils.multicase(mid=six.integer_types)
    @classmethod
    def value(cls, mid):
        '''Return the value of the enumeration member ``mid``.'''
        return idaapi.get_enum_member_value(mid)

    @utils.multicase()
    @classmethod
    def value(cls, enum, member):
        '''Return the value of the specified ``member`` belonging to the enumeration ``enum``.'''
        eid = by(enum)
        mid = cls.by(member)
        return cls.value(mid)

    @utils.multicase(value=six.integer_types)
    @classmethod
    def value(cls, enum, member, value, **bitmask):
        """Set the ``value`` for the enumeration ``member`` belonging to ``enum``.
        If the integer ``bitmask`` is specified, then use it as a bitmask. Otherwise assume all bits are set.
        """
        eid = by(enum)
        mid = cls.by(enum, member)
        #bmask = bitmask.get('bitmask', -1 & mask(eid))
        bmask = bitmask.get('bitmask', -1 & cls.mask(mid))
        return idaapi.set_enum_member_value(mid, value, bmask)

    @utils.multicase(mid=six.integer_types)
    @classmethod
    def serial(cls, mid):
        '''Return the serial of the enumeration member ``mid``.'''
        return idaapi.get_enum_member_serial(mid)

    @utils.multicase()
    @classmethod
    def serial(cls, enum, member):
        '''Return the serial of the enumeration ``member`` belonging to ``enum``.'''
        eid = by(enum)
        mid = cls.by(eid, member)
        return cls.serial(mid)

    @utils.multicase(mid=six.integer_types)
    @classmethod
    def mask(cls, mid):
        '''Return the bitmask for the enumeration member ``mid``.'''
        return idaapi.get_enum_member_bmask(mid)

    @utils.multicase()
    @classmethod
    def mask(cls, enum, member):
        '''Return the bitmask for the enumeration ``member`` belonging to ``enum``.'''
        eid = by(enum)
        mid = cls.by(eid, member)
        return cls.mask(mid)

    # FIXME
    __member_matcher = utils.matcher()

    @classmethod
    def __iterate__(cls, eid):
        bmask = -1 & mask(eid)
        res = idaapi.get_first_enum_member(eid, bmask)
        if res == idaapi.BADADDR: return
        yield res
        while res != idaapi.get_last_enum_member(eid, bmask):
            res = idaapi.get_next_enum_member(eid, res, bmask)
            yield res
        return

    @classmethod
    def iterate(cls, enum):
        '''Iterate through all the member ids associated with the enumeration ``enum``.'''
        eid = by(enum)
        bmask = -1 & mask(eid)
        for v in cls.__iterate__(eid):
            res, _ = idaapi.get_first_serial_enum_member(eid, v, bmask)
            # XXX: what does get_next_serial_enum_member and the rest do?
            yield res
        return

    @classmethod
    def list(cls, enum):
        # FIXME: make this consistent with every other .list
        eid = by(enum)
        res = __builtin__.list(cls.iterate(eid))
        maxindex = max(__builtin__.map(utils.first, enumerate(res)) or [1])
        maxvalue = max(
            __builtin__.map(utils.compose(cls.value, "{:x}".format, len), res)
            or [1])
        for i, mid in enumerate(res):
            print("[{:d}] {:>0{:d}x} {:s}".format(i, cls.value(mid), maxvalue,
                                                  cls.name(mid)))
        return
Ejemplo n.º 11
0
@utils.multicase(enum=six.integer_types, mask=six.integer_types)
def flags(enum, mask):
    return idaapi.get_enum_flag(enum) & mask


def by_name(name):
    '''Return an enum id with the specified ``name``.'''
    res = idaapi.get_enum(name)
    if res == idaapi.BADADDR:
        raise LookupError(
            "{:s}.by_name({!r}) : Unable to locate enumeration.".format(
                __name__, name))
    return res


byName = utils.alias(by_name)


def by_index(index):
    '''Return an enum id at the specified ``index``.'''
    res = idaapi.getn_enum(index)
    if res == idaapi.BADADDR:
        raise LookupError(
            "{:s}.by_index({:x}) : Unable to locate enumeration.".format(
                __name__, index))
    return res


byIndex = utils.alias(by_index)