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)
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 []
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)
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")
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
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
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
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