def calc_pe_size(self, image_base): # Blind guess at PE size based on contigious segments size = idc.get_segm_end(image_base) - image_base prev = idc.get_segm_start(image_base) offset = idc.get_next_seg(image_base) if offset == ida_idaapi.BADADDR: size = 0 # Size based on contigious segments by address while offset != ida_idaapi.BADADDR and idc.get_segm_end( prev) == offset: size += idc.get_segm_end(offset) - offset prev = offset offset = idc.get_next_seg(offset) if size <= 0x1000: name = idc.get_segm_name(image_base) prev = idc.get_segm_start(image_base) offset = idc.get_next_seg(image_base) start = offset # Size based on contigious segments by name while offset != ida_idaapi.BADADDR and idc.get_segm_name( prev) == name: prev = offset offset = idc.get_next_seg(offset) size = idc.get_segm_end(offset) - start self.ret = size return self.ret
def find_pointers(start, end): for va in range(start, end - 0x8): ptr = ida_bytes.get_qword(va) if idc.get_segm_start(ptr) != idc.BADADDR: yield va, ptr, 8 ptr = ida_bytes.get_dword(va) if idc.get_segm_start(ptr) != idc.BADADDR: yield va, ptr, 4
def getSegName(self, segName): for seg in idautils.Segments(): #under IDA 7.4 #if idc.SegName(seg) == segName: #over IDA 7.4 if idc.get_segm_name(seg) == segName: #under IDA 7.4 #return idc.SegStart(seg), idc.SegEnd(seg), idc.SegEnd(seg) - idc.SegStart(seg) #over IDA 7.4 return idc.get_segm_start(seg), idc.get_segm_end( seg), idc.get_segm_end(seg) - idc.get_segm_start(seg)
def main(): idaapi.auto_wait() base = idaapi.get_imagebase() tif = idaapi.tinfo_t() f = open(os.environ.get("DESTPATH", "functype_"), 'w') for ea in Segments(): # only code segment if idaapi.segtype(ea) != idaapi.SEG_CODE: continue for fva in Functions(get_segm_start(ea), get_segm_end(ea)): func_name = get_func_name(fva) has_type = idaapi.get_tinfo(tif, fva) or idaapi.guess_tinfo( tif, fva) if not has_type: continue info = serialize(tif) if info is None: continue print( hex(fva - base)[:-1], "|", func_name, "|", tif, "|", len(info['args'])) f.write("0x%x|%s|%s\n" % (fva - base, func_name, json.dumps(info))) f.close() idaapi.qexit(0)
def enum_func(self): ### iterate to all functions of the malware ea = here() func_addr = 0 seg_start = idc.get_segm_start(ea) seg_end = idc.get_segm_end(ea) for func_addr in idautils.Functions(seg_start, seg_end): func_name = idc.get_func_name(func_addr) if self.seh_func_name in func_name: print("[+] STATUS: Found Needed Function -> {} {}".format( hex(func_addr), func_name)) break else: pass #print("[-] STATUS: Skipped this Function -> {} {}".format(hex(func_addr),func_name)) self.find_xref_func(func_addr) ### find the ehFuncInfo Address which is the mov address before the jmp to ___CxxFrameHandler ### .text:00407B60 mov eax, offset stru_408928 ### .text:00407B65 jmp ___CxxFrameHandler self.find_ehfuncinfo_addr() return
def run(self, arg=0): print("hell2") idaapi.msg("run() called with %d!\n" % arg) heads = Heads(get_segm_start(get_screen_ea()), get_segm_end(get_screen_ea())) funcCalls = [] xor = [] antiVM = [] for i in heads: # Color the Calls off-white if print_insn_mnem(i) == "call": funcCalls.append(i) # Color Anti-VM instructions Red and print their location elif print_insn_mnem(i) in ("sidt", "sgdt", "sldt", "smsw", "str", "in", "cpuid"): antiVM.append(i) # Color non-zeroing out xor instructions Orange elif print_insn_mnem(i) == "xor" and (print_operand(i,0) != print_operand(i,1)): xor.append(i) print("Number of calls: %d" % (len(funcCalls))) for i in funcCalls: set_color(i, CIC_ITEM, 0xc7fdff) print("Number of potential Anti-VM instructions: %d" % (len(antiVM))) for i in antiVM: print("Anti-VM potential at %x" % i) set_color(i, CIC_ITEM, 0x0000ff) print("Number of xor: %d" % (len(xor))) for i in xor: set_color(i, CIC_ITEM, 0x00a5ff)
def find_pointers(start, end): for va in range(start, end - 0x4): ptr = idc.get_wide_dword(va) if idc.get_segm_start(ptr) == idc.BADADDR: continue yield va, ptr
def is_destructor_segment(ea): """Returns `True` if the segment containing `ea` belongs to global destructor section""" seg_ea = idc.get_segm_start(ea) seg_name = idc.get_segm_name(seg_ea).lower() if seg_name in [".fini_array", ".dtor"]: return True return False
def search_idb(self): """Search IDB for possible MZ/PE headers""" # 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{:08x} - {}".format(addr, idc.get_segm_name(s))) self.form.map_pe(image_base=addr) # Resume search from next address addr += 1
def is_external_segment(ea): """Returns `True` if the segment containing `ea` looks to be solely containing external references.""" global _NOT_EXTERNAL_SEGMENTS seg_ea = idc.get_segm_start(ea) if seg_ea in _NOT_EXTERNAL_SEGMENTS: return False if seg_ea in _EXTERNAL_SEGMENTS: return True if is_external_segment_by_flags(ea): _EXTERNAL_SEGMENTS.add(seg_ea) return True ext_types = [] seg_name = idc.get_segm_name(seg_ea).lower() if IS_ELF: if ".got" in seg_name or ".plt" in seg_name: _EXTERNAL_SEGMENTS.add(seg_ea) return True elif IS_PE: if ".idata" == seg_name: # Import table. _EXTERNAL_SEGMENTS.add(seg_ea) return True _NOT_EXTERNAL_SEGMENTS.add(seg_ea) return False
def processDataSegs(): funcdata = {} datafunc = {} for n in xrange(idaapi.get_segm_qty()): seg = idaapi.getnseg(n) ea = seg.startEA segtype = idc.get_segm_attr(ea, idc.SEGATTR_TYPE) if segtype in [idc.SEG_DATA, idc.SEG_BSS]: start = idc.get_segm_start(ea) end = idc.get_segm_end(ea) cur = start while cur <= end: refs = [v for v in DataRefsTo(cur)] for fea in refs: name = get_unified_funcname(fea) if len(name) == 0: continue if name not in funcdata: funcdata[name] = [cur] else: funcdata[name].append(cur) if cur not in datafunc: datafunc[cur] = [name] else: datafunc[cur].append(name) cur = NextHead(cur) return funcdata, datafunc
def is_code(ea): if is_invalid_ea(ea): return False seg_ea = idc.get_segm_start(ea) seg_type = idc.get_segm_attr(seg_ea, idc.SEGATTR_TYPE) return (seg_type == idc.SEG_CODE)
def append_segment(segment_name): """ Add a new segment to the IDB file and return its starting address. Information about function arguments will be stored here. Only works if the segment name is not used yet. This does not affect the original binary. Arguments: segment_name -- the name of the segment to be added """ for segment in idautils.Segments(): if idc.get_segm_name(segment) == segment_name: g_logger.warning('Segment ' + segment_name + ' already exists') return idc.get_segm_start(segment) new_segment_start = get_end_of_last_segment() g_logger.debug('Adding new segment at 0x%08x' % new_segment_start) if not idc.AddSeg(new_segment_start, (new_segment_start + NEW_SEGMENT_SIZE), 0, 1, 0, idaapi.scPub) == 1: raise FailedToAppendSegmentException('Could not add segment') # set new segment's attributes if not idc.set_segm_name(new_segment_start, segment_name): raise FailedToAppendSegmentException('Could not rename segment') if not idc.set_segm_class(new_segment_start, 'DATA'): raise FailedToAppendSegmentException('Could not set segment class') if not idc.set_segm_alignment(new_segment_start, idc.saRelPara): raise FailedToAppendSegmentException('Could not align segment') if not idc.set_segm_addressing(new_segment_start, 1): # 1 -- 32 bit raise FailedToAppendSegmentException( 'Could not set segment addressing') return new_segment_start
def get_func_range(ea): funcs = {} for funcea in idautils.Functions(idc.get_segm_start(ea)): funcname = get_unified_funcname(funcea) func = get_func(funcea) funcs[funcname] = (func.startEA, func.endEA) return funcs
def find_pe(self, cursor=False): """Search IDB for possible MZ/PE headers""" info = idaapi.get_inf_structure() mz_headers = [] # Check current cursor for MZ/PE? if cursor: # Get IDA cursor address addr = idc.here() # Get segment and end address s = idaapi.getseg(addr) e = idc.get_segm_end(addr) # 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 header mz_headers.append([addr, idc.get_segm_name(addr), info.is_64bit()]) self.ret = mz_headers return self.ret # 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 header mz_headers.append([addr, idc.get_segm_name(s), info.is_64bit()]) # Resume search from next address addr += 1 self.ret = mz_headers return self.ret
def get_func_bases(ea): funcs = {} plt_func, plt_data = processpltSegs() for funcea in idautils.Functions(idc.get_segm_start(ea)): funcname = get_unified_funcname(funcea) if funcname in plt_func: continue funcs[funcea] = funcname return funcs
def recover_frame_entries(seg_ea): if seg_ea == idc.BADADDR: return DEBUG("Recover entries from section : {}".format(idc.get_segm_name(seg_ea))) ea = idc.get_segm_start(seg_ea) end_ea = idc.get_segm_end(seg_ea) while ea != idc.BADADDR and ea < end_ea: ea = format_entries(ea)
def gt_funcNames(ea): funcs = [] plt_func, plt_data = processpltSegs() for funcea in idautils.Functions(idc.get_segm_start(ea)): funcname = get_unified_funcname(funcea) if funcname in plt_func: print funcname continue funcs.append(funcname) return funcs
def fill_segments(self): segments = filter(self.segment_filter, idautils.Segments()) for idx, s_ea in enumerate(segments): if idx == 0: self.set_address(idc.get_segm_start(s_ea), idc.get_segm_end(s_ea)) self.cb_segment.addItem(idc.get_segm_name(s_ea), s_ea) if not segments: self.set_address(MinEA(), MaxEA()) self.cb_segment.setEnabled(False)
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 guid_place in [ 'ami_guids', 'asrock_guids', 'dell_guids', 'edk_guids', 'edk2_guids', 'lenovo_guids' ]: for name in self.Protocols[guid_place]: if self.Protocols[guid_place][name] == cur_guid: prot_name = name + '_' + \ '{addr:#x}'.format(addr=ea) record = { 'address': ea, 'service': 'unknown', 'guid': cur_guid, 'protocol_name': name, 'protocol_place': guid_place } find = True break if find: 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_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 = str() if "unk" in idc.get_name(ea, ida_name.GN_VISIBLE): find = False cur_guid = list() 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 guid_place in [ "ami_guids", "asrock_guids", "dell_guids", "edk_guids", "edk2_guids", "lenovo_guids", ]: for name in self.Protocols[guid_place]: if self.Protocols[guid_place][name] == cur_guid: prot_name = f"{name}_{ea:016X}" record = { "address": ea, "service": "unknown", "guid": cur_guid, "protocol_name": name, "protocol_place": guid_place, } find = True break if find: 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 is_external_segment_by_flags(ea): """Returns `True` if IDA believes that `ea` belongs to an external segment.""" try: seg_ea = idc.get_segm_start(ea) seg_type = idc.get_segm_attr(seg_ea, idc.SEGATTR_TYPE) if seg_type == idc.SEG_XTRN: _EXTERNAL_SEGMENTS.add(seg_ea) return True else: return False except: return False
def getSegAddr(): textStart=0 textEnd=0 end = 0 for seg in idautils.Segments(): if (idc.get_segm_name(seg)).lower()=='.text' or (idc.get_segm_name(seg)).lower()=='text': textStart=idc.get_segm_start(seg) textEnd=idc.get_segm_end(seg) tmp = idc.get_segm_end(seg) if end < tmp: end = tmp return textStart,textEnd,end
def get_func_namesWithoutE(ea): funcs = {} plt_func, plt_data = processpltSegs() for funcea in idautils.Functions(idc.get_segm_start(ea)): funcname = get_unified_funcname(funcea) if 'close' in funcname: print funcea if funcname in plt_func: print funcname continue funcs[funcname] = funcea return funcs
def is_invalid_ea(ea): """Returns `True` if `ea` is not valid, i.e. it doesn't point into any valid segment.""" if (idc.BADADDR == ea) or \ (idc.get_segm_name(ea) == "LOAD"): return True try: idc.get_segm_attr(idc.get_segm_start(ea), idc.SEGATTR_TYPE) return False # If we get here, then it must be a valid ea! except: return True
def find_segment(name: str) -> List[Tuple[int, int]]: """ Try to find the segment from name :ivar name: name of segment :ret: Start ant end address """ result = [] for seg in idautils.Segments(): if idc.get_segm_name(seg) == name: result.append((idc.get_segm_start(seg), idc.get_segm_end(seg))) return result
def processAllSegments(self): for seg in idautils.Segments(): if using_ida7api: segStart = idc.get_segm_start(seg) segEnd = idc.get_segm_end(seg) else: segStart = idc.SegStart(seg) segEnd = idc.SegEnd(seg) if self.params.searchPushArgs: self.lookForOpArgs(segStart, segEnd) if self.params.searchDwordArray: self.lookForDwordArray(segStart, segEnd)
def getSegAddr(): textStart = [] textEnd = [] for seg in idautils.Segments(): if (idc.get_segm_name(seg)).lower() == '.text' or ( idc.get_segm_name(seg)).lower() == 'text': tempStart = idc.get_segm_start(seg) tempEnd = idc.get_segm_end(seg) textStart.append(tempStart) textEnd.append(tempEnd) return min(textStart), max(textEnd)
def get_list_of_functions(self): ''' Gets all functions list. ''' functions_list = {} seg_ea = idc.get_segm_by_sel(idc.SEG_NORM) for func_ea in idautils.Functions(idc.get_segm_start(seg_ea), idc.get_segm_end(seg_ea)): function_name = idc.get_func_name(func_ea) functions_list[function_name] = func_ea return functions_list
def _get_segments(self, attr): segments = [] start = idc.BADADDR end = idc.BADADDR seg = idc.get_first_seg() while seg != idc.BADADDR: if idc.get_segm_attr(seg, idc.SEGATTR_TYPE) == attr: start = idc.get_segm_start(seg) end = idc.get_segm_end(seg) segments.append((start, end)) seg = idc.get_next_seg(seg) return segments
def getFuncRanges_ida7(ea, doAllFuncs): if doAllFuncs: funcs = [] funcGen = idautils.Functions(idc.get_segm_start(ea), idc.get_segm_end(ea)) for i in funcGen: funcs.append(i) funcRanges = [] for i in range(len(funcs) - 1): funcRanges.append( (funcs[i], funcs[i+1]) ) funcRanges.append( (funcs[-1], idc.get_segm_end(ea)) ) return funcRanges else: #just get the range of the current function fakeRanges = [( idc.get_func_attr(idc.here(), idc.FUNCATTR_START), idc.get_func_attr(idc.here(), idc.FUNCATTR_END)), ] return fakeRanges
def processCode(self): if (self.params.startAddr==idc.BADADDR) and (self.params.endAddr==idc.BADADDR): if using_ida7api: self.params.startAddr = idc.get_segm_start(idc.here()) self.params.endAddr = idc.get_segm_end(idc.here()) else: self.params.startAddr = idc.SegStart(idc.here()) self.params.endAddr = idc.SegEnd(idc.here()) logger.info('Processing current segment only: 0x%08x - 0x%08x', self.params.startAddr, self.params.endAddr) else: logger.info('Processing range 0x%08x - 0x%08x', self.params.startAddr, self.params.endAddr) if self.params.searchDwordArray: self.lookForDwordArray(self.params.startAddr, self.params.endAddr) if self.params.searchPushArgs: self.lookForOpArgs(self.params.startAddr, self.params.endAddr)
def get_function_bounds(ea): """Get the bounds of the function containing `ea`. We want to discover jump table targets that are missed by IDA, and it's possible that they aren't marked as being part of the current function, and perhaps are after the assumed range of the current function. Ideally they will fall before the beginning of the next function, though. We need to be pretty careful with the case that one function tail-calls another. IDA will sometimes treat the end of the tail-called function (e.g. a thunk) as if it is the end of the caller. For this reason, we start with loose bounds using the prev/next functions, then try to narrow with the bounds of the function containing `ea`. TODO(pag): Handle discontinuous regions (e.g. because of function chunks). It may be worth to return an object here that can we queried for membership using the `__in__` method. """ seg_start, seg_end = idc.get_segm_start(ea), idc.get_segm_end(ea) min_ea = seg_start max_ea = seg_end if is_invalid_ea(min_ea) or not is_code(ea): return ea, ea # Get an upper bound using the next function. next_func_ea = idc.get_next_func(ea) if not is_invalid_ea(next_func_ea): max_ea = min(next_func_ea, max_ea) # Get a lower bound using the previous function. prev_func_ea = idc.get_prev_func(ea) if not is_invalid_ea(prev_func_ea): min_ea = max(min_ea, prev_func_ea) prev_func = idaapi.get_func(prev_func_ea) if prev_func and prev_func.end_ea < ea: min_ea = max(min_ea, prev_func.end_ea) # Try to tighten the bounds using the function containing `ea`. func = idaapi.get_func(ea) if func: min_ea = max(min_ea, func.start_ea) max_ea = min(max_ea, func.end_ea) return min_ea, max_ea
def promptForRange(self): # Only run if QT not available, so not bothering with ida7 check #check if a range has already been selected - if so skip prompt if using_ida7api: selstart = idc.read_selection_start() selend = idc.read_selection_end() segstart = idc.get_segm_start(idc.here()) segend = idc.get_segm_end(idc.here()) else: selstart = idc.SelStart() selend = idc.SelEnd() seg = idc.SegStart(idc.here()) self.params.endAddr = idc.SegEnd(idc.here()) if selstart != idc.BADADDR: self.params.startAddr = selstart self.params.endAddr = selend logger.info('Processing range 0x%08x - 0x%08x', self.params.startAddr, self.params.endAddr) else: self.params.startAddr = segstart self.params.endAddr = segend logger.info('Processing current segment only')