From 183ff676992674ab3793e9525fae1e71898cebdc Mon Sep 17 00:00:00 2001 From: Mike Auty Date: Wed, 7 Dec 2016 16:00:31 +0000 Subject: [PATCH] Attach the kernel virtual offset to intel spaces. --- volatility/framework/__init__.py | 3 +- volatility/framework/automagic/pdbscan.py | 95 +++++++++++++---------- volatility/framework/layers/intel.py | 4 +- volatility/plugins/windows/pslist.py | 6 +- 4 files changed, 61 insertions(+), 47 deletions(-) diff --git a/volatility/framework/__init__.py b/volatility/framework/__init__.py index 6a12c87bb..644937af7 100644 --- a/volatility/framework/__init__.py +++ b/volatility/framework/__init__.py @@ -73,7 +73,8 @@ def import_files(base_module): try: vollog.debug("Importing module: {}.{}".format(base_module.__name__, module)) __import__(base_module.__name__ + "." + module) - except ImportError: + except ImportError as e: + vollog.debug(str(e)) vollog.warning("Failed to import module {} based on file: {}".format(module, modpath)) raise else: diff --git a/volatility/framework/automagic/pdbscan.py b/volatility/framework/automagic/pdbscan.py index 41993b81e..8565db4dc 100644 --- a/volatility/framework/automagic/pdbscan.py +++ b/volatility/framework/automagic/pdbscan.py @@ -114,7 +114,7 @@ class KernelPDBScanner(interfaces.automagic.AutomagicInterface): Returns a list of possible kernel locations in the physical memory """ sub_config_path = interfaces.configuration.path_join(config_path, requirement.name) - results = [] + results = {} if isinstance(requirement, interfaces.configuration.TranslationLayerRequirement): # Check for symbols in this layer # FIXME: optionally allow a full (slow) scan @@ -122,10 +122,10 @@ class KernelPDBScanner(interfaces.automagic.AutomagicInterface): virtual_layer_name = context.config.get(sub_config_path, None) layer_name = context.config.get(interfaces.configuration.path_join(sub_config_path, "memory_layer"), None) if layer_name: - results = scan(context, layer_name) + results = {virtual_layer_name: scan(context, layer_name)} else: for subreq in requirement.requirements.values(): - results += self.recurse_pdb_finder(context, sub_config_path, subreq) + results.update(self.recurse_pdb_finder(context, sub_config_path, subreq)) return results def recurse_symbol_fulfiller(self, context, config_path, requirement): @@ -140,24 +140,32 @@ class KernelPDBScanner(interfaces.automagic.AutomagicInterface): suffix = ".json" if self.potential_kernels: # TODO: Check that the symbols for this kernel will fulfill the requirement - kernel = self.potential_kernels[0] - # Check user symbol directory first, then fallback to the framework's library to allow for overloading - midfix = os.path.join(kernel['pdb_name'], kernel['GUID'] + "-" + str(kernel['age'])) - idd_path = None - for prefix in self.prefixes: - for suffix in self.suffixes: - if os.path.exists(os.path.join(prefix, midfix + suffix)): - idd_path = "file://" + os.path.abspath(os.path.join(prefix, midfix + suffix)) - if idd_path: - vollog.debug("Using symbol library: {}".format(midfix)) - clazz = "volatility.framework.symbols.windows.WindowsKernelIntermedSymbols" - # Set the discovered options - context.config[interfaces.configuration.path_join(sub_config_path, "class")] = clazz - context.config[interfaces.configuration.path_join(sub_config_path, "idd_filepath")] = idd_path - # Construct the appropriate symbol table - requirement.construct(context, config_path) + kernel = None + for pk in self.potential_kernels: + kernel = self.potential_kernels[pk] + if kernel: + kernel = kernel[0] + break + if kernel: + # Check user symbol directory first, then fallback to the framework's library to allow for overloading + midfix = os.path.join(kernel['pdb_name'], kernel['GUID'] + "-" + str(kernel['age'])) + idd_path = None + for prefix in self.prefixes: + for suffix in self.suffixes: + if os.path.exists(os.path.join(prefix, midfix + suffix)): + idd_path = "file://" + os.path.abspath(os.path.join(prefix, midfix + suffix)) + if idd_path: + vollog.debug("Using symbol library: {}".format(midfix)) + clazz = "volatility.framework.symbols.windows.WindowsKernelIntermedSymbols" + # Set the discovered options + context.config[interfaces.configuration.path_join(sub_config_path, "class")] = clazz + context.config[interfaces.configuration.path_join(sub_config_path, "idd_filepath")] = idd_path + # Construct the appropriate symbol table + requirement.construct(context, config_path) + else: + vollog.debug("Symbol library path not found: {}".format(midfix + suffix)) else: - vollog.debug("Symbol library path not found: {}".format(midfix + suffix)) + vollog.debug("No suitable kernel pdb signature found") else: for subreq in requirement.requirements.values(): self.recurse_symbol_fulfiller(context, sub_config_path, subreq) @@ -167,38 +175,43 @@ class KernelPDBScanner(interfaces.automagic.AutomagicInterface): sub_config_path = interfaces.configuration.path_join(config_path, requirement.name) if isinstance(requirement, configuration.requirements.TranslationLayerRequirement): # TODO: Check that this is the right potential kernel to be using - kernel = self.potential_kernels[0] - # Often the kernel is loaded at a fixed mapping (presumably because the memory manager hasn't started yet virtual_layer_name = context.config.get(sub_config_path, None) if virtual_layer_name and isinstance(context.memory[virtual_layer_name], layers.intel.Intel): physical_layer_name = context.config.get( interfaces.configuration.path_join(sub_config_path, "memory_layer"), None) if physical_layer_name: - if context.memory[virtual_layer_name].bits_per_register == 64: - # The kernel starts in a chunk towards the end of the space - kvo = kernel['mz_offset'] + ( - 31 << int(math.ceil(math.log2(context.memory[virtual_layer_name].maximum_address + 1)) - 5)) - else: - # The kernel starts exactly halfway through the address space, so shift the maximum_address down by 1 - kvo = kernel['mz_offset'] + (1 << (context.memory[virtual_layer_name].bits_per_register - 1)) - try: - kvp = context.memory[virtual_layer_name].mapping(kvo, 0) - if (any([(p == kernel['mz_offset'] and l == physical_layer_name) for (_, p, _, l) in kvp])): - kvo_path = interfaces.configuration.path_join(config_path, 'kernel_virtual_offset') - context.config[kvo_path] = kvo - vollog.debug( - "Setting kernel_virtual_offset to {}".format(hex(kvo))) + kernel = self.potential_kernels.get(virtual_layer_name, [None, ])[0] + if kernel: + # It seems the kernel is loaded at a fixed mapping (presumably because the memory manager hasn't started yet) + if context.memory[virtual_layer_name].bits_per_register == 64: + # The kernel starts in a chunk towards the end of the space + kvo = kernel['mz_offset'] + ( + 31 << int( + math.ceil(math.log2(context.memory[virtual_layer_name].maximum_address + 1)) - 5)) else: - vollog.debug( - "Potential kernel_virtual_offset did not map to expected location: {}".format(hex(kvo))) - except exceptions.PagedInvalidAddressException: - vollog.debug("Potential kernel_virtual_offset caused a page fault: {}".format(hex(kvo))) + # The kernel starts exactly halfway through the address space, so shift the maximum_address down by 1 + kvo = kernel['mz_offset'] + ( + 1 << (context.memory[virtual_layer_name].bits_per_register - 1)) + try: + kvp = context.memory[virtual_layer_name].mapping(kvo, 0) + if (any([(p == kernel['mz_offset'] and l == physical_layer_name) for (_, p, _, l) in kvp])): + # Sit the virtual offset under the TranslationLayer it applies to + kvo_path = interfaces.configuration.path_join(sub_config_path, 'kernel_virtual_offset') + context.config[kvo_path] = kvo + vollog.debug( + "Setting kernel_virtual_offset to {}".format(hex(kvo))) + else: + vollog.debug( + "Potential kernel_virtual_offset did not map to expected location: {}".format( + hex(kvo))) + except exceptions.PagedInvalidAddressException: + vollog.debug("Potential kernel_virtual_offset caused a page fault: {}".format(hex(kvo))) else: for subreq in requirement.requirements.values(): self.recurse_set_kernel_virtual_offset(context, sub_config_path, subreq) def __call__(self, context, config_path, requirement): - self.potential_kernels = list(self.recurse_pdb_finder(context, config_path, requirement)) + self.potential_kernels = self.recurse_pdb_finder(context, config_path, requirement) if self.potential_kernels: self.recurse_symbol_fulfiller(context, config_path, requirement) self.recurse_set_kernel_virtual_offset(context, config_path, requirement) diff --git a/volatility/framework/layers/intel.py b/volatility/framework/layers/intel.py index 8c58f26ea..3e99352d0 100644 --- a/volatility/framework/layers/intel.py +++ b/volatility/framework/layers/intel.py @@ -151,7 +151,9 @@ class Intel(interfaces.layers.TranslationLayerInterface): requirements.TranslationLayerRequirement(name = 'swap_layer', optional = True), requirements.IntRequirement(name = 'page_map_offset', - optional = False)] + optional = False), + requirements.IntRequirement(name = 'kernel_virtual_offset', + optional = True)] def scan(self, context, scanner, progress_callback = None, min_address = None, max_address = None): min_address, max_address, scanner, total_size = self._pre_scan(context, min_address, max_address, diff --git a/volatility/plugins/windows/pslist.py b/volatility/plugins/windows/pslist.py index 58859ab9a..90d2ce7f9 100644 --- a/volatility/plugins/windows/pslist.py +++ b/volatility/plugins/windows/pslist.py @@ -12,9 +12,7 @@ class PsList(plugins.PluginInterface): description = "Windows OS"), requirements.IntRequirement(name = 'pid', description = "Process ID", - optional = True), - requirements.IntRequirement(name = 'kernel_virtual_offset', - description = 'Virtual address of the kernel MZ header')] + optional = True)] def update_configuration(self): """No operation since all values provided by config/requirements initially""" @@ -28,7 +26,7 @@ class PsList(plugins.PluginInterface): def run(self): virtual = self.config['primary'] - kvo = self.config['kernel_virtual_offset'] + kvo = self.config['primary.kernel_virtual_offset'] ps_aph_offset = kvo + self.context.symbol_space.get_symbol("ntkrnlmp!PsActiveProcessHead").address list_entry = self.context.object("ntkrnlmp!_LIST_ENTRY", layer_name = virtual, offset = ps_aph_offset) reloff = self.context.symbol_space.get_type("ntkrnlmp!_EPROCESS").relative_child_offset("ActiveProcessLinks")