diff --git a/volatility/framework/automagic/linux.py b/volatility/framework/automagic/linux.py index ce8fc9092..8650f5083 100644 --- a/volatility/framework/automagic/linux.py +++ b/volatility/framework/automagic/linux.py @@ -1,7 +1,7 @@ import logging import typing -from volatility.framework import interfaces, constants, validity +from volatility.framework import constants, interfaces, validity from volatility.framework.automagic import linux_symbol_cache from volatility.framework.configuration import requirements from volatility.framework.layers import intel, scanners @@ -39,12 +39,15 @@ class LinuxSymbolFinder(interfaces.automagic.AutomagicInterface): requirements.SymbolRequirement), shortcut = False) - for (path, sub_path, requirement) in self._requirements: + for (sub_path, requirement) in self._requirements: + parent_path = interfaces.configuration.parent_path(sub_path) + if (isinstance(requirement, requirements.SymbolRequirement) and requirement.unsatisfied(context, path)): - for (tl_path, tl_sub_path, tl_requirement) in self._requirements: + 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 SymbolRequirement if (isinstance(tl_requirement, requirements.TranslationLayerRequirement) and - tl_path == path): + tl_parent_path == parent_path): if context.config.get(tl_sub_path, None): self._banner_scan(context, path, requirement, context.config[tl_sub_path], progress_callback) diff --git a/volatility/framework/automagic/pdbscan.py b/volatility/framework/automagic/pdbscan.py index 31250c449..7c772b813 100644 --- a/volatility/framework/automagic/pdbscan.py +++ b/volatility/framework/automagic/pdbscan.py @@ -10,9 +10,10 @@ import os import struct import typing -from volatility.framework import exceptions, layers, validity, constants +from volatility.framework import constants, exceptions, layers, validity from volatility.framework.configuration import requirements -from volatility.framework.layers import scanners, intel +from volatility.framework.interfaces import configuration +from volatility.framework.layers import intel, scanners from volatility.framework.symbols import intermed, native if __name__ == "__main__": @@ -183,7 +184,7 @@ class KernelPDBScanner(interfaces.automagic.AutomagicInterface): context: Context on which to operate """ join = interfaces.configuration.path_join - for config_path, sub_config_path, requirement in self._symbol_requirements: + for sub_config_path, requirement in self._symbol_requirements: # TODO: Potentially think about multiple symbol requirements in both the same and different levels of the requirement tree # TODO: Consider whether a single found kernel can fulfill multiple requirements suffix = ".json" @@ -205,6 +206,7 @@ class KernelPDBScanner(interfaces.automagic.AutomagicInterface): context.config[join(sub_config_path, "class")] = clazz context.config[join(sub_config_path, "isf_url")] = isf_path # Construct the appropriate symbol table + config_path = interfaces.configuration.parent_path(sub_config_path) requirement.construct(context, config_path) break else: @@ -330,8 +332,9 @@ class KernelPDBScanner(interfaces.automagic.AutomagicInterface): config_path, requirement, requirements.SymbolRequirement) - for symbol_req_config_path, _, symbol_req in self._symbol_requirements: - if symbol_req.unsatisfied(context, symbol_req_config_path): + for sub_config_path, symbol_req in self._symbol_requirements: + parent_path = configuration.parent_path(sub_config_path) + if symbol_req.unsatisfied(context, parent_path): potential_kernels = self.recurse_pdb_finder(context, config_path, requirement, progress_callback) self.valid_kernels = self.determine_valid_kernels(context, potential_kernels, progress_callback) if self.valid_kernels: diff --git a/volatility/framework/automagic/windows.py b/volatility/framework/automagic/windows.py index 88debecb0..d3b7e5722 100644 --- a/volatility/framework/automagic/windows.py +++ b/volatility/framework/automagic/windows.py @@ -382,13 +382,14 @@ class WinSwapLayers(interfaces.automagic.AutomagicInterface): self._translation_requirement = self.find_requirements(context, config_path, requirement, requirements.TranslationLayerRequirement, shortcut = False) - for trans_config, trans_sub_config, trans_req in self._translation_requirement: + for trans_sub_config, trans_req in self._translation_requirement: if not isinstance(trans_req, requirements.TranslationLayerRequirement): # We need this so the type-checker knows we're a TranslationLayerRequirement continue - swap_config, swap_sub_config, swap_req = self.find_swap_requirement(trans_config, trans_sub_config, - trans_req) + swap_sub_config, swap_req = self.find_swap_requirement(trans_sub_config, trans_req) counter = 0 + swap_config = interfaces.configuration.parent_path(swap_sub_config) + if swap_req and swap_req.unsatisfied(context, swap_config): # See if any of them need constructing for swap_location in self.config.get('single_swap_locations', []): @@ -418,9 +419,8 @@ class WinSwapLayers(interfaces.automagic.AutomagicInterface): def find_swap_requirement(self, config: str, - sub_config: str, requirement: requirements.TranslationLayerRequirement) \ - -> typing.Tuple[str, str, typing.Optional[requirements.LayerListRequirement]]: + -> typing.Tuple[str, typing.Optional[requirements.LayerListRequirement]]: """Takes a Translation layer and returns its swap_layer requirement""" swap_req = None for req_name in requirement.requirements: @@ -429,8 +429,8 @@ class WinSwapLayers(interfaces.automagic.AutomagicInterface): swap_req = req continue - swap_config = interfaces.configuration.path_join(sub_config, 'swap_layers') - return sub_config, swap_config, swap_req + swap_config = interfaces.configuration.path_join(config, 'swap_layers') + return swap_config, swap_req @classmethod def get_requirements(cls) -> typing.List[interfaces.configuration.RequirementInterface]: diff --git a/volatility/framework/interfaces/automagic.py b/volatility/framework/interfaces/automagic.py index c7dbebdff..1758a53eb 100644 --- a/volatility/framework/interfaces/automagic.py +++ b/volatility/framework/interfaces/automagic.py @@ -5,7 +5,7 @@ Automagic objects attempt to automatically fill configuration values that a user import typing from abc import ABCMeta -from volatility.framework import validity, interfaces +from volatility.framework import interfaces, validity from volatility.framework.configuration import requirements R = typing.TypeVar('R', bound = interfaces.configuration.RequirementInterface) @@ -61,7 +61,7 @@ class AutomagicInterface(interfaces.configuration.ConfigurableInterface, metacla requirement_root: interfaces.configuration.RequirementInterface, requirement_type: typing.Union[typing.Tuple[typing.Type[R], ...], typing.Type[R]], shortcut: bool = True) \ - -> typing.List[typing.Tuple[str, str, R]]: + -> typing.List[typing.Tuple[str, R]]: """Determines if there is actually an unfulfilled requirement waiting This ensures we do not carry out an expensive search when there is no requirement for a particular requirement @@ -77,11 +77,11 @@ class AutomagicInterface(interfaces.configuration.ConfigurableInterface, metacla A list of tuples containing the config_path, sub_config_path and requirement identifying the SymbolRequirements """ sub_config_path = interfaces.configuration.path_join(config_path, requirement_root.name) - results = [] # type: typing.List[typing.Tuple[str, str, R]] + results = [] # type: typing.List[typing.Tuple[str, R]] recurse = not shortcut if isinstance(requirement_root, requirement_type): if recurse or requirement_root.unsatisfied(context, config_path): - results.append((config_path, sub_config_path, requirement_root)) + results.append((sub_config_path, requirement_root)) else: recurse = True if recurse: diff --git a/volatility/framework/interfaces/configuration.py b/volatility/framework/interfaces/configuration.py index cf06b22c3..f7e9d2571 100644 --- a/volatility/framework/interfaces/configuration.py +++ b/volatility/framework/interfaces/configuration.py @@ -18,8 +18,7 @@ import sys import typing from abc import ABCMeta, abstractmethod -from volatility.framework import constants, interfaces -from volatility.framework import validity +from volatility.framework import constants, interfaces, validity from volatility.framework.interfaces.context import ContextInterface CONFIG_SEPARATOR = "." @@ -39,6 +38,11 @@ def path_join(*args) -> str: return CONFIG_SEPARATOR.join(args) +def parent_path(value: str) -> str: + """Returns the parent configuration path from a configuration path""" + return CONFIG_SEPARATOR.join(value.split(CONFIG_SEPARATOR)[:-1]) + + def path_depth(path: str, depth: int = 1) -> str: """Returns the `path` up to a certain depth