mirror of
https://github.com/volatilityfoundation/volatility3.git
synced 2026-09-08 10:47:38 +02:00
Rip out layer factories, and replace them with a single dependency resolver.
This commit is contained in:
@@ -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,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
|
||||
|
||||
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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
|
||||
|
||||
@@ -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"""
|
||||
|
||||
@@ -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"""
|
||||
|
||||
|
||||
@@ -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,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"
|
||||
|
||||
@@ -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),
|
||||
|
||||
Reference in New Issue
Block a user