def process_bb(self, start, end, size, call_targets, successors, fname): if size == 0: global to_disassemble self._to_disassemble += [start] return h = idautils.Heads(start, end + 1) # basic block: [start;end;(instructions);(successors);(caller-callee-return)] print '[' + ";".join([ hex_wo_L(start), '(' + ','.join(hex_wo_L(i) for i in h) + ')', '(' + ','.join(hex_wo_L(s) for s in successors) + ')', '(' + ','.join( hex_wo_L(c[0]) + "-" + hex_wo_L(c[1]) + "-" + hex_wo_L(c[2]) for c in call_targets) + ')' ]) + ']' # instruction: (addr;mnemonic;opcode;bb_addr;fname) for i in idautils.Heads(start, end + 1): opcodes = [] for op in GetManyBytes(i, ItemSize(i)): if len(str(hex(ord(op)))) % 2 != 0: opcodes.append('0' + '%X' % ord(op)) else: opcodes.append('%X' % ord(op)) print '(' + ";".join([ hex_wo_L(i), GetDisasm(i).split(';', 1)[0].rstrip(), ' '.join(opcodes), hex_wo_L(start), fname ]) + ')' print ""
def bfs_iter_heads(self, startEA=None, reverse=False): """ Iterate over instructions in idaapi.BasicBlocks in breadth-first manner. >>> ea = 0x1001234 # some EA within a function >>> fc = FlowChart(ea) >>> for head_ea in fc.bfs_iter_heads(): >>> print ">>> 0x{:x}: {}".format(head_ea, idc.GetDisasmEx(head_ea, 0)) :param int startEA: optional address to start iterating from. :param bool reverse: iterate in reverse """ _first_block = True for cur_block in self.bfs_iter_blocks(startEA, reverse): if reverse: if startEA and _first_block: ea = startEA else: ea = cur_block.endEA heads = reversed(list(idautils.Heads(cur_block.startEA, ea))) else: if startEA and _first_block: ea = startEA else: ea = cur_block.startEA heads = idautils.Heads(ea, cur_block.endEA) _first_block = False for head in heads: yield head
def readFunction(self, f, discard=True): name = idc.GetFunctionName(f) func = idaapi.get_func(f) flow = idaapi.FlowChart(func) size = func.endEA - func.startEA if discard: # Unnamed function, ignore it... if name.startswith("sub_") or name.startswith( "j_") or name.startswith("unknown"): return False # Already recognized runtime's function flags = idc.GetFunctionFlags(f) if flags & idc.FUNC_LIB or flags == -1: return False nodes = 0 edges = 0 points = 0 instructions = 0 mnems = [] dones = {} for block in flow: nodes += 1 indegree = 0 outdegree = 0 for succ_block in block.succs(): edges += 1 indegree += 1 if not dones.has_key(succ_block.id): dones[succ_block] = 1 for x in list( idautils.Heads(succ_block.startEA, succ_block.endEA)): instructions += 1 mnems.append(idc.GetMnem(x)) for pred_block in block.preds(): edges += 1 outdegree += 1 if not dones.has_key(succ_block.id): dones[succ_block] = 1 for x in list( idautils.Heads(succ_block.startEA, succ_block.endEA)): instructions += 1 mnems.append(idc.GetMnem(x)) if indegree > 0: points += indegree if outdegree > 0: points += outdegree if nodes > 1 and instructions > 5 and edges > 1: #myexport_print("Exporter: Current function 0x%08x %s" % (f, name)) return (name, nodes, edges, points, size, instructions, mnems) return False
def GetInstructions(start_ea, end_ea): ins = [] for head in idautils.Heads(start_ea, end_ea): if idaapi.isCode(idaapi.getFlags(head)): ins.append(Instruction(head, GetDisasm(head))) return ins
def find_lua_function_array(start, end): for head in idautils.Heads(start, end): disasm = idc.generate_disasm_line(head, 2) if disasm.startswith('lea '): result = idc.get_operand_value(head, 1) return result raise RuntimeError('Unable to find Lua function array near 0x%08x' % start)
def OnCommand(self, cmd_id): """ Triggered when a menu command is selected through the menu or its hotkey @return: None """ #print "command:", cmd_id if self.cmd_close == cmd_id: self.Close() return elif self.cmd_color == cmd_id: func_item = idaapi.get_func(idc.ScreenEA()) # get the default color idc.Jump(func_item.startEA) idautils.ProcessUiActions("GraphDefaultColor", 0) defaultcolor = idc.GetColor(func_item.startEA, idc.CIC_ITEM) # reset colors to default idc.SetColor(func_item.startEA, idc.CIC_FUNC, defaultcolor) # RGB for block in self.blocks: start, end = self.getBounds(block) # color all basic blocks for head in idautils.Heads(start, end): idc.SetColor(head, idc.CIC_ITEM, self.options['bb_path_color']) #branch_insn = idc.NextHead(end, func_item.endEA) #print "branch instruction is at 0x%08x" % branch_insn #idc.SetColor(branch_insn, idc.CIC_ITEM, self.options['bb_path_color']) idaapi.refresh_idaview_anyway()
def recoverFunctionFromSet(M, F, blockset, new_eas): processed_blocks = set() while len(blockset) > 0: block = blockset.pop() if block.startEA == block.endEA: sys.stdout.write("Zero sized block: {0:x}\n".format(block.startEA)) if block.startEA in processed_blocks: raise Exception("Attempting to add same block twice: {0:x}".format(block.startEA)) processed_blocks.add(block.startEA) B = basicBlockHandler(F, block, blockset, processed_blocks) prevHead = block.startEA DEBUG("Starting insn at: {0:x}\n".format(prevHead)) for head in idautils.Heads(block.startEA, block.endEA): # we ended the function on a call I, endBlock = instructionHandler(M, B, head, new_eas) # sometimes there is junk after a terminator due to off-by-ones in # IDAPython. Ignore them. if endBlock or isRet(head) or isUnconditionalJump(head) or isTrap(head): break prevHead = head DEBUG("Ending insn at: {0:x}\n".format(prevHead))
def iter_heads(cls, start=None, end=None): """ Class method allowing to iter on all the element **defined** in the IDB. This means elements which are not defined (considered to not *heads*) will not be returned by this function. .. note:: Internally this function iterate on all the ``Heads`` and create the object if the class which is used for it match the element. For example calling ``BipData.iter_heads()`` will return only the heads which are :class:`BipData` object or their children. .. note:: This function will work only on mapped object, it is not possible to use it for getting :class:`BipStruct` for example. :param start: The address at which to start iterating. If this parameter is None (the default) the minimum mapped address will be used. :param end: The address at which to stop iterating. If this parameter is None (the default) the maximum mapped address will be used. :return: A generator of object child of :class:`BipBaseElt` allowing to iter on all the elt define in the idb. """ if start is None: start = BipIdb.min_ea() if end is None: end = BipIdb.max_ea() for h in idautils.Heads(start, end): if cls._is_this_elt(h): yield GetElt(h)
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 find_guid_in_address_space(start_address, end_address): """ This function will try to parse memonique with an operand value as second parameter, then will try to validate it with registry :ivar int start_address: """ result = [] for head in idautils.Heads(start_address, end_address): # search for direct value operand for operand_value in [ idc.get_operand_value(head, 1), idc.get_operand_value(head, 0) ]: guid_bytes = idc.get_bytes(operand_value, 16) guid = guid_bytes_to_string(guid_bytes) try: result.append(build_com_from_class_definition(head, guid)) break except WindowsError as e: pass try: result.append(build_com_from_interface_definition(head, guid)) break except WindowsError as e: pass return result
def getBlockSig(block): hstring = '' for head in idautils.Heads(block.startEA, block.endEA): instruct = idc.GetDisasm(head) #print('head is %s instr: %s' % (str(head), str(instruct))) if instruct.startswith('call'): instruct = 'call' elif instruct.startswith('j'): instruct = idc.GetMnem(head) elif 'ds:' in instruct: instruct = instruct[:instruct.find(',')] elif instruct.startswith('lea') and instruct != 'leave': parts = instruct.split(',') try: if not parts[1].strip().startswith('['): instruct = parts[0] except: print('trouble with %x %s' % (head, instruct)) sys.exit(1) elif ';' in instruct: instruct = instruct.split(';')[0].strip() #print instruct hstring += '%s' % str(instruct).strip() a_hash = hash(hstring) h_string = '%x' % a_hash return h_string
def downloadFuncs(): funcs = list() func = FunctionInfo() i = 0 j = 0 k = 0 line = "" startEA, endEA = 0, 0 for segEA in idautils.Segments(): print "[%d] Segment EA : %016x" % (i, segEA) i += 1 j = 0 for fnEA in idautils.Functions(segEA, SegEnd(segEA)): print "[%d] Function EA : %016x" % (j, fnEA) j += 1 fnName = idc.GetFunctionName(fnEA) func = FunctionInfo() func.m_startAddr = fnEA func.m_funcName = fnName k = 0 for (startEA, endEA) in idautils.Chunks(fnEA): print "[%d] Chunks" % (k) k += 1 for head in idautils.Heads(startEA, endEA): # s = "%s : %x : %s" % (fnName, head, GetDisasm(head)) # print s line = "%016x|%s" % (head, GetDisasm(head)) func.m_ins.append(line) func.m_endAddr = endEA funcs.append(func) return funcs
def cpu_context(self, ea=None, init_context=None): """ Returns the cpu context filled to (but not including) the specified ea. :param int ea: address of interest (defaults to the last ea of the block) :param init_context: Initial context to use for the start of the path. (defaults to an new empty context) :return cpu_context.ProcessorContext: cpu context """ if ea is not None and not (self.bb.start_ea <= ea < self.bb.end_ea): raise KeyError("Provided address 0x{:X} not in this block " "(0x{:X} :: 0x{:X})".format(ea, self.bb.start_ea, self.bb.end_ea)) # Determine address to stop computing. if ea is None: end = self.bb.end_ea # end_ea of a BasicBlock is the first address after the last instruction. else: end = ea # Determine if we need to force the creation of a new context if we have a different init_context. new_init_context = self._init_context != init_context self._init_context = init_context assert end is not None # Fill context up to requested endpoint. if self._context_ea != end or new_init_context: # Create context if: # - not created # - current context goes past requested ea # - given init_context is different from the previously given init_context. if not self._context or self._context_ea > end or new_init_context: # Need to check if there is a prev, if not, then we need to create a default context here... if self.prev: self._context = self.prev.cpu_context( init_context=init_context) # Modify the context for the current branch if required self._context.prep_for_branch(self.bb.start_ea) elif init_context: self._context = deepcopy(init_context) else: self._context = ProcessorContext.from_arch() self._context_ea = self.bb.start_ea if self._context_ea != end: # Fill context up to requested ea. logger.debug( "Emulating instructions 0x{:08X} -> 0x{:08X}".format( self._context_ea, end)) for ip in idautils.Heads(self._context_ea, end): self._context.execute(ip) self._context_ea = end # Set the next instruction pointer to be the end instruction that we did NOT execute. self._context.ip = end return deepcopy(self._context)
def get_branch_table_instrs(): """ Return all jsr or jmp instructions with pc in the operand :return: List of PC-relative jmp and jsr dispatch instructions """ instrs = [] # Iterate instructions in functions for funcea in idautils.Functions(): for (startea, endea) in idautils.Chunks(funcea): for head in idautils.Heads(startea, endea): instr = idc.GetDisasm(head).split() if instr[0] == 'jsr' or instr[0] == 'jmp': if 'pc' in instr[1]: instrs.append(instr) # Iterate instructions not in a function addr = idaapi.find_not_func(0, 1) while addr != idc.BADADDR: instr = idc.GetDisasm(addr).split() if instr[0] == 'jsr' or instr[0] == 'jmp': if 'pc' in instr[1]: instrs.append(instr) addr = idaapi.find_not_func(addr, 1) return instrs
def HandleFunc(func): global g_off_set_random global g_size_ins_block #for ins in idautils.FuncItems(start): # print(idc.GetDisasm(ins)) ea = func end = idc.GetFunctionAttr(func, idc.FUNCATTR_END) for ea in idautils.Heads(func, end): if IsInstrumentIns(ea): #print(idc.GetFunctionName(start)) #print(hex(ea), idc.GetDisasm(ea)) #idc.SetColor(ea+0x13, CIC_ITEM, 0x0000FF) #bbls = GetFunBbls(func) bbl_heads = () #for bbl in bbls: #bbl_heads.append(bbl[0]) write_head = [0] call_stack = [] #FindChildNode(func, ea+g_off_set_random, ea+g_size_ins_block, call_stack, 0) FindChildNode2(func, bbl_heads, ea + g_off_set_random, ea + g_size_ins_block, call_stack, 0, write_head) #ea += g_size_ins_block pass
def heads(self): """List of every head of the element. Elements can be code or data. """ return [ cast.data_or_code_cast(IDAElt(addr)) for addr in idautils.Heads(self.addr, self.endADDR) ]
def recoverFunctionFromSet(M, F, blockset, new_eas, need_trampolines): processed_blocks = set() while len(blockset) > 0: block = blockset.pop() if block.startEA == block.endEA: sys.stdout.write("Zero sized block: {0:x}\n".format(block.startEA)) if block.startEA in processed_blocks: raise Exception("Attempting to add same block twice: {0:x}".format(block.startEA)) processed_blocks.add(block.startEA) B = basicBlockHandler(F, block, blockset, processed_blocks, need_trampolines) for head in idautils.Heads(block.startEA, block.endEA): I, endBlock = instructionHandler(M, F, B, head, new_eas) # sometimes there is junk after a terminator due to off-by-ones in # IDAPython. Ignore them. if endBlock or isRet(head) or isUnconditionalJump(head) or isTrap(head): break if block.startEA not in RECOVERED_EAS: RECOVERED_EAS.add(block.startEA) DEBUG("RECOVERED_EAS.add({0:x})\n".format(block.startEA))
def _split_basic_block(start_ea, end_ea): """ IDA Pro's ``idaapi.Flowchart`` does not consider function calls as basic block boundaries. This function takes an address range and splits the basic blocks found within that range so that function calls are considered basic block boundaries. """ split_bbs = [] func_name = idc.GetFunctionName(start_ea) demangled_name = idc.Demangle(func_name, idc.GetLongPrm(idc.INF_SHORT_DN)) if demangled_name: func_name = demangled_name bb_start_addr = start_ea block = idautils.Heads(start_ea, end_ea) for inst in block: mnem = idc.GetMnem(inst) if mnem == 'call' and inst != end_ea: split_bbs.append( dict(start_addr=bb_start_addr, end_addr=idc.NextHead(inst, end_ea + 1) - 1, function=func_name)) bb_start_addr = idc.NextHead(inst, end_ea + 1) if bb_start_addr < end_ea: split_bbs.append( dict(start_addr=bb_start_addr, end_addr=end_ea - 1, function=func_name)) return split_bbs
def create_pe(): text_start = text_end = 0 for seg in Segments(): if idc.SegName(seg)==".text": text_start=idc.SegStart(seg) text_end=idc.SegEnd(seg) for func in idautils.Functions(): start_address = func end_address = idc.FindFuncEnd(func) #print hex(start_address) for each_step in idautils.Heads(start_address, end_address): #print hex(each_step) op = idc.GetDisasm(each_step) if each_step >= text_start and each_step <text_end: instrument(op,each_step) section_data = '' offsets = [] for index in range(len(ori_op)): offsets.append(len(section_data)) section_data += build_section_data(args0[index],args1[index],args2[index]) # add dispatch function len_funs = len(section_data) section_data = add_dispatch_function(ori_address, offsets) + section_data section_file = open( INPUT_PE + '_newSectionData','wb') section_file.write(section_data) section_file.close() section_size = len(section_data) insert_section(len(section_data),section_data,len_funs)
def _priority_paint_instructions(self, target_address, ignore=set()): """ Paint instructions in the immediate vicinity of the given address. Optionally, one can provide a set of addresses to ignore while painting. """ database_coverage = self._director.coverage # the number of instruction bytes before and after the cursor to paint INSTRUCTION_BUFFER = 200 # determine range of instructions to repaint inst_start = target_address - INSTRUCTION_BUFFER inst_end = target_address + INSTRUCTION_BUFFER instructions = set(idautils.Heads(inst_start, inst_end)) # remove any instructions painted by the function paints instructions -= ignore # mask only the instructions with coverage data in this region instructions_coverage = instructions & database_coverage.coverage # clear all instructions in this region, repaint the coverage data self.clear_instructions(instructions) self.paint_instructions(instructions_coverage) # return the instruction addresses painted return instructions_coverage
def GetDataXrefString(ea): name = idc.GetFunctionName(ea) ea = idc.LocByName(name) f_start = ea f_end = idc.GetFunctionAttr(ea, idc.FUNCATTR_END) ret = [] for chunk in idautils.Chunks(ea): astart = chunk[0] aend = chunk[1] for head in idautils.Heads(astart, aend): # If the element is an instruction if idc.isCode(idc.GetFlags(head)): refs = list(idautils.DataRefsFrom(head)) for ref in refs: s = idc.GetString(ref, -1, idc.ASCSTR_C) if not s or len(s) <= 4: s = idc.GetString(ref, -1, idc.ASCSTR_UNICODE) if s: if len(s) > 4: ret.append(repr(s)) if len(ret) > 0: return "\n\n" + "\n".join(ret) else: return ""
def lookForOpArgs(self, start, end): for head in idautils.Heads(start, end): try: for i in range(2): if using_ida7api: t = idc.get_operand_type(head, i) else: t = idc.GetOpType(head, i) if t == idc.o_imm: if using_ida7api: opval = idc.get_operand_value(head, i) insn = idautils.DecodeInstruction(head) opmask = OPERAND_MASK.get(insn.ops[i].dtype) if opmask: opval = opval & opmask else: opval = idc.GetOperandValue(head, i) if self.params.useXORSeed: opval = opval ^ self.params.XORSeed for h in self.params.hashTypes: hits = self.dbstore.getSymbolByTypeHash( h.hashType, opval) for sym in hits: logger.info("0x%08x: %s", head, str(sym)) self.addHit(head, sym) self.markupLine(head, sym, self.params.useDecompiler) except Exception as err: logger.exception("Exception: %s", str(err))
def get_strings_per_function(self, start_func): strings = [] fs = '' func_obj = idaapi.get_func(start_func) if func_obj: self.clear_comments(start_func, func_obj) for inst_list in idautils.Heads(start_func, idc.FindFuncEnd(start_func)): try: for string in [ self.get_string_type(xref_addr) for xref_addr in idautils.DataRefsFrom(inst_list) ]: if len(string) > 2: strings.append(string) self.string_counter += 1 else: pass except StringException: continue if strings: for c in strings: if '\n' in c: c = c.replace('\n', '') fs += '"' + c + '" ' idaapi.set_func_cmt(func_obj, 'STR {}# {}'.format(len(strings), fs), 1) else: print("func_obj return 0") pass
def get_all(cls): """Return all instructions in the IDB :type: [:class:`midap.code.IDAInstr`]""" return [ IDAInstr(ea) for ea in idautils.Heads() if elt.IDAElt(ea).is_code ]
def iter_fn(self, startAddr): """ Generator function designed to walk all instructions within a function, parse and yield them. """ endAddr = idc.GetFunctionAttr(startAddr, idc.FUNCATTR_END) for head in idautils.Heads(startAddr, endAddr): yield head, idc.GetDisasm(head).split()[0], idc.GetOpnd(head, 0), idc.GetOpnd(head, 1)
def find_interesting_xors(self): next_xor = idc.FindText(idc.MinEA(), idc.SEARCH_DOWN | idc.SEARCH_NEXT, 0, 0, "xor") while next_xor != idc.BADADDR: if idc.GetOpnd(next_xor, 0) != idc.GetOpnd(next_xor, 1): entry = { "func": "", "addr": next_xor, "loop": False, "disasm": idc.GetDisasm(next_xor) } func = idaapi.get_func(next_xor) if func: entry["func"] = idaapi.get_name(idc.BADADDR, func.startEA) heads = idautils.Heads(next_xor, func.endEA) lxors = [] for head in heads: if idc.GetMnem(head).startswith('j'): jmp_addr = idc.GetOperandValue(head, 0) if jmp_addr < next_xor and jmp_addr > func.startEA: entry["loop"] = True break self._interesting_xors.append(entry) next_xor = idc.FindText(idc.NextHead(next_xor), idc.SEARCH_DOWN | idc.SEARCH_NEXT, 0, 0, "xor")
def Instrs(self): """Instructions in the block :type: [:class:`midap.code.IDAInstr`]""" return [ IDAInstr(addr, self) for addr in idautils.Heads(self.addr, self.endADDR) ]
def clear_function_instructions(self, address): """Clear paint from a function instructions.""" for start_ea, end_ea in idautils.Chunks(address): for ea in idautils.Heads(start_ea, end_ea): color = self._get_paint_instruction(ea) # Clear it only if it hasn't been colorized by the user color = color if color != self._bg_color else self.DEFCOLOR self._set_paint_instruction(ea, color)
def send_comments(self): """ Initial sync of comments """ for head in idautils.Heads(): cmt = SkelUtils.get_comment(head) if cmt: self.skel_conn.push_comment(head, cmt)
def highlight(self, color=COLOR): for ea in idautils.Heads(): if idaapi.isCode(idaapi.getFlags(ea)) and idaapi.is_call_insn(ea): current_color = idaapi.get_item_color(ea) if current_color == self.COLOR: idaapi.set_item_color(ea, idc.DEFCOLOR) elif current_color == idc.DEFCOLOR: idaapi.set_item_color(ea, self.COLOR)