예제 #1
0
def sprintf(p, core_taint, plt_path, *_, **__):
    """
    sprintf function summary

    :param p: angr project
    :param core_taint: core taint engine
    :param plt_path: path to the plt entry
    :return: None
    """

    plt_state = plt_path.active[0]
    if are_parameters_in_registers(p):
        frmt_str = getattr(plt_state.regs, arg_reg_name(p, 1))
        str_val = get_string(p, frmt_str.args[0], extended=True)
        n_vargs = str_val.count('%s')
        for i in range(2, 2 + n_vargs):
            name = p.arch.register_names[ordered_argument_regs[p.arch.name][i]]
            reg = getattr(plt_state.regs, name)
            if (core_taint.is_tainted(reg, path=plt_path)
                    or core_taint.is_tainted(
                        core_taint.safe_load(plt_path, reg), path=plt_path)):
                return True
        return False
    else:
        raise Exception("implement me")
예제 #2
0
    def _search_data_key_in_bb(self, p, b, caller_node, data_key):
        """
        Searches if a data key in a basic block

        :param p: angr project
        :param b: binary name
        :param caller_node: basic block of a caller node
        :param data_key: data key to search for
        :return: True if the data key is in the basic block
        """
        found = False
        c = caller_node

        block = p.factory.block(c.addr)

        # consider the constants in the calling block
        for con in block.vex.all_constants:
            val = con.value
            # check if a string
            c_string = get_string(p, val)
            self._binaries_strings[b].append(c_string)
            if c_string and c_string == data_key:
                found = True

        return found
예제 #3
0
    def _search_in_bb(self, caller_node, role_function_info):
        """
        Search for a data key in the passed basic block.

        :param caller_node: node calling the role function
        :param role_function_info: role function info
        :return:
        """

        p = self._p
        c = caller_node

        block = p.factory.block(c.addr)

        # consider the constants in the calling block
        for con in block.vex.all_constants:
            val = con.value
            # check if a string
            c_string = get_string(p, val)
            if c_string:
                if val not in self._role_info:
                    self._role_info[val] = []

                new_role_info = dict(role_function_info)
                new_role_info[RoleInfo.DATAKEY] = c_string
                new_role_info[RoleInfo.X_REF_FUN] = c.function_address
                new_role_info[RoleInfo.CALLER_BB] = c.addr
                new_role_info[RoleInfo.CPF] = self._name

                if new_role_info not in self._role_info[val]:
                    self._role_info[val].append(new_role_info)
예제 #4
0
    def _run_def_use(self, caller_node, role_function_info):
        """
        Run def-use analysis to find the data-key

        :param caller_node: node calling an environment function
        :param role_function_info: role function info
        :return: None
        """

        if not self._normalized_cfg:
            self._normalized_cfg = self._p.analyses.CFG(normalize=True)

        p = self._p
        cfg = self._normalized_cfg

        c = caller_node
        # Reaching definition analysis
        fun = cfg.functions.function(caller_node.function_address)
        t = (caller_node.instruction_addrs[-1], angr.analyses.reaching_definitions.OP_AFTER)
        rd = p.analyses.ReachingDefinitions(func=fun, observation_points=[t,], init_func=True)

        try:
            results = rd.observed_results[t]
        except TimeOutException:
            raise
        except:
            return

        if are_parameters_in_registers(p):
            idx = role_function_info[RoleInfo.PAR_N]
            reg_off = ordered_argument_regs[p.arch.name][idx]

            for r_def in results.register_definitions.get_objects_by_offset(reg_off):
                for val in r_def.data.data:
                    if type(val) == angr.analyses.reaching_definitions.undefined.Undefined:
                        continue
                    if type(val) not in (int, long):
                        print("Data value is not what expected. Check me...")
                        continue

                    c_string = get_string(p, val)
                    if c_string:
                        if val not in self._role_info:
                            self._role_info[val] = []

                        new_role_info = dict(role_function_info)
                        new_role_info[RoleInfo.DATAKEY] = c_string
                        new_role_info[RoleInfo.X_REF_FUN] = c.function_address
                        new_role_info[RoleInfo.CALLER_BB] = c.addr
                        new_role_info[RoleInfo.CPF] = self._name

                        if new_role_info not in self._role_info[val]:
                            self._role_info[val].append(new_role_info)
                        role = self._roles[0]
                        self._roles.append(role)
                        self._data_keys.append(c_string)
                        self._name_funs.append(c.successors[0].name)

        else:
            raise Exception("Envirnoment cpf: Parameters not in registers, implement me")
