Ejemplo n.º 1
0
    def _pre_analysis(self):

        # Call _initialize_cfg() before self.functions is used.
        self._initialize_cfg()

        # Initialize variables used during analysis
        self._pending_jobs = PendingJobs(self.functions, self._deregister_analysis_job)
        self._traced_addresses = set()
        self._changed_functions = set()
        self._updated_nonreturning_functions = set()

        self._nodes = {}
        self._nodes_by_addr = defaultdict(list)

        self._function_returns = defaultdict(set)

        entry = self.project.entry  # type:SootAddressDescriptor
        entry_func = entry.method

        obj = self.project.loader.main_object

        if entry_func is not None:
            method_inst = obj.get_soot_method(
                entry_func.name, class_name=entry_func.class_name, params=entry_func.params)
        else:
            l.warning('The entry method is unknown. Try to find a main method.')
            method_inst = next(obj.main_methods, None)
            if method_inst is not None:
                entry_func = SootMethodDescriptor(method_inst.class_name, method_inst.name, method_inst.params)
            else:
                l.warning('Cannot find any main methods. Start from the first method of the first class.')
                for cls in obj.classes.values():
                    method_inst = next(iter(cls.methods), None)
                    if method_inst is not None:
                        break
                if method_inst is not None:
                    entry_func = SootMethodDescriptor(method_inst.class_name, method_inst.name,
                                                      method_inst.params)
                else:
                    raise AngrCFGError('There is no method in the Jar file.')

        # project.entry is a method
        # we should get the first block
        if method_inst.blocks:
            block_idx = method_inst.blocks[0].idx
            self._insert_job(CFGJob(SootAddressDescriptor(entry_func, block_idx, 0), entry_func, 'Ijk_Boring'))

        total_methods = 0

        # add all other methods as well
        for cls in self.project.loader.main_object.classes.values():
            for method in cls.methods:
                total_methods += 1
                if method.blocks:
                    method_des = SootMethodDescriptor(cls.name, method.name, method.params)
                    # TODO shouldn't this be idx?
                    block_idx = method.blocks[0].label
                    self._insert_job(CFGJob(SootAddressDescriptor(method_des, block_idx, 0), method_des, 'Ijk_Boring'))

        self._total_methods = total_methods
Ejemplo n.º 2
0
    def _soot_create_invoke_successors(self, stmt, addr, invoke_expr):

        method_class = invoke_expr.class_name
        method_name = invoke_expr.method_name
        method_params = invoke_expr.method_params
        method_desc = SootMethodDescriptor(method_class, method_name,
                                           method_params)

        callee_soot_method = self.project.loader.main_object.get_soot_method(
            method_desc, none_if_missing=True)
        caller_soot_method = self.project.loader.main_object.get_soot_method(
            addr.method)

        if callee_soot_method is None:
            # this means the called method is external
            return [(stmt.label, addr,
                     SootAddressDescriptor(method_desc, 0, 0), 'Ijk_Call')]

        targets = self._soot_class_hierarchy.resolve_invoke(
            invoke_expr, callee_soot_method, caller_soot_method)

        successors = []
        for target in targets:
            target_desc = SootMethodDescriptor(target.class_name, target.name,
                                               target.params)
            successors.append(
                (stmt.label, addr, SootAddressDescriptor(target_desc, 0,
                                                         0), 'Ijk_Call'))

        return successors
Ejemplo n.º 3
0
def get_entry_state_of_method(project, method_fullname):
    # get SootAddressDescriptor of method entry
    soot_method = project.loader.main_object.get_soot_method(method_fullname)
    method = SootMethodDescriptor.from_soot_method(soot_method)
    addr = SootAddressDescriptor(method, 0, 0)
    # create call state
    return project.factory.blank_state(addr=addr)
