Example #1
0
def _get_blocks_codes_per_func_iter():
    """
    Iterative function to generate all blocks and opcodes
    :return: N/A
    """
    all_blocks = {}
    all_codes = {}
    all_opcodes = []
    for func in idautils.Functions():
        # blocks_in_func contains
        #   <idaapi.BasicBlock object at 0x0545F3F0>, ...
        blocks_in_func = idaapi.FlowChart(idaapi.get_func(func))
        blocks = []
        for block in blocks_in_func:

            # IDA BUG! block.startEA == block.endEA??
            # Should be in the range "block.startEA <= block < block.endEA"
            if block.startEA != block.endEA:
                blocks.append((block.startEA, block.endEA))
            for head in idautils.Heads(block.startEA, block.endEA):
                ibytes = idc.GetManyBytes(head, idc.ItemEnd(head) - head)
                spd = idc.GetSpd(head)
                all_codes[head] = insn.Instruction(head, ibytes, spd)

                # IDA BUG! all_codes[head].bytes == 0??
                # The size of the code should be positive
                if all_codes[head].bytes != 0:
                    all_opcodes.append(
                        (all_codes[head].addr,
                         all_codes[head].addr + len(all_codes[head].bytes)))
        all_blocks[func] = blocks
    yield (all_blocks, all_opcodes)
