Source code for angr.state_plugins.javavm_classloader

import logging

from archinfo.arch_soot import SootAddressDescriptor, SootAddressTerminator, SootClassDescriptor

from ..engines.soot.method_dispatcher import resolve_method
from ..engines import UberEngine
from ..sim_state import SimState
from .plugin import SimStatePlugin

l = logging.getLogger("angr.state_plugins.javavm_classloader")


[docs]class SimJavaVmClassloader(SimStatePlugin): """ JavaVM Classloader is used as an interface for resolving and initializing Java classes. """
[docs] def __init__(self, initialized_classes=None): super().__init__() self._initialized_classes = set() if initialized_classes is None else initialized_classes
[docs] def get_class(self, class_name, init_class=False, step_func=None): """ Get a class descriptor for the class. :param str class_name: Name of class. :param bool init_class: Whether the class initializer <clinit> should be executed. :param func step_func: Callback function executed at every step of the simulation manager during the execution of the main <clinit> method """ # try to get the soot class object from CLE java_binary = self.state.javavm_registers.load("ip_binary") soot_class = java_binary.get_soot_class(class_name, none_if_missing=True) # create class descriptor class_descriptor = SootClassDescriptor(class_name, soot_class) # load/initialize class if init_class: self.init_class(class_descriptor, step_func=step_func) return class_descriptor
[docs] def get_superclass(self, class_): """ Get the superclass of the class. """ if not class_.is_loaded or class_.superclass_name is None: return None return self.get_class(class_.superclass_name)
[docs] def get_class_hierarchy(self, base_class): """ Walks up the class hierarchy and returns a list of all classes between base class (inclusive) and java.lang.Object (exclusive). """ classes = [base_class] while classes[-1] is not None and classes[-1] != "java.lang.Object": classes.append(self.get_superclass(classes[-1])) return classes[:-1]
[docs] def is_class_initialized(self, class_): """ Indicates whether the classes initializing method <clinit> was already executed on the state. """ return class_ in self.initialized_classes
[docs] def init_class(self, class_, step_func=None): """ This method simulates the loading of a class by the JVM, during which parts of the class (e.g. static fields) are initialized. For this, we run the class initializer method <clinit> (if available) and update the state accordingly. Note: Initialization is skipped, if the class has already been initialized (or if it's not loaded in CLE). """ if self.is_class_initialized(class_): l.debug("Class %r already initialized.", class_) return l.debug("Initialize class %r.", class_) self.initialized_classes.add(class_) if not class_.is_loaded: l.warning("Class %r is not loaded in CLE. Skip initializiation.", class_) return clinit_method = resolve_method( self.state, "<clinit>", class_.name, include_superclasses=False, init_class=False ) if clinit_method.is_loaded: engine = UberEngine(self.state.project) # use a fresh engine, as the default engine instance may be in use at this time javavm_simos = self.state.project.simos clinit_state = javavm_simos.state_call( addr=SootAddressDescriptor(clinit_method, 0, 0), base_state=self.state, ret_addr=SootAddressTerminator() ) simgr = self.state.project.factory.simgr(clinit_state) l.info(">" * 15 + " Run class initializer %r ... " + ">" * 15, clinit_method) simgr.run(step_func=step_func, engine=engine) l.debug("<" * 15 + " Run class initializer %r ... done " + "<" * 15, clinit_method) # The only thing that can be updated during initialization are # static or rather global information, which are either stored on # the heap or in the vm_static_table self.state.memory.vm_static_table = simgr.deadended[-1].memory.vm_static_table.copy() self.state.memory.heap = simgr.deadended[-1].memory.heap.copy() else: l.debug("Class initializer <clinit> is not loaded in CLE. Skip initializiation.")
@property def initialized_classes(self): """ List of all initialized classes. """ return self._initialized_classes @SimStatePlugin.memo def copy(self, memo): # pylint: disable=unused-argument return SimJavaVmClassloader(initialized_classes=self.initialized_classes.copy())
[docs] def merge(self, others, merge_conditions, common_ancestor=None): # pylint: disable=unused-argument l.warning("Merging is not implemented for JavaVM classloader!") return False
[docs] def widen(self, others): # pylint: disable=unused-argument l.warning("Widening is not implemented for JavaVM classloader!") return False
# TODO use a default JavaVM preset # see for reference: angr/engines/__init__.py SimState.register_default("javavm_classloader", SimJavaVmClassloader)