First stab at refactoring the add_process_layer code out of the Windows _EPROCESS structure.

This commit is contained in:
Mike Auty
2017-08-07 21:42:10 +01:00
parent ab8d76eeef
commit 2caeeb275e
2 changed files with 51 additions and 35 deletions
@@ -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
@@ -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"""