Beispiel #1
0
    def trace(self, ea):
        '''
        Given an EA where an argument register is set, attempt to trace what
        function call that argument is passed to.

        @ea - The address of an instruction that modifies a function argument
        register.

        Returns a tuple of (function EA, argv index, argument register name) on
        success.
        Returns None on failure.
        '''
        insn = ida_shims.decode_insn(ea)
        features = ida_shims.get_canon_feature(insn)

        if self.arch.unknown:
            return (None, None, None)

        for n in range(0, len(self.CHANGE_OPND)):
            ops = ida_shims.get_operands(insn)
            if ops[n].type in [idaapi.o_reg, idaapi.o_displ, idaapi.o_phrase]:
                try:
                    regname = self.arch.registers[ops[n].reg]
                    index = self.arch.argv.index(regname)
                except ValueError:
                    continue

                if features & self.CHANGE_OPND[n]:
                    ea = ea - (self.arch.delay_slot * self.arch.insn_size)

                    while True:
                        insn = ida_shims.decode_insn(ea)

                        if idaapi.is_call_insn(ea):
                            for xref in idautils.XrefsFrom(ea):
                                if xref.type in [idaapi.fl_CF, idaapi.fl_CN]:
                                    return (xref.to, index, regname)
                            # If we couldn't figure out where the function call
                            # was going to, just quit
                            break

                        try:
                            is_block_end = idaapi.is_basic_block_end(ea)
                        except TypeError:
                            is_block_end = idaapi.is_basic_block_end(ea, True)

                        if is_block_end:
                            break

                        # TODO: Use idc.NextHead(ea) instead...
                        ea += self.arch.insn_size

        return (None, None, None)
Beispiel #2
0
    def trace(self, ea):
        '''
        Given an EA where an argument register is set, attempt to trace what
        function call that argument is passed to.

        @ea - The address of an instruction that modifies a function argument register.

        Returns a tuple of (function EA, argv index, argument register name) on success.
        Returns None on failure.
        '''
        idaapi.decode_insn(ea)
        features = idaapi.cmd.get_canon_feature()

        if self.arch.unknown:
            return (None, None, None)

        for n in range(0, len(self.CHANGE_OPND)):
            if idaapi.cmd.Operands[n].type in [idaapi.o_reg, idaapi.o_displ, idaapi.o_phrase]:
                try:
                    regname = self.arch.registers[idaapi.cmd.Operands[n].reg]
                    index = self.arch.argv.index(regname)
                except ValueError:
                    continue

                if features & self.CHANGE_OPND[n]:
                    ea = ea - (self.arch.delay_slot * self.arch.insn_size)

                    while True:
                        idaapi.decode_insn(ea)

                        if idaapi.is_call_insn(ea):
                            for xref in idautils.XrefsFrom(ea):
                                if xref.type in [idaapi.fl_CF, idaapi.fl_CN]:
                                    return (xref.to, index, regname)
                            # If we couldn't figure out where the function call was going to, just quit
                            break

                        try:
                            is_block_end = idaapi.is_basic_block_end(ea)
                        except TypeError:
                            is_block_end = idaapi.is_basic_block_end(ea, True)

                        if is_block_end:
                            break

                        # TODO: Use idc.NextHead(ea) instead...
                        ea += self.arch.insn_size

        return (None, None, None)
Beispiel #3
0
 def blocks(start, end):
     '''Returns each block between the specified range of instructions'''
     block = start
     for ea in iterate(start, end):
         nextea = next(ea)
         if idaapi.is_basic_block_end(ea):
             yield block, nextea
             block = nextea
         continue
     return
Beispiel #4
0
    def is_end_block_call(self):
        """
            Property indicating if this instruction is the end of a basic
            block. This property will return True if the instruction is a
            call, see :meth:`is_end_block` for returning False on call which
            are not at the end of a block.

            :return bool: True if this instruction is the last one for a
                block, including the case when it is a call.
        """
        return idaapi.is_basic_block_end(self.ea, True)
Beispiel #5
0
    def is_end_block(self):
        """
            Property indicating if this instruction is the end of a basic block.
            This property will return False if the instruction is a call which
            does not end a block such as display by IDA, see
            :meth:`is_end_block_call` for returning True on call.

            :return bool: True if this instruction is the last one for a
                block.
        """
        return idaapi.is_basic_block_end(self.ea, False)