Ejemplo n.º 4
0
def test_java_simple4():
    binary_path = os.path.join(self_dir, "simple4.jar")

    proj = angr.Project(binary_path)
    print proj.loader.main_object._classes['simple4.Class1']

    simgr = proj.factory.simgr()
    main_method = next(proj.loader.main_object.main_methods)
    simgr.active[0].ip = SootAddressDescriptor(
        SootMethodDescriptor.from_method(main_method), 0, 0)

    simgr.explore()

    paths = simgr.deadended
    assert len(paths) == 2

    winnning_paths = []
    for pp in paths:
        pp.state.posix.set_pos(0, 0)
        pp.state.posix.set_pos(1, 0)
        oo = pp.state.posix.read_from(1, 1)
        # a winning path is printing 'W'
        pp.state.add_constraints(oo == pp.state.se.BVV(ord('W'), 8))
        if pp.satisfiable():
            winnning_paths.append(pp)
    assert len(winnning_paths) == 1
    winning_path = winnning_paths[0]

    # on the winning path, we ask for the input
    ii = winning_path.state.posix.read_from(0, 1)
    solution = chr(winning_path.state.se.eval(ii))
    print repr(solution)
    assert solution == 'F'
Ejemplo n.º 5
0
    def _invoke(self,
                method_id,
                obj=None,
                dynamic_dispatch=True,
                args_in_array=None):
        # get invoke target
        class_name = obj.type if dynamic_dispatch else method_id.class_name
        invoke_target = resolve_method(self.state, method_id.name, class_name,
                                       method_id.params)
        invoke_addr = SootAddressDescriptor(invoke_target, 0, 0)

        # get args
        no_of_args = len(invoke_target.params)
        if args_in_array is not None:
            arg_values = self._get_arg_values_from_array(
                args_in_array, no_of_args)
        else:
            arg_values = self._get_arg_values(no_of_args)

        # setup java args
        java_args = self._setup_java_args(arg_values,
                                          invoke_target,
                                          this_ref=obj)

        # call java method
        # => after returning, the execution will be continued in _return_result_of_computation
        self.call(invoke_addr,
                  java_args,
                  "return_from_invocation",
                  cc=SimCCSoot(ArchSoot()))
Ejemplo n.º 6
0
def get_entry_state_of_method(project, method_fullname):
    # get SootAddressDescriptor of method entry
    soot_method = project.loader.main_object.get_soot_method(method_fullname)
    method = SootMethodDescriptor.from_soot_method(soot_method)
    addr = SootAddressDescriptor(method, 0, 0)
    # create call state
    return project.factory.blank_state(addr=addr, add_options={angr.options.ZERO_FILL_UNCONSTRAINED_MEMORY})
Ejemplo n.º 7
0
 def _get_next_linear_instruction(state, stmt_idx):
     addr = state.addr.copy()
     addr.stmt_idx = stmt_idx
     method = state.regs._ip_binary.get_soot_method(addr.method)
     current_bb = method.blocks[addr.block_idx]
     new_stmt_idx = addr.stmt_idx + 1
     if new_stmt_idx < len(current_bb.statements):
         return SootAddressDescriptor(addr.method, addr.block_idx,
                                      new_stmt_idx)
     else:
         new_bb_idx = addr.block_idx + 1
         if new_bb_idx < len(method.blocks):
             return SootAddressDescriptor(addr.method, new_bb_idx, 0)
         else:
             l.warning("falling into a non existing bb: %d in %s",
                       new_bb_idx,
                       SootMethodDescriptor.from_soot_method(method))
             raise IncorrectLocationException()
Ejemplo n.º 8
0
    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."
            )
Ejemplo n.º 9
0
    def _get_bb_addr_from_instr(self, instr):
        """
        Returns the address of the methods basic block that contains the given
        instruction.

        :param instr: The index of the instruction (within the current method).
        :rtype: SootAddressDescriptor
        """
        current_method = self.state.addr.method
        try:
            bb = current_method.block_by_label[instr]
        except KeyError:
            l.error("Possible jump to a non-existing bb %s --> %d",
                    self.state.addr, instr)
            raise IncorrectLocationException()

        return SootAddressDescriptor(current_method, bb.idx, 0)
