From 2caeeb275e0e8f2954d8087128aad58eb0d38e8e Mon Sep 17 00:00:00 2001 From: Mike Auty Date: Mon, 7 Aug 2017 21:42:10 +0100 Subject: [PATCH] First stab at refactoring the add_process_layer code out of the Windows _EPROCESS structure. --- .../framework/symbols/generic/__init__.py | 40 ++++++++++++++++ .../symbols/windows/extensions/__init__.py | 46 +++++-------------- 2 files changed, 51 insertions(+), 35 deletions(-) create mode 100644 volatility/framework/symbols/generic/__init__.py diff --git a/volatility/framework/symbols/generic/__init__.py b/volatility/framework/symbols/generic/__init__.py new file mode 100644 index 000000000..e414c1002 --- /dev/null +++ b/volatility/framework/symbols/generic/__init__.py @@ -0,0 +1,40 @@ +import random +import string + +from volatility.framework import objects, interfaces + + +class GenericIntelProcess(objects.Struct): + def _add_process_layer(self, context, dtb, config_prefix = None, preferred_name = None): + """Constructs a new layer based on the process's DirectoryTableBase""" + + if config_prefix is None: + # TODO: Ensure collisions can't happen by verifying the config_prefix is empty + random_prefix = ''.join( + random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(8)) + config_prefix = interfaces.configuration.path_join("temporary", "_" + random_prefix) + + # Figure out a suitable name we can use for the new layer + if preferred_name is None: + preferred_name = context.memory.free_layer_name( + prefix = self.vol.layer_name + "_Process_") + else: + if preferred_name in context.memory: + preferred_name = context.memory.free_layer_name(prefix = preferred_name) + + # Copy the parent's config and then make suitable changes + parent_layer = context.memory[self.vol.layer_name] + parent_config = parent_layer.build_configuration() + # It's an intel layer, because we hardwire the "memory_layer" config option + # FIXME: this could be for other architectures if we don't hardwire this/these values + parent_config['memory_layer'] = parent_layer.config['memory_layer'] + parent_config['page_map_offset'] = dtb + + # Set the new configuration and construct the layer + config_path = interfaces.configuration.path_join(config_prefix, preferred_name) + context.config.splice(config_path, parent_config) + new_layer = parent_layer.__class__(context, config_path = config_path, name = preferred_name) + + # Add the constructed layer and return the name + context.memory.add_layer(new_layer) + return preferred_name diff --git a/volatility/framework/symbols/windows/extensions/__init__.py b/volatility/framework/symbols/windows/extensions/__init__.py index ce0f33791..3ca8a4773 100644 --- a/volatility/framework/symbols/windows/extensions/__init__.py +++ b/volatility/framework/symbols/windows/extensions/__init__.py @@ -1,25 +1,24 @@ import collections.abc -import random -import string -from volatility.framework import interfaces -from volatility.framework import objects from volatility.framework import exceptions - +from volatility.framework import objects # Keep these in a basic module, to prevent import cycles when symbol providers require them +from volatility.framework.symbols.generic import GenericIntelProcess + class _ETHREAD(objects.Struct): def owning_process(self, kernel_layer = None): """Return the EPROCESS that owns this thread""" return self.ThreadsProcess.dereference(kernel_layer) + class _CMHIVE(objects.Struct): @property def name(self): """Determine a name for the hive. Note that some attributes are unpredictably blank across different OS versions while others are populated, so we check all possibilities and take the first one that's not empty""" - + for attr in ["FileFullPath", "FileUserName", "HiveRootPath"]: try: return getattr(self, attr).String @@ -28,6 +27,7 @@ class _CMHIVE(objects.Struct): return None + class _UNICODE_STRING(objects.Struct): @property def String(self): @@ -38,44 +38,20 @@ class _UNICODE_STRING(objects.Struct): encoding = "utf16") -class _EPROCESS(objects.Struct): +class _EPROCESS(GenericIntelProcess): def add_process_layer(self, context, config_prefix = None, preferred_name = None): """Constructs a new layer based on the process's DirectoryTableBase""" - if config_prefix is None: - # TODO: Ensure collisions can't happen by verifying the config_prefix is empty - random_prefix = ''.join( - random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(8)) - config_prefix = interfaces.configuration.path_join("temporary", "_" + random_prefix) - - # Figure out a suitable name we can use for the new layer - if preferred_name is None: - preferred_name = context.memory.free_layer_name( - prefix = self.vol.layer_name + "_PID" + str(self.UniqueProcessId) + "_") - else: - if preferred_name in context.memory: - preferred_name = context.memory.free_layer_name(prefix = preferred_name) - - # Copy the parent's config and then make suitable changes parent_layer = context.memory[self.vol.layer_name] - parent_config = parent_layer.build_configuration() - parent_config['memory_layer'] = parent_layer.config['memory_layer'] # Presumably for 64-bit systems, the DTB is defined as an array, rather than an unsigned long long if isinstance(self.Pcb.DirectoryTableBase, objects.Array): - parent_config['page_map_offset'] = self.Pcb.DirectoryTableBase.cast("unsigned long long") + dtb = self.Pcb.DirectoryTableBase.cast("unsigned long long") else: - parent_config['page_map_offset'] = self.Pcb.DirectoryTableBase - parent_config['page_map_offset'] = parent_config['page_map_offset'] & ( - (1 << parent_layer.bits_per_register) - 1) - - # Set the new configuration and construct the layer - config_path = interfaces.configuration.path_join(config_prefix, preferred_name) - context.config.splice(config_path, parent_config) - new_layer = parent_layer.__class__(context, config_path = config_path, name = preferred_name) + dtb = self.Pcb.DirectoryTableBase + dtb = dtb & ((1 << parent_layer.bits_per_register) - 1) # Add the constructed layer and return the name - context.memory.add_layer(new_layer) - return preferred_name + return self._add_process_layer(context, dtb, config_prefix, preferred_name) def load_order_modules(self): """Generator for DLLs in the order that they were loaded"""