def _btn_trace_color_clicked(self): col = 0xccffcc col2 = 0xbbeebb if False: for ea, basic_block in self.infoparser.basic_blocks.iteritems(): while ea != idaapi.BADADDR: idc.set_color(ea, idc.CIC_ITEM, col) ea = idc.next_head(ea, basic_block['end']) for target_pc, flow in self.infoparser.flows.iteritems(): refs = [] for xref in idautils.XrefsTo(target_pc): refs.append(xref.frm) for jump_from_pc, flowtype in flow.iteritems(): if jump_from_pc in refs: continue if ida_ua.ua_mnem(jump_from_pc) == 'call': flowtype = idaapi.fl_CN else: flowtype = idaapi.fl_JN idc.set_color(jump_from_pc, idc.CIC_ITEM, col2) idc.AddCodeXref(jump_from_pc, target_pc, flowtype)
def add_call_xref(frm, to): """ Add XREF to a call function @param frm: EA of From address (The CALL instruction address) @param to: EA of To Address (The called funciton address) @return: True if XREF was added successfully, otherwise False """ return idc.AddCodeXref(frm, to, 0x31)
def objc_msgsend_xref(self, call_ea, objc_self, objc_selector, create_xref=True): ''' This function will create a code xref to an objc method call_ea : location of call/jmp objc_msgsend (regardless of direct/indirect) objc_self: ea where RDI is set to static value (or that we find it's from a previous call or the RDI of the current function) objc_selector: ea where RSI is set to static value This ignores the RDI register, which is the `self` argument to objc_msgsend() id objc_msgSend(id self, SEL op, ...); So far, this seems to be fine as far as the cross-references are concerned. ''' # get instruction mnemonic at address - I guess to check and make sure # it's mov rsi, blah instruction = idc.GetDisasm(objc_selector) if self.debugflag: print ">>> objc_msgsend_xref 0x%08x %s" % (objc_selector, instruction) # get outbound references in the appropriate segment # implicit assumption is there is exacltly one target_selref = None for _ref in idautils.DataRefsFrom(objc_selector): if idc.SegName(_ref) == "__objc_selrefs": target_selref = _ref if not target_selref: return False # get outbound references in the appropriate segment # implicit assumption is there is exacltly one target_methname = None for _ref in idautils.DataRefsFrom(target_selref): if idc.SegName(_ref) == "__objc_methname": target_methname = _ref if not target_methname: return False # get inbound references # __objc_const # must be a __objc2_meth # I hope this method is correct to find __objc2_meth structs # BUG: when the binary has mutiple objc methods by the same name, this logic fails # Track RDI register. have to figure out what instance/class is referenced objc2_meth_struct_id = ida_struct.get_struc_id("__objc2_meth") meth_struct_found = False target_method = None for _ref in idautils.DataRefsTo(target_methname): # multiple may match # we care about the __obj2_meth struct found in references if idc.SegName(_ref) == "__objc_const": # check the outbound references for _meth_ref in idautils.DataRefsFrom(_ref): if _meth_ref == objc2_meth_struct_id: meth_struct_found = True if meth_struct_found: # only do this once # TODO: check against RDI here to make sure it's the proper class # meth_struct_found = False for _meth_ref in idautils.DataRefsFrom(_ref): # assumption made on function always being in text segment if idc.SegName(_meth_ref) == "__text": # save the method implementation -- this is the function ptr if self.debugflag: print "0x%08x checking for the proper method -- %s" % ( _meth_ref, idc.get_name( idc.get_func_attr( _meth_ref, idc.FUNCATTR_START))) target_method = _meth_ref if not target_method: return False # After dereferencing across the IDB file, we finally have a target function. # In other words, if there isn't a method **in this binary** no xref is made (IDA only loads one binary?) # that is referenced from the mov rsi, <selector> instruction if self.debugflag: print "Found target method 0x%08x" % target_method if create_xref: idc.AddCodeXref(objc_selector, target_method, idc.fl_CF) return True
def import_branches(data_json, resolver): image_functions = set(idautils.Functions()) image_base = idaapi.get_imagebase() n_new_functions = 0 n_new_xrefs = 0 for element in data_json["indirect_branches"]: # Rebase all the addresses. call_addr = resolver.rebase(element["from"], image_base) refs = map(lambda x: resolver.rebase(x, image_base), element["to"]) # If not present in ida's function list, add it. if not call_addr in image_functions: # assert idc.MakeCode(call_addr) != 0 # assert idc.MakeFunction(call_addr) != 0 # image_functions.add(call_addr) # print "Creating function @ %.16x" % call_addr n_new_functions += 1 # Get the references function_xrefs = [x.frm for x in idautils.XrefsTo(call_addr, 0)] # Add the references if missing. for ref in refs: if not ref in function_xrefs: print "Creating XREF from %.16x to %.16x" % (call_addr, ref) # Make code just in case. idc.MakeCode(call_addr) idc.MakeCode(ref) idc.AddCodeXref(call_addr, ref, idc.XREF_USER | idc.fl_CN) n_new_xrefs += 1 for element in data_json["direct_branches"]: # Rebase all the addresses. func_addr = resolver.rebase(element["function"], image_base) refs = map(lambda x: resolver.rebase(x, image_base), element["references"]) # If not present in ida's function list, add it. if not func_addr in image_functions: # assert idc.MakeCode(func_addr) != 0 # assert idc.MakeFunction(func_addr) != 0 # image_functions.add(func_addr) print "Creating function @ %.16x" % func_addr n_new_functions += 1 # Get the references function_xrefs = [x.frm for x in idautils.XrefsTo(func_addr, 0)] # Add the references if missing. for ref in refs: if not ref in function_xrefs: print "Creating XREF from %.16x to %.16x" % (ref, func_addr) # idc.AddCodeXref(ref, func_addr, idc.XREF_USER | idc.fl_CN) n_new_xrefs += 1 print "Created %d new functions" % n_new_functions print "Created %d new xrefs" % n_new_xrefs
def NasmAssemble(self, function_ea, write_ea): dir = self.opty_dir nasm = "C:\\Program Files\\nasm\\nasm.exe" arg1 = "f_%08x.asm" % function_ea arg2 = "-o f_%08x.o" % function_ea arg3 = "-l f_%08x.lst" % function_ea arg4 = "-Ox" orig_dir = os.getcwd() os.chdir(dir) idc.Batch(0) while 1: try: p = subprocess.Popen([nasm, arg1, arg2, arg3, arg4], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) o, e = p.communicate() if o != "": print o if e != "": print e fop = open("f_%08x.o" % function_ea, "rb") ans = idaapi.askyn_c( 0, "HIDECANCEL\nDo you want to manually edit function before writing to IDA?" ) if ans == 1: os.startfile(arg1, "open") idaapi.warning( "Press OK button when you're done editing file.") fop.close() continue else: idc.Batch(1) break except: error_msg = '\n'.join(e.split("\n")[:15]) os.startfile(arg1, "open") ans = idaapi.askyn_c( 1, """HIDECANCEL\nNASM failed to assemble [f_%08x.o] file. You can manually edit and NASM this file [f_%08x.asm] and click Yes when you're done. File is located in directory where your IDB is located. If you want to skip this function press No. Nasm output: %s""" % (function_ea, function_ea, error_msg)) if ans == 1: continue else: os.chdir(orig_dir) idc.Batch(1) return None os.chdir(orig_dir) print ">>>Writing function [%08x] @ [%08x]" % (function_ea, write_ea) data = fop.read() data_len = len(data) for offset in xrange(0, data_len): idc.PatchByte(write_ea + offset, ord(data[offset])) fop.close() idc.MakeCode(write_ea) fp = open("%s\\f_%08x.lst" % (dir, function_ea), "r") asm_lst = fp.read() base_addr = re.search(r"ORG ([\dABCDEF]+)H", asm_lst).group(1) base_addr = int(base_addr, 16) for jt in self.jmp_table_refs: m = re.search(r"\s*\d+\s+([\dABCDEF]{8}).*?%s" % re.escape(jt), asm_lst, re.IGNORECASE) if m != None: jt_ea = int(m.group(1), 16) jt_str = re.search(r"SJ_.{8}", jt, re.IGNORECASE).group() for m in re.findall( r"(?i)\n\s*\d+\s+[\dABCDEF]{8}\s+.*?\s+%s" % re.escape(jt_str), asm_lst): r = re.search(r"\d+\s([\dABCDEF]{8})", m.strip(), re.IGNORECASE).group(1) #print "AddCodeXref(0x%08x, 0x%08x, idc.XREF_USER)" % (jt_ea+base_addr, idc.Dword(int(r, 16)+base_addr)) idc.AddCodeXref(jt_ea + base_addr, idc.Dword(int(r, 16) + base_addr), idc.XREF_USER) else: raise MiscError for line in asm_lst.split("\n"): comment = re.search(r"###(.*?)###", line) if comment != None: data = re.search(r"\s*\d+\s([\dABCDEF]+)\s([\dABCDEF\(\)]+)", line) if data != None: offset = int(data.group(1), 16) idc.MakeComm(write_ea + offset, comment.group(1)) fp.close() return write_ea + data_len + 10
def scanDataForRelocs(M, D, start, end, new_eas, seg_offset): i = start while i < end: more_dref = [d for d in idautils.DataRefsFrom(i)] dref_size = idc.ItemSize(i) or 1 if len(more_dref) == 0 and dref_size == 1: dword = readDword(i) DEBUG("Testing address: {0:x}... ".format(i)) # check for unmakred references if isInData(dword, dword+1): idc.MakeDword(i) idc.add_dref(i, dword, idc.XREF_USER|idc.dr_O) DEBUG("making New Data Reference at: {0:x} => {1:x}\n".format(i, dword)) dref_size = 4 elif isInternalCode(dword): idc.MakeDword(i) idc.AddCodeXref(i, dword, idc.XREF_USER|idc.fl_F) DEBUG("making New Code Reference at: {0:x} => {1:x}\n".format(i, dword)) dref_size = 4 else: DEBUG("not code or data ref\n") i += dref_size def insertReference(M, D, ea, pointsto, seg_offset, new_eas): # do not make code references for mid-function code accessed via a JMP -- # they will be found via the jumptable code. This prevents the insertion # of lots of extra code, but could be wrong for some cases if ea in ACCESSED_VIA_JMP and not isStartOfFunction(pointsto): # bail only if we are access via JMP and not the start # of a function DEBUG("\t\tNOT ADDING REF: {:08x} -> {:08x}\n".format(ea, pointsto)) return DEBUG("\t\tFound a probable ref from: {0:x} => {1:x}\n".format(ea, pointsto)) real_size = idc.ItemSize(pointsto) DEBUG("\t\tReal Ref: {0:x}, size: {1}\n".format(pointsto, real_size)) insertRelocatedSymbol(M, D, pointsto, ea, seg_offset, new_eas, real_size) def checkIfJumpData(ea, size): """ Loop through ea to ea+size, and if every dword there points to code, this is a jump data section returns true or false and list of recovered ea => destination mappings """ table_map = {} for jea in xrange(ea, ea+size, 4): dword = readDword(jea) if not isInternalCode(dword): DEBUG("Dword {:x} does not point to code, not a table\n".format(dword)) return False, table_map table_map[jea] = dword return True, table_map i = start while i < end: DEBUG("Checking address: {:x}\n".format(i)) dref_size = idc.ItemSize(i) or 1 if dref_size > 4 and dref_size % 4 == 0: DEBUG("Possible table data at {:x}; size: {:x}\n".format(i, dref_size)) (is_table, addrs) = checkIfJumpData(i, dref_size) if is_table: DEBUG("Its a table, adding {} references\n".format(len(addrs))); for ta in sorted(addrs.keys()): insertReference(M, D, ta, addrs[ta], seg_offset, new_eas) else: DEBUG("Its not a table\n"); elif dref_size == 4: more_cref = [c for c in idautils.CodeRefsFrom(i,0)] more_dref = [d for d in idautils.DataRefsFrom(i)] more_dref.extend(more_cref) if len(more_dref) > 0: DEBUG("\t\tFound a probable ref from: {0:x} => {1:x}\n".format(i, more_dref[0])) if len(more_dref) == 1: insertReference(M, D, i, more_dref[0], seg_offset, new_eas) else: DEBUG("\t\tWARNING: Possible data ref problem\n"); insertReference(M, D, i, more_dref[0], seg_offset, new_eas) i += dref_size
def addxref(x, y, z, i, k): idc.AddCodeXref(x, y, idc.XREF_USER | idc.fl_F) idc.AddCodeXref(y, z, idc.XREF_USER | idc.fl_F) print 'add xref for', k