diff --git a/volatility/framework/interfaces/configuration.py b/volatility/framework/interfaces/configuration.py index 93f236260..9ce843b25 100644 --- a/volatility/framework/interfaces/configuration.py +++ b/volatility/framework/interfaces/configuration.py @@ -196,9 +196,18 @@ class ConfigurableInterface(validity.ValidityRoutines, metaclass = ABCMeta): def config(self): return self._context.config.branch(self._config_path) - @abstractmethod - def update_configuration(self): - """Ensures that if the class has been created, its configuration is correct""" + def build_configuration(self): + """Constructs a HierarchicalDictionary of all the options required to build this component in the current context. + + Ensures that if the class has been created, it can be recreated using the configuration built + Inheriting classes must override this to ensure any dependent classes update their configurations too + """ + result = HierarchicalDict() + for req in self.get_requirements(): + value = getattr(self, "_" + req.name, req.default) + if value is not None: + result[req.name] = value + return result @classmethod def get_requirements(cls): diff --git a/volatility/framework/interfaces/layers.py b/volatility/framework/interfaces/layers.py index f6e56fda8..c34f88f4c 100644 --- a/volatility/framework/interfaces/layers.py +++ b/volatility/framework/interfaces/layers.py @@ -228,6 +228,18 @@ class TranslationLayerInterface(DataLayerInterface, metaclass = ABCMeta): for x in scanner(chunk, offset): yield x + def build_configuration(self): + config = super().build_configuration() + + # Translation Layers are constructable, and therefore require a class configuration variable + config["class"] = self.__class__.__module__ + "." + self.__class__.__name__ + for req in self.get_requirements(): + if isinstance(req, configuration.TranslationLayerRequirement): + layer = self.config.get(req.name, None) + if layer is not None: + config.splice(req.name, self.context.memory[layer].build_configuration()) + return config + class Memory(validity.ValidityRoutines, collections.abc.Mapping): """Container for multiple layers of data""" diff --git a/volatility/framework/layers/intel.py b/volatility/framework/layers/intel.py index b7afb1fc0..944412161 100644 --- a/volatility/framework/layers/intel.py +++ b/volatility/framework/layers/intel.py @@ -148,11 +148,6 @@ class Intel(interfaces.layers.TranslationLayerInterface): requirements.IntRequirement(name = 'page_map_offset', optional = False)] - def update_configuration(self): - self.config["class"] = self.__class__.__name__ - self.config["memory_layer"] = self._base_layer - self.config["page_map_offset"] = self._page_map_offset - class IntelPAE(Intel): """Class for handling Physical Address Extensions for Intel architectures""" diff --git a/volatility/framework/layers/physical.py b/volatility/framework/layers/physical.py index 963cfa8e4..f117afba8 100644 --- a/volatility/framework/layers/physical.py +++ b/volatility/framework/layers/physical.py @@ -56,9 +56,6 @@ class BufferDataLayer(interfaces.layers.DataLayerInterface): return [requirements.BytesRequirement(name = 'buffer', description = "The direct bytes to interact with", optional = False)] - def update_configuration(self): - self.config["buffer"] = self._buffer - class FileLayer(interfaces.layers.DataLayerInterface): """a DataLayer backed by a file on the filesystem""" @@ -140,6 +137,3 @@ class FileLayer(interfaces.layers.DataLayerInterface): @classmethod def get_requirements(cls): return [requirements.StringRequirement(name = 'filename', optional = False)] - - def update_configuration(self): - self.config['filename'] = self._filename