def main(): clist = build_color_list() filepath = idaapi.askfile_c(False, "*.*", "Pin log file") imagebase = idaapi.get_imagebase() try: f = open(filepath, "rb") except: print("Need log file to parse data...") return buff = f.read() functions = set() for index in range(0, len(buff)): exec_count = ord(buff[index]) if exec_count == 0: continue exec_count = exec_count / 10 if exec_count > 11: exec_count = 11 ida_color = clist[exec_count] if (not (idc.GetFunctionName(imagebase + index) in functions)): func = idc.GetFunctionName(imagebase + index) print "hit @ 0x%08x function %s" % (imagebase + index, func) functions.add(func) idc.SetColor(imagebase + index, CIC_ITEM, ida_color)
def get_patch_byte(self, ea, fpos, org_val, patch_val): # Aggregate contiguous bytes (base ea + length) # NOTE: Looking at the last item [-1] is sufficient # since we are dealing with sorted data. if len(self.items_data) and (ea - self.items_data[-1][0] == self.items_data[-1][2]): # Increment length self.items_data[-1][2] += 1 self.items[-1][2] = str(self.items_data[-1][2]) # Append patched bytes self.items_data[-1][3].append(patch_val) self.items[-1][3] = " ".join(["%02X" % x for x in self.items_data[-1][3]]) # Append original bytes self.items_data[-1][4].append(org_val) self.items[-1][4] = " ".join(["%02X" % x for x in self.items_data[-1][4]]) # Add new patch byte to the list else: name = idc.SegName(ea) if idc.GetFunctionName(ea) or idc.Name(ea): name += ": %s" % idc.GetFunctionName(ea) or idc.Name(ea) comment = idc.Comment(ea) or idc.RptCmt(ea) or "" # DATA STORAGE FORMAT: address, function / fpos, len, patched byte(s), original byte(s), comments self.items.append( ["%08X" % ea, name, "1", "%02X" % patch_val, "%02X" % org_val, comment]) self.items_data.append([ ea, fpos, 1, [patch_val], [org_val], None] ) return 0
def getCallGraph(): callGraph = nx.DiGraph() for func_addr in idautils.Functions(MinEA(), MaxEA()): #print func_addr #coderefler bulunur ve hepsi grapha eklenir fn = idc.GetFunctionName(func_addr) #print "for function ",fn, " caller functions listed below:" i = 0 callers = idautils.CodeRefsTo(func_addr, 1) #avoid if there is no caller if (len(callers) == 0): #print "empty set!" continue callGraph.add_node(func_addr, name=fn) for caller_addr in callers: cn = idc.GetFunctionName(caller_addr) #print i,".caller is ",cn, " address: 0x %x" %caller_addr i += 1 #avoid circle if (fn == cn): print fn continue cf_addr = idc.GetFunctionAttr(caller_addr, FUNCATTR_START) if cf_addr is None: #print "none function -> 0x%x"%caller_addr continue if not (cf_addr in callGraph): callGraph.add_node(cf_addr, name=cn) callGraph.add_edge(cf_addr, func_addr) return callGraph
def isCall(self, xref, tid): if xref in self._call_lut: return True elif idc.GetMnem(xref) == 'jmp': curf = idc.GetFunctionName(xref) if curf is not None: val = idc.GetOperandValue(xref, 0) if val is not None and val > 0: tarf = idc.GetFunctionName(val) if tarf is not None and tarf != curf: self._call_lut.add(xref) for thread in self["mem_areas"][0]['threads']: if thread['tid'] == tid: thread['calls'].append({ "execs": 1, "name": "", "target": val, "xrefs": [{ "addr": xref, "execs": 1, "params": [] }] }) return True return False
def SearchCodePathDialog(ret_only=False, extended=False): f1 = idaapi.choose_func("Select starting function", 0) if not f1: return sea = f1.startEA f2 = idaapi.choose_func("Select target function", idc.ScreenEA()) if not f2: return tea = f2.startEA nodes = SearchCodePath(sea, tea, extended) if len(nodes) > 0: if ret_only: return nodes else: g = PathsBrowser( "Code paths from %s to %s" % (idc.GetFunctionName(sea), idc.GetFunctionName(tea)), nodes, sea, tea) g.Show() else: idaapi.info("No codepath found between %s and %s" % (idc.GetFunctionName(sea), idc.GetFunctionName(tea))) return nodes
def find_dispatch_by_cfg(): """ Finds the functions in the binary which are not directly called anywhere and counts how many other functions they call, returing all functions which call > 0 other functions but are not called themselves. As a dispatch function is not normally directly called but will normally many other functions this is a fairly good way to guess which function it is. """ out = [] called = set() caller = dict() # Loop through all the functions in the binary for function_ea in idautils.Functions(): flags = idc.get_func_flags(function_ea) # skip library functions if flags & idc.FUNC_LIB: continue f_name = idc.GetFunctionName(function_ea) # For each of the incoming references for ref_ea in idautils.CodeRefsTo(function_ea, 0): called.add(f_name) # Get the name of the referring function caller_name = idc.GetFunctionName(ref_ea) if caller_name not in caller.keys(): caller[caller_name] = 1 else: caller[caller_name] += 1 while True: if len(caller.keys()) == 0: break potential = max(caller, key=caller.get) if potential not in called: out.append(potential) del caller[potential] return out
def findroot(TargetFunc): global rootpath global rootfunc global m_rootpath global depth global dstfunc depth += 1 if (depth >= 10): rootfunc.append(TargetFunc) rootpath.append( "It's difficult to reverse because depth is too deep!!Try: " + TargetFunc) return for xref in idautils.XrefsTo(idc.LocByName(TargetFunc)): if (idc.GetFunctionName(xref.frm) == ""): #if root function for storcheck in idautils.XrefsTo(idc.LocByName(TargetFunc)): if (storcheck.type == 17): #not root function return if m_rootpath not in rootpath: if (depth > 7): m_rootpath = dstfunc + "<--" + TargetFunc rootfunc.append(idc.GetFunctionName(xref.to)) rootpath.append(m_rootpath) return else: g_rootpath = m_rootpath m_rootpath += "<--" + idc.GetFunctionName(xref.frm) findroot(idc.GetFunctionName(xref.frm)) depth -= 1 m_rootpath = g_rootpath
def scan_functions(self): from mybase import function self.logger.info("For function %s:" % idc.GetFunctionName(self.ea)) for ea in function.iterate(self.ea): for xref in idautils.XrefsFrom(ea, 0): if idautils.XrefTypeName(xref.type) == 'Code_Near_Call' or\ idautils.XrefTypeName(xref.type) == 'Code_Far_Call': self.logger.info("found call at %s --> %s" % (hex(ea), idc.GetFunctionName(xref.to))) #skip constructors fn = FunctionName(idc.GetFunctionName(xref.to)) if fn.namespace == fn.basename: continue tif = idaapi.tinfo_t() if idaapi.get_tinfo2(xref.to, tif): funcdata = idaapi.func_type_data_t() tif.get_func_details(funcdata) #funcdata.get_call_method() if funcdata.size() >= 1 and funcdata[0].name == "this": self.funcs.add( FunctionName(idc.GetFunctionName(xref.to))) self.logger.info("Call to %s found" % idc.GetFunctionName(xref.to)) else: self.logger.info("idaapi.get_tinfo2 failed") self.logger.info("%d subcalls found" % len(self.funcs))
def import_func_names(fname): s = idautils.Strings(False) s.setup(strtypes=idautils.Strings.STR_UNICODE | idautils.Strings.STR_C) f = open(fname) jsontable = json.load(f) f.close() string2ea = dict([(unicode(v), v.ea) for v in s]) for entry in jsontable: if unicode(entry['string']) in string2ea.keys(): ea = string2ea[unicode(entry['string'])] xrefs = [x.frm for x in idautils.XrefsTo(ea)] ret = [idaapi.get_func(x) for x in xrefs if idaapi.get_func(x)] names = [] funcs = [] for func in ret: if idc.GetFunctionName(func.startEA) not in names: names.append(idc.GetFunctionName(func.startEA)) funcs.append(func) if len(funcs) == 1: print "%s %s -> %s\tstr: %s" % (hex( funcs[0].startEA), idc.GetFunctionName( funcs[0].startEA), entry['func_name'], entry['string'])
def get_patch_byte(self, ea, fpos, org_val, patched_val): org_byte = "%02x" % org_val patched_byte = "%02x" % patched_val if self.prev_addr is None or ea != (self.prev_addr + 1): name = idc.SegName(ea) if idc.GetFunctionName(ea) or idc.Name(ea): name += ": %s" % idc.GetFunctionName(ea) or idc.Name(ea) comment = idc.Comment(ea) or idc.RptCmt(ea) or "" self.patched_bytes.append({ 'name': name, 'begin_addr': ea, 'original': org_byte, 'patched': patched_byte, 'comment': comment }) else: self.patched_bytes[-1]['original'] += org_byte self.patched_bytes[-1]['patched'] += patched_byte self.prev_addr = ea return 0
def _valid_call(self, ref_addr, target_addr): if ref_addr and target_addr: ref_func = idc.GetFunctionName(ref_addr) target_func = idc.GetFunctionName(target_addr) if ref_func == target_func: return False return True
def getFunctionName(self, ea): """Returns the name of the function to which ea belongs""" demangled_name = idc.Demangle(idc.GetFunctionName(ea), idc.GetLongPrm(idc.INF_SHORT_DN)) if not demangled_name: return idc.GetFunctionName(ea) else: return demangled_name
def threads(self): for thread in self["mem_areas"][0]['threads']: fname = idc.GetFunctionName(thread["tfunc"]) if len(fname) == 0: if idc.MakeFunction(thread["tfunc"]) == 0: fname = "0x%x" % thread["tfunc"] else: fname = idc.GetFunctionName(thread["tfunc"]) yield fname, thread["tfunc"], thread["tid"]
def addEdges(self): for ea in self.result: refs = GetCodeRefsFrom(ea) for ref in refs: name = idc.GetFunctionName(ref) name2 = idc.GetFunctionName(ea) try: if name in self.added: self.AddEdge(self.nodes[idc.LocByName(name2)], self.nodes[idc.LocByName(name)]) self.added.append((ea, ref)) except: print "Error", sys.exc_info()[1]
def is_call(self, instruction=None): """Return whether the last instruction processed is a call or not.""" # If there are instructions defined as being specifically used for "calls" # we take those as a unique indentifier for whether the instruction is # if fact a call or not # if self.INSTRUCTIONS_CALL: if instruction.itype in self.INSTRUCTIONS_CALL: return True else: return False if not instruction.itype in self.INSTRUCTIONS_BRANCH: return False trgt = list(idautils.CodeRefsFrom(instruction.ip, 0)) if not trgt: trgt = list(idautils.DataRefsFrom(instruction.ip)) if len(trgt) > 0: # When getting the name there's a fall back from # using GetFunctionName() to Name() as sometimes # imported functions are not defined as functions # and the former will return an empty string while # the later will return the import name. # trgt_name = idc.GetFunctionName(trgt[0]) if trgt_name == '': trgt_name = idc.Name(trgt[0]) trgt_name_prev = idc.GetFunctionName(trgt[0] - 1) if trgt_name_prev == '': trgt_name_prev = idc.Name(trgt[0] - 1) # In order for the reference to be a call the following # must hold. # -There must be a valid function name # -The function name should be different at the target # address then the name in the immediately posterior # address (i.e. target must point to begging of function) # -The function name should be different than the function # name of the branch source # if (trgt_name is not None and trgt_name != '' and trgt_name != trgt_name_prev and idc.GetFunctionName(instruction.ip) != trgt_name): return True return False
def getFunc(self, ea=None, next=False): if ea == None: ea = idaapi.get_screen_ea() if next: ea = idc.NextFunction(ea) if ea == -1: return (0xFFFFFFFFL, 0xFFFFFFFFL) if ea < 0: return (0xFFFFFFFFL, 0xFFFFFFFFL) elif idc.GetFunctionName(ea) == idc.GetFunctionName(idc.PrevAddr(ea)): ea = idc.PrevFunction(ea) return (ea, idc.FindFuncEnd(ea))
def GetCFG(): SingleBBS = {} # head -> pred_bbl MultiBBS = {} # head -> [pred_bbls] bbls = {} # head -> bbl # bbls2 = {} # tail -> bbl edges = { } # dict struct. head -> of (head, ..., head) #set() # set of (tail, head) or (head, head) edges_count = 0 #bbls_t, edges_t, count, SingleBBS_t, MultiBBS_t = GetFunEdgesAndBbls(0x08F7790) # deubg #exit() for func in idautils.Functions(): if IsSanFunc(func): continue print('%x %s') % (func, idc.GetFunctionName(func)) bbls_t, edges_t, count, SingleBBS_t, MultiBBS_t = GetFunEdgesAndBbls( func) bbls.update(bbls_t) # bbls2.update(bbls2_t) edges.update(edges_t) # union edges_count += count SingleBBS.update(SingleBBS_t) MultiBBS.update(MultiBBS_t) return bbls, edges, edges_count, SingleBBS, MultiBBS
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 format_rules(fva, rules): ''' given the address of a function, and the byte signatures for basic blocks in the function, format a complete YARA rule that matches all of the basic block signatures. ''' name = idc.GetFunctionName(fva) # some characters aren't valid for YARA rule names safe_name = name BAD_CHARS = '@ /\\!@#$%^&*()[]{};:\'",./<>?' for c in BAD_CHARS: safe_name = safe_name.replace(c, '') md5 = idautils.GetInputFileMD5() ret = [] ret.append('rule a_%s_%s {' % (md5, safe_name)) ret.append(' meta:') ret.append(' sample_md5 = "%s"' % (md5)) ret.append(' function_address = "0x%x"' % (fva)) ret.append(' function_name = "%s"' % (name)) ret.append(' strings:') for rule in rules: formatted_rule = ' '.join(rule.masked_bytes) ret.append(' %s = { %s }' % (rule.name, formatted_rule)) ret.append(' condition:') ret.append(' all of them') ret.append('}') return '\n'.join(ret)
def get_current_function_xrefs_from(self): addr_in_func = idc.ScreenEA() curr_func = idc.GetFunctionName(addr_in_func) refs = self.find_xrefs_from(addr_in_func) return [ref.get_row(XrefsFromFinder.XREF_TYPE2STR) for ref in refs]
def run(self, arg): """ :param arg: Integer, a non-zero value enables auto-run feature for IDA batch (no gui) processing mode. Default is 0. """ log("plugin run") if not is_jni_header_loaded(): idaapi.warning('Please load jni.h first') load_jni_header() st = idc.set_ida_state(idc.IDA_STATUS_WORK) infos = load_methods() failed = [] succ = 0 for ea in idautils.Functions(): fname = idc.GetFunctionName(ea) if fname.startswith('Java_'): info = infos.get(fname) if info is None: failed.append(fname) else: succ += 1 apply_signature(ea, info) if fname == 'JNI_OnLoad': apply_load_unload(ea, True) succ += 1 if fname == 'JNI_OnUnload': apply_load_unload(ea, False) succ += 1 idaapi.info('JNI functions loaded, {} success. {} failed. \n{}'.format( succ, len(failed), '\n'.join(failed) )) idc.set_ida_state(st)
def codeify(self, ea=idc.BADADDR): func_count = 0 code_count = 0 if ea == idc.BADADDR: ea = self.get_start_ea(self.CODE) if ea == idc.BADADDR: ea = idc.FirstSeg() print "\nLooking for undefined code starting at: %s:0x%X" % ( idc.SegName(ea), ea) if self.get_start_ea(self.DATA) == idc.BADADDR: print "WARNING: No data segments defined! I don't know where the code segment ends and the data segment begins." while ea != idc.BADADDR: try: if idc.GetSegmentAttr(ea, idc.SEGATTR_TYPE) == self.CODE: if idc.GetFunctionName(ea) != '': ea = idc.FindFuncEnd(ea) continue else: if idc.MakeFunction(ea): func_count += 1 elif idc.MakeCode(ea): code_count += 1 except: pass ea = idc.NextAddr(ea) print "Created %d new functions and %d new code blocks\n" % ( func_count, code_count)
def get_flow_to_name(name): global idx mflow_addrs = [] mflow_names = [] print "In call %x Name: %s"%(idx,name) idx+=1 for flow in get_name_flow_info(name): print flow a2a = get_addr_to_addr(flow) n2n = get_name_to_name(flow) src = a2a.split()[0].strip() # arrows at 1 dst = a2a.split()[2].strip() sname = idc.GetFunctionName(int(src,16)) print "Obtaining flow information for: ", sname flow_addrs, flow_names = get_flow_to_name(sname) print "Obatained the following flow info for %s: %s"%(sname,str(flow_names)) if len(flow_addrs) == 0: mflow_addrs.append(a2a) if len(flow_names) == 0: mflow_names.append(n2n) for i in flow_addrs: mflow_addrs.append(i + " ==> " + a2a) for i in flow_names: mflow_names.append(i + " ==> " + n2n) idx -= 1 return [i for i in set(mflow_addrs)], [i for i in set(mflow_names)]
def codeify(self, ea=idc.BADADDR): func_count = 0 code_count = 0 if ea == idc.BADADDR: ea = self.get_start_ea(self.CODE) if ea == idc.BADADDR: ea = idc.FirstSeg() self.say("\nLooking for undefined code starting at: %s:0x%X" % (idc.SegName(ea), ea)) while ea != idc.BADADDR: try: if idc.GetSegmentAttr(ea, idc.SEGATTR_TYPE) == self.CODE: if idc.GetFunctionName(ea) != '': ea = idc.FindFuncEnd(ea) continue else: if idc.MakeFunction(ea): func_count += 1 elif idc.MakeCode(ea): code_count += 1 except: pass ea = idc.NextAddr(ea) self.say("Created %d new functions and %d new code blocks\n" % (func_count, code_count))
def push_comms(): global skel_conn commBL = [ "size_t", "int", "LPSTR", "char", "char *", "lpString", "unsigned int", "void *", "indirect table for switch statement", "this", "jump table for switch statement", "switch jump" ] for i in range(idc.MinEA(), idc.MaxEA()): if idc.GetCommentEx( i, 0) is not None and not idc.GetCommentEx(i, 0) in commBL: if not skel_conn.push_comment(i, idc.GetCommentEx(i, 0)): return -1 elif idc.GetCommentEx( i, 1) is not None and not idc.GetCommentEx(i, 1) in commBL: if not skel_conn.push_comment(i, idc.GetCommentEx(i, 1)): return -1 for function_ea in idautils.Functions(idc.MinEA(), idc.MaxEA()): fName = idc.GetFunctionName(function_ea) if hasSubNoppedPrefix(fName) is False: if not skel_conn.push_name(function_ea, fName): g_logger.error("Error sending function name %s" % (fName)) # if idc.GetFunctionCmt(function_ea,0) != "": # push_change("idc.SetFunctionCmt",shex(function_ea),idc.GetFunctionCmt(i,0)) # elif idc.GetFunctionCmt(function_ea,1) != "": # push_change("idc.SetFunctionCmt",shex(function_ea),idc.GetFunctionCmt(function_ea,1)) return
def PrintMsrTable(self, msr_code, function_ea, inst_ea): mnemonic = idc.GetMnem(inst_ea) call_addr = self.GetJumpAddr(inst_ea, function_ea) function_name = idc.GetFunctionName(function_ea) + '+' + call_addr dwSize = 30 - len(function_name) delimeter = " " * dwSize if (msr_code == None): msr_code_hex = 'Not imm value' else: msr_code_hex = self.NormalizeHexValue(msr_code) if (msr_code == None): msr_name = msr_code_hex else: msr_name = msr_list.get(int(msr_code_hex, 16)) idc.MakeComm(inst_ea, '{}({})'.format(mnemonic, msr_name)) idc.SetColor(inst_ea, idc.CIC_ITEM, 0xf8abef) msr_name_delimeter = (" " * (15 - len(msr_code_hex))) print '{}{}| {} | {} {} | {}'.format(function_name, delimeter, mnemonic, msr_code_hex, msr_name_delimeter, msr_name)
def Create(self): ea = ScreenEA() if not idaapi.simplecustviewer_t.Create(self, '%s - Nao' % (idc.GetFunctionName(ea))): return False self.instruction_list = idautils.GetInstructionList() self.instruction_list.extend(['ret']) self.register_list = idautils.GetRegisterList() self.register_list.extend(['r8l', 'r9l', 'r10l', 'r11l', 'r12l', 'r13l', 'r14l', 'r15l', 'r8w', 'r9w', 'r10w', 'r11w', 'r12w', 'r13w', 'r14w', 'r15w', 'r8d', 'r9d', 'r10d', 'r11d', 'r12d', 'r13d', 'r14d', 'r15d', 'eax', 'ebx', 'ecx', 'edx', 'edi', 'esi', 'ebp', 'esp', 'rax', 'rbx', 'rcx', 'rdx', 'rdi', 'rsi', 'rbp', 'rsp']) f = idaapi.get_func(ea) self.fc = idaapi.FlowChart(f) self.block_list = [] for block in self.fc: self.block_list.append(format(block.startEA, 'x').upper()) self.load(ea) action_desc = idaapi.action_desc_t( 'nao:jump', # The action name. 'Jump', # The action text. JumpHandler(self), # The action handler. '', # Optional: the action shortcut '', # Optional: the action tooltip (available in menus/toolbar) ) # Optional: the action icon (shows when in menus/toolbars) use numbers 1-255 idaapi.register_action(action_desc) idaapi.attach_action_to_popup(self.GetWidget(), None, 'nao:jump', None) return True
def load_crash_report(self, log_file): with open(log_file, 'r') as f: log = f.read() traceback = process_stack_trace(log) self.log_txt.setText(log) self.stack_trace_table.clear() self.stack_trace_table.setHorizontalHeaderLabels( ["Address", "Function"]) self.stack_trace_table.setRowCount(len(traceback)) for i, addr in enumerate(traceback): func_name = idc.GetFunctionName(addr) func_name_demangled = idc.Demangle( func_name, idc.GetLongPrm(idc.INF_SHORT_DN)) if func_name_demangled is not None: func_name = func_name_demangled self.stack_trace_table.setRowHeight(i, 20) self.stack_trace_table.setItem( i, 0, QtWidgets.QTableWidgetItem("0x{:016x}".format(addr))) self.stack_trace_table.setItem( i, 1, QtWidgets.QTableWidgetItem(func_name)) self.log_txt.setEnabled(True) self.stack_trace_table.setEnabled(True)
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 log_stack_chains(chains): f = open("%s/%s" % (LOG_PATH, "stack_chains"), "wb") long_chains = 0 for c in chains: if len(c) > 3: long_chains += 1 for a in c: if type(a) == type("x"): s = a else: s = "[0x%08x] %s+0x%x" % (a, str(idc.GetFunctionName( Dword(a))), Dword(a) - idaapi.get_func(Dword(a)).startEA) #print s f.write(s) f.write("\n") f.write("\n") print "%d chains found" % len(chains) print "%d long chains" % long_chains f.close()