def _handle_calls(self, fn, fn_an): num_calls = len(fn_an['calls']) if num_calls != 1: return dis = fn_an['calls'][0] if dis.Op1.type not in (o_imm, o_far, o_near, o_mem): return ea = dis.Op1.value if not ea and dis.Op1.addr: ea = dis.Op1.addr if idaapi.has_dummy_name(idaapi.getFlags(ea)): return # TODO: check is there jmp, push+retn then don't rename the func if fn_an['strange_flow']: return possible_name = idaapi.get_ea_name(ea) if not possible_name or possible_name in blacklist: return normalized = self.normalize_name(possible_name) # if self._cfg.get('auto_rename'): if len(fn_an['math']) < self._MIN_MAX_MATH_OPS_TO_ALLOW_RENAME: idaapi.do_name_anyway(fn.startEA, normalized) # TODO: add an API to the view print 'fn: %#08x: %d calls, %d math%s possible name: %s, normalized: %s' % ( fn.startEA, len(fn_an['calls']), len(fn_an['math']), 'has bads' if fn_an['has_bads'] else '', possible_name, normalized)
def rename(self, name=None): """ Renames (and comments) the string variable in IDA. :param str name: New name to given encoded string. (defaults to decoded_string) """ name = name or self.display_name if not name: append_debug( 'Unable to rename encoded string due to no decoded string: {!r}'.format(self), log_token='[!]') return # Add comment comment = '"{}"'.format(name[:self._MAX_COMMENT_LENGTH]) if len(name) > self._MAX_COMMENT_LENGTH: comment += ' (truncated)' if self.string_location not in (INVALID, UNUSED): idc.MakeRptCmt(self.string_location, comment) if self.string_reference not in (INVALID, UNUSED): idc.MakeRptCmt(self.string_reference, comment) # Set variable name if self.string_location not in (INVALID, UNUSED): idaapi.do_name_anyway(self.string_location, name[:self._MAX_NAME_LENGTH])
def set_name(address, name, anyway=False): """Set the name of an address. Sets the name of an address in IDA. If the name already exists, check the `anyway` parameter: True - Add `_COUNTER` to the name (default IDA behaviour) False - Raise an `exceptions.SarkErrorNameAlreadyExists` exception. :param address: The address to rename. :param name: The desired name. :param anyway: Set anyway or not. Defualt `False`. :return: None """ success = idaapi.set_name(address, name, idaapi.SN_NOWARN | idaapi.SN_NOCHECK) if success: return if anyway: success = idaapi.do_name_anyway(address, name) if success: return raise exceptions.SarkSetNameFailed("Failed renaming 0x{:08X} to {!r}.".format(address, name)) raise exceptions.SarkErrorNameAlreadyExists( "Can't rename 0x{:08X}. Name {!r} already exists.".format(address, name))
def set_name(address, name, anyway=False): """Set the name of an address. Sets the name of an address in IDA. If the name already exists, check the `anyway` parameter: True - Add `_COUNTER` to the name (default IDA behaviour) False - Raise an `exceptions.SarkErrorNameAlreadyExists` exception. Args address: The address to rename. name: The desired name. anyway: Set anyway or not. Defualt ``False``. """ success = idaapi.set_name(address, name, idaapi.SN_NOWARN | idaapi.SN_NOCHECK) if success: return if anyway: success = idaapi.do_name_anyway(address, name) if success: return raise exceptions.SarkSetNameFailed( "Failed renaming 0x{:08X} to {!r}.".format(address, name)) raise exceptions.SarkErrorNameAlreadyExists( "Can't rename 0x{:08X}. Name {!r} already exists.".format( address, name))
def rename(self, new_name): ''' Description: Attempts to apply new_name to the object at <ea>. If more than one object starts at <ea>, the largest object will be renamed. If that name already exists, let IDA resolve the collission and then return that name. If new_name is "", reset the name to IDA's default. Input: new_name - The desired new name for the function. Output: The name that ended up getting set (unless no name was set, then return None). ''' if new_name == '': if idaapi.set_name(self.function_obj.startEA, new_name): return idaapi.get_name(self.function_obj.startEA, self.function_obj.startEA) else: append_debug('Failed to reset name at 0x%X' % self.function_obj.startEA) elif idaapi.do_name_anyway(self.function_obj.startEA, new_name): self.name = idaapi.get_name(self.function_obj.startEA, self.function_obj.startEA) if self.name != new_name: append_debug('IDA changed name "%s" to "%s"' % (new_name, self.name)) return self.name else: append_debug('Failed to rename at 0x%X' % self.function_obj.startEA)
def activate(self, ctx): sel = [] for idx in ctx.chooser_selection: # rename the function ea = get_name_ea_simple(self.items[idx][2]) sfname = str(self.items[idx][4]) #set_name(ea, sfname) idaapi.do_name_anyway(ea, sfname) success('{:#x}: renamed to {}'.format(ea, sfname)) # set the function prototype sptype = str(self.items[idx][5]) if sptype != 'None': tinfo = idaapi.tinfo_t() idaapi.parse_decl2(idaapi.cvar.idati, sptype, tinfo, 0) #idaapi.apply_callee_tinfo(ea, tinfo) if idaapi.apply_tinfo(ea, tinfo, 0): success('{:#x}: function prototype set to {}'.format( ea, sptype)) else: error( '{:#x}: function prototype set FAILED (maybe you should import the types?)' .format(ea)) if ask_yn(0, 'Do you import types from the secondary idb?' ) == 1: if self.import_types(): tinfo = idaapi.tinfo_t() idaapi.parse_decl2(idaapi.cvar.idati, sptype, tinfo, 0) if idaapi.apply_tinfo(ea, tinfo, 0): success('{:#x}: function prototype set to {}'. format(ea, sptype)) else: error( '{:#x}: function prototype set FAILED again' .format(ea)) # insert the comment score = self.items[idx][0] mmatch = self.items[idx][1] cmt = 'fn_fuzzy: ssdeep={}, machoc={}'.format(score, mmatch) set_func_cmt(ea, cmt, 1) #set_decomplier_cmt(ea, cmt) # not sure how to avoid orphan comment # update the Choose rows ida_kernwin.refresh_chooser(self.title)
def main(): info('start') eh = flare_emu.EmuHelper() # search the decoding functions cnts = {} for fva in Functions(): #if fva != 0x1000A19F: # continue if idc.get_func_flags(fva) & (idc.FUNC_LIB | idc.FUNC_THUNK): continue size = 0 fn_bytes = idc.get_bytes(fva, get_func_attr(fva, FUNCATTR_END) - fva) for pname, pat in g_pats.items(): m = pat.search(fn_bytes) if m: try: if pname == 'sub': key = int.from_bytes(m.group(1), 'little') size = int.from_bytes(m.group(2), 'little') else: key = None size = int.from_bytes(m.group(1), 'little') except ValueError: pass else: print('\n') info('{:#x}: {}-encoded function detected (size = {:#x})'. format(fva, pname, size)) idaapi.do_name_anyway( fva, 'fn_ADVobfuscator_decode_{}_len{}'.format(pname, size)) cnt = emulate(pname, eh, fva, size, key) if cnts.get(pname): cnts[pname] += cnt else: cnts[pname] = cnt break info('number of decoded strings: {}'.format(cnts)) info('done')
def handle_string(self, offb, op, addr): sym_addr = addr symbols = self.get_string_symbols(addr) if symbols: for i, symbol in enumerate(symbols): if symbol.is_var(): var_addr = self.rebase_var_addr(symbol.nvar) ua_add_dref(offb, var_addr, dr_R) sym_addr += 4 elif symbol.is_string(): n = str_to_number(symbol) if n is None: ua_add_dref(offb, sym_addr, dr_R) string_name = canonize_name(symbol) idaapi.make_ascii_string(sym_addr, len(symbol), ASCSTR_C) idaapi.do_name_anyway(sym_addr, string_name[:15]) sym_addr += len(symbol) else: sym_addr += 4
def _rename(cls, ea, new_name): if not ea or ea == idaapi.BADADDR: return if idaapi.IDA_SDK_VERSION >= 700: return idaapi.force_name(ea, new_name, idaapi.SN_NOCHECK) return idaapi.do_name_anyway(ea, new_name, 0)
def load_file(li, neflags, format): idaapi.set_processor_type("arm", idaapi.SETPROC_ALL | idaapi.SETPROC_FATAL) f = load_nxo(li) if f.armv7: SetShortPrm(INF_LFLAGS, GetShortPrm(INF_LFLAGS) | LFLG_PC_FLAT) else: SetShortPrm(INF_LFLAGS, GetShortPrm(INF_LFLAGS) | LFLG_64BIT) SetCharPrm(INF_DEMNAMES, idaapi.DEMNAM_GCC3) idaapi.set_compiler_id(idaapi.COMP_GNU) idaapi.add_til2('gnulnx_arm' if f.armv7 else 'gnulnx_arm64', 1) loadbase = 0x60000000 if f.armv7 else 0x7100000000 f.binfile.seek(0) as_string = f.binfile.read(f.bssoff) idaapi.mem2base(as_string, loadbase) if f.text[1] != None: li.file2base(f.text[1], loadbase + f.text[2], loadbase + f.text[2] + f.text[3], True) if f.ro[1] != None: li.file2base(f.ro[1], loadbase + f.ro[2], loadbase + f.ro[2] + f.ro[3], True) if f.data[1] != None: li.file2base(f.data[1], loadbase + f.data[2], loadbase + f.data[2] + f.data[3], True) for start, end, name, kind in f.sections: if name.startswith('.got'): kind = 'CONST' idaapi.add_segm(0, loadbase + start, loadbase + end, name, kind) segm = idaapi.get_segm_by_name(name) if kind == 'CONST': segm.perm = idaapi.SEGPERM_READ elif kind == 'CODE': segm.perm = idaapi.SEGPERM_READ | idaapi.SEGPERM_EXEC elif kind == 'DATA': segm.perm = idaapi.SEGPERM_READ | idaapi.SEGPERM_WRITE elif kind == 'BSS': segm.perm = idaapi.SEGPERM_READ | idaapi.SEGPERM_WRITE idaapi.update_segm(segm) idaapi.set_segm_addressing(segm, 1 if f.armv7 else 2) # do imports # TODO: can we make imports show up in "Imports" window? undef_count = 0 for s in f.symbols: if not s.shndx and s.name: undef_count += 1 last_ea = max(loadbase + end for start, end, name, kind in f.sections) undef_entry_size = 8 undef_ea = ( (last_ea + 0xFFF) & ~0xFFF ) + undef_entry_size # plus 8 so we don't end up on the "end" symbol idaapi.add_segm(0, undef_ea, undef_ea + undef_count * undef_entry_size, "UNDEF", "XTRN") segm = idaapi.get_segm_by_name("UNDEF") segm.type = idaapi.SEG_XTRN idaapi.update_segm(segm) for i, s in enumerate(f.symbols): if not s.shndx and s.name: MakeQword(undef_ea) idaapi.do_name_anyway(undef_ea, s.name) s.resolved = undef_ea undef_ea += undef_entry_size elif i != 0: assert s.shndx s.resolved = loadbase + s.value if s.name: if s.type == STT_FUNC: print hex(s.resolved), s.name idaapi.add_entry(s.resolved, s.resolved, s.name, 0) else: idaapi.do_name_anyway(s.resolved, s.name) else: # NULL symbol s.resolved = 0 funcs = set() for s in f.symbols: if s.name and s.shndx and s.value: if s.type == STT_FUNC: funcs.add(loadbase + s.value) got_name_lookup = {} for offset, r_type, sym, addend in f.relocations: target = offset + loadbase if r_type in (R_ARM_GLOB_DAT, R_ARM_JUMP_SLOT, R_ARM_ABS32): if not sym: print 'error: relocation at %X failed' % target else: idaapi.put_long(target, sym.resolved) elif r_type == R_ARM_RELATIVE: idaapi.put_long(target, idaapi.get_long(target) + loadbase) elif r_type in (R_AARCH64_GLOB_DAT, R_AARCH64_JUMP_SLOT, R_AARCH64_ABS64): idaapi.put_qword(target, sym.resolved + addend) if addend == 0: got_name_lookup[offset] = sym.name elif r_type == R_AARCH64_RELATIVE: idaapi.put_qword(target, loadbase + addend) if addend < f.textsize: funcs.add(loadbase + addend) else: print 'TODO r_type %d' % (r_type, ) ida_make_offset(f, target) for func, target in f.plt_entries: if target in got_name_lookup: addr = loadbase + func funcs.add(addr) idaapi.do_name_anyway(addr, got_name_lookup[target]) funcs |= find_bl_targets(loadbase, loadbase + f.textsize) for addr in sorted(funcs, reverse=True): AutoMark(addr, AU_CODE) AutoMark(addr, AU_PROC) return 1
def load_one_file(li, options, idx, basename=None): bypass_plt = OPT_BYPASS_PLT in options f = load_nxo(li) if idx == 0: if f.armv7: idc.SetShortPrm(idc.INF_LFLAGS, idc.GetShortPrm(idc.INF_LFLAGS) | idc.LFLG_PC_FLAT) else: idc.SetShortPrm(idc.INF_LFLAGS, idc.GetShortPrm(idc.INF_LFLAGS) | idc.LFLG_64BIT) idc.SetCharPrm(idc.INF_DEMNAMES, idaapi.DEMNAM_GCC3) idaapi.set_compiler_id(idaapi.COMP_GNU) idaapi.add_til2('gnulnx_arm' if f.armv7 else 'gnulnx_arm64', 1) # don't create tails idc.set_inf_attr(idc.INF_AF, idc.get_inf_attr(idc.INF_AF) & ~idc.AF_FTAIL) if OPT_LOAD_31_BIT in options: loadbase = 0x8000000 step = 0x1000000 elif f.armv7: loadbase = 0x60000000 step = 0x10000000 else: loadbase = 0x7100000000 step = 0x100000000 loadbase += idx * step f.binfile.seek(0) as_string = f.binfile.read(f.bssoff) idaapi.mem2base(as_string, loadbase) seg_prefix = basename if basename is not None else '' for start, end, name, kind in f.sections: if name.startswith('.got'): kind = 'CONST' idaapi.add_segm(0, loadbase+start, loadbase+end, seg_prefix+name, kind) segm = idaapi.get_segm_by_name(seg_prefix+name) if kind == 'CONST': segm.perm = idaapi.SEGPERM_READ elif kind == 'CODE': segm.perm = idaapi.SEGPERM_READ | idaapi.SEGPERM_EXEC elif kind == 'DATA': segm.perm = idaapi.SEGPERM_READ | idaapi.SEGPERM_WRITE elif kind == 'BSS': segm.perm = idaapi.SEGPERM_READ | idaapi.SEGPERM_WRITE idaapi.update_segm(segm) idaapi.set_segm_addressing(segm, 1 if f.armv7 else 2) # do imports # TODO: can we make imports show up in "Imports" window? undef_count = 0 for s in f.symbols: if not s.shndx and s.name: undef_count += 1 last_ea = max(loadbase + end for start, end, name, kind in f.sections) undef_entry_size = 8 undef_ea = ((last_ea + 0xFFF) & ~0xFFF) + undef_entry_size # plus 8 so we don't end up on the "end" symbol undef_seg = basename + '.UNDEF' if basename is not None else 'UNDEF' idaapi.add_segm(0, undef_ea, undef_ea+undef_count*undef_entry_size, undef_seg, 'XTRN') segm = idaapi.get_segm_by_name(undef_seg) segm.type = idaapi.SEG_XTRN idaapi.update_segm(segm) for i,s in enumerate(f.symbols): if not s.shndx and s.name: idc.MakeQword(undef_ea) idaapi.do_name_anyway(undef_ea, s.name) s.resolved = undef_ea undef_ea += undef_entry_size elif i != 0: assert s.shndx s.resolved = loadbase + s.value if s.name: if s.type == STT_FUNC: idaapi.add_entry(s.resolved, s.resolved, s.name, 0) else: idaapi.do_name_anyway(s.resolved, s.name) else: # NULL symbol s.resolved = 0 funcs = set() for s in f.symbols: if s.name and s.shndx and s.value: if s.type == STT_FUNC: funcs.add(loadbase+s.value) symend = loadbase+s.value+s.size if Dword(symend) != 0: funcs.add(symend) got_name_lookup = {} for offset, r_type, sym, addend in f.relocations: target = offset + loadbase if r_type in (R_ARM_GLOB_DAT, R_ARM_JUMP_SLOT, R_ARM_ABS32): if not sym: print 'error: relocation at %X failed' % target else: idaapi.put_long(target, sym.resolved) elif r_type == R_ARM_RELATIVE: idaapi.put_long(target, idaapi.get_long(target) + loadbase) elif r_type in (R_AARCH64_GLOB_DAT, R_AARCH64_JUMP_SLOT, R_AARCH64_ABS64): idaapi.put_qword(target, sym.resolved + addend) if addend == 0: got_name_lookup[offset] = sym.name elif r_type == R_AARCH64_RELATIVE: idaapi.put_qword(target, loadbase + addend) if addend < f.textsize: funcs.add(loadbase + addend) else: print 'TODO r_type %d' % (r_type,) ida_make_offset(f, target) for func, target in f.plt_entries: if target in got_name_lookup: addr = loadbase + func funcs.add(addr) idaapi.do_name_anyway(addr, got_name_lookup[target]) if not f.armv7: funcs |= find_bl_targets(loadbase, loadbase+f.textsize) if bypass_plt: plt_lookup = f.plt_lookup for pco in xrange(0, f.textsize, 4): pc = loadbase + pco d = Dword(pc) if (d & 0x7c000000) == (0x94000000 & 0x7c000000): imm = d & 0x3ffffff if imm & 0x2000000: imm |= ~0x1ffffff if 0 <= imm <= 2: continue target = (pc + imm * 4) - loadbase if target in plt_lookup: new_target = plt_lookup[target] + loadbase new_instr = (d & ~0x3ffffff) | (((new_target - pc) / 4) & 0x3ffffff) idaapi.put_long(pc, new_instr) for pco in xrange(0, f.textsize, 4): pc = loadbase + pco d = Dword(pc) if d == 0x14000001: funcs.add(pc + 4) for pc, _ in f.eh_table: funcs.add(loadbase + pc) for addr in sorted(funcs, reverse=True): idaapi.auto_make_proc(addr) return 1
def NameCanonical(f,mod_name,func_name): n = "%s_%s_%08x" % (mod_name,func_name,f) print "Renaming %s to %s\n" % (idc.GetFunctionName(f),n) idaapi.do_name_anyway(f,n)
def do_import_name(ea, name): idaapi.do_name_anyway(ea, "_import_" + name) #guess wrapper if idaapi.get_long(ea - 4) == 0xE51FF004: # "ldr pc, [pc, #-4]" idaapi.do_name_anyway(ea - 4, name)
def load_file(li, netflags, format): nsis = nsisfile.NSIS.from_path(idaapi.get_input_file_path()) # Create NSIS netnode. nsis_netnode = idaapi.netnode("$ NSIS", 0, True) nsis_netnode.hashset("VERSION_MAJOR", nsis.version_major) nsis_netnode.hashset("VERSION_MINOR", nsis.version_minor) # Create blocks segments. for name, n, sclass in BLOCKS: offset = nsis.header.blocks[n].offset if offset == 0: continue content = nsis.block(n) # Create block segment seg = idaapi.segment_t() seg.startEA = offset seg.endEA = offset + len(content) idaapi.add_segm_ex(seg, name, sclass, 0) idaapi.mem2base(content, offset) # Add one virtual segment to hold variables. var_seg = idaapi.segment_t() var_start = align(nsis.size()) var_seg.startEA = var_start var_seg.endEA = var_start + 0x1000 # Size chosen arbitrarily, should be enough. idaapi.add_segm_ex(var_seg, "VARS", "BSS", 0) # Create standard vars. for i, v in enumerate(nrs.strings.SYSVAR_NAMES.values()): idaapi.do_name_anyway(var_seg.startEA + i + 20, "$" + v) code_base = nsis.header.blocks[fileform.NB_ENTRIES].offset # Create sections functions. for i, section in enumerate(nsis.sections): if section.code == PTR_NONE: continue name = nsis.get_string(section.name_ptr) if not name: name = "_section" + str(i) ea = code_base + nrs.entry_to_offset(section.code) cname = canonize_name(name) AddEntryPoint(ea, ea, cname, 1) # Mark pages handlers. for i, page in enumerate(nsis.pages): for fn in ["prefunc", "showfunc", "leavefunc"]: addr = getattr(page, fn) if addr != PTR_NONE: name = "_page_{}_{}".format(i, fn) ea = code_base + nrs.entry_to_offset(addr) AddEntryPoint(ea, ea, name, 1) # Mark installer handlers. for event in [ "Init", "InstSuccess", "InstFailed", "UserAbort", "GUIInit", "GUIEnd", "MouseOverSection", "VerifyInstDir", "SelChange", "RebootFailed", ]: addr = getattr(nsis.header, "code_on" + event) if addr != PTR_NONE: name = "_on" + event ea = code_base + nrs.entry_to_offset(addr) AddEntryPoint(ea, ea, name, 1) # Create strings. """ strings_data = nsis.block(fileform.NB_STRINGS) strings_off = nsis.header.blocks[fileform.NB_STRINGS].offset i = 0 while i < len(strings_data): decoded_string, length = \ nrs.strings.decode(strings_data, i, nsis.version_major) decoded_string = str(decoded_string) string_name = canonize_name(decoded_string) idaapi.make_ascii_string(strings_off + i, length, ASCSTR_C) idaapi.set_cmt(strings_off + i, decoded_string, True) idaapi.do_name_anyway(strings_off + i, string_name) i += length #""" # Set processor to nsis script. SetProcessorType("nsis", SETPROC_ALL | SETPROC_FATAL) return 1