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)
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)
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()
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]
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
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()
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)
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()