Exemplo n.º 1
0
def trans_cb_addr_to_IDA(addr):
    try:
        cb = sark.CodeBlock(addr)
        if cb:
            return cb.startEA
        return idaapi.BADADDR
    except:
        return idaapi.BADADDR
Exemplo n.º 2
0
    def btn_mark_color(self):
        sender = self.parent.sender()
        cb = sark.CodeBlock()

        if sender is self.btn_mark_neutral:
            cb.color = col_t2ida(self.plugin.col_neutral)
        elif sender is self.btn_mark_visited:
            cb.color = col_t2ida(self.plugin.col_visited)
        elif sender is self.btn_mark_unreachable:
            cb.color = col_t2ida(self.plugin.col_unreachable)
Exemplo n.º 3
0
def coverage(pin_bb_log_file):
    base = idaapi.get_imagebase()
    covered_functions = set()
    for bb in bb_read_pin_logs(pin_bb_log_file):
        sark.CodeBlock(bb.start + base).color = 0xffff00
        sark_fn = sark.Function(bb.start + base)
        covered_functions.add(sark_fn.name)

    all_functions = set()
    for fn in sark.functions():
        all_functions.add(fn.name)

    print "function coverage summary! coverage {:.0f}%".format(
        float(len(covered_functions)) / float(len(all_functions)) * 100)
Exemplo n.º 4
0
def get_func_hash(ea):
    m = md5.new()
    ea = sark.Function(ea).start_ea
    blk = sark.CodeBlock(ea)
    went_over_blks = set()
    rem_blks = [blk]

    while len(rem_blks):
        blk = rem_blks[0]
        rem_blks = rem_blks[1:]
        m.update('s')
        m.update(struct.pack(">L", blk.start_ea))
        for n_blk in blk.next:
            m.update(struct.pack(">L", n_blk.start_ea))
            if n_blk.start_ea not in went_over_blks:
                rem_blks += [n_blk]
        went_over_blks.add(blk.start_ea)
    return m.digest()
Exemplo n.º 5
0
    def analyzeFunctionBlock(self, block_ea):
        """Return pairs indicating function calls (or fptr refs) from the lines in the basic block instance.

        Args:
            block_ea (int): basic block ea

        Return Value:
            (ordered) list of tuples: [<address of function ref (src), referenced address of the function (dest)>, ]
        """
        function_calls = []
        try:
            func_start = sark.Function(block_ea).start_ea
            block_lines = sark.CodeBlock(block_ea).lines
        except Exception:
            return function_calls
        # scan each of the lines
        for line in block_lines:
            instr_pos = line.ea
            call_candidates = set()
            # Data Refs (strings, fptrs)
            for ref in line.drefs_from:
                # Check for a string (finds un-analyzed strings too)
                str_const = self.disas.stringAt(ref)
                if str_const is not None and len(str_const) >= MIN_STR_SIZE:
                    continue
                # Check for an fptr
                try:
                    call_candidates.add(sark.Function(ref).start_ea)
                except sark.exceptions.SarkNoFunction:
                    continue
            # Check for a function call
            for cref in line.crefs_from:
                try:
                    if (cref == func_start and line.insn.is_call
                        ) or sark.Function(cref).start_ea != func_start:
                        call_candidates.add(sark.Function(cref).start_ea)
                except sark.exceptions.SarkNoFunction:
                    continue
            # handle each ref
            for ref in call_candidates:
                # record the call
                function_calls.append((instr_pos, sark.Function(ref).start_ea))
        # return the result
        return function_calls