Beispiel #6
0
    def argv(self, func):
        '''
        Attempts to identify what types of arguments are passed to a given
        function. Currently unused.
        '''
        args = [None for x in self.arch.argv]

        if not self.arch.unknown:
            start_ea = ida_shims.start_ea(func)
            for xref in idautils.XrefsTo(start_ea):
                if idaapi.is_call_insn(xref.frm):
                    insn = ida_shims.decode_insn(xref.frm)

                    ea = xref.frm + (self.arch.delay_slot *
                                     self.arch.insn_size)
                    end_ea = (xref.frm - (self.arch.insn_size * 10))

                    while ea >= end_ea:
                        if idaapi.is_basic_block_end(ea) or \
                                (ea != xref.frm and idaapi.is_call_insn(ea)):
                            break

                        insn = ida_shims.decode_insn(ea)
                        features = ida_shims.get_canon_feature(insn)

                        for n in range(0, len(self.CHANGE_OPND)):
                            ops = ida_shims.get_operands(insn)
                            if ops[n].type in [
                                    idaapi.o_reg, idaapi.o_displ,
                                    idaapi.o_phrase
                            ]:
                                try:
                                    regname = self.arch.registers[ops[n].reg]
                                    index = self.arch.argv.index(regname)
                                except ValueError:
                                    continue

                                if features & self.CHANGE_OPND[n]:
                                    for xref in idautils.XrefsFrom(ea):
                                        # TODO: Where is this xref type defined?
                                        if xref.type == 1:
                                            string = \
                                                ida_shims.get_strlit_contents(
                                                    xref.to)
                                            if string and len(string) > 4:
                                                args[index] = str
                                            break

                        ea -= self.arch.insn_size

                yield args
Beispiel #7
0
    def argv(self, func):
        '''
        Attempts to identify what types of arguments are passed to a given function.
        Currently unused.
        '''
        args = [None for x in self.arch.argv]

        for xref in idautils.XrefsTo(func.startEA):
            if idaapi.is_call_insn(xref.frm):
                idaapi.decode_insn(xref.frm)

                ea = xref.frm + (self.arch.delay_slot * self.arch.insn_size)
                end_ea = (xref.frm - (self.arch.insn_size * 10))

                while ea >= end_ea:
                    # Stop searching if we've reached a conditional block or another call
                    if idaapi.is_basic_block_end(ea) or (
                            ea != xref.frm and idaapi.is_call_insn(ea)):
                        break

                    idaapi.decode_insn(ea)
                    features = idaapi.cmd.get_canon_feature()

                    for n in range(0, len(self.CHANGE_OPND)):
                        if idaapi.cmd.Operands[n].type in [
                                idaapi.o_reg, idaapi.o_displ, idaapi.o_phrase
                        ]:
                            try:
                                regname = self.arch.registers[
                                    idaapi.cmd.Operands[n].reg]
                                index = self.arch.argv.index(regname)
                            except ValueError:
                                continue

                            if features & self.CHANGE_OPND[n]:
                                for xref in idautils.XrefsFrom(ea):
                                    # TODO: Where is this xref type defined?
                                    if xref.type == 1:
                                        string = idc.GetString(xref.to)
                                        if string and len(string) > 4:
                                            args[index] = str
                                        break

                    ea -= self.arch.insn_size

                yield args
Beispiel #8
0
    def argv(self, func):
        '''
        Attempts to identify what types of arguments are passed to a given function.
        Currently unused.
        '''
        args = [None for x in self.arch.argv]

        if not self.arch.unknown:
            for xref in idautils.XrefsTo(func.startEA):
                if idaapi.is_call_insn(xref.frm):
                    idaapi.decode_insn(xref.frm)

                    ea = xref.frm + (self.arch.delay_slot * self.arch.insn_size)
                    end_ea = (xref.frm - (self.arch.insn_size * 10))

                    while ea >= end_ea:
                        # Stop searching if we've reached a conditional block or another call
                        if idaapi.is_basic_block_end(ea) or (ea != xref.frm and idaapi.is_call_insn(ea)):
                            break

                        idaapi.decode_insn(ea)
                        features = idaapi.cmd.get_canon_feature()

                        for n in range(0, len(self.CHANGE_OPND)):
                            if idaapi.cmd.Operands[n].type in [idaapi.o_reg, idaapi.o_displ, idaapi.o_phrase]:
                                try:
                                    regname = self.arch.registers[idaapi.cmd.Operands[n].reg]
                                    index = self.arch.argv.index(regname)
                                except ValueError:
                                    continue

                                if features & self.CHANGE_OPND[n]:
                                    for xref in idautils.XrefsFrom(ea):
                                        # TODO: Where is this xref type defined?
                                        if xref.type == 1:
                                            string = idc.GetString(xref.to)
                                            if string and len(string) > 4:
                                                args[index] = str
                                            break

                        ea -= self.arch.insn_size

                yield args
