From 03cdd91fbf6216bc622a5923c2375dfcd299cd60 Mon Sep 17 00:00:00 2001 From: Mike Auty Date: Thu, 20 Jul 2017 00:49:36 +0100 Subject: [PATCH] Add in the capability to merge two config dicts (so that manually set settings aren't overwritten). --- volatility/cli/__init__.py | 11 +++++++++++ volatility/framework/automagic/stacker.py | 4 +++- .../framework/interfaces/configuration.py | 19 +++++++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/volatility/cli/__init__.py b/volatility/cli/__init__.py index ae22f4c34..50e55bfb3 100644 --- a/volatility/cli/__init__.py +++ b/volatility/cli/__init__.py @@ -48,6 +48,9 @@ class CommandLine(object): description = "An open-source memory forensics framework") parser.add_argument("-c", "--config", help = "Load the configuration from a json file", default = None, type = str) + parser.add_argument("-e", "--extend", help = "Extend the configuration with a new (or changed) setting", + default = None, + action = 'append') parser.add_argument("-p", "--plugins", help = "Semi-colon separated list of paths to find plugins", default = "", type = str) parser.add_argument("-v", "--verbosity", help = "Increase output verbosity", default = 0, action = "count") @@ -134,6 +137,14 @@ class CommandLine(object): extended_path = interfaces.configuration.path_join(config_path, requirement.name) ctx.config[extended_path] = value + if args.extend: + for extension in args.extend: + if '=' not in extension: + raise ValueError( + "Invalid extension (extensions must be of the format \"conf.path.value='value'\")") + address, value = extension[:extension.find('=')], json.loads(extension[extension.find('=') + 1:]) + ctx.config[address] = value + ### # BACK TO THE FRAMEWORK ### diff --git a/volatility/framework/automagic/stacker.py b/volatility/framework/automagic/stacker.py index c05ff03f4..c950dde9c 100644 --- a/volatility/framework/automagic/stacker.py +++ b/volatility/framework/automagic/stacker.py @@ -100,7 +100,9 @@ class LayerStacker(interfaces.automagic.AutomagicInterface): if result: path, layer = result # splice in the new configuration into the original context - context.config.splice(path, new_context.memory[layer].build_configuration()) + print("BEFORE", dict(context.config)) + context.config.merge(path, new_context.memory[layer].build_configuration()) + print("AFTER ", dict(context.config)) # Call the construction magic now we may have new things to construct constructor = construct_layers.ConstructionMagic(context, interfaces.configuration.path_join(self.config_path, diff --git a/volatility/framework/interfaces/configuration.py b/volatility/framework/interfaces/configuration.py index 70903c5fb..b4bf8ef2e 100644 --- a/volatility/framework/interfaces/configuration.py +++ b/volatility/framework/interfaces/configuration.py @@ -186,6 +186,25 @@ class HierarchicalDict(collections.abc.Mapping): raise TypeError("Splice requires a string key and HierarchicalDict value") self._setitem(key, value, False) + def merge(self, key, value, overwrite = False): + """Acts similarly to splice, but maintains previous values + + If overwrite is true, then entries in the new value are used over those that exist within key already + + @param key: The location within the hierarchy at which to merge the `value` + @type key: str + @param value: HierarchicalDict to be merged under the key node + @type value: HierarchicalDict + """ + if not isinstance(key, str) or not isinstance(value, HierarchicalDict): + raise TypeError("Splice requires a string key and HierarchicalDict value") + for item in dict(value): + if self.get(key + self._separator + item, None): + if overwrite: + self[key + self._separator + item] = value[item] + else: + self[key + self._separator + item] = value[item] + def clone(self): """Duplicates the configuration, allowing changes without affecting the original""" return copy.deepcopy(self)