Exemplo n.º 6
0
    def analyzeIslandFunction(self, blocks):
        """Analyze a given island function, and creates a canonical representation for it.

        Args:
            blocks (list): ordered list of code blocks (as returned from searchIslands())

        Return Value:
            IslandContext object representing the analyzed island
        """
        island_start = blocks[0].startEA
        func = sark.Function(island_start)
        func_start = func.startEA
        context = islandContext()(self.funcNameInner(func.name), island_start)
        for block in blocks:
            for line in sark.CodeBlock(block.startEA).lines:
                # Numeric Constants
                data_refs = list(line.drefs_from)
                for oper in filter(lambda x: x.type.is_imm,
                                   line.insn.operands):
                    if oper.imm not in data_refs:
                        context.recordConst(oper.imm)
                # Data Refs (strings, fptrs)
                for ref in data_refs:
                    # Check for a string (finds un-analyzed strings too)
                    str_const = self.disas.stringAt(ref)
                    if str_const is not None and len(
                            str_const) >= MIN_STR_SIZE:
                        context.recordString(str_const)
                        continue
                    # Check for an fptr
                    called_func = self.disas.funcAt(ref)
                    if called_func is not None:
                        context.recordCall(self.disas.funcStart(called_func))
                # Code Refs (calls)
                for cref in line.crefs_from:
                    called_func = self.disas.funcAt(cref)
                    if called_func is None:
                        continue
                    called_func_start = self.disas.funcStart(called_func)
                    if (cref == func_start and line.insn.is_call
                        ) or called_func_start != func_start:
                        context.recordCall(called_func_start)

        return context
Exemplo n.º 7
0
def CodeBlock(ea):
    cb = sark.CodeBlock(ea)
    #fix next and prev blocks - must be in func
    next = []
    prev = []
    for e_cb in cb.next:
        if sark.Function(e_cb.start_ea).start_ea == sark.Function(
                cb.start_ea).start_ea:
            next += [e_cb]
    for e_cb in cb.prev:
        if sark.Function(e_cb.start_ea).start_ea == sark.Function(
                cb.start_ea).start_ea:
            prev += [e_cb]

    class new_cb(object):
        pass

    ncb = new_cb()
    ncb.start_ea = cb.start_ea
    ncb.end_ea = cb.end_ea
    ncb.next = next
    ncb.prev = prev
    return ncb
Exemplo n.º 8
0
    def analyzeFunction(self, func_ea, src_mode):
        """Analyze a given function, and creates a canonical representation for it.

        Args:
            func_ea (int): effective address of the wanted function
            src_mode (bool): True iff analyzing a self-compiled source file, otherwise analyzing a binary function

        Return Value:
            FunctionContext object representing the analyzed function
        """
        func = sark.Function(func_ea)
        if src_mode:
            context = sourceContext()(self.funcNameInner(
                func.name), 0)  # Index is irrelevant for the source analysis
        else:
            context = binaryContext()(func_ea, self.funcNameInner(
                func.name), 0)  # The index will be adjusted later, manually

        func_start = func.start_ea
        instr_count = 0
        call_candidates = set()
        code_hash = md5()
        for line in func.lines:
            instr_count += 1
            # Numeric Constants
            data_refs = list(line.drefs_from)
            for oper in [x for x in line.insn.operands if x.type.is_imm]:
                if oper.imm not in data_refs:
                    context.recordConst(oper.imm)
            # Data Refs (strings, fptrs)
            for ref in data_refs:
                # Check for a string (finds un-analyzed strings too)
                str_const = self.disas.stringAt(ref)
                if str_const is not None and len(str_const) >= MIN_STR_SIZE:
                    context.recordString(str_const)
                    continue
                # Check for an fptr
                called_func = self.disas.funcAt(ref)
                if called_func is not None:
                    call_candidates.add(self.disas.funcStart(called_func))
                elif src_mode:
                    call_candidates.add(ref)
                    continue
            # Code Refs (calls and unknowns)
            for cref in line.crefs_from:
                called_func = self.disas.funcAt(cref)
                if called_func is None:
                    continue
                called_func_start = self.disas.funcStart(called_func)
                if (cref == func_start and
                        line.insn.is_call) or called_func_start != func_start:
                    call_candidates.add(called_func_start)
            # in binary mode don't let the call_candidates expand too much
            if not src_mode:
                [context.recordCall(x) for x in call_candidates]
                call_candidates = set()
            # hash the instruction (only in source mode)
            else:
                # two cases:
                # 1. No linker fixups, hash the binary - easy case
                # 2. Linker fixups, hash the text (includes the symbol name that the linker will use too)
                has_fixups = False
                # data variables
                for dref in line.drefs_from:
                    if sark.Line(dref).name in self.disas.exports():
                        has_fixups = True
                        break
                # external code functions
                if not has_fixups:
                    for cref in line.crefs_from:
                        if sark.Line(cref).name in self.disas.exports():
                            has_fixups = True
                            break
                # case #2
                if has_fixups:
                    code_hash.update(line.disasm.encode("utf-8"))
                # case #1
                else:
                    code_hash.update(line.bytes)

        # check all the call candidates together
        if src_mode:
            for candidate in call_candidates:
                ref_func = None
                called_func = self.disas.funcAt(candidate)
                if called_func is not None:
                    ref_func = self.disas.funcName(called_func)
                    risky = False
                else:
                    ref_func = self.disas.nameAt(candidate)
                    risky = True
                # check if known or unknown
                if sark.Line(candidate).disasm.split(" ")[0].lower() in (
                        "extrn", "extern", "import"):
                    context.recordUnknown(ref_func, is_fptr=risky)
                elif not risky:
                    context.recordCall(ref_func)
            # set the function's hash
            context.setHash(code_hash.hexdigest())

        context.setFrame(func.frame_size)
        context.setInstrCount(instr_count)

        # Now, record the code blocks
        flow = idaapi.FlowChart(func.func_t)
        for block in flow:
            try:
                context.recordBlock(
                    len(list(sark.CodeBlock(block.start_ea).lines)))
            except Exception:
                # happens with code outside of a function
                continue
        context.blocks.sort(reverse=True)

        # Now add the flow analysis
        context.setCallOrder(self.disas.analyzeFunctionGraph(
            func_ea, src_mode))

        return context