Ejemplo n.º 10
0
    def __init__(self,
                 path,
                 additional_jars=None,
                 additional_jar_roots=None,
                 main_class=None,
                 **kwargs):

        if not pysoot:
            raise ImportError(
                'Cannot import PySoot. The Soot backend requires PySoot to function. '
                'Please install PySoot first.')

        if kwargs.get('has_memory', False):
            raise CLEError(
                'The parameter "has_memory" must be False for Soot backend.')

        super(Soot, self).__init__(path, has_memory=False, **kwargs)

        if not main_class:
            # parse main_class from the manifest
            self.manifest = self.get_manifest()
            main_class = self.manifest.get('Main-Class', None)

        # load the classes
        pysoot_lifter = Lifter(
            path,
            additional_jars=additional_jars,
            additional_jar_roots=additional_jar_roots,
            # main_class=main_class,
        )
        self._classes = pysoot_lifter.classes

        # find entry method
        try:
            main_method_descriptor = SootMethodDescriptor.from_method(
                next(self.get_method("main", main_class)))
            entry = SootAddressDescriptor(main_method_descriptor, 0, 0)
        except CLEError:
            _l.warning(
                'Failed to identify the entry (the Main method) of this JAR.')
            entry = None
        self._entry = entry
        self.os = 'javavm'
        self.rebase_addr = None
        self.set_arch(archinfo.arch_from_id('soot'))
Ejemplo n.º 11
0
def test_java_simple3():
    binary_path = os.path.join(self_dir, "simple3.jar")
    proj = angr.Project(binary_path)
    print proj.loader.main_object._classes['simple3.Class1']

    simgr = proj.factory.simgr()
    main_method = next(proj.loader.main_object.main_methods)
    simgr.active[0].ip = SootAddressDescriptor(
        SootMethodDescriptor.from_method(main_method), 0, 0)

    simgr.explore()

    pp = simgr.deadended[0]
    pp.state.posix.set_pos(0, 0)
    pp.state.posix.set_pos(1, 0)
    ii = pp.state.posix.read_from(0, 1)
    oo = pp.state.posix.read_from(1, 1)
    pp.state.add_constraints(oo == pp.state.se.BVV(ord('c'), 8))

    print ii, "-->", oo
    cinput = chr(pp.state.se.eval(ii))
    print repr(cinput)
    assert cinput == "b"
Ejemplo n.º 12
0
    def __init__(self,
                 path,
                 entry_point=None,
                 entry_point_params=(),
                 input_format=None,
                 additional_jars=None,
                 additional_jar_roots=None,
                 jni_libs_ld_path=None,
                 jni_libs=None,
                 android_sdk=None,
                 **kwargs):

        if not pysoot:
            raise ImportError(
                'Cannot import PySoot. The Soot backend requires PySoot.')

        if kwargs.get('has_memory', False):
            raise CLEError(
                'The parameter "has_memory" must be False for Soot backend.')

        super(Soot, self).__init__(path, has_memory=False, **kwargs)

        # load the classes
        l.debug("Lifting to Soot IR ...")
        start_time = time.time()
        pysoot_lifter = Lifter(path,
                               input_format=input_format,
                               android_sdk=android_sdk,
                               additional_jars=additional_jars,
                               additional_jar_roots=additional_jar_roots)
        end_time = time.time()
        l.debug("Lifting completed in %ds", round(end_time - start_time, 2))
        self._classes = pysoot_lifter.classes

        # find entry method
        if entry_point:
            try:
                ep_method = self.get_soot_method(entry_point,
                                                 params=entry_point_params)
                ep_method_descriptor = SootMethodDescriptor.from_soot_method(
                    ep_method)
                self._entry = SootAddressDescriptor(ep_method_descriptor, 0, 0)
                l.debug("Entry point set to %s", self._entry)
            except CLEError:
                l.warning("Couldn't find entry point %s.", entry_point)
                self._entry = None

        self.os = 'javavm'
        self.rebase_addr = None
        self.set_arch(ArchSoot())

        if jni_libs:
            # native libraries are getting loaded by adding them as a dependency of this object
            self.deps += [jni_libs] if type(jni_libs) in (str,
                                                          bytes) else jni_libs
            # if available, add additional load path(s)
            if jni_libs_ld_path:
                path_list = [jni_libs_ld_path] if type(jni_libs_ld_path) in (
                    str, bytes) else jni_libs_ld_path
                self.extra_load_path += path_list
            self.jni_support = True
        else:
            self.jni_support = False
