Rip out layer factories, and replace them with a single dependency resolver.

This commit is contained in:
Mike Auty
2015-12-30 21:58:41 +00:00
parent bcbfee9016
commit ff1e326a9c
12 changed files with 33 additions and 180 deletions
+4 -15
View File
@@ -6,6 +6,7 @@ import volatility.framework
import volatility.plugins
from volatility.cli import argparse_adapter
from volatility.framework import interfaces, plugins, configuration, contexts
from volatility.framework.configuration import depresolver
__author__ = 'mike'
@@ -37,6 +38,9 @@ class CommandLine(object):
parser.parse_args()
# Determine the selected plugin
# Resolve the dependencies on that plugin
dldr = depresolver.DataLayerDependencyResolver(plugin)
# Translate the parsed args to a context configuration
# Generate the layers from the arguments
@@ -47,17 +51,6 @@ class CommandLine(object):
# Construct and run the plugin
plugin(context).run()
@staticmethod
def construct_translation_layer_factory(name, requirement):
"""Create a factory that can provides requirements for the configuration
The factory also populates the
"""
factory = contexts.LayerFactory(name, requirement,
[contexts.physical.PhysicalContextModifier,
contexts.intel.IntelContextModifier,
contexts.windows.WindowsContextModifier])
return factory
def collect_plugin_requirements(self, plugin):
"""Generates the requirements necessary for the plugin"""
reqs = plugin.requirements()
@@ -69,10 +62,6 @@ class CommandLine(object):
if isinstance(req, configuration.TranslationLayerRequirement):
# Choose an appropriate LayerFactory (add layer to the req.name so we don't blat the requirement itself
namespace = interfaces.configuration.schema_name_join([plugin.__name__, req.name + "_layer"])
factory = self.construct_translation_layer_factory(namespace, req)
req_mapping[req] = factory
for facreq in factory.requirements():
context.config.add_item(facreq, namespace = namespace)
else:
context.config.add_item(req, plugin.__name__)
return context, req_mapping
@@ -3,7 +3,7 @@ import volatility.framework.interfaces as interfaces
import volatility.framework.validity as validity
class TranslationLayerDependencyResolver(validity.ValidityRoutines):
class DataLayerDependencyResolver(validity.ValidityRoutines):
def __init__(self):
# Maintain a cache of translation layers
self.layer_cache = []
@@ -13,8 +13,16 @@ class TranslationLayerDependencyResolver(validity.ValidityRoutines):
self.layer_cache.append(layer_class)
def resolve_dependencies(self, configurable):
"""Takes a configurable and produces a priority ordered tree of possible solutions to satisfy the various requirements"""
"""Takes a configurable and produces a priority ordered tree of possible solutions to satisfy the various requirements
The return should include each of the potential nodes (and requirements, including optional ones) allowing the UI
to decide the layer build-path and get all the necessary variables from the user for that path.
"""
self._check_type(configurable, interfaces.configuration.Configurable)
for requirement in configurable.get_schemas():
pass
# If the requirement is a layer/configurable
# Recurse over it
print(requirement)
# Add all base-type requirements
# Add all optional base-type requirements in order
+1 -49
View File
@@ -1,56 +1,8 @@
from volatility.framework import validity, interfaces, symbols, layers
from volatility.framework.contexts import intel, physical, windows
from volatility.framework.interfaces.context import ContextModifierInterface
from volatility.framework import interfaces, symbols, layers
__author__ = 'mike'
class LayerFactory(validity.ValidityRoutines, list):
"""Class to establish and load the appropriate components of the context for a given operating system"""
def __init__(self, name, requirement, lst = None):
if lst is None:
lst = []
self._check_type(lst, list)
self._check_type(name, str)
self._name = name
self._req = requirement
validity.ValidityRoutines.__init__(self)
list.__init__(self, [])
for element in lst:
self.append(element)
@property
def name(self):
return self._name
def __setitem__(self, key, value):
self._check_class(value, ContextModifierInterface)
super(LayerFactory, self).__setitem__(key, value)
def requirements(self):
"""Returns all the possible configuration options that might be required for this particular LayerFactory"""
groups = []
for index in range(len(self)):
modifier = self[index]
group = interfaces.configuration.ConfigurationSchemaGroup(modifier.__name__ + str(index))
for req in modifier.requirements():
group.add_item(req)
groups.append(group)
return groups
def __call__(self, context):
"""Constructs a standard context based on the architecture information
Returns a new context with all appropriate modifications (symbols, layers, etc)
"""
for index in range(len(self)):
namespace = interfaces.configuration.schema_name_join([self.name, self[index].__name__ + str(index)])
self[index](namespace).modify_context(context = context)
return context
class Context(interfaces.context.ContextInterface):
"""Maintains the context within which to construct objects
-44
View File
@@ -1,44 +0,0 @@
from volatility.framework import interfaces, layers, configuration
__author__ = 'mike'
class IntelContextModifier(interfaces.context.ContextModifierInterface):
@classmethod
def requirements(cls):
return [configuration.ChoiceRequirement(name = "architecture",
choices = ["auto", "pae", "32", "64"],
description = "Determines the memory image",
default = "auto"),
configuration.IntRequirement(name = "page_map_offset",
description = "Offset to the directory table base"),
configuration.StringRequirement(name = 'layer_name',
description = 'Name of the layer to be added to the memory space',
default = 'intel'),
configuration.TranslationLayerRequirement(name = 'physical_layer',
description = 'Physical Address Space',
os_type = 'windows',
architectures = None,
layer_type = 'physical'),
configuration.TranslationLayerRequirement(name = 'swap_layer',
description = "Layer name for the swap layer",
optional = True)]
def modify_context(self, context):
# TODO: Attempt to determine whether the image is 32, PAE or x64 (although the context must already know whether it is x64)
config = self.config_get(context)
if config.get('architecture') == 'pae':
layer = layers.intel.IntelPAE
elif config.get('architecture') == '32':
layer = layers.intel.Intel
elif config.get('architecture') == '64':
layer = layers.intel.Intel32e
else:
# TODO: Add automagic here
layer = layers.intel.IntelPAE
intel = layer(context, config.get_value('layer_name'),
config.get_value('physical_layer').name,
page_map_offset = config.get_value('page_map_offset'))
context.add_layer(intel)
-22
View File
@@ -1,22 +0,0 @@
from volatility.framework import interfaces, layers, configuration
__author__ = 'mike'
class PhysicalContextModifier(interfaces.context.ContextModifierInterface):
@classmethod
def requirements(cls):
return [configuration.StringRequirement(name = 'location',
description = 'URL to the physical address space',
default = '/home/mike/memory/jon-fres.dmp'),
configuration.StringRequirement(name = 'layer_name',
description = 'Layer name for the physical space',
default = 'physical')]
def modify_context(self, context):
# Ideally allow for the plugin to specify the layering, but if not then guess at the best one
modconfig = self.config_get(context)
base = layers.physical.FileLayer(context,
modconfig.get_value('layer_name'),
filename = modconfig.get_value('location'))
context.add_layer(base)
-24
View File
@@ -1,24 +0,0 @@
from volatility.framework import interfaces
from volatility.framework.symbols import vtypes, windows
__author__ = 'mike'
class WindowsContextModifier(interfaces.context.ContextModifierInterface):
# TODO: Only import the vtypes only when necessary
def __init__(self, namespace):
interfaces.context.ContextModifierInterface.__init__(namespace)
from volatility.framework import xp_sp2_x86_vtypes
self._virtual_types = xp_sp2_x86_vtypes.ntkrnlmp_types
@classmethod
def requirements(cls):
return []
def modify_context(self, context):
virtual_types = self._virtual_types
ntkrnlmp = vtypes.VTypeSymbolTable('ntkrnlmp', virtual_types, context.symbol_space.natives)
ntkrnlmp.set_structure_class('_ETHREAD', windows._ETHREAD)
ntkrnlmp.set_structure_class('_LIST_ENTRY', windows._LIST_ENTRY)
context.symbol_space.append(ntkrnlmp)
@@ -76,7 +76,7 @@ class ConfigurationSchemaNode(validity.ValidityRoutines):
"""
class Configurable(metaclass = ABCMeta):
class Configurable(object, metaclass = ABCMeta):
"""Class to allow objects to have requirements and populate the context config tree"""
@classmethod
+2 -7
View File
@@ -6,6 +6,7 @@ Created on 6 May 2013
from abc import ABCMeta, abstractmethod, abstractproperty
from volatility.framework import validity
from volatility.framework.interfaces import configuration
class ContextInterface(object, metaclass = ABCMeta):
@@ -51,7 +52,7 @@ class ContextInterface(object, metaclass = ABCMeta):
"""
class ContextModifierInterface(validity.ValidityRoutines, metaclass = ABCMeta):
class ContextModifierInterface(validity.ValidityRoutines, configuration.Configurable, metaclass = ABCMeta):
def __init__(self, namespace):
"""Initializes the context modifier
@@ -63,12 +64,6 @@ class ContextModifierInterface(validity.ValidityRoutines, metaclass = ABCMeta):
def config_get(self, context):
return context.config[self.namespace]
@classmethod
@abstractmethod
def requirements(cls):
"""Returns all the options that might need to be passed to modify the context"""
return []
@abstractmethod
def modify_context(self, context):
"""Modifies the context in place"""
+1 -1
View File
@@ -61,8 +61,8 @@ class DataLayerInterface(validity.ValidityRoutines, configuration.Configurable,
(exceptions will be thrown using a DataLayer after destruction)"""
pass
@abstractmethod
@classmethod
@abstractmethod
def get_schema(cls):
"""Returns a list of requirements for this type of layer"""
+4 -3
View File
@@ -5,8 +5,9 @@ Created on 6 May 2013
"""
from abc import abstractmethod, ABCMeta
from volatility.framework import interfaces
from volatility.framework import validity
from volatility.framework.interfaces import configuration as configuration_interface
from volatility.framework.interfaces import context as context_interface
#
@@ -22,11 +23,11 @@ from volatility.framework import validity
# The plugin accepts the context and modifies as necessary
# The plugin runs and produces a TreeGrid output
class PluginInterface(validity.ValidityRoutines, interfaces.configuration.Configurable, metaclass = ABCMeta):
class PluginInterface(validity.ValidityRoutines, configuration_interface.Configurable, metaclass = ABCMeta):
"""Class that defines the interface all Plugins must maintain"""
def __init__(self, context):
self._check_type(context, interfaces.context.ContextInterface)
self._check_type(context, context_interface.ContextInterface)
self._context = context
self.validate_inputs()
+7 -8
View File
@@ -7,16 +7,15 @@ Created on 7 May 2013
import math
import struct
import volatility.framework.configuration as configuration
from volatility.framework import interfaces, exceptions
from volatility.framework import interfaces, exceptions, configuration
class Intel(interfaces.layers.TranslationLayerInterface):
"""Translation Layer for the Intel IA32 memory mapping"""
def __init__(self, context, name, memory_layer, page_map_offset):
def __init__(self, context, name, physical_layer, page_map_offset):
interfaces.layers.TranslationLayerInterface.__init__(self, context, name)
self._base_layer = memory_layer
self._base_layer = physical_layer
self._page_map_offset = page_map_offset
# All Intel address spaces work on 4096 byte pages
self._page_size_in_bits = 12
@@ -135,8 +134,8 @@ class Intel(interfaces.layers.TranslationLayerInterface):
class IntelPAE(Intel):
"""Class for handling Physical Address Extensions for Intel architectures"""
def __init__(self, context, name, memory_layer, page_map_offset):
Intel.__init__(self, context, name, memory_layer, page_map_offset)
def __init__(self, context, name, physical_layer, page_map_offset):
Intel.__init__(self, context, name, physical_layer, page_map_offset)
# These can vary depending on the type of space
self._entry_format = "<Q"
@@ -150,8 +149,8 @@ class IntelPAE(Intel):
class Intel32e(Intel):
def __init__(self, context, name, memory_layer, page_map_offset):
Intel.__init__(self, context, name, memory_layer, page_map_offset)
def __init__(self, context, name, physical_layer, page_map_offset):
Intel.__init__(self, context, name, physical_layer, page_map_offset)
# These can vary depending on the type of space
self._entry_format = "<Q"
+2 -3
View File
@@ -4,12 +4,11 @@ from volatility.framework import configuration
class PsList(plugins.PluginInterface):
@classmethod
def requirements(cls):
def get_schema(cls):
return [configuration.TranslationLayerRequirement(name = 'primary',
description = 'Kernel Address Space',
os_type = 'windows',
architectures = None,
layer_type = 'kernel'),
architectures = None),
configuration.IntRequirement(name = 'pid',
description = "Process ID",
optional = True),