Exemplo n.º 9
0
 def fun(addr, color):
     cb = sark.CodeBlock(addr)
     if cb:
         cb.color = color
Exemplo n.º 10
0
 def fun():
     cb[0] = sark.CodeBlock()
Exemplo n.º 11
0
def _get_block_ranges(eas, reg):
    ranges = []
    blks = set()
    for ea in eas:
        blk_ea = sark.CodeBlock(ea).start_ea
        blks |= set([blk_ea])

    #for blk_ea in blks:
    for blk_ea in sorted(list(blks)):
        # four possible ranges:
        # 1. start till change
        # 2. change till end
        # 3. change till change - in case all references are in one block
        # 4. start till end
        # notice that 1,2 may both happen in a block
        possibility_one__found_ref = False
        possibility_one_two__found_change = False
        possibility_one__first_change_ea = None
        possibility_two__last_change_ea = None
        possibility_two__ref_after_last_change_ea = None
        possibility_three__first_ref_after_change_ea = None
        possibility_three__first_change_after_ref_ea = None
        possibility_four__no_change = True
        s_addr = None
        blk = sark.CodeBlock(blk_ea)
        for l in blk.lines:
            if (l.ea in eas):  #needs to be in range
                if possibility_one_two__found_change and (
                        possibility_two__ref_after_last_change_ea is None):
                    possibility_two__ref_after_last_change_ea = l.ea

                if (possibility_one_two__found_change) and (
                        possibility_three__first_change_after_ref_ea is None
                ) and (possibility_three__first_ref_after_change_ea is None):
                    possibility_three__first_ref_after_change_ea = l.ea

                possibility_one__found_ref = True

            #elif (l.ea not in eas) and (reg in oregami_gen.proc_ops.get_regs(l.ea)): #needs to be not in range
            elif (l.ea not in eas) and (oregami_gen.proc_ops.is_load(
                    l.ea, reg) or oregami_gen.proc_ops.is_store(
                        l.ea, reg)):  #needs to be not in range
                if (not possibility_one_two__found_change) and (
                        possibility_one__found_ref):
                    possibility_one__first_change_ea = l.ea

                if (possibility_three__first_ref_after_change_ea is not None
                    ) and (possibility_three__first_change_after_ref_ea is
                           None):
                    possibility_three__first_change_after_ref_ea = l.ea

                possibility_two__ref_after_last_change_ea = None
                possibility_one_two__found_change = True
                possibility_four__no_change = False

        # possibility 1 - found change after only references
        if possibility_one__first_change_ea is not None:
            ranges += [(blk.start_ea, possibility_one__first_change_ea)]
            debug('p1: %x:%x' % (ranges[-1][0], ranges[-1][1]))

        # possibility 2 - found only references after change
        if possibility_two__ref_after_last_change_ea is not None:
            ranges += [(possibility_two__ref_after_last_change_ea, blk.end_ea)]
            debug('p2: %x:%x' % (ranges[-1][0], ranges[-1][1]))

        # possibility 3 - found sequrence change->ref->change
        if (possibility_three__first_ref_after_change_ea
                is not None) and (possibility_three__first_change_after_ref_ea
                                  is not None):
            ranges += [(possibility_three__first_ref_after_change_ea,
                        possibility_three__first_change_after_ref_ea)]
            debug('p3: %x:%x' % (ranges[-1][0], ranges[-1][1]))

        # possibility 4 - no change happened
        if possibility_four__no_change:
            ranges += [(blk.start_ea, blk.end_ea)]
            debug('p4: %x:%x' % (ranges[-1][0], ranges[-1][1]))

    return ranges
