[docs]classSootFunction(Function):""" A representation of a function and various information about it. """
[docs]def__init__(self,function_manager,addr,name=None,syscall=None):""" Function constructor for Soot :param addr: The address of the function. :param name: (Optional) The name of the function. :param syscall: (Optional) Whether this function is a syscall or not. """self.transition_graph=networkx.DiGraph()self._local_transition_graph=None# The Shimple CFG is already normalized.self.normalized=True# block nodes at whose ends the function returnsself._ret_sites=set()# block nodes at whose ends the function jumps out to another function (jumps outside)self._jumpout_sites=set()# block nodes at whose ends the function calls out to another non-returning functionself._callout_sites=set()# block nodes that ends the function by returning out to another function (returns outside). This is rare.self._retout_sites=set()# block nodes (basic block nodes) at whose ends the function terminates# in theory, if everything works fine, endpoints == ret_sites | jumpout_sites | callout_sitesself._endpoints=defaultdict(set)self._call_sites={}self.addr=addrself._function_manager=function_managerself.is_syscall=syscallself._project=project=self._function_manager._kb._projectself.is_plt=Falseself.is_simprocedure=Falseifproject.is_hooked(addr):self.is_simprocedure=Truebinary_name=Noneifself.is_simprocedure:hooker=project.hooked_by(addr)ifhookerisnotNone:binary_name=hooker.library_nameifbinary_nameisNoneandself.binaryisnotNone:binary_name=os.path.basename(self.binary.binary)self._name=addr.__repr__()self.binary_name=binary_name# Stack offsets of those arguments passed in stack variablesself._argument_stack_variables=[]# These properties are set by VariableManagerself.bp_on_stack=Falseself.retaddr_on_stack=Falseself.sp_delta=0# Calling conventionself.calling_convention=None# Function prototypeself.prototype=None# Whether this function returns or not. `None` means it's not determined yetself._returning=Noneself.alignment=None# Determine returning status for SimProcedures and Syscallshooker=Noneifself.is_simprocedure:hooker=project.hooked_by(addr)ifhookerandhasattr(hooker,"NO_RET"):self.returning=nothooker.NO_RETself.prepared_registers=set()self.prepared_stack_variables=set()self.registers_read_afterwards=set()# startpoint can always be None if this CFGNode is a syscall nodeself.startpoint=Noneself._addr_to_block_node={}# map addresses to nodesself._block_sizes={}# map addresses to block sizesself._block_cache={}# a cache of real, hard data Block objectsself._local_blocks={}# a dict of all blocks inside the functionself._local_block_addrs=set()# a set of addresses of all blocks inside the functionself.info={}# storing special information, like $gp values for MIPS32self.tags=()# store function tags. can be set manually by performing CodeTagging analysis.
[docs]defnormalize(self):# The Shimple CFG is already normalized.pass
def_register_nodes(self,is_local,*nodes):ifnotisinstance(is_local,bool):raiseAngrValueError('_register_nodes(): the "is_local" parameter must be a bool')fornodeinnodes:self.transition_graph.add_node(node)node._graph=self.transition_graphifnode.addrnotinselforself._block_sizes[node.addr]==0:self._block_sizes[node.addr]=node.sizeifnode.addr==self.addr.addr:ifself.startpointisNoneornotself.startpoint.is_hook:self.startpoint=nodeifis_local:self._local_blocks[node.addr]=nodeself._local_block_addrs.add(node.addr)# add BlockNodes to the addr_to_block_node cache if not already thereifisinstance(node,BlockNode):ifnode.addrnotinself._addr_to_block_node:self._addr_to_block_node[node.addr]=node