예제 #5
0
    def _search_data_key_in_bb(self, p, b, caller_node, data_key):
        """
        Finds if the given data key is within the calling basic block.

        :param p: angr project
        :param b: binary
        :param caller_node: calling basic block
        :param data_key: data key value
        :return: True if found, False otherwise
        """

        found = False
        c = caller_node

        block = p.factory.block(c.addr)

        # consider the constants in the calling block
        for con in block.vex.all_constants:
            val = con.value
            # check if a string
            c_string = get_string(p, val)
            self._binaries_strings[b].append(c_string)
            if c_string and c_string == data_key:
                found = True

        return found
예제 #6
0
    def _inet_pton(self, ct, caller_path, plt_path):
        """
        inet_pton summary
        :param ct: core taint engine
        :param caller_path: angr path leading to the inet_path
        :param plt_path:  angr path leading to the plt entry of inet_pton
        :return:
        """

        p = ct.p
        new_state = plt_path.active[0]
        old_state = caller_path.active[0]

        # move data key from argument to destination addr
        addr_reg = ordered_argument_regs[p.arch.name][1]
        dst_reg = ordered_argument_regs[p.arch.name][2]
        addr_str = getattr(plt_path.active[0].regs,
                           p.arch.register_names[addr_reg])
        cnt_str = get_string(p, addr_str.args[0], extended=True)

        # do the inet_pton conversion.
        # this is not exactly the conversion the inet_pton does, it's a trick we use to keep track of the addresses
        inet_pton_convesions[self._pton_counter] = cnt_str
        bits = p.arch.bits
        to_store = claripy.BVV(self._pton_counter, bits)
        self._pton_counter += 1

        # store it!
        dst_mem = getattr(plt_path.active[0].regs,
                          p.arch.register_names[dst_reg])
        new_state.memory.store(dst_mem, to_store)

        # restore registers to return from the function call
        lr = p.arch.register_names[link_regs[p.arch.name]]
        ret_addr = getattr(new_state.regs, lr)
        ret_func = getattr(old_state.regs, lr)

        plt_path.active[0].ip = ret_addr
        setattr(plt_path.active[0].regs, lr, ret_func)
        plt_path.active[0].history.jumpkind = "Ijk_FakeRet"
예제 #7
0
    def _search_in_bb(self, caller_node, role_function_info):
        """
        Finds whether the data-key is the called basic block.
        As we know the protype of nvram functions, if there's a string within the basic block, that's our
        data key.

        :param caller_node: caller basic block
        :param role_function_info: role function info
        :return: None
        """

        p = self._p
        c = caller_node

        block = p.factory.block(c.addr)

        # consider the constants in the calling block
        for con in block.vex.all_constants:
            val = con.value
            # check if a string
            c_string = get_string(p, val)
            if c_string:
                if val not in self._role_info:
                    self._role_info[val] = []

                new_role_info = dict(role_function_info)
                new_role_info[RoleInfo.DATAKEY] = c_string
                new_role_info[RoleInfo.X_REF_FUN] = c.function_address
                new_role_info[RoleInfo.CALLER_BB] = c.addr
                new_role_info[RoleInfo.CPF] = self._name

                if new_role_info not in self._role_info[val]:
                    self._role_info[val].append(new_role_info)
                role = self._roles[0]
                self._roles.append(role)
                self._data_keys.append(c_string)
                self._name_funs.append(c.successors[0].name)
예제 #8
0
    def _save_file_name(self, current_path, guards_info, *_, **__):
        """
        Save and apply taint to the open function

        :param current_path: angr current path
        :param guards_info: guards info
        :return: None
        """

        if not self._ct.taint_applied:
            # first get the address of the filename
            next_path = current_path.copy(copy_states=True).step()
            name_reg = self._p.arch.register_names[ordered_argument_regs[
                self._p.arch.name][0]]
            addr = getattr(next_path.active[0].regs, name_reg)
            if addr.concrete:
                self._last_file_name = get_string(self._p,
                                                  addr.args[0],
                                                  extended=True)

            self._ct.apply_taint(current_path, addr, "filename")
            self._ct.apply_taint(current_path, self._current_key_addr,
                                 "key_str")
            self._check_func(current_path, guards_info, *_, **__)