def run(self, arg): self.term() self.view = Initrefview_t() if not self.view.Create(WINDOW_NAME): return for start in idautils.Segments(): segm = self.init_segm if self.is_seg_init( start) else self.non_init_segm segm.add((start, idaapi.getseg(start).end_ea)) if not self.refs: self.generate_refs() self.display_refs() self.view.Show()
def rename_guids(): labels = {} # Load GUIDs guids = dict( (str(GUID(array=v)), k) for k, v in efiguids.GUIDs.iteritems() ) guids.update(dict((v, k) for k, v in local_guids.iteritems())) # Find all the data segments in this binary for seg_addr in idautils.Segments(): seg = ida_segment.getseg(seg_addr) print "Processing data segment at 0x{:08x}".format(seg_addr) # Find any GUIDs we know about in the data segment cur_addr = seg.start_ea seg_end = seg.end_ea while cur_addr < seg_end: d = [ida_bytes.get_dword(cur_addr), ida_bytes.get_dword(cur_addr+0x4), ida_bytes.get_dword(cur_addr+0x8), ida_bytes.get_dword(cur_addr+0xC)] if (d[0] == 0 and d[1] == 0 and d[2] == 0 and d[3] == 0) or \ ( d[0] == 0xFFFFFFFF and d[1] == 0xFFFFFFFF and d[2] == 0xFFFFFFFF and d[3] == 0xFFFFFFFF ): cur_addr += 0x10 else: guid = GUID(bytes=struct.pack( "<LLLL", d[0], d[1], d[2], d[3] )) gstr = str(guid) if gstr in guids.keys(): print " - Found GUID {} ({}) at 0x{:08x}".format( gstr, guids[gstr], cur_addr ) struct_label = get_next_unused_label( underscore_to_global(guids[gstr]) ) ida_name.set_name(cur_addr, struct_label) labels[struct_label] = (cur_addr, guids[gstr]) cur_addr += 0x10 else: cur_addr += 0x08 return labels
def initialize_data_offsets(): """Convert offsets in data segments into offsets in IDA. Segment names must be initialized with segments.initialize_segments() first. """ # Normally, for user-space programs, this operation would be dangerous because there's a good # chance that a valid userspace address would happen to show up in regular program data that is # not actually an address. However, since kernel addresses are numerically much larger, the # chance of this happening is much less. for seg in idautils.Segments(): name = idc.get_segm_name(seg) if not (name.endswith('__DATA_CONST.__const') or name.endswith('__got') or name.endswith('__DATA.__data') or name.endswith('__DATA_CONST.__auth_ptr')): continue for word, ea in idau.ReadWords(seg, idc.get_segm_end(seg), addresses=True): if idau.is_mapped(word, value=False): idc.op_plain_offset(ea, 0, 0)
def __init__(self, title, api_results, flags=0): Choose.__init__(self, title, [["#", 6], ["Offset", 14], ["API Address", 14], ["DLL", 20], ["API", 35]], embedded=True, width=140, height=20, flags=flags) self.row_count = 0 self.base_address = [ea for ea in idautils.Segments()][0] self.scout = ApiScout() self.scout.setBaseAddress(self.base_address) self.api_results = api_results self.all_items = self.populate(api_results) self.items = self.populate(api_results) self.icon = 4 self.selcount = 0
def findMostUsedFunctions(count, notModified=False, disp=True): # type: (int, bool, bool) -> list[int] """ Returns the functions with the highest count of xrefsTo. if notModified, only those that are in the format *_xxxxxxx are returned. if disp, the output is formatted and printed as well :param count: the number of the most used functions to find :param notModified: only functions with names ending in func_ea, or all functions :param disp: print the output :return: list of function linear addresses to the most used functions """ funcXrefs = [] if count <= 0: count = 1 for i in range(count): funcXrefs.append((0, 0)) for seg_ea in idautils.Segments(): for func_ea in idautils.Functions(seg_ea, idc_bc695.SegEnd(seg_ea)): if notModified: name = Function.Function(func_ea).getName() if not ('_' in name and name[name.rindex('_'):] == ('_%X' % func_ea)): continue xrefs = Function.Function(func_ea).getXRefsTo() numXrefs = len(xrefs[0]) + len(xrefs[1]) # add if more than least in the list and sort if numXrefs > funcXrefs[0][1]: funcXrefs[0] = (func_ea, numXrefs) funcXrefs = sorted(funcXrefs, key=lambda tup: tup[1]) # reverse to display most common first funcXrefs = sorted(funcXrefs, key=lambda tup: tup[1], reverse=True) if disp: for func_ea, xrefCount in funcXrefs: print('%07x <%s::%s>: %d' % (func_ea, mtcomm.ea2gf(func_ea), Function.Function(func_ea).getName(), xrefCount)) output = [] for func_ea, xrefCount in funcXrefs: output.append(func_ea) return output
def __patch_indirect_call_instructions(): for seg in idautils.Segments(): for func in idautils.Functions(seg): function_name = idc.get_func_name(func) print('[+] Checking function "{}"'.format(function_name)) for (startea, endea) in idautils.Chunks(func): for head in idautils.Heads(startea, endea): m = idc.print_insn_mnem(head) if m == 'call': op = idc.get_operand_type(head, 0) if op == idc.o_displ: print('{}: 0x{:08x}: {}'.format( function_name, head, idc.generate_disasm_line(head, 0))) ida_bytes.patch_word(head, 0x15ff) print('{}: 0x{:08x}: {}'.format( function_name, head, idc.generate_disasm_line(head, 0)))
def initialize_stub_symbols(make_thunk=True): """Populate IDA with information about the stubs in an iOS kernelcache. Search through the kernelcache for stubs (__stubs sections) and rename each stub function according to the target function it calls. Arm64 only. Options: make_thunk: Set the thunk attribute for each stub function. Default is True. """ next_stub = internal.make_name_generator(kernelcache_stub_suffix) for ea in idautils.Segments(): segname = idc.SegName(ea) if not segname.endswith('__stubs'): continue _log(3, 'Processing segment {}', segname) _process_stubs_section(ea, make_thunk, next_stub)
def getAllSegments(): segs = list() si = SegmInfo() i = 0 for ea in idautils.Segments(): seg = idaapi.getseg(ea) si.m_name = idc.SegName(ea) si.m_startAddr = int(idc.SegStart(ea)) si.m_endAddr = int(idc.SegEnd(ea)) si.m_className = idaapi.get_segm_class(seg) segs.append(si) print "[%d]" % (i) print "Segment name: %s" % (si.m_name) print "Segment start address: 0x%08x" % (si.m_startAddr) print "Segment end address: 0x%08x" % (si.m_endAddr) print "Segment class name: %s" % (si.m_className) i += 1 return segs
def main(): print("[*] Start Replace Symbolic Constant") for start in idautils.Segments(): #if idc.get_segm_name(start) != '.text': # continue ea = start end = idc.get_segm_end(start) while ea < end: ea = idc.next_head(ea, end) op = idc.print_insn_mnem(ea) if op == "call": api = is_replace_api(ea) if api == False: continue replace_sym_const(ea, api) print("[*] Finished Replace Symbolic Constant")
def preprocessBinary(): # loop through every instruction and # keep a list of jump tables references in the # data section. These are used so we can # avoid generating unwanted function entry points for seg_ea in idautils.Segments(): for head in idautils.Heads(seg_ea, idc.SegEnd(seg_ea)): if idc.isCode(idc.GetFlags(head)): si = idaapi.get_switch_info_ex(head) if si is not None and isUnconditionalJump(head): DEBUG("Found a jmp based switch at: {0:x}\n".format(head)) esize = si.get_jtable_element_size() base = si.jumps count = si.get_jtable_size() for i in xrange(count): fulladdr = base+i*esize DEBUG("Address accessed via JMP: {:x}\n".format(fulladdr)) ACCESSED_VIA_JMP.add(fulladdr)
def getModuleFunctions(self): """ This traverses all segments, and all defined modules to retrieve all functions with that module name. :return: a list of Functions that are in this module, saved in the database. """ output = [] for seg_ea in idautils.Segments(): for func_ea in idautils.Functions(idc_bc695.SegStart(seg_ea), idc_bc695.SegEnd(seg_ea)): func = Function.Function(func_ea) # if the function starts with '<moduleName>'... funcName = func.getName() inModel = len(funcName) >= len( self.name) + 1 and funcName[0:len(self.name) + 1] == self.name + '_' if inModel: output.append(func) return output
def _get_memory(): """ stolen from Dan aka @push_pnx copies bytes from IDB into memory that yara scans :return: """ result = "" segments_starts = [ea for ea in idautils.Segments()] offsets = [] start_len = 0 for start in segments_starts: end = idc.get_segm_end(start) # range or xrange can fail on 64-bit addresses due to an overflow for ea in _wowrange(start, end): result += chr(idc.Byte(ea)) offsets.append((start, start_len, len(result))) start_len = len(result) return result, offsets
def seh(): print "Searching places where SEH are set..." founds = [] for seg in idautils.Segments(): heads = list(Heads(SegStart(seg), SegEnd(seg))) for i,ea in enumerate(heads): mnem = GetMnem(ea) if (mnem == 'push') and ('fs:0' in GetOpnd(ea, 0)) and ('security_cookie' not in GetOpnd(heads[i+1], 1)): SetColor(ea, CIC_ITEM, 0xFF00FF) SetColor(heads[i-1], CIC_ITEM, 0xFF00FF) SetColor(heads[i+1], CIC_ITEM, 0xFF00FF) founds.append(hex(ea)) MakeComm(heads[i-1], "SEH CREATING") print "Finished. Addresses were highlighted", founds printSehImports()
def search_idb(self): """Search IDB for possible MZ/PE headers""" # Determine pointer display width info = idaapi.get_inf_structure() if info.is_64bit(): width = 16 else: width = 8 # Search all segments for seg in idautils.Segments(): s = idc.get_segm_start(seg) e = idc.get_segm_end(seg) addr = s while True: # Find first byte of MZ header addr = ida_bytes.find_byte(addr, e - addr, 0x4d, 0) if addr == ida_idaapi.BADADDR or addr >= e: break # Check for MZ magic if ida_bytes.get_word(addr) == 0x5a4d: # Ensure the PE header is in the segment e_lfanew = ida_bytes.get_dword(addr + 0x3c) if addr + e_lfanew + 1 < e: # Check for PE magic if ida_bytes.get_word(addr + e_lfanew) == 0x4550: # Found possible MZ/PE file self.form.runtime.log("0x{:0{w}x} - {}".format( addr, idc.get_segm_name(s), w=width)) self.form.map_pe(image_base=addr, filename="{} - 0x{:0{w}x}".format( idc.get_segm_name(s), addr, w=width)) # Resume search from next address addr += 1
def enumerate_function_names(): func_name = dict() for seg_ea in idautils.Segments(): # For each of the functions function_ea = seg_ea while function_ea != 0xffffffffL: function_name = idc.GetFunctionName(function_ea) # if already analyzed if func_name.get(function_name, None) != None: function_ea = idc.NextFunction(function_ea) continue image_base = idaapi.get_imagebase(function_ea) addr = function_ea - image_base addr = str(hex(addr)) addr = addr.replace("L", "") addr = addr.replace("0x", "") func_name[function_name] = get_list_of_function_instr(function_ea) function_ea = idc.NextFunction(function_ea) return func_name
def get_architecture_name(self): """Fetch the name to be used to identify the architecture.""" # Get the addressing mode of the first segment in the IDB and # set it to describe the module in the database. # This would need to be rethought for the cases where addressing # might change withing a module. # bitness = idc.GetSegmentAttr( list(idautils.Segments())[0], idc.SEGATTR_BITNESS) if bitness == 0: bitness = 16 elif bitness == 1: bitness = 32 elif bitness == 2: bitness = 64 return '%s-%d' % (self.arch_name, bitness)
def _find_prelink_info_segments(): """Find all candidate __PRELINK_INFO segments (or sections). We try to identify any IDA segments with __PRELINK_INFO in the name so that this function will work both before and after automatic rename. A more reliable method would be parsing the Mach-O. """ segments = [] # Gather a list of all the possible segments. for seg in idautils.Segments(): name = idc.get_segm_name(seg) if '__PRELINK_INFO' in name or name == '__info': segments.append(seg) if len(segments) < 1: _log(0, 'Could not find any __PRELINK_INFO segment candidates') elif len(segments) > 1: _log(1, 'Multiple segment names contain __PRELINK_INFO: {}', [idc.get_segm_name(seg) for seg in segments]) return segments
def _collect_metaclasses(): """Collect OSMetaClass information from all kexts in the kernelcache.""" # Collect associations from class names to metaclass instances and vice versa. metaclass_to_classname_builder = _OneToOneMapFactory() metaclass_to_class_size = dict() metaclass_to_meta_superclass = dict() def found_metaclass(metaclass, classname, class_size, meta_superclass): metaclass_to_classname_builder.add_link(metaclass, classname) metaclass_to_class_size[metaclass] = class_size metaclass_to_meta_superclass[metaclass] = meta_superclass for ea in idautils.Segments(): segname = idc.get_segm_name(ea) if not _should_process_segment(ea, segname): continue _log(2, 'Processing segment {}', segname) _process_mod_init_func_section_for_metaclasses(ea, found_metaclass) # Filter out any class name (and its associated metaclasses) that has multiple metaclasses. # This can happen when multiple kexts define a class but only one gets loaded. def bad_classname(classname, metaclasses): _log(0, 'Class {} has multiple metaclasses: {}', classname, ', '.join(['{:#x}'.format(mc) for mc in metaclasses])) # Filter out any metaclass (and its associated class names) that has multiple class names. I # have no idea why this would happen. def bad_metaclass(metaclass, classnames): _log(0, 'Metaclass {:#x} has multiple classes: {}', metaclass, ', '.join(classnames)) # Return the final dictionary of metaclass info. metaclass_to_classname = metaclass_to_classname_builder.build( bad_metaclass, bad_classname) metaclass_info = dict() for metaclass, classname in list(metaclass_to_classname.items()): meta_superclass = metaclass_to_meta_superclass[metaclass] superclass_name = metaclass_to_classname.get(meta_superclass, None) metaclass_info[metaclass] = classes.ClassInfo( classname, metaclass, None, None, metaclass_to_class_size[metaclass], superclass_name, meta_superclass) return metaclass_info
def _listUpdatedSymbols(elfPath): """ 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 :return: list of (name_ea, [(new_name, isLocal)]) """ # TODO [DESIGN]: function exists in Srch too. Remove redundancy output = [] 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: if ea in symTable 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 for symName, isLocal in symTable[name_ea]: if name == symName: nameInSymTable = True # a name change was detected if not nameInSymTable: output.append((ea, symTable[name_ea])) return output
def _find_prelink_info_segment(): """Find the __PRELINK_INFO segment. We try to identify a unique segment with __PRELINK_INFO in the name so that this function will work both before and after automatic rename. A more reliable method would be parsing the Mach-O. """ segments = [] for seg in idautils.Segments(): name = idc.SegName(seg) if '__PRELINK_INFO' in name: segments.append(seg) if len(segments) < 1: _log(0, 'No segment name contains __PRELINK_INFO') elif len(segments) > 1: _log(0, 'Multiple segment names contain __PRELINK_INFO: {}', [idc.SegName(seg) for seg in segments]) else: return segments[0] return None
def initialize_data_offsets(): """Convert offsets in data segments into offsets in IDA. This function should only be run on 11-normal style kernelcaches. Segment names must be initialized with segments.initialize_segments() first. """ assert kernel.kernelcache_format == kernel.KC_11_NORMAL, 'Wrong kernelcache format' # Normally, for user-space programs, this operation would be dangerous because there's a good # chance that a valid userspace address would happen to show up in regular program data that is # not actually an address. However, since kernel addresses are numerically much larger, the # chance of this happening is much less. for seg in idautils.Segments(): name = idc.SegName(seg) if not (name.endswith('__DATA_CONST.__const') or name.endswith('__got') or name.endswith('__DATA.__data')): continue for word, ea in idau.ReadWords(seg, idc.SegEnd(seg), addresses=True): if idau.is_mapped(word, value=False): idc.OpOff(ea, 0, 0)
def getx86CodeSize(ea=None): ''' For a given EA, finds the code size. Returns 16 for-16bit, 32 for 32-bit, or 64 for 64-bit. If no EA is given, searches through all segments for a code segment to use. ''' if ea is None: for seg in idautils.Segments(): if idc.GetSegmentAttr(seg, idc.SEGATTR_TYPE) == idc.SEG_CODE: ea = seg break if ea is None: raise RuntimeError('Could not find code segment to use for getx86CodeSize') bitness = idc.GetSegmentAttr(ea, idc.SEGATTR_BITNESS) if bitness == 0: return 16 elif bitness == 1: return 32 elif bitness == 2: return 64 raise RuntimeError('Bad bitness')
def get_sections(): """ Get section names and start/end addrs from IDA database :return: Dict containing section info """ sections = {} for ea in idautils.Segments(): segm = ida_segment.getseg(ea) name = ida_segment.get_segm_name(segm) if name == 'LOAD': continue curr = {} curr['start'] = segm.start_ea curr['end'] = segm.end_ea sections[name] = curr return sections
def parse_func_pointer(): renamed = 0 for segea in idautils.Segments(): for addr in idautils.Functions(segea, idc.SegEnd(segea)): #for addr in idautils.Functions(text_seg.startEA, text_seg.endEA): name = idc.GetFunctionName(addr) # Look at data xrefs to the function - find the pointer that is located in .rodata data_ref = idaapi.get_first_dref_to(addr) while data_ref != idc.BADADDR: if 'rodata' in idc.get_segm_name(data_ref): # Only rename things that are currently listed as an offset; eg. off_9120B0 if 'off_' in idc.GetTrueName(data_ref): if idc.MakeNameEx(data_ref, ('%s_ptr' % name), flags=idaapi.SN_FORCE): idaapi.autoWait() renamed += 1 else: log._error('Failed to name pointer @ 0x%02x for %s' % (data_ref, name)) data_ref = idaapi.get_next_dref_to(addr, data_ref)
def add_rodata_segment(self): last_seg_end = idc.get_first_seg() # print(hex(last_seg_end)) for s in idautils.Segments(): start = idc.get_segm_start(s) end = idc.get_segm_end(s) if int(start) != int(last_seg_end): # found idaapi.add_segm(0, last_seg_end, start, "roooodata", "CONST") print("Adding segment from 0x%x to 0x%x" % (last_seg_end, start)) print("OK") break else: last_seg_end = end idc.plan_and_wait(ida_ida.inf_get_min_ea(), ida_ida.inf_get_max_ea()) # idc.plan_and_wait(idc.MinEA(), idc.MaxEA()) self.start = last_seg_end self.end = start return last_seg_end, start
def create_call_map(self, ftype): assert_ida_available() import idc import idautils seg_mapping = { idc.SegName(x): (idc.SegStart(x), idc.SegEnd(x)) for x in idautils.Segments() } imports = seg_mapping[".idata"] if ftype == PE else seg_mapping['.plt'] start, stop = seg_mapping[".text"] current = start while current <= stop: inst = current if idc.GetMnem(inst) in ["call", "jmp"]: value = idc.GetOperandValue(inst, 0) name = idc.GetOpnd(inst, 0) if imports[0] <= value <= imports[1]: entry = self.config.call_map.add() entry.address = inst entry.name = name current = idc.NextHead(current, stop)
def init_strings(force=False, target_seg_name=None): global string_initialized if not force and string_initialized: return for ea in idautils.Segments(): seg = ida_segment.getseg(ea) seg_name = ida_segment.get_segm_name(seg) # We only check target segment since it may take too much time. if target_seg_name and seg_name == target_seg_name: continue print("Initializing %x -> %x (%s)" % (seg.start_ea, seg.end_ea, seg_name)) # TODO: we may use other strategy to find string pointers analyze_str_ptr(seg.start_ea, seg.end_ea) analyze_ida_str() string_initialized = True
def __init__(self, fmt='[+] srch (IDB/binary searching utils)'): """ This module is responsible for printing disassemblies and necessary compoents of disassemblies """ super(srch, self).__init__(fmt) self.registerCommand(self, self.nextarm, "nextarm", "<search_ea> [ui=True]") self.registerCommand(self, self.nextascii, "nextascii", "<search_ea> [ui=True]") self.registerCommand(self, self.nextfakeinst, "nextfakeinst", "<search_ea> [ui=True]") self.registerCommand(self, self.nextname, "nextname", "<search_ea> [ui=True]") self.registerCommand(self, self.nextknown, "nextknown", "<search_ea> [ui=True]") self.registerCommand(self, self.nextbin, "nextbin", "<search_ea> [ui=True]") self.registerCommand(self, self.nextred, "nextred", "<search_ea> [ui=True]") self.registerCommand(self, self.nextimmref, "nextimmref", "<search_ea> [ui=True]") # figure out the very last ea reachable self.end_ea = 0 for seg in idautils.Segments(): if idc.SegEnd(seg) > self.end_ea: self.end_ea = idc.SegEnd(seg)
def run_yara_on_segment(rule_text, name=None, start_ea=None, callback_func=_yara_callback): ''' Description: Applies yara rule to the bytes in the specified segment and returns raw results. Segments may be specified by name or start EA, but one or the other is required. Clears the matches each time to prevent duplicates. Input: name - The name of the target segment start_ea - The start EA of the target segment callback_func - A pointer to the callback function for YARA's matching to use Output: Returns a list of YARA's match results with items (location, description) ''' global _YARA_MATCHES, FROM_FILE _YARA_MATCHES = [] FROM_FILE = False if name is None and start_ea is None: raise Exception( "Either a segment name or start EA are required to YARA scan a specific segment." ) rule = yara.compile(source=rule_text) found_segment = False for seg in map(idaapi.getseg, idautils.Segments()): if seg.startEA == start_ea or idaapi.get_segm_name( seg.startEA) == name: found_segment = True for bites in _read_bytes(seg.startEA, seg.endEA): rule.match(data=bites, callback=callback_func) if not found_segment: append_debug("Failed to find segment \"" + name + "\"") return _YARA_MATCHES
def rename_supposed_guids(self): EFI_GUID = "EFI_GUID *" for seg in idautils.Segments(): if idc.SegName(seg) == ".data": seg_start = idc.SegStart(seg) seg_end = idc.SegEnd(seg) break ea = seg_start while (ea <= seg_end - 15): prot_name = "" if idc.Name(ea).find("unk_") != -1: find = False CurrentGuid = [] CurrentGuid.append(idc.Dword(ea)) CurrentGuid.append(idc.Word(ea + 4)) CurrentGuid.append(idc.Word(ea + 6)) for addr in range(ea + 8, ea + 16, 1): CurrentGuid.append(idc.Byte(addr)) for name in self.Protocols["Edk2Guids"]: if self.Protocols["Edk2Guids"][name] == CurrentGuid: prot_name = name + "_" + hex(ea) find = True break for name in self.Protocols["EdkGuids"]: if self.Protocols["EdkGuids"][name] == CurrentGuid: prot_name = name + "_" + hex(ea) find = True break for name in self.Protocols["AmiGuids"]: if self.Protocols["AmiGuids"][name] == CurrentGuid: prot_name = name + "_" + hex(ea) find = True break if (find and \ idc.Name(ea) != prot_name and \ CurrentGuid[0] != 0 ): idc.SetType(ea, EFI_GUID) idc.MakeName(ea, prot_name) ea += 1