Beispiel #1
0
    def __call__(self,
                 context: interfaces.context.ContextInterface,
                 config_path: str,
                 requirement: interfaces.configuration.RequirementInterface,
                 progress_callback: constants.ProgressCallback = None) -> None:
        useful = []
        sub_config_path = interfaces.configuration.path_join(
            config_path, requirement.name)
        if (isinstance(requirement, requirements.TranslationLayerRequirement)
                and requirement.requirements.get("class", False)
                and requirement.unsatisfied(context, config_path)):
            class_req = requirement.requirements["class"]

            for test in self.tests:
                if (test.layer_type.__module__ + "." +
                        test.layer_type.__name__ == class_req.config_value(
                            context, sub_config_path)):
                    useful.append(test)

            # Determine if a class has been chosen
            # Once an appropriate class has been chosen, attempt to determine the page_map_offset value
            if ("memory_layer" in requirement.requirements and
                    not requirement.requirements["memory_layer"].unsatisfied(
                        context, sub_config_path)):
                # Only bother getting the DTB if we don't already have one
                page_map_offset_path = interfaces.configuration.path_join(
                    sub_config_path, "page_map_offset")
                if not context.config.get(page_map_offset_path, None):
                    physical_layer_name = requirement.requirements[
                        "memory_layer"].config_value(context, sub_config_path)
                    if not isinstance(physical_layer_name, str):
                        raise TypeError(
                            f"Physical layer name is not a string: {sub_config_path}"
                        )
                    physical_layer = context.layers[physical_layer_name]
                    # Check lower layer metadata first
                    if physical_layer.metadata.get('page_map_offset', None):
                        context.config[
                            page_map_offset_path] = physical_layer.metadata[
                                'page_map_offset']
                    else:
                        hits = physical_layer.scan(context,
                                                   PageMapScanner(useful),
                                                   progress_callback)
                        for test, dtb in hits:
                            context.config[page_map_offset_path] = dtb
                            break
                        else:
                            return None
                if isinstance(
                        requirement, interfaces.configuration.
                        ConstructableRequirementInterface):
                    requirement.construct(context, config_path)
        else:
            for subreq in requirement.requirements.values():
                self(context, sub_config_path, subreq)
Beispiel #2
0
    def __call__(self,
                 context: interfaces.context.ContextInterface,
                 config_path: str,
                 requirement: interfaces.configuration.RequirementInterface,
                 progress_callback=None,
                 optional=False) -> List[str]:

        # Make sure we import the layers, so they can reconstructed
        framework.import_files(sys.modules['volatility3.framework.layers'])

        result = []  # type: List[str]
        if requirement.unsatisfied(context, config_path):
            # Having called validate at the top level tells us both that we need to dig deeper
            # but also ensures that TranslationLayerRequirements have got the correct subrequirements if their class is populated

            subreq_config_path = interfaces.configuration.path_join(
                config_path, requirement.name)
            for subreq in requirement.requirements.values():
                try:
                    self(context,
                         subreq_config_path,
                         subreq,
                         optional=optional or subreq.optional)
                except Exception as e:
                    # We don't really care if this fails, it tends to mean the configuration isn't complete for that item
                    vollog.log(constants.LOGLEVEL_VVVV,
                               "Construction Exception occurred: {}".format(e))
                invalid = subreq.unsatisfied(context, subreq_config_path)
                # We want to traverse optional paths, so don't check until we've tried to validate
                # We also don't want to emit a debug message when a parent is optional, hence the optional parameter
                if invalid and not (optional or subreq.optional):
                    vollog.log(
                        constants.LOGLEVEL_V,
                        "Failed on requirement: {}".format(subreq_config_path))
                    result.append(
                        interfaces.configuration.path_join(
                            subreq_config_path, subreq.name))
            if result:
                return result
            elif isinstance(
                    requirement, interfaces.configuration.
                    ConstructableRequirementInterface):
                # We know all the subrequirements are filled, so let's populate
                requirement.construct(context, config_path)

        if progress_callback is not None:
            progress_callback(100, "Reconstruction finished")

        return []
