Example #1
0
 def call_effects(self, addr, instr):
     assignblks, extra = super(IRADelModCallStack,
                               self).call_effects(addr, instr)
     if use_ida_stack:
         stk_before = idc.get_spd(instr.offset)
         stk_after = idc.get_spd(instr.offset + instr.l)
         stk_diff = stk_after - stk_before
         print(hex(stk_diff))
         call_assignblk = AssignBlock([
             ExprAssign(self.ret_reg, ExprOp('call_func_ret', addr)),
             ExprAssign(self.sp,
                        self.sp + ExprInt(stk_diff, self.sp.size))
         ], instr)
         return [call_assignblk], []
     else:
         if not dontmodstack:
             return assignblks, extra
         out = []
         for assignblk in assignblks:
             dct = dict(assignblk)
             dct = {
                 dst: src
                 for (dst, src) in viewitems(dct) if dst != self.sp
             }
             out.append(AssignBlock(dct, assignblk.instr))
     return out, extra
Example #2
0
 def call_effects(self, ad, instr):
     print(hex(instr.offset), instr)
     stk_before = idc.get_spd(instr.offset)
     stk_after = idc.get_spd(instr.offset + instr.l)
     stk_diff = stk_after - stk_before
     print(hex(stk_diff))
     call_assignblk = AssignBlock([
         ExprAssign(self.ret_reg, ExprOp('call_func_ret', ad)),
         ExprAssign(self.sp, self.sp + ExprInt(stk_diff, self.sp.size))
     ], instr)
     return [call_assignblk], []
Example #3
0
def get_operand_value_replacement(ea, pos, state):
    """ A replacement for Ida's idc.get_operand_value that handles displacements more reasonably

        :param ea: memory location
        :param pos: argument location
                    example:
                        add eax, ebx
                        eax is position 0, ebx is position 1
        :param state: the current stack pointer register family (usually sp)

        :return: computes a numerical replacement for an operand
    """
    if is_displ(ea, pos):
        bit_size = 64 if is_64_bit() else 32
        stack_reg = 'rsp' if bit_size == 64 else 'esp'
        cmd = idaapi.insn_t()
        idaapi.decode_insn(cmd, ea)
        offset = cmd.ops[pos].addr
        # Convert the offset to a signed value
        if offset & (1 << (bit_size - 1)):
            offset -= (1 << bit_size)
        if stack_reg in get_opnd_replacement(ea, pos):
            offset += idc.get_spd(ea) or 0
        return offset
    else:
        return idc.get_operand_value(ea, pos)
Example #4
0
 def handle_call(self, state):
     """Updates the state of the stack string finding based on a call instruction"""
     stack_pointer = idc.get_spd(state.ea)
     next_ea = state.ea + idc.get_item_size(state.ea)
     stack_pointer_delta = idc.get_sp_delta(next_ea)
     if stack_pointer is not None and stack_pointer_delta is not None:
         next_reg = tracing.get_reg_fam(idc.print_operand(next_ea, POS_FIRST))
         # Caller cleanup handling, vulnerable to instruction reordering though.
         if next_reg and "esp" in next_reg and "add" in idc.print_insn_mnem(next_ea).lower():
             stack_pointer_delta += idc.get_sp_delta(next_ea + idc.get_item_size(next_ea))
         for index in range(stack_pointer, stack_pointer + stack_pointer_delta):
             if index in state.stack:
                 del state.stack[index]
