def add_line(self, s=None): if not s: s = '' target = s.rsplit(':')[0].replace('\x01\x0c', '').replace('\x02\x0c', '') if target in self.block_list: self.AddLine( '----------------------------------------------------------------' ) if idc.Name(int(target, 16)) != '': self.AddLine(idc.Name(int(target, 16))) self.AddLine(s)
def renameDword(self): proc_addr = self._import_table.item(self._import_table.currentRow(), 3).text() proc_name = str(self._import_table.item(self._import_table.currentRow(), 2).text()) renamed = 0 if proc_addr: try: proc_addr = int(proc_addr, 16) proc_bin_str = " ".join([x.encode("hex") for x in struct.pack("<I", proc_addr)]) next_dword = idc.FindBinary(idc.MinEA(), idc.SEARCH_DOWN|idc.SEARCH_NEXT, proc_bin_str) while next_dword != idc.BADADDR: log.debug("Trying to fix-up 0x{:08x}".format(next_dword)) # DWORDs can be "inaccessible" for many reasons and it requires "breaking up" the data blobs # and manually fixing them # Reason 1: In a dword array in an unknown section if idc.isUnknown(next_dword): idc.MakeUnkn(next_dword, idc.DOUNK_EXPAND) idc.MakeDword(next_dword) # Reason 2: In a dword array in a data section elif idc.isData(next_dword): hd = idc.ItemHead(next_dword) idc.MakeDword(hd) idc.MakeDword(next_dword) # Reason 3: In a dword array in a code section (validate via "dd <dword>,") elif idc.isCode(next_dword) and idc.GetDisasm(next_dword).startswith("dd "): hd = idc.ItemHead(next_dword) idc.MakeDword(hd) idc.MakeDword(next_dword) # Only perform if idc.Name(next_dword).startswith(("off_", "dword_")) or idc.Name(next_dword) == "": success = idc.MakeNameEx(next_dword, proc_name, idc.SN_NOWARN|idc.SN_NON_AUTO) i = 0 new_proc_name = proc_name while not success and i < 10: new_proc_name = "{}{}".format(proc_name, i) success = idc.MakeNameEx(next_dword, new_proc_name, idc.SN_NOWARN|idc.SN_NON_AUTO) i += 1 if success: renamed += 1 item = self._import_table.item(self._import_table.currentRow(), 5) item.setText("{}, {}".format(str(item.text()), new_proc_name)) log.debug("DWORD @ 0x{:08x} now has name {}".format(next_dword, new_proc_name)) else: log.error("Unable to auto-rename successfully, terminating search") break else: log.debug("Value at 0x{:08x} does not meet renaming requirements".format(next_dword)) next_dword = idc.FindBinary(next_dword+4, idc.SEARCH_DOWN|idc.SEARCH_NEXT, proc_bin_str) except Exception, e: log.error("Error encountered: {}".format(e)) log.debug("Renamed {:d} instances of {}".format(renamed, proc_name))
def listUpdatedSymbols(elfPath, symTable): """ Searches through the symtable in the elfPath, and computes a list of name_eas, and their new names :param elfPath: path of the elf file to process :param symTable: use instead of recalculating from elf :return: list of (name_ea, new_name) """ output = [] if not symTable: symTable = getSymTable(elfPath) # compute all names in RAM and ROM names = [] for seg_ea in idautils.Segments(): # skip BIOS if seg_ea == 0: continue for head in idautils.Heads(seg_ea, idc_bc695.SegEnd(seg_ea)): if idc.Name(head): names.append((head, idc.Name(head))) for ea, name in names: eaInSymTable = ea in symTable if eaInSymTable or ea + 1 in symTable: # increment by 1 for thumb function symbols if ea + 1 in symTable and idc.isCode(idc.GetFlags(ea)): name_ea = ea + 1 else: name_ea = ea # check if the name exists in the symTable nameInSymTable = False globalSymbol = '' for symName, isLocal in symTable[name_ea]: if name == symName: nameInSymTable = True if not isLocal: globalSymbol = symName if nameInSymTable: continue # At this point, a name must have changed. if globalSymbol: output.append((ea, globalSymbol)) else: output.append((ea, symTable[name_ea][0][0])) return output
def actionF(): """ Shift+F - Display current file """ gfs = env['gameFiles'] gf = mt.ea2gf(here()) fileAddr = here() - gfs[gf][0] size = gfs[gf][1] - gfs[gf][0] # get last name found ea = here() while not idc.Name(ea): ea -= 1 relAddr = here() - ea print('%s+0x%X::<%s>+0x%X (%d%%)' % (gf, fileAddr, idc.Name(ea), relAddr, float(fileAddr) / size * 100))
def search(self): if self.ea: self.type = self.bin_data['ivars'][self.ea] self.name = idc.Name(self.ea).split('._')[-1] self.instance = idc.Name(self.ea).idc.replace('_OBJC_IVAR_$_', '').split('.')[0] return self elif self.type: ret = [] if self.type in self.bin_data['ivars2']: for ivar in self.bin_data['ivars2'][self.type]: iv = IVar(self.bin_data, ea=ivar).search() ret.append(iv) return ret
def _activate(self, ctx): node_id = lca_viewer.current_node_id lca_viewer.remove_target(lca_viewer[node_id]) lca_viewer.rebuild_graph() lca_viewer.Refresh() idaapi.msg("[LCA] Target Removed: {}\n".format( idc.Name(lca_viewer[node_id])))
def rename_functions(self, debug=True, dry_run=False): ''' Renames functions starting with "sub_" based on unique string xrefs. @debug - Set to False to supress debug output. @dry_run - Set to True to perform a dry run (functions will not actually be renamed). Returns the number of renamed functions. ''' count = 0 for (function_address, function_name) in self.func2str_mappings().iteritems(): if idc.Name(function_address).startswith("sub_"): if dry_run == True or idc.MakeName(function_address, function_name) == True: if debug == True: print "0x%.8X => %s" % (function_address, function_name) count += 1 if debug == True: print "Renamed %d functions based on unqiue string xrefs!" % count return count
def load(self): self._import_table.clear() self._import_table.setHorizontalHeaderLabels( ["Address", "DLL", "ProcName", "ProcAddress", "Type", "IDA Name"]) self._import_table.itemDoubleClicked.connect(self.clickRow) self._import_table.setRowCount(len(self.parent.impts)) self._import_table.setAlternatingRowColors(True) row = 0 for impt in self.parent.impts: self._import_table.setItem(row, 0, qt.qtablewidgetitem()(impt["addr"])) self._import_table.setItem(row, 1, qt.qtablewidgetitem()(impt["dll"])) self._import_table.setItem( row, 2, qt.qtablewidgetitem()(impt["proc_name"])) self._import_table.setItem( row, 3, qt.qtablewidgetitem()(impt["proc_address"])) self._import_table.setItem(row, 4, qt.qtablewidgetitem()(impt["type"])) self._import_table.setItem( row, 5, qt.qtablewidgetitem()(idc.Name(int(impt["proc_address"], 16)))) self._import_table.resizeRowToContents(row) row += 1 self._import_table.setSortingEnabled(True)
def _name(self, ea): name = idc.Name(ea) if not name: name = idc.GetFuncOffset(ea) if not name: name = '0x%X' % ea return name
def _find_and_plot_paths(self, sources, targets, pfc=pathfinder.FunctionPathFinder): results = [] for target in targets: pf = pfc(target) for source in sources: s = time.time() r = pf.paths_from(source) e = time.time() #print "paths_from took %f seconds." % (e-s) if r: results += r else: name = idc.Name(target) if not name: name = "0x%X" % target print "No paths found to", name if results: # Be sure to close any previous graph before creating a new one. # Failure to do so may crash IDA. try: self.graph.Close() except: pass self.graph = pathfinder.PathFinderGraph(results, 'Path Graph', pf.colorize) self.graph.Show()
def populate_items(self): self.items = [] for function in self.lb.functions: candidates = [] if function.leaf: if function.xrefs < self.min_xrefs: continue if function.loop == False and self.must_have_loop == True: continue for candidate in function.candidates: candidates.append(candidate) if function.xrefs: xrefs = str(function.xrefs) else: xrefs = "*" if function.argc is not None: argc = str(function.argc) else: argc = "*" if function.leaf: loops = str(function.loop) else: loops = "*" name = idc.Name(function.start) self.items.append([ name, xrefs, argc, loops, ', '.join(candidates), function.leaf ])
def _getArrDisasm(self, elemsPerLine, dataType): # type: (int, int, str) -> str """ :param ea: linear address to disassemble :param elemsPerLine: number of elements to disassemble in one line :param dataType: 'DCB', 'DCW', 'DCD', etc :return: disassembly string """ # Grab all of the bytes in the array arr = self.getContent() # whether to display a name, or data, is determiend by the xrefs from this item! xrefs = self.getXRefsFrom() # only bother to check for names if it's an array of words wordArray = dataType == 'DCD' # generate disassembly for array disasm = dataType + ' ' elemIndex = 0 for elem in arr: # tab if new line if disasm[-1] == '\n': disasm += '\t%s' % (dataType + ' ') # add element and increment counter until new line # if it's a pointer and defined as an xref, display its label not just the number # isPointer is a bottleneck call, so prefer to call it last if wordArray and (elem in xrefs[1] or elem in xrefs[0]) and self.isPointer(elem): # TODO: maybe you ahould get the name of Data.Data(elem) also, for +index elemEA = Data(elem).ea name = idc.Name(elemEA) if name: offset = elem - elemEA if offset != 0: offset = '+%d' % offset else: offset = '' disasm += "%s%s, " % (name, offset) else: disasm += '0x%X, ' % elem else: disasm += '0x%X, ' % elem elemIndex += 1 # if we reach the number of elements a line, we add a new line if elemIndex % elemsPerLine == 0: # replace ", " at the end if present disasm = disasm[len(disasm) - 2:] == ', ' and disasm[:-2] or disasm # advance for the next line disasm += "\n" # remove ", " at the end if present disasm = disasm[len(disasm) - 2:] == ', ' and disasm[:-2] or disasm # remove new line at the end if present disasm = disasm[len(disasm) - 1:] == '\n' and disasm[:-1] or disasm return disasm
def remFuncChunks(): """ deletes all functions that have function chunks in them and appends "function_chunks_" to their names """ foundProblem = False for seg in idautils.Segments(): for ea in idautils.Functions(start=idc.SegStart(seg), end=idc.SegEnd(seg)): f = idaapi.get_func(ea) # chunk f if f.tailqty > 0: foundProblem = True print("Removing chunk function @ %07X" % f.startEA) idaapi.del_func(f.startEA) name = idc.Name(f.startEA) if "function_chunks_" not in name: newName = 'function_chunks_%s' % name print("Renaming %s -> %s" % ((name, newName))) idc.MakeName(f.startEA, newName) if foundProblem: print("Removed all function chunks!") else: print("No function chunks detected!")
def get_op(ea, op, stkvars=None): '''ea_t -> int -> opt:{int : tinfo_t} -> op_ret''' cmd = idautils.DecodeInstruction(ea) cmd.Operands = get_operands(cmd) # for mips_op_hack op = mips_op_hack(cmd, op) opd = cmd[op] if opd.type == idaapi.o_reg: # gpr, XXX sorta MIPS-specific return op_ret(op_ty.reg, regs.gpr(opd.reg), 0) elif opd.type == idaapi.o_idpspec1: # fpr, XXX sorta MIPS-specific return op_ret(op_ty.reg, regs.fpr(opd.reg), 0) elif opd.type in [idaapi.o_near, idaapi.o_mem]: return op_ret(op_ty.name, idc.Name(opd.addr), 0) elif idc.isStkvar1(idc.GetFlags(ea)): # IDA seems to set this flag even for operands beyond the second, # i.e. both of these are true for isStkvar1: # .text:10003A84 sd $a1, 0x2E0+var_58($sp) # .text:10003A68 addiu $a1, $sp, 0x2E0+var_2D8 try: func = idaapi.get_func(ea) off = idaapi.calc_stkvar_struc_offset(func, ea, op) (name, ti) = stkvars[off] return op_ret_for_ti(ti, name, off, off) except KeyError: raise OperandUnresolvableError('unable to get operand %u at %s' % (op, idc.atoa(ea))) elif opd.type in [idaapi.o_imm, idaapi.o_displ]: return cpu_ida.ida_current_cpu().data.get_op_addrmode(ea, op, cmd) else: raise OperandUnresolvableError('unable to get operand %u at %s' % (op, idc.atoa(ea)))
def populate_items(self): self.items = [] for (func_ea, xrefs) in self.profile.functions.iteritems(): if not self.function_filters or func_ea in self.function_filters: orig_items_len = len(self.items) for xref in xrefs: if not self.string_filters or xref.string in self.string_filters: if xref.type == callable: display_string = xref.string + "()" elif xref.type == str: display_string = '"%s"' % xref.string else: display_string = xref.string self.items.append([ idc.Name(func_ea), display_string, xref.xref, func_ea ]) if len(self.items) != orig_items_len: self.items.append([ self.DELIM_COL_1, self.DELIM_COL_2, idc.BADADDR, idc.BADADDR ]) # Remove the last delimiter column if self.items and self.items[-1][-1] == idc.BADADDR: self.items.pop(-1)
def actionT(): """ Test Action. Scratchpad, you can erase this. """ # for ea in range(0x3005B00, 0x3007FFF): # if idc.Name(ea): # print('.equ %s, 0x%07x' % (idc.Name(ea), ea)) # print(mt.getLabelsWithSpaceDirective(0x2009450, 0x203a9b0)) # print(mt.getLabelsWithSpaceDirective(0x203C4A0, 0x203F7E4)) global currSymbols, lastDump if not currSymbols: currSymbols = dis._listUpdatedSymbols('dev/dis/bn6f.elf') if not lastDump: lastDump = dis._listUpdatedSymbols('dev/dis/bn6f_ida.elf') # separate changes made by IDA from external changes newSymbols = [] for symbol in (currSymbols or lastDump): if symbol not in lastDump: newSymbols.append(symbol) for ea, names in newSymbols: if (len(names) == 1 and '_' in names[0][0] and names[0][0][:names[0][0].index('_')+1] in ['loc_', 'unk_', 'byte_', 'word_', 'dword_', 'locret_'] ): continue print('%07X <%s>: ' % (ea, idc.Name(ea)) + str(names))
def _activate(self, ctx): if lca_plugin._lca_viewer: with ignored(KeyError): lca_plugin._lca_viewer.add_target(ctx.cur_ea) lca_plugin._lca_viewer.rebuild_graph() idaapi.msg("[LCA] Target Added: {}\n".format( idc.Name(ctx.cur_ea)))
def visit_expr(self, i): if i.op == idaapi.cot_asg: if i.x.op == idaapi.cot_var: if i.x.v.idx == self.var_expr.v.idx: self.ret_expr = i.y elif i.x.op == idaapi.cot_ptr: if i.x.x.op == idaapi.cot_var: if i.x.x.v.idx == self.var_expr.v.idx: self.ret_expr = i.y elif i.x.x.op == idaapi.cot_cast: if i.x.x.x.op == idaapi.cot_var: if i.x.x.x.v.idx == self.var_expr.v.idx: self.ret_expr = i.y elif i.op == idaapi.cot_call: if i.x.helper in HELPER_COPY or idc.Name( i.x.obj_ea) in FUNC_COPY: if i.a[0].op == idaapi.cot_var: if i.a[0].v.idx == self.var_expr.v.idx: self.ret_expr = i.a[1] elif i.a[0].op == idaapi.cot_cast or i.a[ 0].op == idaapi.cot_ref: if i.a[0].x.op == idaapi.cot_var: if i.a[0].x.v.idx == self.var_expr.v.idx: self.ret_expr = i.a[1] elif i.a[0].x.op == idaapi.cot_ref: if i.a[0].x.x.op == idaapi.cot_var: if i.a[0].x.x.v.idx == self.var_expr.v.idx: self.ret_expr = i.a[1] if i.ea == self.stop_ea: return 1 return 0
def __init__(self, **kwargs): self.argc = None self.loop = False self.leaf = False self.xrefs = None self.fmtarg = None self.start = idc.BADADDR self.end = idc.BADADDR self.candidates = {} self.argp = ArgParser() for (k, v) in kwargs.iteritems(): setattr(self, k, v) self.name = idc.Name(self.start) if self.xrefs is None: self.xrefs = len([x for x in idautils.XrefsTo(self.start)]) if not self.candidates: for prototype in self.PROTOTYPES: if self.leaf and prototype.fmtarg is None and prototype.argc == self.argc and prototype.loop == self.loop: if self.candidates.has_key(prototype.name): self.candidates[prototype.name] += 1 else: self.candidates[prototype.name] = 1 elif not self.leaf and self.fmtarg is not None and prototype.fmtarg is not None and self.fmtarg == prototype.fmtarg: if self.candidates.has_key(prototype.name): self.candidates[prototype.name] += 1 else: self.candidates[prototype.name] = 1
def get_names(start, end): names = {} for addr in xrange(start, end): name = idc.Name(addr) if name != "": names[addr] = name return names
def currentType(self, check=CHECK_NONE, **kwargs): tnm = None if self.typeid: tnm = self.typeid else: nm = idc.Name(idaapi.get_screen_ea()) if nm and nm.startswith('vtbl_'): tnm = nm[5:] if not tnm: obj = MODS.explore.Explore(self.typeid).getVar() if obj: tnm = obj[-1].get('type') if not tnm: raise self.TypeNotExistsError("Type not found") tnm = tnm.replace('*', '').strip() tpdescr = {'name': tnm} sid = idc.GetStrucIdByName(tnm) if sid != idc.BADADDR: tpdescr['id'] = sid svid = idc.GetStrucIdByName(tnm + 'Vtbl') if svid != idc.BADADDR: tpdescr['vtblid'] = svid tpdescr['vtblnm'] = tnm + 'Vtbl' else: tpdescr = self.getTypeVtbl(tpdescr) ea = idc.LocByName('vtbl_' + tnm) if ea != idc.BADADDR: tpdescr['vtblea'] = ea if check == self.CHECK_VTBL and not tpdescr.get('vtblea'): raise self.TypeNotExistsError("vtbl not found", tnm) return tpdescr
def get_new_operators(): newoperators = set() for i, func_addr in enumerate(idautils.Functions(plt_start, plt_end)): demangled_name = idc.Demangle(idc.Name(func_addr), 0) if demangled_name is not None and "operator new" in demangled_name: newoperators.add(func_addr) return newoperators
def visit_expr(self, i): """ From FLARE article Search for dw1234 = GetProcAddress("LoadLibrary") """ if i.op == idaapi.cot_call: # look for calls to GetProcAddress if idc.Name(i.x.obj_ea) == "GetProcAddress": # ASCSTR_C == 0 # Check to see if the second argument is a C string if idc.GetStringType(i.a[1].obj_ea) == 0: targetName = idc.GetString(i.a[1].obj_ea, -1, 0) # Found function name # Look for global assignment parent = self.cfunc.body.find_parent_of(i) if parent.op == idaapi.cot_cast: # Ignore casts and look for the parent parent = self.cfunc.body.find_parent_of(parent) if parent.op == idaapi.cot_asg: # We want to find the left hand side (x) self.results[targetName] = parent.cexpr.x.obj_ea idc.MakeName(parent.cexpr.x.obj_ea, targetName) return 0
def update(self, **kwargs): tp = self.currentType(self.CHECK_VTBL, **kwargs) tp = self.checkVtblStruct(tp) Logger.debug("Updating class %s", str(tp)) ea = tp['vtblea'] nm = None funcs = [] while (not nm): ofs = idc.Qword(ea) if not ofs or ofs == idc.BADADDR: break func = FuncDescr.fromEA(ofs) if self.untouchedFunc(func.name): func.checkThis(tp['name'] + '*') Logger.debug("found vtbl function: %s", str(func)) name = func.name i = 2 while name in funcs: name = func.name + "_" + str(i) i += 1 self.setStrucPntr(tp['vtblid'], ea - tp['vtblea'], name, func.buildType(True)) funcs += [name] ea += 8 nm = idc.Name(ea)
def get_node_name(self, ea): name = idc.Name(ea) if not name: name = idc.GetFuncOffset(ea) if not name: name = "0x%X" % ea return name
def updateIIDs(self, **kwargs): h = GuidHelper() inst = self.struct.instances() inst.update(self.struct2.instances()) busy = [] for x in inst: n = h.guidOfVals((inst[x]['Data1'], inst[x]['Data2'], inst[x]['Data3'], inst[x]['Data4'])) found = h.findGuid(n) if found: nm = found['name'] for c in " ,.:;-+<>/*": nm = nm.replace(c, '_') for c in nm: if ord(c) > 0x7F: nm = nm.replace(c, '_') if found['prefix'] and not nm.startswith(found['prefix']): nm = found['prefix'] + "_" + nm else: nm = "iid_" + str(n).replace('-', '_') rnm = nm if nm: if idc.Name(x).startswith(nm): busy += [nm] continue i = 2 while nm in busy and i < 10: nm = rnm + "__" + str(i) i += 1 while (idaapi.get_name_ea(idc.BADADDR, nm) != idc.BADADDR or not idc.MakeName(x, nm)) and i < 10: nm = rnm + "__" + str(i) i += 1 busy += [nm]
def _find_and_plot_paths(self, sources, targets, klass=AlleyCatFunctionPaths): results = [] for target in targets: for source in sources: s = time.time() r = klass(source, target).paths e = time.time() print "Found %d paths in %f seconds." % (len(r), (e - s)) if r: results += r else: name = idc.Name(target) if not name: name = "0x%X" % target print "No paths found to", name if results: # Be sure to close any previous graph before creating a new one. # Failure to do so may crash IDA. try: self.graph.Close() except: pass self.graph = AlleyCatGraph(results, 'Path Graph') self.graph.Show()
def find_and_plot_paths(sources, targets, klass=AlleyCatFunctionPaths): results = [] for target in targets: for source in sources: s = time.time() r = klass(source, target).paths e = time.time() print 'Found %d paths in %f seconds.' % (len(r), (e - s)) if r: results += r else: name = idc.Name(target) if not name: name = '0x%X' % target print 'No paths found to', name if not results: return # Be sure to close any previous graph before creating a new one. # Failure to do so may crash IDA. try: idapathfinder_t.graph.Close() except: pass idapathfinder_t.graph = AlleyCatGraph(results, 'Path Graph') idapathfinder_t.graph.Show()
def parse_function_tables(self): count = 0 for pattern in self.search(): name2func = {} ea = pattern.start while ea < pattern.stop: string_address = idc.Dword(ea + (pattern.name_element * pattern.element_size)) function_address = idc.Dword(ea + (pattern.function_element * pattern.element_size)) new_function_name = idc.GetString(string_address) current_function_name = idc.Name(function_address) if not self.valid_function_name(new_function_name): print "ERROR: '%s' is not a valid function name. This is likely not a function table, or I have parsed it incorrectly!" % new_function_name print " Ignoring all entries in the structures between 0x%X and 0x%X.\n" % ( pattern.start, pattern.stop) name2func = {} break elif current_function_name.startswith("sub_"): name2func[new_function_name] = function_address ea += (pattern.num_elements * pattern.element_size) for (name, address) in name2func.iteritems(): print "0x%.8X => %s" % (address, name) idc.MakeName(address, name) count += 1 print "Renamed %d functions!" % count
def dbg_bpt(self, tid, ea): self.ea = ea try: if self.done: print('should be done') return 0 try: self.func_name = None if ea in self.replay_handlers: self.func_name = idc.Name(ea) if not self.do_replay: next(self.hx) else: self.replay_handler(ea) except Exception as e: self.done = 1 tb.print_exc() except Exception as e: tb.print_exc() self.done = 1 print('FAILURE') return 0