Ejemplo n.º 13
0
    def _soot_get_successors(self, addr, function_id, block, cfg_node):

        # soot method
        method = self.project.loader.main_object.get_soot_method(function_id)

        block_id = block.idx

        if addr.stmt_idx is None:
            addr = SootAddressDescriptor(addr.method, block_id, 0)

        successors = [ ]

        has_default_exit = True

        next_stmt_id = block.label + len(block.statements)
        last_stmt_id = method.blocks[-1].label + len(method.blocks[-1].statements) - 1

        if next_stmt_id >= last_stmt_id:
            # there should not be a default exit going to the next block
            has_default_exit = False

        # scan through block statements, looking for those that generate new exits
        for stmt in block.statements[addr.stmt_idx - block.label : ]:
            if isinstance(stmt, IfStmt):
                succ = (stmt.label, addr,
                        SootAddressDescriptor(function_id, method.block_by_label[stmt.target].idx, stmt.target),
                        'Ijk_Boring'
                        )
                successors.append(succ)

            elif isinstance(stmt, InvokeStmt):
                invoke_expr = stmt.invoke_expr

                succs = self._soot_create_invoke_successors(stmt, addr, invoke_expr)
                if succs:
                    successors.extend(succs)
                    has_default_exit = False
                    break

            elif isinstance(stmt, GotoStmt):
                target = stmt.target
                succ = (stmt.label, addr, SootAddressDescriptor(function_id, method.block_by_label[target].idx, target),
                        'Ijk_Boring')
                successors.append(succ)

                # blocks ending with a GoTo should not have a default exit
                has_default_exit = False
                break

            elif isinstance(stmt, AssignStmt):

                expr = stmt.right_op

                if isinstance(expr, SootInvokeExpr):
                    succs = self._soot_create_invoke_successors(stmt, addr, expr)
                    if succs:
                        successors.extend(succs)
                        has_default_exit = False
                        break


        if has_default_exit:
            successors.append(('default', addr,
                               SootAddressDescriptor(function_id, method.block_by_label[next_stmt_id].idx, next_stmt_id),
                               'Ijk_Boring'
                               )
                              )

        return successors
Ejemplo n.º 14
0
    def _handle_soot_stmt(self, state, successors, stmt_idx, stmt):
        # execute statement
        try:
            l.debug("Executing statement: %s", stmt)
            s_stmt = translate_stmt(stmt, state)
        except SimEngineError as e:
            l.error("Skipping statement: %s", e)
            return False

        # add invoke exit
        if s_stmt.has_invoke_target:
            invoke_state = state.copy()
            # parse invoke expression
            invoke_expr = s_stmt.invoke_expr
            method = invoke_expr.method
            args = invoke_expr.args
            ret_var = invoke_expr.ret_var if hasattr(invoke_expr,
                                                     'ret_var') else None
            # setup callsite
            ret_addr = self._get_next_linear_instruction(state, stmt_idx)
            if 'NATIVE' in method.attrs:
                # the target of the call is a native function
                # => we need to setup a native call-site
                l.debug("Native invoke: %r", method)
                addr = self.project.simos.get_addr_of_native_method(method)
                if not addr:
                    # native function could not be found
                    # => skip invocation and continue execution linearly
                    return False
                invoke_state = self._setup_native_callsite(
                    invoke_state, addr, method, args, ret_addr, ret_var)
            else:
                l.debug("Invoke: %r", method)
                self.setup_callsite(invoke_state, args, ret_addr, ret_var)
                addr = SootAddressDescriptor(method, 0, 0)
            # add invoke state as the successor and terminate execution
            # prematurely, since Soot does not guarantee that an invoke stmt
            # terminates a block
            successors.add_successor(invoke_state, addr, state.solver.true,
                                     'Ijk_Call')
            return True

        # add jmp exit
        elif s_stmt.has_jump_targets:
            for target, condition in s_stmt.jmp_targets_with_conditions:
                if not target:
                    target = self._get_next_linear_instruction(state, stmt_idx)
                l.debug("Possible jump: %s -> %s", state._ip, target)
                successors.add_successor(state.copy(), target, condition,
                                         'Ijk_Boring')
            return True

        # add return exit
        elif isinstance(s_stmt, (SimSootStmt_Return, SimSootStmt_ReturnVoid)):
            l.debug("Return exit")
            self._add_return_exit(state, successors, s_stmt.return_value)
            return True

        # go on linearly
        else:
            return False