Example #5
0
    def elements(self):
        value = self.cbReg.value
        if value in self.stk_args:
            line = self.ircfg.blocks[self.loc_key][self.line_nb].instr
            arg_num = self.stk_args[value]
            stk_high = m2_expr.ExprInt(idc.get_spd(line.offset), ir_arch.sp.size)
            stk_off = m2_expr.ExprInt(self.ira.sp.size // 8 * arg_num, ir_arch.sp.size)
            element =  m2_expr.ExprMem(self.mn.regs.regs_init[ir_arch.sp] + stk_high + stk_off, self.ira.sp.size)
            element = expr_simp(element)
            # Force stack unaliasing
            self.stk_unalias_force = True
        elif value:
            element = self.ira.arch.regs.all_regs_ids_byname.get(value, None)

        else:
            raise ValueError("Unknown element '%s'!" % value)
        return set([element])
Example #6
0
    def get_stack_strings(self, functions):
        """
        Finds all the stack strings it can in the given functions.

        Parameters set globally:
            STRING_GAP_TOLERANCE - the gap allowed between string characters.
            MAX_CHARACTER_WIDTH  - the maximum character size, in bytes
            ASCII                - Whether character values must be 0-127
        """
        stack_strings = []
        for func in functions:
            state = tracing.BranchingTraceState(func.start_ea)
            state.strs = set()
            states = [state]
            func_eas = []
            ea = state.ea
            while ea < func.end_ea:
                func_eas.append(ea)
                ea += idc.get_item_size(ea)
            while states:
                state = states.pop()
                while state.ea < func.end_ea:
                    try:
                        func_eas.remove(state.ea)
                    except:
                        pass
                    state.visited_eas.append(state.ea)
                    mnemonic = idc.print_insn_mnem(state.ea)
                    if mnemonic in IGNORED_MNEMONICS:
                        pass
                    elif "pop" in mnemonic:
                        reg = tracing.get_reg_fam(tracing.get_opnd_replacement(state.ea, POS_FIRST))
                        if reg:
                            value = state.stack.get(idc.get_spd(state.ea), None)
                            if value is not None:
                                state.regs[reg[0]] = value
                            else:
                                self.clear_reg_if_needed(reg, state.regs)
                    elif "push" in mnemonic:
                        # bug where idc.get_spd was not correctly tracking the pointer,
                        # this case also hasn't really been seen often as part of a stack string
                        # self.set_stack(idc.get_spd(ea), ea, POS_FIRST, regs, stack)
                        pass
                    elif "mov" in mnemonic:
                        self.handle_mov(state)
                    elif (
                        (
                            "xor" in mnemonic
                            and tracing.get_reg_fam(tracing.get_opnd_replacement(state.ea, POS_FIRST))
                            == tracing.get_reg_fam(tracing.get_opnd_replacement(state.ea, POS_SECOND))
                        )
                        or ("lea" in mnemonic and idc.print_operand(state.ea, POS_SECOND) == "[0]")
                        or (
                            "sub" in mnemonic
                            and tracing.get_opnd_replacement(state.ea, POS_FIRST)
                            == tracing.get_opnd_replacement(state.ea, POS_SECOND)
                        )
                    ):
                        reg = tracing.get_reg_fam(tracing.get_opnd_replacement(state.ea, POS_FIRST))
                        if reg:
                            state.regs[reg[0]] = (0, state.ea)
                    elif "loop" in mnemonic or "movsb" in mnemonic:
                        state.regs["rcx"] = (0, state.ea)
                    elif mnemonic in JUMPS:
                        try:
                            target = next(idautils.CodeRefsFrom(state.ea, 0))
                        except StopIteration:
                            target = None
                        if target and target not in state.visited_eas:
                            if func.end_ea > target >= func.start_ea:
                                state.visited_eas.append(target)
                                new_state = tracing.BranchingTraceState(target, state)
                                new_state.strs = state.strs
                                states.append(new_state)
                            else:
                                self.report_strings(state.strs, state.stack)
                        # Always follow an unconditional jump
                        if mnemonic == "jmp":
                            break
                    elif (
                        "rep" in idc.GetDisasm(state.ea).split(" ")[0]
                        and "scas" not in idc.GetDisasm(state.ea).split(" ")[1]
                    ):
                        self.report_strings(state.strs, state.stack)
                    elif "lea" in mnemonic:
                        self.handle_lea(state)
                    elif "call" in mnemonic:
                        self.handle_call(state)
                    elif "ret" in mnemonic:
                        break
                    elif (
                        idc.get_operand_type(state.ea, POS_FIRST) == idc.o_reg
                    ):  # If we find a target register we were tracking, stop tracking it.
                        self.clear_reg_if_needed(
                            tracing.get_reg_fam(tracing.get_opnd_replacement(state.ea, POS_FIRST)), state.regs
                        )
                    state.ea += idc.get_item_size(state.ea)
                self.report_strings(state.strs, state.stack)
                if not states and func_eas:
                    new_state = tracing.BranchingTraceState(func_eas[0])
                    new_state.strs = set()
                    states.append(new_state)
                stack_strings.extend(state.strs)
        self.strings.update(stack_strings)
Example #7
0
def launch_depgraph():
    global graphs, comments, sol_nb, settings, addr, ir_arch, ircfg
    # Get the current function
    addr = idc.get_screen_ea()
    func = ida_funcs.get_func(addr)

    # Init
    machine = guess_machine(addr=func.start_ea)
    mn, dis_engine, ira = machine.mn, machine.dis_engine, machine.ira

    bs = bin_stream_ida()
    mdis = dis_engine(bs, dont_dis_nulstart_bloc=True)
    ir_arch = ira(mdis.loc_db)

    # Populate symbols with ida names
    for ad, name in idautils.Names():
        if name is None:
            continue
        mdis.loc_db.add_location(name, ad)

    asmcfg = mdis.dis_multiblock(func.start_ea)

    # Generate IR
    ircfg = ir_arch.new_ircfg_from_asmcfg(asmcfg)

    # Get settings
    settings = depGraphSettingsForm(ir_arch, ircfg, mn)
    settings.Execute()

    loc_key, elements, line_nb = settings.loc_key, settings.elements, settings.line_nb
    # Simplify assignments
    for irb in list(viewvalues(ircfg.blocks)):
        irs = []
        offset = ir_arch.loc_db.get_location_offset(irb.loc_key)
        fix_stack = offset is not None and settings.unalias_stack
        for assignblk in irb:
            if fix_stack:
                stk_high = m2_expr.ExprInt(idc.get_spd(assignblk.instr.offset), ir_arch.sp.size)
                fix_dct = {ir_arch.sp: mn.regs.regs_init[ir_arch.sp] + stk_high}

            new_assignblk = {}
            for dst, src in viewitems(assignblk):
                if fix_stack:
                    src = src.replace_expr(fix_dct)
                    if dst != ir_arch.sp:
                        dst = dst.replace_expr(fix_dct)
                dst, src = expr_simp(dst), expr_simp(src)
                new_assignblk[dst] = src
            irs.append(AssignBlock(new_assignblk, instr=assignblk.instr))
        ircfg.blocks[irb.loc_key] = IRBlock(irb.loc_key, irs)

    # Get dependency graphs
    dg = settings.depgraph
    graphs = dg.get(loc_key, elements, line_nb,
                    set([ir_arch.loc_db.get_offset_location(func.start_ea)]))

    # Display the result
    comments = {}
    sol_nb = 0

    # Register and launch
    ida_kernwin.add_hotkey("Shift-N", next_element)
    treat_element()