# pylint:disable=missing-class-docstringfrom__future__importannotationsimportloggingfromtypingimportTYPE_CHECKINGfromcollectionsimportdefaultdictfromdataclassesimportdataclassfromsortedcontainersimportSortedDictfromangr.analysesimportAnalysis,AnalysesHubfromangr.utils.bitsimportffsifTYPE_CHECKING:fromangr.knowledge_pluginsimportFunctionlog=logging.getLogger(__name__)classOverlappingFunctionsAnalysis(Analysis):""" Identify functions with interleaved blocks. """overlapping_functions:dict[int,list[int]]def__init__(self):self.overlapping_functions=defaultdict(list)addr_to_func_max_addr=SortedDict()forfuncinself.project.kb.functions.values():iffunc.is_alignment:continuefunc_max_addr=max((block.addr+block.size)forblockinfunc.blocks)addr_to_func_max_addr[func.addr]=(func,func_max_addr)foridx,(addr,(_func,max_addr))inenumerate(addr_to_func_max_addr.items()):forother_addrinaddr_to_func_max_addr.islice(idx+1):ifother_addr>=max_addr:breakself.overlapping_functions[addr].append(other_addr)classFunctionAlignmentAnalysis(Analysis):""" Determine typical function alignment """alignment:int|Nonedef__init__(self):self.alignment=Noneiflen(self.project.kb.functions)==0:ifself.project.kb.cfgs.get_most_accurate()isNone:log.warning("Please run CFGFast analysis first, to identify functions")returnalignment_bins=defaultdict(int)count=0forfuncinself.project.kb.functions.values():ifnot(func.is_alignmentorfunc.is_pltorfunc.is_simprocedure):alignment_bins[ffs(func.addr)]+=1count+=1# FIXME: Higher alignment values will be naturally alignedtypical_alignment=max(alignment_bins,key=lambdak:alignment_bins[k])ifcount>10andalignment_bins[typical_alignment]>=count/4:# XXX: cutoffself.alignment=1<<max(typical_alignment,0)log.debug("Function alignment appears to be %d bytes",self.alignment)@dataclassclassAtypicallyAlignedFunction:function:Functionexpected_alignment:int@dataclassclassPatchedOutFunctionality:patched_function:Functionpatched_out_function:Function
[文档]classPatchFinderAnalysis(Analysis):""" Looks for binary patches using some basic heuristics: - Looking for interleaved functions - Looking for unaligned functions """# FIXME: Possible additional heuristics:# - Jumps out to end of function, then back# - Looking for patch jumps, e.g. push <addr>; ret# - Looking for instruction partials broken by a patch (nodecode)# - Unusual stack manipulationatypical_alignments:list[Function]possibly_patched_out:list[PatchedOutFunctionality]
[文档]def__init__(self):self.atypical_alignments=[]self.possibly_patched_out=[]iflen(self.project.kb.functions)==0:ifself.project.kb.cfgs.get_most_accurate()isNone:log.warning("Please run CFGFast analysis first, to identify functions")return# In CFGFast with scanning enabled, a function may be created from unreachable blocks within another function.# Search for interleaved/overlapping functions to identify possible patches.overlapping_functions=self.project.analyses.OverlappingFunctions().overlapping_functionsforaddr,overlapping_func_addrsinoverlapping_functions.items():func=self.project.kb.functions[addr]# Are the overlapping functions reachable?foroverlapping_addrinoverlapping_func_addrs:overlapping_func=self.project.kb.functions[overlapping_addr]ifself.project.kb.callgraph.in_degree(overlapping_addr)==0:self.possibly_patched_out.append(PatchedOutFunctionality(func,overlapping_func))# FIXME: What does the patch do?# Look for unaligned functionsexpected_alignment=self.project.analyses.FunctionAlignment().alignmentifexpected_alignmentisnotNoneandexpected_alignment>self.project.arch.instruction_alignment:forfuncinself.project.kb.functions.values():ifnot(func.is_alignmentorfunc.is_pltorfunc.is_simprocedure)andfunc.addr&(expected_alignment-1):self.atypical_alignments.append(AtypicallyAlignedFunction(func,expected_alignment))