def main(): kbase = min(Segments()) define_funcs = [] define_data = [] # Add functions for ea in Functions(): fname = idc.get_name(ea) ftype = idc.get_type(ea) fslide = ea - kbase if fname.startswith('sub_'): continue if ftype is None: if TYPED_FUNCS_ONLY: continue ftype = 'uint64_t (...)' define_funcs.append((fname, fslide, ftype)) # Add data for ea, _ in Names(): dname = idc.get_name(ea) dtype = idc.get_type(ea) dslide = ea - kbase flags = GetFlags(ea) if idc.is_code(flags) or idc.is_strlit(flags): continue if dtype is None: if TYPED_DATA_ONLY: continue dtype = 'void' define_data.append((dname, dslide, dtype)) # Generate source files generate_sdk(define_funcs, define_data)
def prepare_parse_type(typestr, addr): """ idc.ParseType doesnt accept types without func / local name as exported by default GetType this is an ugly hack to fix it """ lname = idc.get_name(addr) if lname is None: lname = "Default" # func pointers conventions = ["__cdecl *", "__stdcall *", "__fastcall *", # "__usercall *", # "__userpurge *", "__thiscall *", "__cdecl", "__stdcall", "__fastcall", # "__usercall", # "__userpurge", "__thiscall"] mtype = None for conv in conventions: if conv in typestr: mtype = typestr.replace(conv, conv + " " + lname) break return mtype
def populate_table(self): """ Download the list of proposed names and display it """ functions = self.skel_conn.get_proposed_names() items = [] for func in functions: func_name = idc.get_name(func["address"]) for name in func["proposed_names"]: item = self.SkelFuncListItem( hex(func["address"]), func_name, hex(func["machoc_hash"]), name) items.append(item) self.setRowCount(len(items)) self.add_items_to_table(items)
def get_symbol_name(from_ea, ea=None, allow_dummy=False): if ea is None: ea = from_ea global _FORCED_NAMES if ea in _FORCED_NAMES: return _FORCED_NAMES[ea] flags = idc.get_full_flags(ea) if not allow_dummy and idaapi.has_dummy_name(flags): return "" name = "" try: name = name or idc.get_name(ea, 0) #calc_gtn_flags(from_ea, ea)) except: pass try: name = name or idc.get_func_name(ea) except: pass return name
def NameEx(From, ea): return idc.get_name(ea, ida_name.GN_VISIBLE | calc_gtn_flags(From, ea))
def update_func_name_with_class(func_ea, class_name): name = idc.get_name(func_ea) if name.startswith("sub_"): new_name = class_name + VTABLE_DELIMITER + name return utils.set_func_name(func_ea, new_name), True return name, False
def activate(self, ctx): if self.action in ACTION_CONVERT: # convert t0, t1, view = idaapi.twinpos_t(), idaapi.twinpos_t( ), idaapi.get_current_viewer() if idaapi.read_selection(view, t0, t1): start, end = t0.place(view).toea(), t1.place(view).toea() size = end - start elif idc.get_item_size(idc.get_screen_ea()) > 1: start = idc.get_screen_ea() size = idc.get_item_size(start) end = start + size else: return False data = idc.get_bytes(start, size) if isinstance(data, str): # python2 compatibility data = bytearray(data) name = idc.get_name(start, idc.GN_VISIBLE) if not name: name = "data" if data: print("\n[+] Dump 0x%X - 0x%X (%u bytes) :" % (start, end, size)) if self.action == ACTION_CONVERT[0]: # escaped string output = '"%s"' % "".join("\\x%02X" % b for b in data) elif self.action == ACTION_CONVERT[1]: # hex string output = "".join("%02X" % b for b in data) elif self.action == ACTION_CONVERT[2]: # C array output = "unsigned char %s[%d] = {" % (name, size) for i in range(size): if i % 16 == 0: output += "\n " output += "0x%02X, " % data[i] output = output[:-2] + "\n};" elif self.action == ACTION_CONVERT[3]: # C array word data += b"\x00" array_size = (size + 1) // 2 output = "unsigned short %s[%d] = {" % (name, array_size) for i in range(0, size, 2): if i % 16 == 0: output += "\n " output += "0x%04X, " % u16(data[i:i + 2]) output = output[:-2] + "\n};" elif self.action == ACTION_CONVERT[4]: # C array dword data += b"\x00" * 3 array_size = (size + 3) // 4 output = "unsigned int %s[%d] = {" % (name, array_size) for i in range(0, size, 4): if i % 32 == 0: output += "\n " output += "0x%08X, " % u32(data[i:i + 4]) output = output[:-2] + "\n};" elif self.action == ACTION_CONVERT[5]: # C array qword data += b"\x00" * 7 array_size = (size + 7) // 8 output = "unsigned long %s[%d] = {" % (name, array_size) for i in range(0, size, 8): if i % 32 == 0: output += "\n " output += "0x%016X, " % u64(data[i:i + 8]) output = output[:-2] + "\n};" elif self.action == ACTION_CONVERT[6]: # python list output = "[%s]" % ", ".join("0x%02X" % b for b in data) elif self.action == ACTION_CONVERT[7]: # python list word data += b"\x00" output = "[%s]" % ", ".join("0x%04X" % u16(data[i:i + 2]) for i in range(0, size, 2)) elif self.action == ACTION_CONVERT[8]: # python list dword data += b"\x00" * 3 output = "[%s]" % ", ".join("0x%08X" % u32(data[i:i + 4]) for i in range(0, size, 4)) elif self.action == ACTION_CONVERT[9]: # python list qword data += b"\x00" * 7 output = "[%s]" % ", ".join( "%#018X" % u64(data[i:i + 8]) for i in range(0, size, 8)).replace("0X", "0x") copy_to_clip(output) print(output) elif self.action == ACTION_XORDATA: t0, t1, view = idaapi.twinpos_t(), idaapi.twinpos_t( ), idaapi.get_current_viewer() if idaapi.read_selection(view, t0, t1): start, end = t0.place(view).toea(), t1.place(view).toea() else: if idc.get_item_size(idc.get_screen_ea()) > 1: start = idc.get_screen_ea() end = start + idc.get_item_size(start) else: return False data = idc.get_bytes(start, end - start) if isinstance(data, str): # python2 compatibility data = bytearray(data) x = idaapi.ask_long(0, "Xor with...") if x: x &= 0xFF print("\n[+] Xor 0x%X - 0x%X (%u bytes) with 0x%02X:" % (start, end, end - start, x)) print(repr("".join(chr(b ^ x) for b in data))) elif self.action == ACTION_FILLNOP: t0, t1, view = idaapi.twinpos_t(), idaapi.twinpos_t( ), idaapi.get_current_viewer() if idaapi.read_selection(view, t0, t1): start, end = t0.place(view).toea(), t1.place(view).toea() idaapi.patch_bytes(start, b"\x90" * (end - start)) print("\n[+] Fill 0x%X - 0x%X (%u bytes) with NOPs" % (start, end, end - start)) elif self.action == ACTION_SCANVUL: print("\n[+] Finding Format String Vulnerability...") found = [] for addr in idautils.Functions(): name = idc.get_func_name(addr) if "printf" in name and "v" not in name and idc.get_segm_name( addr) in (".text", ".plt", ".idata"): xrefs = idautils.CodeRefsTo(addr, False) for xref in xrefs: vul = self.check_fmt_function(name, xref) if vul: found.append(vul) if found: print("[!] Done! %d possible vulnerabilities found." % len(found)) ch = VulnChoose("Vulnerability", found, None, False) ch.Show() else: print("[-] No format string vulnerabilities found.") else: return 0 return 1
def cmd_get_named_addrs(self, a_start, a_end): # idautils.Names() does not work in 7.3 return " ".join([ self.fmt_addr(a) for a in range(int(a_start, 0), int(a_end, 0)) if idc.get_name(a) ])
def get_addr_name(self, ea): return idc.get_name(ea)
def get_name(): return idc.get_name(name["address"])
def get_data_guids(self): ''' rename GUIDs in idb ''' EFI_GUID = 'EFI_GUID *' EFI_GUID_ID = idc.get_struc_id('EFI_GUID') segments = ['.text', '.data'] for segment in segments: seg_start, seg_end = 0, 0 for seg in idautils.Segments(): if idc.get_segm_name(seg) == segment: seg_start = idc.get_segm_start(seg) seg_end = idc.get_segm_end(seg) break ea = seg_start while (ea <= seg_end - 15): prot_name = '' if idc.get_name(ea, ida_name.GN_VISIBLE).find('unk_') != -1: find = False cur_guid = [] cur_guid.append(idc.get_wide_dword(ea)) cur_guid.append(idc.get_wide_word(ea + 4)) cur_guid.append(idc.get_wide_word(ea + 6)) for addr in range(ea + 8, ea + 16, 1): cur_guid.append(idc.get_wide_byte(addr)) if cur_guid == [0] * 11: ea += 1 continue for name in self.Protocols['Edk2Guids']: if self.Protocols['Edk2Guids'][name] == cur_guid: prot_name = name + '_' + '{addr:#x}'.format( addr=ea) record = { 'address': ea, 'service': 'unknown', 'guid': cur_guid, 'protocol_name': name, 'protocol_place': 'edk2_guids' } find = True break for name in self.Protocols['EdkGuids']: if self.Protocols['EdkGuids'][name] == cur_guid: prot_name = name + '_' + '{addr:#x}'.format( addr=ea) prot_name = name + '_' + '{addr:#x}'.format( addr=ea) record = { 'address': ea, 'service': 'unknown', 'guid': cur_guid, 'protocol_name': name, 'protocol_place': 'edk_guids' } find = True break for name in self.Protocols['AmiGuids']: if self.Protocols['AmiGuids'][name] == cur_guid: prot_name = name + '_' + '{addr:#x}'.format( addr=ea) prot_name = name + '_' + '{addr:#x}'.format( addr=ea) record = { 'address': ea, 'service': 'unknown', 'guid': cur_guid, 'protocol_name': name, 'protocol_place': 'ami_guids' } find = True break if find and (idc.get_name(ea, ida_name.GN_VISIBLE) != prot_name): idc.SetType(ea, EFI_GUID) self.apply_struct(ea, 16, EFI_GUID_ID) idc.set_name(ea, prot_name) self.Protocols['Data'].append(record) ea += 1
def get_name(self, offset): """Get name for offset from IDB""" self.ret = idc.get_name(offset, ida_name.GN_VISIBLE) return self.ret
def getName(self, addr): return idc.get_name(addr, idc.ida_name.GN_VISIBLE)
def get_thunks(ea, typename, funclist): funcidx = 0 instance = (int, long) if version_info[0] < 3 else int for i in range(len(funclist)): if isinstance(funclist[i], instance): funcidx = i break # No thunks here if not funcidx: return [], [] funcs = [] gotthunks = False # Index all these thunks so they line up for when we check for an offset # Get rid of extra destructor too thunklist = [ get_func_postname(i) for i in funclist[funcidx:] if not isinstance(i, instance) and not i.startswith("_ZTI") and not i.endswith(typename + "D1Ev") ] while ea != idc.BADADDR: size = idc.get_item_size(ea) # CTFRocketLauncher_DirectHit has its thunks below some random ass string # Don't know what's up with that but we'll check 2 more offsets beyond that if size != 4: ea = ida_bytes.next_not_tail(ea) size = idc.get_item_size(ea) if size != 4: ea = ida_bytes.next_not_tail(ea) size = idc.get_item_size(ea) if size != 4: # This is really bad break offs = idc.get_wide_dword(ea) name = idc.get_name(offs, ida_name.GN_VISIBLE) if name: if name.startswith("??_R4"): # if typename not in name: # break gotthunks = True ea = ida_bytes.next_not_tail(ea) continue else: s = "%02x" % offs if not s.lower().startswith("ffff"): ea = ida_bytes.next_not_tail(ea) continue break if gotthunks: funcs.append((offs, name)) ea = ida_bytes.next_not_tail(ea) return funcs, thunklist
def prep_vtable(linuxtable, key, wintable, winv): if not linuxtable.get(key): return None funclist = linuxtable[key] # Compat for 2.7, strings are in unicode if version_info[0] < 3: funclist = [ i if isinstance(i, (int, long)) else str(i) for i in linuxtable[key] ] thunks, thunklist = get_thunks(winv, key, funclist) # We've got the thunks, now we don't need anything beyond another typeinfo instance = (int, long) if version_info[0] < 3 else int for i, v in enumerate(funclist): if isinstance(v, instance): funclist = funclist[:i] # Skipping thisoffs break # Get rid of extra destructor for linux for i, n in enumerate(funclist): name = idc.demangle_name(n, idc.get_inf_attr(idc.INF_SHORT_DN)) if name: if "::~" in name: del funclist[i] break # Windows does overloads backwards, reverse them # Also check for thunks while we're at it i = 0 funcoverloads = {} while i < len(funclist): # and i < len(wintable): n = funclist[i] if n.startswith("__cxa"): i += 1 continue # I shouldn't need to do this, but destructors are wonky if i == 0: demangled = idc.demangle_name(n, idc.get_inf_attr(idc.INF_SHORT_DN)) if demangled and "::~" in demangled: i += 1 continue overloadname = get_func_sname(n) shortname = get_func_postname(n) if not shortname: i += 1 continue # Windows skips the vtable function if it exists in the thunks and # the thunk does not jmp into it (because the thunk is the function) try: thunkidx = thunklist.index(shortname) delete = 1 except: thunkidx = -1 delete = 0 if i < len(wintable): if thunkidx != -1 and thunkidx < len(thunks): if not isinthunk(wintable[i], thunks[thunkidx]): currname = idc.get_name(thunks[thunkidx][0], ida_name.GN_VISIBLE) if currname and currname != funclist[ i] and EXPORT_MODE != Export_YesOnly: nameflags = ida_name.SN_FORCE if not currname.startswith("sub_"): if not USE_WEAK_NAMES: del funclist[i] continue nameflags |= ida_name.SN_WEAK elif USE_WEAK_NAMES: global FUNCS FUNCS += 1 idc.set_name(thunks[thunkidx][0], funclist[i], nameflags) del funclist[i] continue else: # Class has thunks at the end of the vtable # This doesn't change anything but it should link up the lengths of both tables if delete: del funclist[i] continue node = funcoverloads.get(overloadname, []) # Is this a half-ass decent overload go = 1 for loadnode in range(len(node)): if not any( [i - funclist.index(val) > F**K for val in node[loadnode]]): node[loadnode].append(n) go = 0 break if go: node.append([n]) funcoverloads[overloadname] = node i += 1 for k, value in get_bcompat_items(funcoverloads): # if len(value) <= 1: # continue # split = [] # # # Since subclass overloads shouldn't scoot up next to their baseclass brethren # # hackily separate overloads by classname # for mname in value: # found = 0 # # name = idc.demangle_name(mname, idc.get_inf_attr(idc.INF_SHORT_DN)) # typename = name[:name.find("::")] # # for i2 in range(len(split)): # for othermname in split[i2]: # name = idc.demangle_name(othermname, idc.get_inf_attr(idc.INF_SHORT_DN)) # othertypename = name[:name.find("::")] # # if typename == othertypename: # found = 1 # split[i2].append(mname) # break # # if found: # break # # if not found: # split.append([mname]) for v in value: if len(v) <= 1: continue lowestidx = len(funclist) for func in v: temp = funclist.index(func) if lowestidx > temp: lowestidx = temp count = 0 while len(v): k = v.pop() funclist.insert(lowestidx + count, funclist.pop(funclist.index(k))) count += 1 diff = len(funclist) - len(wintable) if diff: print("WARNING: {} vtable may be wrong! L{} - W{} = {}".format( key, len(funclist), len(wintable), diff)) return funclist
def implement(self): if idc.get_name(self._ea, ida_name.GN_LOCAL) != self._name: ida_name.set_name(self._ea, self._name, ida_name.SN_LOCAL)
def has_non_default_name(address: int, name: Optional[str]) -> bool: sym_name = idc.get_name(address, idaapi.GN_NOT_DUMMY) return False if sym_name == '' else (sym_name != name)
def GetTrueNameEx(From, ea): return idc.get_name(ea, calc_gtn_flags(From, ea))
item = [] item.append(addr + j * addr_gap) func_addr, func_name = funcs[j].split() item.append((int(func_addr, 16), func_name.strip("<>"))) items.append(item) if items != []: print("============Find PLT Table============") for i in items: print("%x: %x %s" % (i[0], i[1][0], i[1][1])) print("======================================") else: print("No PLT Table found") exit() print("Use Lowest 16bits Matching") currentEA = ScreenEA() segstart = idc.SegStart(currentEA) segend = idc.SegEnd(currentEA) for i in items: item_addr = i[0] if (segstart & addr_mask) < (item_addr & addr_mask) and ( segend & addr_mask) > (item_addr & addr_mask): patch_addr = (item_addr & addr_mask) + (segstart & (~addr_mask)) prev_name = idc.get_name(patch_addr) if prev_name == "" or in_default(prev_name): idc.MakeName(patch_addr, i[1][1] + suffix) print("MakeName: %x %s" % (patch_addr, i[1][1]))
def makesig(): addr = idc.get_screen_ea() addr = idc.get_func_attr(addr, idc.FUNCATTR_START) funcstart = addr if addr == idc.BADADDR: print("Make sure you are in a function!") return name = idc.get_name(addr, ida_name.GN_VISIBLE) funcend = idc.get_func_attr(addr, idc.FUNCATTR_END) sig = "" found = 0 done = 0 addr = funcstart while addr != idc.BADADDR: info = ida_ua.insn_t() if not ida_ua.decode_insn(info, addr): return None done = 0 if info.Op1.type == ida_ua.o_near or info.Op1.type == ida_ua.o_far: if (idc.get_wide_byte(addr)) == 0x0F: # Two-byte instruction sig = sig + ("0F %02X " % idc.get_wide_byte(addr + 1)) + print_wildcards( get_dt_size(info.Op1.dtype)) else: sig = sig + ("%02X " % idc.get_wide_byte(addr)) + print_wildcards( get_dt_size(info.Op1.dtype)) done = 1 if not done: # Unknown, just wildcard addresses i = 0 size = idc.get_item_size(addr) while 1: # Screw u python loc = addr + i if ((idc.get_fixup_target_type(loc) & 0xF) == ida_fixup.FIXUP_OFF32): sig = sig + print_wildcards(4) i = i + 3 else: sig = sig + ("%02X " % idc.get_wide_byte(loc)) i = i + 1 if i >= size: break if is_good_sig(sig): found = 1 break addr = idc.next_head(addr, funcend) if found == 0: print(sig) print("Ran out of bytes to create unique signature.") return None l = len(sig) - 1 smsig = r"\x" for i in range(l): c = sig[i] if c == " ": smsig = smsig + r"\x" elif c == "?": smsig = smsig + "2A" else: smsig = smsig + c print("Signature for %s:\n%s\n%s" % (name, sig, smsig)) return smsig
def set_func_name(func_ea, new_name): if not idc.set_name(func_ea, new_name, ida_name.SN_CHECK | ida_name.SN_FORCE): log.warn("%08X Couldn't set func name '%s'", func_ea, new_name) return idc.get_name(func_ea)
def to_nice_str(ea): """ Shows address as function name + offset """ func_start_ea = idc.get_func_attr(ea, idc.FUNCATTR_START) func_name = idc.get_name(func_start_ea) offset = ea - func_start_ea return "{}+0x{:X}".format(func_name, offset)
def kernelcache_find_virtual_method_overrides(classname=None, method=None): import idc import idaapi import ida_name import ida_kernelcache as kc # Define the form to ask for the arguments. class MyForm(idaapi.Form): def __init__(self): swidth = 40 idaapi.Form.__init__( self, r"""STARTITEM 0 Find virtual method overrides <#The class#Class :{classname}> <#The virtual method#Method:{method}>""", { 'classname': idaapi.Form.StringInput(tp=idaapi.Form.FT_IDENT, swidth=swidth), 'method': idaapi.Form.StringInput(tp=idaapi.Form.FT_IDENT, swidth=swidth), }) def OnFormChange(self, fid): return 1 kc.collect_class_info() if any(arg is None for arg in (classname, method)): f = MyForm() f.Compile() f.classname.value = classname or '' f.method.value = method or '' ok = f.Execute() if ok != 1: print('Cancelled') return False classname = f.classname.value method = f.method.value f.Free() if classname not in kc.class_info: print('Not a valid class: {}'.format(classname)) return False print('Subclasses of {} that override {}:'.format(classname, method)) baseinfo = kc.class_info[classname] found = False for classinfo in baseinfo.descendants(): for _, override, _ in kc.vtable.class_vtable_overrides( classinfo, superinfo=baseinfo, methods=True): name = idc.get_name( override, ida_name.GN_VISIBLE | idc.calc_gtn_flags(idc.BADADDR, override)) demangled = idc.demangle_name( name, idc.get_inf_attr(idc.INF_SHORT_DEMNAMES)) name = demangled if demangled else name if method in name: print('{:#x} {}'.format(override, classinfo.classname)) found = True if not found: print('No subclass of {} overrides {}'.format(classname, method)) return found
def make_func_sig(config, func): """ type config: Config type func: idc.func_t """ logger = logging.getLogger("idb2pat:make_func_sig") if func.end_ea - func.start_ea < config.min_func_length: logger.debug("Function is too short") raise FuncTooShortException() publics = [] # type: tuple(idc.ea_t, name) refs = {} # type: dict(idc.ea_t, idc.ea_t) variable_bytes = set([]) # type: set of idc.ea_t func_len = func.end_ea - func.start_ea # get function name and all public names in function func_name = idc.get_func_name(func.start_ea) if func_name == "": func_name = "?" # pat standard ea = func.start_ea while ea != idc.BADADDR and ea < func.end_ea: if ea > func.start_ea: # skip first byte name = idc.get_name(ea) if name != "" and idaapi.is_uname(name): logger.debug(str("ea 0x%X has a name %s" % (ea, name))) publics.append((ea, name)) ref = idc.get_first_dref_from(ea) if ref != idc.BADADDR: # data ref logger.debug(str("ea 0x%X has data ref 0x%X" % (ea, ref))) start, end = find_ref_loc(ea, ref) if start != idc.BADADDR: logger.debug( str("data ref: %s - %X - %X - %X" % (func_name, ea, start, end))) logger.debug( str("\tref_loc: 0x%X - size %d" % (ea + start, end - start))) for i in range(start, end): logger.debug(str("\tvariable 0x%X" % (ea + i))) variable_bytes.add(ea + i) refs[ea + start] = ref else: # code ref ref = idc.get_first_fcref_from(ea) if ref != idc.BADADDR: logger.debug(str("ea 0x%X has code ref 0x%X" % (ea, ref))) if ref < func.start_ea or ref >= func.end_ea: # code ref is outside function start, end = find_ref_loc(ea, ref) if start != idc.BADADDR: logger.debug( str("code ref: %s - %X - %d - %d" % (func_name, ea, start, end))) logger.debug( str("\tref_loc: 0x%X - size %d" % (ea + start, end - start))) for i in range(start, end): logger.debug(str("\tvariable 0x%X" % (ea + i))) variable_bytes.add(ea + i) refs[ea + start] = ref ea = idc.next_not_tail(ea) # first 32 bytes, or til end of function sig = "" for ea in zrange(func.start_ea, min(func.start_ea + 32, func.end_ea)): if ea in variable_bytes: sig += ".." else: sig += "%02X" % (idaapi.get_byte(ea)) if func_len > 32: crc_len = min(func_len - 32, 0xff) # for 255 bytes starting at index 32, or til end of function, or variable byte for off in range(crc_len): if func.start_ea + 32 + off in variable_bytes: crc_len = off break crc = crc16(idaapi.get_bytes(func.start_ea + 32, crc_len), crc=0xFFFF) else: sig += ".." * (32 - func_len) crc_len = 0 crc = 0 sig += " %02X" % (crc_len) sig += " %04X" % (crc) sig += " %04X" % min(func_len, MAX_FUNC_LEN) sig += " :0000 %s" % (func_name) for ea, name in publics: # @ at end of offset, for local public name, pat standard sig += " :%04X@ %s" % (ea - func.start_ea, name) for ref_loc, ref in sorted(refs.iteritems()): # HTC - remove dummy, auto names name = idc.get_name(ref) if name == "" or not idaapi.is_uname(name): continue logger.debug( str("ref_loc = 0x%X - ref = 0x%X - name = %s" % (ref_loc, ref, name))) if ref_loc >= func.start_ea: # this will be either " ^%04d %s" or " ^%08d %s" addr = ref_loc - func.start_ea ref_format = " ^%%0%dX %%s" % (config.pointer_size) else: # this will be either " ^-%04d %s" or " ^-%08d %s" addr = func.start_ea - ref_loc ref_format = " ^-%%0%dX %%s" % (config.pointer_size) sig += ref_format % (addr, name) # Tail of the module starts at the end of the CRC16 block. if func_len > 32 + crc_len: sig += " " for ea in range(func.start_ea + 32 + crc_len, min(func.end_ea, func.start_ea + MAX_FUNC_LEN)): if ea in variable_bytes: sig += ".." else: sig += "%02X" % (idaapi.get_byte(ea)) logger.debug("sig: %s", sig) return sig
def cmd_get_label(self, addr): return idc.get_name(int(addr, 0))
def make_func_sigs(config): logger = logging.getLogger("idb2pat:make_func_sigs") sigs = [] if config.mode == USER_SELECT_FUNCTION: f = idaapi.choose_func("Choose Function:", idc.BADADDR) if f is None: logger.error("No function selected") return [] idc.jumpto(f.start_ea) if not idaapi.has_any_name(idc.get_full_flags(f.start_ea)): logger.error("Function doesn't have a name") return [] try: sigs.append(make_func_sig(config, f)) except Exception as e: logger.exception(e) logger.error("Failed to create signature for function at %s (%s)", hex(f.start_ea), idc.get_func_name(f.start_ea) or "") elif config.mode == NON_AUTO_FUNCTIONS: for f in get_functions(): # HTC - remove check FUNC_LIB flag to include library functions if idaapi.has_name(idc.get_full_flags(f.start_ea)): # and f.flags & idc.FUNC_LIB == 0: try: sigs.append(make_func_sig(config, f)) except FuncTooShortException: pass except Exception as e: logger.exception(e) logger.error( "Failed to create signature for function at %s (%s)", hex(f.start_ea), idc.get_name(f.start_ea) or "") elif config.mode == LIBRARY_FUNCTIONS: for f in get_functions(): if idaapi.has_name(idc.get_full_flags( f.start_ea)) and f.flags & idc.FUNC_LIB != 0: try: sigs.append(make_func_sig(config, f)) except FuncTooShortException: pass except Exception as e: logger.exception(e) logger.error( "Failed to create signature for function at %s (%s)", hex(f.start_ea), idc.get_name(f.start_ea) or "") elif config.mode == PUBLIC_FUNCTIONS: for f in get_functions(): if idaapi.is_public_name(f.start_ea): try: sigs.append(make_func_sig(config, f)) except FuncTooShortException: pass except Exception as e: logger.exception(e) logger.error( "Failed to create signature for function at %s (%s)", hex(f.start_ea), idc.get_name(f.start_ea) or "") elif config.mode == ENTRY_POINT_FUNCTIONS: for i in zrange(idaapi.get_func_qty()): f = idaapi.get_func(idaapi.get_entry(idaapi.get_entry_ordinal(i))) if f is not None: try: sigs.append(make_func_sig(config, f)) except FuncTooShortException: pass except Exception as e: logger.exception(e) logger.error( "Failed to create signature for function at %s (%s)", hex(f.start_ea), idc.get_name(f.start_ea) or "") elif config.mode == ALL_FUNCTIONS: n = idaapi.get_func_qty() for i, f in enumerate(get_functions()): try: logger.info("[ %d / %d ] %s %s", i + 1, n, idc.get_name(f.start_ea), hex(f.start_ea)) sigs.append(make_func_sig(config, f)) except FuncTooShortException: pass except Exception as e: logger.exception(e) logger.error( "Failed to create signature for function at %s (%s)", hex(f.start_ea), idc.get_name(f.start_ea) or "") return sigs
def activate(self, ctx): if self.action in ACTION_MENU_CONVERT: sel, start, end = lazy_read_selection() if not sel: idc.msg("[LazyIDA] Nothing to convert.") return False size = end - start data = idc.get_bytes(start, size) if isinstance(data, str): # python2 compatibility data = bytearray(data) assert size == len(data) name = idc.get_name(start, idc.GN_VISIBLE) if not name: name = "data" if data: output = None plg_print("Dump from 0x%X to 0x%X (%u bytes):" % (start, end - 1, size)) if self.action == ACTION_MENU_CONVERT[0]: # escaped string output = '"%s"' % "".join("\\x%02X" % b for b in data) elif self.action == ACTION_MENU_CONVERT[1]: # hex string, space output = " ".join("%02X" % b for b in data) elif self.action == ACTION_MENU_CONVERT[2]: # C array output = "unsigned char %s[%d] = {" % (name, size) for i in range(size): if i % 16 == 0: output += "\n " output += "0x%02X, " % data[i] output = output[:-2] + "\n};" elif self.action == ACTION_MENU_CONVERT[3]: # C array word data += b"\x00" array_size = (size + 1) // 2 output = "unsigned short %s[%d] = {" % (name, array_size) for i in range(0, size, 2): if i % 16 == 0: output += "\n " output += "0x%04X, " % u16(data[i:i+2]) output = output[:-2] + "\n};" elif self.action == ACTION_MENU_CONVERT[4]: # C array dword data += b"\x00" * 3 array_size = (size + 3) // 4 output = "unsigned int %s[%d] = {" % (name, array_size) for i in range(0, size, 4): if i % 32 == 0: output += "\n " output += "0x%08X, " % u32(data[i:i+4]) output = output[:-2] + "\n};" elif self.action == ACTION_MENU_CONVERT[5]: # C array qword data += b"\x00" * 7 array_size = (size + 7) // 8 output = "unsigned long %s[%d] = {" % (name, array_size) for i in range(0, size, 8): if i % 32 == 0: output += "\n " output += "%#018X, " % u64(data[i:i+8]) output = output[:-2] + "\n};" output = output.replace("0X", "0x") elif self.action == ACTION_MENU_CONVERT[6]: # python list output = "[%s]" % ", ".join("0x%02X" % b for b in data) elif self.action == ACTION_MENU_CONVERT[7]: # python list word data += b"\x00" output = "[%s]" % ", ".join("0x%04X" % u16(data[i:i+2]) for i in range(0, size, 2)) elif self.action == ACTION_MENU_CONVERT[8]: # python list dword data += b"\x00" * 3 output = "[%s]" % ", ".join("0x%08X" % u32(data[i:i+4]) for i in range(0, size, 4)) elif self.action == ACTION_MENU_CONVERT[9]: # python list qword data += b"\x00" * 7 output = "[%s]" % ", ".join("%#018X" % u64(data[i:i+8]) for i in range(0, size, 8)).replace("0X", "0x") elif self.action == ACTION_MENU_CONVERT[10]: # MASM byte array header = "%s db " % name output = header for i in range(size): if i and i % 16 == 0: output += "\n" output += " " * len(header) output += "0%02Xh, " % data[i] output = output[:-2] elif self.action == ACTION_MENU_CONVERT[11]: # GNU ASM byte array header = "%s: .byte " % name output = header for i in range(size): if i and i % 16 == 0: output += "\n" output += " " * len(header) output += "0x%02X, " % data[i] output = output[:-2] if output: print(output) copy_to_clip(output) output = None elif self.action == ACTION_MENU_COPY_DATA: # added by merc, modified by HTC sel, start, end = lazy_read_selection() if not sel: return 0 data = idaapi.get_bytes(start, end - start) if isinstance(data, str): data = bytearray(data) output = "".join("%02X" % b for b in data) copy_to_clip(output) plg_print("Hex string '%s' copied" % output) elif self.action == ACTION_MENU_DUMP_DATA: # add by HTC sel, start, end = lazy_read_selection() if not sel: return 0 size = end - start data = idaapi.get_bytes(start, size) assert len(data) == size if data and len(data) == size: dump_data_to_file("Dump_At_%X_Size_%d.dump" % (start, size), data) else: plg_print("0x%X: unable to get %d bytes" % (start, size)) elif self.action == ACTION_MENU_XOR_DATA: sel, start, end = lazy_read_selection() if not sel: return 0 size = end - start key = idaapi.ask_str("AA BB CC DD", 0, "Xor with hex values (or a string begin and end with\" or ')...") if not key: return 0 bytes_key = bytearray() if is_str(key): bytes_key = str_to_bytes(key) else: bytes_key = hex_to_bytes(key) if not bytes_key: return 0 data = idc.get_bytes(start, end - start) if isinstance(data, str): # python2 compatibility data = bytearray(data) output = xor_data(data, bytes_key) if not output: plg_print("Sorry, error occurred. My bug :( Please report.") return 0 assert size == len(output) plg_print("Xor result from 0x%X to 0x%X (%d bytes) with %s:" % (start, end, end - start, key)) process_data_result(start, output) elif self.action == ACTION_MENU_FILL_NOP: sel, start, end = lazy_read_selection() if not sel: return 0 idaapi.patch_bytes(start, b"\x90" * (end - start)) idc.create_insn(start) plg_print("Fill 0x%X to 0x%X (%u bytes) with NOPs" % (start, end, end - start)) elif self.action == ACTION_MENU_B64STD: base64_decode(True) elif self.action == ACTION_MENU_B64URL: base64_decode(False) elif self.action == ACTION_MENU_SCAN_VUL: plg_print("Finding Format String Vulnerability...") found = [] for addr in idautils.Functions(): name = idc.get_func_name(addr) if "printf" in name and "v" not in name and idc.get_segm_name(addr) in (".text", ".plt", ".idata"): xrefs = idautils.CodeRefsTo(addr, False) for xref in xrefs: vul = self.check_fmt_function(name, xref) if vul: found.append(vul) if found: plg_print("Done! %d possible vulnerabilities found." % len(found)) ch = VulnChoose("Vulnerability", found, None, False) ch.Show() else: plg_print("No format string vulnerabilities found.") else: return 0 return 1
def name(self): return get_name(self.__ea, GN_VISIBLE)
def get_functions(): functions = dict() for f_ea in idautils.Functions(): functions[f_ea] = idc.get_name(f_ea) return functions
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 draw(self, min_x, max_x, min_y): self.lines = {} root_tree = self.reader.roots[self.activeIndex] trees = [(root_tree, 0, 0)] while len(trees) > 0: tree, x, y = trees.pop(0) width = tree['size'] if x + width > min_x and x < max_x: addr = tree['addr'] if addr == 0: name = '(root)' theme = 'red' else: symbol = self.reader.symbols.get(addr) if symbol: theme = 'purple' else: theme = 'green' name = idc.get_name(addr) if not name: if symbol: name = symbol else: name = "sub_%X" % (addr, ) if addr not in self.colors: self.colors[addr] = self.new_color(theme) if y >= min_y: this_y = y - min_y if this_y not in self.lines: self.lines[this_y] = [] self.lines[this_y].append({ 'addr': addr, 'x0': max(0, x - min_x), 'x1': min(max_x, x - min_x + width), 'color': self.colors[addr], 'name': name, 'cropped': x - min_x < 0 }) children = self.reader.get_children(tree) x_child = x + 1 for child in children: trees.append((child, x_child, y + 1)) x_child += child['size'] return self.lines
def Name(ea): return idc.get_name(ea, ida_name.GN_VISIBLE)
def activate(self, ctx): if self.action in ACTION_CONVERT: sel, start, end = lazy_read_selection() if not sel: idc.msg("[LazyIDA] Nothing to convert.") return False size = end - start data = idc.get_bytes(start, size) if isinstance(data, str): # python2 compatibility data = bytearray(data) assert size == len(data) name = idc.get_name(start, idc.GN_VISIBLE) if not name: name = "data" if data: print("\n[+] Dump 0x%X - 0x%X (%u bytes) :" % (start, end, size)) if self.action == ACTION_CONVERT[0]: # escaped string print('"%s"' % "".join("\\x%02X" % b for b in data)) elif self.action == ACTION_CONVERT[1]: # hex string print("".join("%02X" % b for b in data)) elif self.action == ACTION_CONVERT[2]: # C array output = "unsigned char %s[%d] = {" % (name, size) for i in range(size): if i % 16 == 0: output += "\n " output += "0x%02X, " % data[i] output = output[:-2] + "\n};" print(output) elif self.action == ACTION_CONVERT[3]: # C array word data += b"\x00" array_size = (size + 1) // 2 output = "unsigned short %s[%d] = {" % (name, array_size) for i in range(0, size, 2): if i % 16 == 0: output += "\n " output += "0x%04X, " % u16(data[i:i+2]) output = output[:-2] + "\n};" print(output) elif self.action == ACTION_CONVERT[4]: # C array dword data += b"\x00" * 3 array_size = (size + 3) // 4 output = "unsigned int %s[%d] = {" % (name, array_size) for i in range(0, size, 4): if i % 32 == 0: output += "\n " output += "0x%08X, " % u32(data[i:i+4]) output = output[:-2] + "\n};" print(output) elif self.action == ACTION_CONVERT[5]: # C array qword data += b"\x00" * 7 array_size = (size + 7) // 8 output = "unsigned long %s[%d] = {" % (name, array_size) for i in range(0, size, 8): if i % 32 == 0: output += "\n " output += "%#018X, " % u64(data[i:i+8]) output = output[:-2] + "\n};" print(output.replace("0X", "0x")) elif self.action == ACTION_CONVERT[6]: # python list print("[%s]" % ", ".join("0x%02X" % b for b in data)) elif self.action == ACTION_CONVERT[7]: # python list word data += b"\x00" print("[%s]" % ", ".join("0x%04X" % u16(data[i:i+2]) for i in range(0, size, 2))) elif self.action == ACTION_CONVERT[8]: # python list dword data += b"\x00" * 3 print("[%s]" % ", ".join("0x%08X" % u32(data[i:i+4]) for i in range(0, size, 4))) elif self.action == ACTION_CONVERT[9]: # python list qword data += b"\x00" * 7 print("[%s]" % ", ".join("%#018X" % u64(data[i:i+8]) for i in range(0, size, 8)).replace("0X", "0x")) elif self.action == ACTION_COPYDATA: # added by merc, modfiy by HTC sel, start, end = lazy_read_selection() if not sel: return 0 data = idaapi.get_bytes(start, end - start) data = data.encode('hex') copy_to_clip(data) print("[LazyIDA] copied hex string '%s'" % data) elif self.action == ACTION_XORDATA: sel, start, end = lazy_read_selection() if not sel: return 0 data = idc.get_bytes(start, end - start) if isinstance(data, str): # python2 compatibility data = bytearray(data) x = idaapi.ask_long(0, "Xor with...") if x: x &= 0xFF print("\n[+] Xor 0x%X - 0x%X (%u bytes) with 0x%02X:" % (start, end, end - start, x)) print(repr("".join(chr(b ^ x) for b in data))) elif self.action == ACTION_FILLNOP: sel, start, end = lazy_read_selection() if not sel: return 0 idaapi.patch_bytes(start, b"\x90" * (end - start)) print("\n[+] Fill 0x%X - 0x%X (%u bytes) with NOPs" % (start, end, end - start)) elif self.action == ACTION_SCANVUL: print("\n[+] Finding Format String Vulnerability...") found = [] for addr in idautils.Functions(): name = idc.get_func_name(addr) if "printf" in name and "v" not in name and idc.get_segm_name(addr) in (".text", ".plt", ".idata"): xrefs = idautils.CodeRefsTo(addr, False) for xref in xrefs: vul = self.check_fmt_function(name, xref) if vul: found.append(vul) if found: print("[!] Done! %d possible vulnerabilities found." % len(found)) ch = VulnChoose("Vulnerability", found, None, False) ch.Show() else: print("[-] No format string vulnerabilities found.") elif self.action == ACTION_COPYNAME: copy_highlight_name() elif self.action == ACTION_PASTENAME: paste_highlight_name() else: return 0 return 1
def generate(self): signatures = RizzoSignatures() # Generate unique string-based function signatures for (ea, string) in self.strings.items(): # Only generate signatures on reasonably long strings with one xref if len(string.value) < 8 or len(string.xrefs) != 1: continue func = idaapi.get_func(string.xrefs[0]) if not func: continue strhash = self.sighash(string.value) # Check for and remove string duplicate signatures (the same # string can appear more than once in an IDB). # If no duplicates, add this to the string signature dict. if strhash in signatures.strings: del signatures.strings[strhash] signatures.stringdups.add(strhash) elif strhash not in signatures.stringdups: signatures.strings[strhash] = func.start_ea # Generate formal, fuzzy, and immediate-based function signatures for ea in idautils.Functions(): func = idaapi.get_func(ea) if not func: continue # Generate a signature for each block in this function blocks = self.function(func) # Build function-wide formal and fuzzy signatures by simply # concatenating the individual function block signatures. formal = self.sighash(''.join([str(e) for (e, f, i, c) in blocks])) fuzzy = self.sighash(''.join([str(f) for (e, f, i, c) in blocks])) # Add this signature to the function dictionary. signatures.functions[func.start_ea] = (idc.get_name(func.start_ea, ida_name.GN_VISIBLE), blocks) # Check for and remove formal duplicate signatures. # If no duplicates, add this to the formal signature dict. if formal in signatures.formal: del signatures.formal[formal] signatures.formaldups.add(formal) elif formal not in signatures.formaldups: signatures.formal[formal] = func.start_ea # Check for and remove fuzzy duplicate signatures. # If no duplicates, add this to the fuzzy signature dict. if fuzzy in signatures.fuzzy: del signatures.fuzzy[fuzzy] signatures.fuzzydups.add(fuzzy) elif fuzzy not in signatures.fuzzydups: signatures.fuzzy[fuzzy] = func.start_ea # Check for and remove immediate duplicate signatures. # If no duplicates, add this to the immediate signature dict. for (e, f, immediates, c) in blocks: for immediate in immediates: if immediate in signatures.immediates: del signatures.immediates[immediate] signatures.immediatedups.add(immediate) elif immediate not in signatures.immediatedups: signatures.immediates[immediate] = func.start_ea # These need not be maintained across function calls, # and only add to the size of the saved signature file. signatures.fuzzydups = set() signatures.formaldups = set() signatures.stringdups = set() signatures.immediatedups = set() # DEBUG signatures.show() return signatures