Example #2
0
def get_operand_value_replacement(ea, pos, state):
    ''' A replacement for Ida's idc.GetOperandValue 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):
        idaapi.decode_insn(ea)
        offset = idaapi.cmd.Operands[pos].addr
        flipped = (offset ^
                   (0xffffffffffffffff if is_64_bit(ea) else 0xffffffff)) + 1
        # Use reg_fam[2] here as opposed to reg_fam[0] like usual because we need to mach the reg name string
        if any(reg_fam[2] in get_opnd_replacement(ea, pos)
               for reg_fam in state.stack_pointer_reg_fams):
            adjustment = idc.GetSpd(ea)
        else:
            adjustment = 0
        if not adjustment:
            adjustment = 0
        if flipped < offset:
            return -flipped + adjustment
        else:
            return offset + adjustment
    else:
        return idc.GetOperandValue(ea, pos)
Example #3
0
def get_code_and_blocks(ea):
    """Extracts the control flow graph for the function at the given address.
  Returns a dictionary with the instructions (ea->insn.Instruction) and a list
  of the basic blocs (bbl.BasicBlock)."""

    code = {}
    blocks = {}
    ida_blocks = set(idaapi.FlowChart(idaapi.get_func(ea)))

    for bb in ida_blocks:

        # XXX: it seems that it's not a bug but inter-function jumps!
        if bb.startEA == bb.endEA:  # skip that .. it's IDA's bug
            #print "skipping block %x : %x in func %x"%(bb.startEA, bb.endEA, ea)
            continue

        blocks[bb.startEA] = bbl.BasicBlock(bb.startEA, bb.endEA, {})

        for head in idautils.Heads(bb.startEA, bb.endEA):
            ibytes = idc.GetManyBytes(head, idc.ItemEnd(head) - head)
            spd = idc.GetSpd(head)
            code[head] = insn.Instruction(head, ibytes, spd)
            blocks[bb.startEA].instrs.append(code[head])
            next_head = idc.NextHead(head, bb.endEA)

            if idaapi.isFlow(idc.GetFlags(next_head)):
                code[head].succ.add(next_head)

        for suc_bb in (s for s in bb.succs() if s.startEA != s.endEA):
            #assume head is the last instruction of the block
            code[head].succ.add(suc_bb.startEA)

    for bb in (b for b in ida_blocks if b.startEA != b.endEA):
        for suc_bb in (s for s in bb.succs() if s.startEA != s.endEA):
            # a jump with zero offset (like, jz 0) gives two succs to the same bb
            if blocks[suc_bb.startEA] not in blocks[bb.startEA].successors:
                blocks[bb.startEA].successors.append(blocks[suc_bb.startEA])
        blocks[bb.startEA].successors.sort(key=lambda x: x.begin, reverse=True)

    #FIXME: find a better way ..
    for block in blocks.itervalues():
        if block.instrs[0].addr == ea:
            #print "found the entry!:", block.instrs
            block.instrs[0].f_entry = True
            block.type |= bbl.BasicBlock.ENTRY
            break
    else:
        print "BUG: could not find function entry in instrs!!"
    #print "blocks:", blocks

    return code, blocks.values()
Example #4
0
    def elements(self):
        value = self.cbReg.value
        if value in self.stk_args:
            line = self.ira.blocks[self.label].irs[self.line_nb].instr
            arg_num = self.stk_args[value]
            stk_high = m2_expr.ExprInt(idc.GetSpd(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(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])
 def handle_call(self, state):
     '''Updates the state of the stack string finding based on a call instruction'''
     stack_pointer = idc.GetSpd(state.ea)
     next_ea = state.ea + idc.ItemSize(state.ea)
     stack_pointer_delta = idc.GetSpDiff(next_ea)
     if stack_pointer is not None and stack_pointer_delta is not None:
         next_reg = tracingutils.get_reg_fam(idc.GetOpnd(
             next_ea, POS_FIRST))
         # Caller cleanup handling, vulnerable to instruction reordering though.
         if next_reg and 'esp' in next_reg and "add" in idc.GetMnem(
                 next_ea).lower():
             stack_pointer_delta += idc.GetSpDiff(next_ea +
                                                  idc.ItemSize(next_ea))
         for index in xrange(stack_pointer,
                             stack_pointer + stack_pointer_delta):
             if index in state.stack:
                 del state.stack[index]
Example #6
0
        def db_read(cls, address, key=None, repeatable=0):
            result = comment.toDict( idc.GetCommentEx(address, repeatable) )

            name = idc.NameEx(address, address)
            if name:
                result['__name__'] = name

            # defaults
            if '__color__' not in result:
                c = cls.color(address)
                if c is not None:
                    result['__color__'] = c
            if '__address__' not in result:
                result['__address__'] = address

            if '__context__' not in result:
                result['__context__'] = idc.GetFunctionAttr(address, idc.FUNCATTR_START)
            if '__sp__' not in result:
                result['__sp__'] = idc.GetSpd(address)

            if key is not None:
                return result[key]
            return result
Example #7
0
def launch_depgraph():
    global graphs, comments, sol_nb, settings, addr, ir_arch
    # Init
    machine = guess_machine()
    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.symbol_pool)

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

    # Get the current function
    addr = idc.ScreenEA()
    func = ida_funcs.get_func(addr)
    blocks = mdis.dis_multiblock(func.startEA)

    # Generate IR
    for block in blocks:
        ir_arch.add_block(block)

    # Get settings
    settings = depGraphSettingsForm(ir_arch)
    settings.Execute()

    label, elements, line_nb = settings.label, settings.elements, settings.line_nb
    # Simplify affectations
    for irb in ir_arch.blocks.values():
        irs = []
        fix_stack = irb.label.offset is not None and settings.unalias_stack
        for assignblk in irb.irs:
            if fix_stack:
                stk_high = m2_expr.ExprInt(idc.GetSpd(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 assignblk.iteritems():
                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))
        ir_arch.blocks[irb.label] = IRBlock(irb.label, irs)

    # Get dependency graphs
    dg = settings.depgraph
    graphs = dg.get(label, elements, line_nb,
                    set([ir_arch.symbol_pool.getby_offset(func.startEA)]))

    # Display the result
    comments = {}
    sol_nb = 0

    # Register and launch
    ida_kernwin.add_hotkey("Shift-N", next_element)
    treat_element()
Example #8
0
def getSpDelta(ea):
    '''Gets the stack delta at the specified address'''
    return idc.GetSpd(ea)
 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 = tracingutils.BranchingTraceState(func.startEA)
         state.strs = set()
         states = [state]
         func_eas = []
         ea = state.ea
         while ea < func.endEA:
             func_eas.append(ea)
             ea += idc.ItemSize(ea)
         while states:
             state = states.pop()
             while state.ea < func.endEA:
                 try:
                     func_eas.remove(state.ea)
                 except:
                     pass
                 state.visited_eas.append(state.ea)
                 mnemonic = idc.GetMnem(state.ea)
                 if mnemonic in IGNORED_MNEMONICS:
                     pass
                 elif 'pop' in mnemonic:
                     reg = tracingutils.get_reg_fam(
                         tracingutils.get_opnd_replacement(
                             state.ea, POS_FIRST))
                     if reg:
                         value = state.stack.get(idc.GetSpd(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:
                     pass  #bug where idc.GetSpd 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.GetSpd(ea), ea, POS_FIRST, regs, stack)
                 elif 'mov' in mnemonic:
                     self.handle_mov(state)
                 elif ('xor' in mnemonic and tracingutils.get_reg_fam(tracingutils.get_opnd_replacement(state.ea, POS_FIRST)) ==
                       tracingutils.get_reg_fam(tracingutils.get_opnd_replacement(state.ea, POS_SECOND))) or \
                      ('lea' in mnemonic and idc.GetOpnd(state.ea, POS_SECOND) == '[0]') or \
                      ('sub' in mnemonic and tracingutils.get_opnd_replacement(state.ea, POS_FIRST) ==
                       tracingutils.get_opnd_replacement(state.ea, POS_SECOND)):
                     reg = tracingutils.get_reg_fam(
                         tracingutils.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 = idautils.CodeRefsFrom(state.ea, 0).next()
                     except StopIteration:
                         target = None
                     if target and target not in state.visited_eas:
                         if func.endEA > target >= func.startEA:
                             state.visited_eas.append(target)
                             new_state = tracingutils.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)
                     #reg = tracingutils.get_reg_fam(tracingutils.get_opnd_replacement(state.ea, POS_FIRST))
                 elif 'lea' in mnemonic:
                     self.handle_lea(state)
                 elif 'call' in mnemonic:
                     self.handle_call(state)
                 elif 'ret' in mnemonic:
                     break
                 elif idc.GetOpType(
                         state.ea, POS_FIRST
                 ) == idc.o_reg:  # If we find a target register we were tracking, stop tracking it.
                     self.clear_reg_if_needed(
                         tracingutils.get_reg_fam(
                             tracingutils.get_opnd_replacement(
                                 state.ea, POS_FIRST)), state.regs)
                 state.ea += idc.ItemSize(state.ea)
             self.report_strings(state.strs, state.stack)
             if not states and func_eas:
                 new_state = tracingutils.BranchingTraceState(func_eas[0])
                 new_state.strs = set()
                 states.append(new_state)
             stack_strings.extend(state.strs)
     self.strings.update(stack_strings)
Example #10
0
def launch_depgraph():
    global graphs, comments, sol_nb, settings, addr, ir_arch, ircfg
    # Get the current function
    addr = idc.ScreenEA()
    func = ida_funcs.get_func(addr)

    # Init
    machine = guess_machine(addr=func.startEA)
    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.startEA)

    # 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.GetSpd(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.startEA)]))

    # Display the result
    comments = {}
    sol_nb = 0

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