Exemplo n.º 12
0
def _get_block_ranges(eas, reg):
    ranges = []
    blks = set()
    for ea in eas:
        blk_ea = sark.CodeBlock(ea).start_ea
        blks |= {blk_ea}

    # for blk_ea in blks:
    for blk_ea in sorted(list(blks)):
        # four possible ranges:
        # 1. start till change
        # 2. change till end
        # 3. change till change - in case all references are in one block
        # 4. start till end
        # notice that 1,2 may both happen in a block
        pos1__found_ref = False
        pos1_2__found_change = False
        pos1__first_change_ea = None
        pos2__ref_after_last_change_ea = None
        pos3__first_ref_after_change_ea = None
        pos3__first_change_after_ref_ea = None
        pos4__no_change = True
        blk = sark.CodeBlock(blk_ea)
        for line in blk.lines:
            opbits = RegInstruction(line.ea).get_reg_op_bits(
                reg, op_mask=UsageBits.OP_RW | UsageBits.USAGE_MASK)

            if line.ea in eas:  # needs to be in range
                if pos1_2__found_change and \
                        (pos2__ref_after_last_change_ea is None):
                    pos2__ref_after_last_change_ea = line.ea

                if pos1_2__found_change and \
                        (pos3__first_change_after_ref_ea is None) and \
                        (pos3__first_ref_after_change_ea is None):
                    pos3__first_ref_after_change_ea = line.ea

                pos1__found_ref = True

            # needs to be not in range
            elif ((line.ea not in eas)
                  and bool(opbits & UsageBits.USAGE_EXPLICIT)
                  and bool(opbits & UsageBits.OP_RW)):
                if (not pos1_2__found_change) and pos1__found_ref:
                    pos1__first_change_ea = line.ea

                if (pos3__first_ref_after_change_ea is not None) and \
                        (pos3__first_change_after_ref_ea is None):
                    pos3__first_change_after_ref_ea = line.ea

                pos2__ref_after_last_change_ea = None
                pos1_2__found_change = True
                pos4__no_change = False

        # possibility 1 - found change after only references
        if pos1__first_change_ea is not None:
            ranges += [(blk.start_ea, pos1__first_change_ea)]
            logger.debug('p1: %x:%x' % (ranges[-1][0], ranges[-1][1]))

        # possibility 2 - found only references after change
        if pos2__ref_after_last_change_ea is not None:
            ranges += [(pos2__ref_after_last_change_ea, blk.end_ea)]
            logger.debug('p2: %x:%x' % (ranges[-1][0], ranges[-1][1]))

        # possibility 3 - found sequrence change->ref->change
        if (pos3__first_ref_after_change_ea is not None) and \
                (pos3__first_change_after_ref_ea is not None):
            ranges += [(pos3__first_ref_after_change_ea,
                        pos3__first_change_after_ref_ea)]
            logger.debug('p3: %x:%x' % (ranges[-1][0], ranges[-1][1]))

        # possibility 4 - no change happened
        if pos4__no_change:
            ranges += [(blk.start_ea, blk.end_ea)]
            logger.debug('p4: %x:%x' % (ranges[-1][0], ranges[-1][1]))

    return ranges