def _get_api(sea): calls = 0 api = [] flags = idc.GetFunctionFlags(sea) # ignore library functions if flags & idc.FUNC_LIB or flags & idc.FUNC_THUNK: return calls, api # list of addresses addresses = list(idautils.FuncItems(sea)) for instr in addresses: tmp_api_address = "" if idaapi.is_call_insn(instr): for xref in idautils.XrefsFrom(instr, idaapi.XREF_FAR): if xref.to is None: calls += 1 continue tmp_api_address = xref.to break if tmp_api_address == "": calls += 1 continue api_flags = idc.GetFunctionFlags(tmp_api_address) if api_flags & idaapi.FUNC_LIB is True \ or api_flags & idaapi.FUNC_THUNK: tmp_api_name = idc.NameEx(0, tmp_api_address) if tmp_api_name: api.append(tmp_api_name) else: calls += 1 return calls, api
def _process_possible_stub(stub, make_thunk, next_stub): """Try to process a stub function.""" # First, make sure this is a stub format we recognize. target = stub_target(stub) if not target: _log(0, 'Unrecognized stub format at {:#x}', stub) return False # Next, check if IDA sees this as a function chunk rather than a function, and correct it if # reasonable. if not idau.force_function(stub): _log(1, 'Could not convert stub to function at {:#x}', stub) return False # Next, set the appropriate flags on the stub. Make the stub a thunk if that was requested. flags = idc.GetFunctionFlags(stub) if flags == -1: _log(1, 'Could not get function flags for stub at {:#x}', stub) return False target_flags = idc.GetFunctionFlags(target) if target_flags != -1 and target_flags & idc.FUNC_NORET: flags |= idc.FUNC_NORET if make_thunk: flags |= idc.FUNC_THUNK if idc.SetFunctionFlags(stub, flags | idc.FUNC_THUNK) == 0: _log(1, 'Could not set function flags for stub at {:#x}', stub) return False # Next, ensure that IDA sees the target as a function, but continue anyway if that fails. if not idau.force_function(target): _log(1, 'Stub {:#x} has target {:#x} that is not a function', stub, target) # Finally symbolicate the stub. if not _symbolicate_stub(stub, target, next_stub): return False return True
def _collect_data(self, collect_args): func_item = collect_args["func_item"] code_refs_from_list = list(idautils.CodeRefsFrom(func_item, False)) for code_ref in code_refs_from_list: is_loaded_dynamically = False is_library_function = False function_name = "" if (idc.GetFunctionFlags(code_ref) == -1): # Find code_ref in functions that are imported dynamically for imported_module in self._imported_modules: if code_ref in imported_module.get_addresses(): is_loaded_dynamically = True break else: if ((idc.GetFunctionFlags(code_ref) & idaapi.FUNC_LIB) != 0 and idaapi.get_func(code_ref) != idaapi.get_func(func_item)): # code_ref is imported statically is_library_function = True if (is_library_function or is_loaded_dynamically): # get name function_name = idc.NameEx(func_item, code_ref) # include in attribute if not (function_name in self._lib_calls_counters): self._lib_calls_counters[function_name] = 0 self._lib_calls_counters[function_name] += 1
def _collect_data(self, collect_args): func_item = collect_args["func_item"] code_refs_from_list = \ list(idautils.CodeRefsFrom(func_item, False)) for code_ref in code_refs_from_list: is_loaded_dynamically = False is_library_function = False called_function_name = "" if (idc.GetFunctionFlags(code_ref) == -1): # Find code_ref in functions that are imported dynamically for imported_module in self._imported_modules: if code_ref in imported_module.get_addresses(): is_loaded_dynamically = True break else: # get_func(code_ref) != get_func(func_item) -> # do not include coderefs to self. if ((idc.GetFunctionFlags(code_ref) & idaapi.FUNC_LIB) != 0 and idaapi.get_func(code_ref) != idaapi.get_func(func_item)): # code_ref is imported statically is_library_function = True # Data is gathered only for library functions or Imports. if (is_library_function or is_loaded_dynamically): # get name called_function_name = idc.NameEx(func_item, code_ref) # include in attribute self._lib_calls_list.append(called_function_name)
def check_for_wrapper(func): flags = idc.GetFunctionFlags(func) #跳过库函数和简单的跳转函数 if flags & FUNC_LIB or flags & FUNC_THUNK: return dism_addr = list(idautils.FuncItems(func)) #获取函数的长度 func_length = len(dism_addr) #如果函数的超过32条指令则返回 if func_length > 0x20: return func_call = 0 instr_cmp = 0 op = None op_addr = None op_type = None #遍历函数中的每条指令 for ea in dism_addr: m = idc.GetMnem(ea) if m == 'call' or m == 'jmp': if m == 'jmp': temp = idc.GetOperandValue(ea, 0) # 忽略函数边界内的跳转 if temp in dism_addr: continue func_call += 1 #封装函数内不会包含多个函数调用 if func_call == 2: return op_addr = idc.GetOperandValue(ea, 0) op_type = idc.GetOpType(ea, 0) elif m == 'cmp' or m == 'test': # 封装函数内不应该包含太多的逻辑运算 instr_cmp += 1 if instr_cmp == 3: return else: continue # 所有函数内的指令都被分析过了 if op_addr == None: return name = idc.Name(op_addr) #跳过名称粉碎的函数名称 if "[" in name or "$" in name or "?" in name or "@" in name or name == "": return name = "w_" + name if op_type == o_near: if idc.GetFunctionFlags(op_addr) & FUNC_THUNK: rename_wrapper(name, func) return if op_type == o_mem or op_type == o_far: rename_wrapper(name, func) return
def get_call_expression(self, ea): """ get an expression representing a function call at this address. """ insn = idautils.DecodeInstruction(ea) fct = self.get_operand_expression(ea, 0) if type(fct) == value_t and \ idc.GetFunctionFlags(fct.value) & idaapi.FUNC_THUNK == idaapi.FUNC_THUNK: print '%x: call to function thunk %x' % (ea, fct.value) expr = call_t(fct, None) #~ return expr, [] spoils = [] else: #~ if self.follow_calls and type(fct) == value_t: if type(fct) == value_t: fct_ea = fct.value #~ try: #~ call_flow = flow_t(fct_ea, follow_calls = False) #~ call_flow.reduce_blocks() #~ params = [p.copy() for p in call_flow.uninitialized_uses] #~ spoils = [p.copy() for p in call_flow.spoils] #~ except: print '%x could not analyse call to %x' % (ea, fct.value) params = [] spoils = [] else: params = [] spoils = [] # for all uninitialized register uses in the target function, resolve to a value. #~ params = [(self.get_value_at(p) or p) for p in params] expr = call_t(fct, None) # check if eax is a spoiled register for the target function. # if it is, change the expression into an assignment to eax if type(fct) != value_t or not (idc.GetFunctionFlags(fct.value) & idaapi.FUNC_NORET): expr = assign_t(self.resultreg.copy(), expr) return expr, spoils
def run(self, arg): print("Running") PE = peutils_t() print("Image base is %016X" % PE.imagebase) print("Exporting functions...") filename = os.path.splitext(idc.GetIdbPath())[0] + ".sym" rawOffsetsFilename = os.path.splitext(idc.GetIdbPath())[0] + ".raw.sym" f = open(filename, 'w') rawOffsetsFile = open(rawOffsetsFilename, 'w') count = 0 for address, name in Names(): offset = address - PE.imagebase rawOffset = idaapi.get_fileregion_offset(address) if idc.GetFunctionFlags(address) != -1: size = idc.FindFuncEnd(address) - address else: size = 4 #namesList.append((offset, name)) count += 1 f.write("%08X %08X;%s\n" % (offset, size, name)) rawOffsetsFile.write("%08X %08X;%s\n" % (rawOffset, size, name)) f.close() rawOffsetsFile.close() print("%d functions exported" % count)
def sequence3(out_path=config.path['outfolder']): FeatList = [] s = "" opcodelist_path = out_path + config.filename['opcodetmp'] # wait for IDA idaapi.autoWait() for func in idautils.Functions(): flags = idc.GetFunctionFlags(func) if flags & FUNC_LIB or flags & FUNC_THUNK: continue dism_addr = list(idautils.FuncItems(func)) for line in dism_addr: opcode = idc.GetMnem(line) s += str(opcode) + " " # 考虑到其他算法,这里不能去重 if opcode in s3_cutpoint: FeatList.append(s) s = "" # save the last sequence if s not in FeatList and s != "": FeatList.append(s) # write the sequences to the file f = open(opcodelist_path, 'w') f.write("\n".join(FeatList)) f.close() idc.Exit(0)
def get_f5_comments(self): cmts = [] for seg in idautils.Segments(): ea = idc.SegStart(seg) if idc.GetSegmentAttr(ea, idc.SEGATTR_TYPE) != idaapi.SEG_CODE: continue seg_name = idc.SegName(seg) end = idc.SegEnd(seg) while ea < end: if ea != idc.BADADDR and idc.GetFunctionFlags( ea) != 0xffffffff: try: cfunc = idaapi.decompile(ea) for tl, citem in cfunc.user_cmts.items(): current_cmt = [ "%s:%-16X" % (seg_name, tl.ea), 'F5', idc.GetDisasm(tl.ea), citem.c_str() ] # F5 comments cmts.append(current_cmt) self.n += 1 except idaapi.DecompilationFailure: pass finally: ea = idc.GetFunctionAttr(ea, idc.FUNCATTR_END) else: ea = idc.next_head(ea, end) return cmts
def resolve_unknown_functions(): proc_name = get_proc_name() if proc_name.startswith("mips"): prolog_pattern = FUNCTION_PROLOGS.get(proc_name, "BAD ARCH") elif proc_name.startswith("ARM"): prolog_pattern = FUNCTION_PROLOGS.get(proc_name, "BAD ARCH") else: # TODO: support another arch return ea = get_start_ea(idaapi.SEG_CODE) if ea == idc.BADADDR: ea = idc.FirstSeg() cur_seg_end = idc.SegEnd(ea) while ea != idc.BADADDR: if ea < cur_seg_end and idc.GetSegmentAttr(ea, idc.SEGATTR_TYPE) == idaapi.SEG_CODE: if idc.GetFunctionFlags(ea) == -1: # not function raw_data_hex = read_addr(ea) if re.match(prolog_pattern, raw_data_hex.decode('hex')): idc.MakeFunction(ea) ea = ea + 4 else: ea = idc.NextSeg(ea) cur_seg_end = idc.SegEnd(ea)
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 yacheck_function_flags(self): addrs = yaunit.load('function_flags') for i, k in enumerate(flag_types): addr = addrs[i] flags = idc.GetFunctionFlags(addr) self.assertNotEqual(flags, -1) self.assertEqual(flags & k, k)
def is_noreturn_function(ea): """Returns `True` if the function at `ea` is a no-return function.""" flags = idc.GetFunctionFlags(ea) return 0 < flags and \ (flags & idaapi.FUNC_NORET) and \ ea not in FUNC_LSDA_ENTRIES.keys() and \ "cxa_throw" not in get_symbol_name(ea)
def combine_noreturns(flow, block, container): """ if the last call before a goto_t is a noreturn call, then remove the goto_t (which is not correct). """ if len(container) < 2 or type(container[-1]) != goto_t: return False goto = container[-1] if type(goto.expr) != value_t or type(container[-2]) != statement_t: return False dst_block = flow.blocks[goto.expr.value] if type(container[-2].expr) == call_t: call = container[-2].expr elif type(container[-2].expr) == assign_t and type( container[-2].expr.op2) == call_t: call = container[-2].expr.op2 else: return False if type(call.fct) != value_t: return False if not (idc.GetFunctionFlags(call.fct.value) & idaapi.FUNC_NORET): return False container.remove(goto) block.jump_to.remove(dst_block) dst_block.jump_from.remove(block) return True
def isFuncLib(ea): if idc.GetFunctionFlags(ea) & idc.FUNC_LIB: return True elif GetName(ea).startswith("."): return True else: return False
def cb_imp(self, imp, func, nid): name = self.func_get_name("imp", imp.library_name, nid) make_func(func, name) idc.SetFunctionFlags(func, idc.GetFunctionFlags(func) | idaapi.FUNC_THUNK | idaapi.FUNC_LIB) self.apply_proto(func, nid) self.add_nid_cmt(func, "[Import LIB: 0x{:08X} ({}), NID: 0x{:08X}]".format(imp.library_nid, imp.library_name, nid))
def build_stack_args(f): stackArgs = dict() name = idc.Name(f) end = idc.GetFunctionAttr(f, idc.FUNCATTR_END) _locals = idc.GetFunctionAttr(f, idc.FUNCATTR_FRSIZE) _uses_bp = 0 != (idc.GetFunctionFlags(f) & idc.FUNC_FRAME) frame = idc.GetFrame(f) if frame is None: return stackArgs func_type = idc.GetType(f) if (func_type is not None) and ("(" in func_type): args = func_type[ func_type.index('(')+1: func_type.rindex(')') ] args_list = [ x.strip() for x in args.split(',')] if "..." in args_list: return stackArgs if name in RECOVER_DEBUG_FL: return stackArgs #grab the offset of the stored frame pointer, so that #we can correlate offsets correctly in referent code # e.g., EBP+(-0x4) will match up to the -0x4 offset delta = idc.GetMemberOffset(frame, " s") if -1 == delta: #indicates that it wasn't found. Unsure exactly what to do # in that case, punting for now delta = 0 offset = idc.GetFirstMember(frame) while -1 != _signed_from_unsigned(offset): memberName = idc.GetMemberName(frame, offset) if memberName is None: # gaps in stack usage are fine, but generate trash output # gaps also could indicate a buffer that IDA doesn't recognize offset = idc.GetStrucNextOff(frame, offset) continue if (memberName == " r" or memberName == " s"): #the return pointer and start pointer, who cares offset = idc.GetStrucNextOff(frame, offset) continue memberSize = idc.GetMemberSize(frame, offset) if offset >= delta: offset = idc.GetStrucNextOff(frame, offset) continue memberFlag = idc.GetMemberFlag(frame, offset) #TODO: handle the case where a struct is encountered (FF_STRU flag) flag_str = _get_flags_from_bits(memberFlag) stackArgs[offset-delta] = {"name":memberName, "size":memberSize, "flags":flag_str, "writes":list(), "referent":list(), "reads":list(), "safe": False} offset = idc.GetStrucNextOff(frame, offset) return stackArgs
def yatest_function_flags(self): addrs = [] for i, k in enumerate(flag_types): addr = yaunit.get_next_function() flags = idc.GetFunctionFlags(addr) self.assertNotEqual(flags, -1) self.assertEqual(idc.SetFunctionFlags(addr, flags | k), 1) addrs.append(addr) yaunit.save('function_flags', addrs)
def hook_lib_funcs(): from angrdbg import load_project project = load_project() for func in idautils.Functions(): flags = idc.GetFunctionFlags(func) if flags & idc.FUNC_LIB: name = idc.GetFunctionName(func) simproc = search_simproc(name) if simproc is not None: print name, simproc project.hook_symbol(func, simproc())
def make_islands_xrefs_force_bl_call(ea, verbose=True): """ makes all BL references to a branch islands as call """ segname = idc.SegName(ea) if verbose: print "[+] forcing bl call on: %s [0x%X]" % (segname, ea) if "branch_islands" in segname: idc.SetFunctionFlags(ea, idc.GetFunctionFlags(ea) & (0xffffffff - 1)) for x in idautils.XrefsTo(ea): make_islands_xrefs_force_bl_call(x.frm) return idc.ArmForceBLCall(ea)
def analysis(): global fCount all_funcs = idautils.Functions() for f in all_funcs: fflags = idc.GetFunctionFlags(f) if (fflags & FUNC_LIB) or (fflags & FUNC_THUNK): continue fCount = fCount + 1 print "In %s:\n" % (idc.GetFunctionName(f), ) fAddr = GetFunctionAttr(f, FUNCATTR_START) f = idaapi.FlowChart(idaapi.get_func(f), flags=idaapi.FC_PREDS) calculate_weight(f, fAddr)
def build_functions_tree(self, functions_list): '''Build tree of functions.''' func_state = FunctionState() functions_tree = OrderedDict() for function_name in sorted(functions_list): func_state.args = '' func_state.addr = functions_list[function_name] func_state.flags = idc.GetFunctionFlags(func_state.addr) chunks = self.get_chunks(function_name, func_state) self.maybe_push(chunks, functions_tree, func_state) return functions_tree
def is_function_unsafe(func_ea, blockset): """ Returns `True` if the function uses bp and it might access the stack variable indirectly using the base pointer. """ if not (idc.GetFunctionFlags(func_ea) & idc.FUNC_FRAME): return False for block_ea in blockset: inst_eas, succ_eas = analyse_block(func_ea, block_ea, True) for inst_ea in inst_eas: if is_instruction_unsafe(inst_ea, func_ea): return True return False
def OnGetText(self, node_id): ea, label = self[node_id] flags = idc.GetFunctionFlags(ea) if label == "Return ...": color = 0xfff000 return (label, color) elif node_id == 0: color = 0x00f000 return (label, color) elif flags & idc.FUNC_LIB or flags == -1 or label.startswith("."): color = 0xf000f0 return (label, color) else: return label
def rename(self, ea, name): # Don't rely on the name in curfunc, as it could have already been renamed curname = idc.Name(ea) # Don't rename if the name is a special identifier, or if the ea has already been named # TODO: What's a better way to check for reserved name prefixes? if curname.startswith('sub_') and name.split('_')[0] not in set(['sub', 'loc', 'unk', 'dword', 'word', 'byte']): # Don't rename if the name already exists in the IDB if idc.LocByName(name) == idc.BADADDR: if idc.MakeName(ea, name): idc.SetFunctionFlags(ea, (idc.GetFunctionFlags(ea) | idc.FUNC_LIB)) #print "%s => %s" % (curname, name) return 1 #else: # print "WARNING: Attempted to rename '%s' => '%s', but '%s' already exists!" % (curname, name, name) return 0
def functionParse(self): print "+++++ Auto Analyis ++++++" print " Starting " print "+++++++++++++++++++++++++" # Parse each functions // Skip library calls for segea in idautils.Segments(): for funcea in idautils.Functions(segea, idc.SegEnd(segea)): functionName = idc.GetFunctionName(funcea) functionFlags = idc.GetFunctionFlags(funcea) if (functionFlags & idaapi.FUNC_LIB or functionFlags & idaapi.FUNC_THUNK or functionFlags & idaapi.FUNC_HIDDEN or functionFlags & idaapi.FUNC_STATICDEF): continue self.analyzeFunction(funcea)
def OnGetText(self, node_id): try: ea, label = self[node_id] flags = idc.GetFunctionFlags(ea) if ea in self.start or ea in self.target or ea in self.hits: color = 0x00f000 return (label, color) elif flags & idc.FUNC_LIB or flags == -1 or label.startswith("."): color = 0xf000f0 return (label, color) else: return label except: label = str(sys.exc_info()[1]) #return "Error " + str(label) + " EA 0x%08x" % ea return "oxtixe"
def calc_most_common_start_bytes(): """ Description: Iterate over all non-lib (and non-thunk) functions and record their first instruction. Return the bytes for whichever instruction appears most. Output: A space separated string of bytes of the most common first instruction. """ counts = {} for func_ea in idautils.Functions(): if not idc.GetFunctionFlags(func_ea) & (idc.FUNC_LIB | idc.FUNC_THUNK): start_bytes = idaapi.get_many_bytes(func_ea, idc.ItemSize(func_ea)) if start_bytes in counts: counts[start_bytes] += 1 else: counts[start_bytes] = 1 return ' '.join('%02X' % ord(c) for c in sorted(counts.items(), key=lambda tup: tup[1], reverse=True)[0][0])
def _IsFunctionHandled(self, addr): first_addr = idaapi.get_func(addr).startEA flags = idc.GetFunctionFlags(first_addr) if (flags & (idc.FUNC_THUNK | idc.FUNC_LIB)): err_str = "REDB: function has been identified by IDA as a " err_str += "thunk or a library function and therefore will " err_str += "not be handled." print err_str return False else: if (len(list(idautils.FuncItems(addr))) < MIN_INS_PER_HANDLED_FUNCTION): err_str = "REDB: function has too few instructions " err_str += "and therefore will not be handled." print err_str return False else: return True
def addRequiredNodes(self, father, level=0): for ea in GetCodeRefsFrom(father): ea = GetFunctionStartEA(ea) if not self.nodes.has_key(ea): if idc.GetFunctionFlags(ea) & idc.FUNC_LIB and not self.show_runtime_functions: continue name = GetName(ea, True) if name: if self.show_string: name += GetDataXrefString(ea) if ea not in self.hidden: self.nodes[ea] = self.AddNode((ea, name)) if level < self.max_level: self.addRequiredNodes(ea, level+1) elif level == self.max_level: self.last_level.append(ea)