Beispiel #3
0
    def __call__(self,
                 context: interfaces.context.ContextInterface,
                 config_path: str,
                 requirement: interfaces.configuration.RequirementInterface,
                 progress_callback: constants.ProgressCallback = None) -> None:
        new_config_path = interfaces.configuration.path_join(
            config_path, requirement.name)
        if not isinstance(requirement,
                          configuration.requirements.ModuleRequirement):
            # Check subrequirements
            for req in requirement.requirements:
                self(context, new_config_path, requirement.requirements[req],
                     progress_callback)
            return
        if not requirement.unsatisfied(context, config_path):
            return
        # The requirement is unfulfilled and is a ModuleRequirement

        context.config[interfaces.configuration.path_join(
            new_config_path,
            'class')] = 'volatility3.framework.contexts.ConfigurableModule'

        for req in requirement.requirements:
            if requirement.requirements[req].unsatisfied(
                    context, new_config_path) and req != 'offset':
                return

        # We now just have the offset requirement, but the layer requirement has been fulfilled.
        # Unfortunately we don't know the layer name requirement's exact name

        for req in requirement.requirements:
            if isinstance(
                    requirement.requirements[req],
                    configuration.requirements.TranslationLayerRequirement):
                layer_kvo_config_path = interfaces.configuration.path_join(
                    new_config_path, req, 'kernel_virtual_offset')
                offset_config_path = interfaces.configuration.path_join(
                    new_config_path, 'offset')
                offset = context.config[layer_kvo_config_path]
                context.config[offset_config_path] = offset
            elif isinstance(requirement.requirements[req],
                            configuration.requirements.SymbolTableRequirement):
                symbol_shift_config_path = interfaces.configuration.path_join(
                    new_config_path, req, 'symbol_shift')
                context.config[symbol_shift_config_path] = 0

        # Now construct the module based on the sub-requirements
        requirement.construct(context, config_path)
Beispiel #4
0
    def __call__(self,
                 context: interfaces.context.ContextInterface,
                 config_path: str,
                 requirement: interfaces.configuration.RequirementInterface,
                 progress_callback: constants.ProgressCallback = None) -> None:
        if requirement.unsatisfied(context, config_path):
            if "pdbscan" not in context.symbol_space:
                context.symbol_space.append(
                    native.NativeTable("pdbscan", native.std_ctypes))
            # TODO: check if this is a windows symbol requirement, otherwise ignore it
            self._symbol_requirements = self.find_requirements(
                context, config_path, requirement,
                requirements.SymbolTableRequirement)
            potential_layers = self.find_virtual_layers_from_req(
                context=context,
                config_path=config_path,
                requirement=requirement)
            for sub_config_path, symbol_req in self._symbol_requirements:
                parent_path = interfaces.configuration.parent_path(
                    sub_config_path)
                if symbol_req.unsatisfied(context, parent_path):
                    valid_kernel = self.determine_valid_kernel(
                        context, potential_layers, progress_callback)
                    if valid_kernel:
                        self.recurse_symbol_fulfiller(context, valid_kernel,
                                                      progress_callback)
                        self.set_kernel_virtual_offset(context, valid_kernel)

        if progress_callback is not None:
            progress_callback(100, "PDB scanning finished")
Beispiel #5
0
    def find_requirements(self,
                          context: interfaces.context.ContextInterface,
                          config_path: str,
                          requirement_root: interfaces.configuration.RequirementInterface,
                          requirement_type: Union[Tuple[Type[interfaces.configuration.RequirementInterface], ...],
                                                  Type[interfaces.configuration.RequirementInterface]],
                          shortcut: bool = True) -> List[Tuple[str, interfaces.configuration.RequirementInterface]]:
        """Determines if there is actually an unfulfilled `Requirement`
        waiting.

        This ensures we do not carry out an expensive search when there is no need for a particular `Requirement`

        Args:
            context: Context on which to operate
            config_path: Configuration path of the top-level requirement
            requirement_root: Top-level requirement whose subrequirements will all be searched
            requirement_type: Type of requirement to find
            shortcut: Only returns requirements that live under unsatisfied requirements

        Returns:
            A list of tuples containing the config_path, sub_config_path and requirement identifying the unsatisfied `Requirements`
        """
        sub_config_path = interfaces.configuration.path_join(config_path, requirement_root.name)
        results: List[Tuple[str, interfaces.configuration.RequirementInterface]] = []
        recurse = not shortcut
        if isinstance(requirement_root, requirement_type):
            if recurse or requirement_root.unsatisfied(context, config_path):
                results.append((sub_config_path, requirement_root))
        else:
            recurse = True
        if recurse:
            for subreq in requirement_root.requirements.values():
                results += self.find_requirements(context, sub_config_path, subreq, requirement_type, shortcut)
        return results