Beispiel #9
0
    def PopulateModel(self):
        self.Clean()
        vmr = get_vmr()
        w = NotifyProgress()
        w.show()
        ctr = 0
        max = len(self.trace)

        # present clustering analysis in viewer
        prev_ctx = defaultdict(lambda: 0)
        for line in self.trace:

            ctr += 1
            w.pbar_set(int(float(ctr) / float(max) * 100))

            if isinstance(line, Traceline):
                tid = QtGui.QStandardItem('%s' % line.thread_id)
                addr = QtGui.QStandardItem('%x' % line.addr)
                disasm = QtGui.QStandardItem(line.disasm_str())
                comment = QtGui.QStandardItem(''.join(
                    c for c in line.comment if line.comment is not None))
                context = QtGui.QStandardItem(''.join(
                    '%s:%s ' % (c, line.ctx[c]) for c in line.ctx
                    if line.ctx is not None))
                prev_ctx = line.ctx
                self.sim.appendRow([tid, addr, disasm, comment, context])
            else:
                cluster_node = QtGui.QStandardItem(
                    'Cluster %x-%x' % (line[0].addr, line[-1].addr))
                self.sim.appendRow(cluster_node)
                if vmr.bb:
                    cluster = line
                    bbs = []
                    bb = []
                    # subdivide the clusters by basic blocks
                    for line in cluster:
                        assert isinstance(line, Traceline)
                        if is_basic_block_end(line.addr):
                            bb.append(line)
                            bbs.append(bb)
                            bb = []
                        else:
                            bb.append(line)

                    for bb in bbs:

                        bb_sum = self.bb_func(bb, self.ctx_reg_size, prev_ctx)
                        bb_node = QtGui.QStandardItem(
                            'BB%s Summary %x-%x: %s\t%s\t%s' %
                            (bbs.index(bb), bb[0].addr, bb[-1].addr, ''.join(
                                '%s ; ' % (''.join('%s, ' % c for c in line))
                                for line in bb_sum.disasm), ''.join(
                                    '%s, ' % c
                                    for c in filter(None, bb_sum.comment)
                                    if bb_sum.comment is not None), ''.join(
                                        '%s:%s ' % (c, bb_sum.ctx[c])
                                        for c in bb_sum.ctx
                                        if bb_sum.ctx is not None)))
                        for line in bb:
                            tid = QtGui.QStandardItem('%s' % line.thread_id)
                            addr = QtGui.QStandardItem('%x' % line.addr)
                            disasm = QtGui.QStandardItem(line.disasm_str())
                            comment = QtGui.QStandardItem(''.join(
                                c for c in line.comment
                                if line.comment is not None))
                            context = QtGui.QStandardItem(''.join(
                                '%s:%s ' % (c, line.ctx[c]) for c in line.ctx
                                if line.ctx is not None))
                            bb_node.appendRow(
                                [tid, addr, disasm, comment, context])
                        cluster_node.appendRow(bb_node)
                        self.treeView.setFirstColumnSpanned(
                            bbs.index(bb), cluster_node.index(), True)

                        prev_ctx = bb[-1].ctx
                else:
                    for l in line:
                        tid = QtGui.QStandardItem('%s' % l.thread_id)
                        addr = QtGui.QStandardItem('%x' % l.addr)
                        disasm = QtGui.QStandardItem(l.disasm_str())
                        comment = QtGui.QStandardItem(''.join(
                            c for c in l.comment if l.comment is not None))
                        context = QtGui.QStandardItem(''.join(
                            '%s:%s ' % (c, l.ctx[c]) for c in l.ctx
                            if l.ctx is not None))
                        cluster_node.appendRow(
                            [tid, addr, disasm, comment, context])

        w.close()

        self.treeView.resizeColumnToContents(0)
        self.treeView.resizeColumnToContents(1)
        self.treeView.resizeColumnToContents(2)
        self.treeView.resizeColumnToContents(3)
        self.treeView.resizeColumnToContents(4)