def find_exported_eas(): """Find the address of all exported functions. Exported functions are entrypoints into this program that external code can execute.""" exported_eas = set() for index, ordinal, ea, name in idautils.Entries(): # Not sure how this happens, but IDA seemed to treat # `obstack_alloc_failed_handler` in `call cs:[obstack_alloc_failed_handler]` # as an entrypoint. num_data_refs = len(tuple(idautils.DataRefsTo(ea))) num_code_refs = len(tuple(idautils.CodeRefsTo(ea, True))) num_code_refs += len(tuple(idautils.CodeRefsTo(ea, True))) if num_data_refs and not num_code_refs: log.warning( "Ignoring entrypoint {:08x}, it's only referenced by data". format(ea)) continue if not has_segment_type(ea, idc.SEG_CODE): log.warning( "Ignoring entrypoint {:08x}, it is not in a code segment". format(ea)) continue if not idc.hasName(ea): old_name = name if name.startswith("."): name = idc.GetCommentEx(ea, 0) log.info("Renaming `{}` at {:08x} to `{}`".format( old_name, ea, name)) idc.MakeName(ea, name) return exported_eas
def find_exported_eas(): """Find the address of all exported functions. Exported functions are entrypoints into this program that external code can execute.""" exported_eas = set() for index, ordinal, ea, name in idautils.Entries(): # Not sure how this happens, but IDA seemed to treat # `obstack_alloc_failed_handler` in `call cs:[obstack_alloc_failed_handler]` # as an entrypoint. num_data_refs = len(tuple(idautils.DataRefsTo(ea))) num_code_refs = len(tuple(idautils.CodeRefsTo(ea, True))) num_code_refs += len(tuple(idautils.CodeRefsTo(ea, True))) if num_data_refs and not num_code_refs: log.warning( "Ignoring entrypoint {:08x}, it's only referenced by data".format(ea)) continue if not is_code(ea): log.warning( "Ignoring entrypoint {:08x}, it is not in a code segment".format(ea)) continue if not idc.hasName(ea): old_name = name if name.startswith("."): name = idc.GetCommentEx(ea, 0) log.info("Renaming `{}` at {:08x} to `{}`".format(old_name, ea, name)) idc.MakeName(ea, name) return exported_eas
def analyse_subroutines(): """Goes through all the subroutines that IDA's initial auto analysis discovers.""" log.info("Analysing subroutines") exported_eas = find_exported_eas() log.info("IDA identified {} exported functions".format(len(exported_eas))) subs = set() sub_eas = set() # Work list. sub_eas.update(exported_eas) # Get all subroutines that IDA recognised. for seg_ea in idautils.Segments(): min_ea, max_ea = idc.SegStart(seg_ea), idc.SegEnd(seg_ea) sub_eas.update(idautils.Functions(min_ea, max_ea)) log.info("IDA identified {} functions".format(len(sub_eas))) bad_sub_eas = set() for sub_ea in sub_eas: if has_segment_type(sub_ea, idc.SEG_CODE): sub = program.get_subroutine(sub_ea) # Mark `ea` as a subroutine. # Iteratively analyse the blocks in subroutines. This may discover new # subroutines because our block analysis can be more aggressive than what # IDA finds. while len(sub_eas): sub_ea = sub_eas.pop() if not has_segment_type(sub_ea, idc.SEG_CODE): log.warning( "Not analysing subroutine at non-code address {:08x}".format( sub_ea)) continue sub = program.get_subroutine(sub_ea) if sub in subs: log.debug("Skipping {:08x}; already analysed.".format(sub_ea)) continue subs.add(sub) if idc.hasName(sub_ea): sub.name = idc.GetFunctionName(sub_ea) # Mark this subroutine as exported. if sub_ea in exported_eas: sub.visibility = program.Subroutine.VISIBILITY_EXPORTED analyse_subroutine(sub) sub_eas.update(get_called_subroutines(sub)) return subs
def analyse_subroutines(): """Goes through all the subroutines that IDA's initial auto analysis discovers.""" log.info("Analysing subroutines") exported_eas = find_exported_eas() log.info("IDA identified {} exported functions".format(len(exported_eas))) subs = set() sub_eas = set() # Work list. sub_eas.update(exported_eas) # Get all subroutines that IDA recognised. for seg_ea in idautils.Segments(): min_ea, max_ea = idc.SegStart(seg_ea), idc.SegEnd(seg_ea) sub_eas.update(idautils.Functions(min_ea, max_ea)) log.info("IDA identified {} functions".format(len(sub_eas))) bad_sub_eas = set() for sub_ea in sub_eas: if is_code(sub_ea): sub = program.get_subroutine(sub_ea) # Mark `ea` as a subroutine. # Iteratively analyse the blocks in subroutines. This may discover new # subroutines because our block analysis can be more aggressive than what # IDA finds. while len(sub_eas): sub_ea = sub_eas.pop() if not is_code(sub_ea): log.warning( "Not analysing subroutine at non-code address {:08x}".format(sub_ea)) continue sub = program.get_subroutine(sub_ea) if sub in subs: log.debug("Skipping {:08x}; already analysed.".format(sub_ea)) continue subs.add(sub) if idc.hasName(sub_ea): sub.name = idc.GetFunctionName(sub_ea) # Mark this subroutine as exported. if sub_ea in exported_eas: sub.visibility = program.Subroutine.VISIBILITY_EXPORTED analyse_subroutine(sub) sub_eas.update(get_called_subroutines(sub)) return subs
def getsize(self): actual_ea = self.addr while (True): # first entry case f = idc.GetFlags(actual_ea) if (len(self.entries) == 0): if (not (idc.isRef(f) and (idc.hasName(f) or (f & FF_LABL)))): print("[-] Not an entry of vtable") return 0 elif (idc.isRef(f) and (idc.hasName(f) or (f & FF_LABL))): # next vtable ? break if (not idc.hasValue(f) or not idc.isData(f)): break c = idc.Dword(actual_ea) if c: f = idc.GetFlags(c) if (not idc.hasValue(f) or not idc.isCode(f) or idc.Dword(c) == 0): break else: break self.entries.append(actual_ea) actual_ea += 4 print("[+] Vtable %08X - %08X, methods : %d" % (self.addr, actual_ea, (actual_ea - self.addr) / 4))