Beispiel #6
0
    def __call__(
        self,
        context: interfaces.context.ContextInterface,
        config_path: str,
        requirement: interfaces.configuration.RequirementInterface,
        progress_callback: constants.ProgressCallback = None
    ) -> Optional[List[str]]:
        """Runs the automagic over the configurable."""

        framework.import_files(sys.modules['volatility3.framework.layers'])

        # Quick exit if we're not needed
        if not requirement.unsatisfied(context, config_path):
            return None

        # Bow out quickly if the UI hasn't provided a single_location
        unsatisfied = self.unsatisfied(self.context, self.config_path)
        if unsatisfied:
            vollog.info(
                "Unable to run LayerStacker, unsatisfied requirement: {}".
                format(unsatisfied))
            return list(unsatisfied)
        if not self.config or not self.config.get('single_location', None):
            raise ValueError(
                "Unable to run LayerStacker, single_location parameter not provided"
            )

        # Search for suitable requirements
        self.stack(context, config_path, requirement, progress_callback)

        if progress_callback is not None:
            progress_callback(100, "Stacking attempts finished")
        return None
Beispiel #7
0
    def find_suitable_requirements(
            cls, context: interfaces.context.ContextInterface,
            config_path: str,
            requirement: interfaces.configuration.RequirementInterface,
            stacked_layers: List[str]) -> Optional[Tuple[str, str]]:
        """Looks for translation layer requirements and attempts to apply the
        stacked layers to it.  If it succeeds it returns the configuration path
        and layer name where the stacked nodes were spliced into the tree.

        Returns:
            A tuple of a configuration path and layer name for the top of the stacked layers
                or None if suitable requirements are not found
        """
        child_config_path = interfaces.configuration.path_join(
            config_path, requirement.name)
        if isinstance(requirement, requirements.TranslationLayerRequirement):
            if requirement.unsatisfied(context, config_path):
                original_setting = context.config.get(child_config_path, None)
                for layer_name in stacked_layers:
                    context.config[child_config_path] = layer_name
                    if not requirement.unsatisfied(context, config_path):
                        return child_config_path, layer_name
                # Clean-up to restore the config
                if original_setting:
                    context.config[child_config_path] = original_setting
                else:
                    del context.config[child_config_path]
            else:
                return child_config_path, context.config.get(
                    child_config_path, None)
        for req_name, req in requirement.requirements.items():
            result = cls.find_suitable_requirements(context, child_config_path,
                                                    req, stacked_layers)
            if result:
                return result
        return None
Beispiel #8
0
    def __call__(self,
                 context: interfaces.context.ContextInterface,
                 config_path: str,
                 requirement: interfaces.configuration.RequirementInterface,
                 progress_callback: constants.ProgressCallback = None) -> None:
        """Searches for SymbolTableRequirements and attempt to populate
        them."""

        # Bomb out early if our details haven't been configured
        if self.symbol_class is None:
            return

        self._requirements = self.find_requirements(
            context,
            config_path,
            requirement, (requirements.TranslationLayerRequirement,
                          requirements.SymbolTableRequirement),
            shortcut=False)

        for (sub_path, requirement) in self._requirements:
            parent_path = interfaces.configuration.parent_path(sub_path)

            if (isinstance(requirement, requirements.SymbolTableRequirement)
                    and requirement.unsatisfied(context, parent_path)):
                for (tl_sub_path, tl_requirement) in self._requirements:
                    tl_parent_path = interfaces.configuration.parent_path(
                        tl_sub_path)
                    # Find the TranslationLayer sibling to the SymbolTableRequirement
                    if (isinstance(tl_requirement,
                                   requirements.TranslationLayerRequirement)
                            and tl_parent_path == parent_path):
                        if context.config.get(tl_sub_path, None):
                            self._banner_scan(context, parent_path,
                                              requirement,
                                              context.config[tl_sub_path],
                                              progress_callback)
                            break