diff --git a/volatility/framework/configuration/requirements.py b/volatility/framework/configuration/requirements.py index 0d3faa85b..a969ac89e 100644 --- a/volatility/framework/configuration/requirements.py +++ b/volatility/framework/configuration/requirements.py @@ -1,5 +1,4 @@ import logging -import sys from volatility.framework.interfaces import configuration as config_interface @@ -58,9 +57,7 @@ class TranslationLayerRequirement(config_interface.ConstructableRequirementInter :param layer_name: String detailing the expected name of the required layer, this can be None if it is to be randomly generated :return: """ - config_interface.RequirementInterface.__init__(self, name, description, default, optional) - self.add_requirement(ClassRequirement("class", "Class of the translation layer")) - self._current_class_requirements = set() + config_interface.ConstructableRequirementInterface.__init__(self, name, description, default, optional) # TODO: Add requirements: acceptable OSes from the address_space information # TODO: Add requirements: acceptable arches from the available layers @@ -82,60 +79,38 @@ class TranslationLayerRequirement(config_interface.ConstructableRequirementInter ### NOTE: This validate method has side effects (the dependencies can change)!!! - # See if our class is valid and if so populate the other requirements - # (but no need to validate, since we're invalid already) - class_req = self.requirements['class'] - subreq_config_path = config_interface.path_join(config_path, self.name) - if class_req.validate(context, subreq_config_path): - # We have a class, and since it's validated we can construct our requirements from it - if issubclass(class_req.cls, config_interface.ConfigurableInterface): - # In case the class has changed, clear out the old requirements - for old_req in self._current_class_requirements.copy(): - del self._requirements[old_req] - self._current_class_requirements.remove(old_req) - # And add the new ones - for requirement in class_req.cls.get_requirements(): - self._current_class_requirements.add(requirement.name) - self.add_requirement(requirement) + self._check_class(context, config_path) vollog.debug("IndexError - No configuration provided for layer") return False def construct(self, context, config_path): """Constructs the appropriate layer and adds it based on the class parameter""" + # Determine the layer name + name = self.name + counter = 2 + while name in context.memory: + name = self.name + str(counter) + counter += 1 + + args = {"context": context, + "config_path": config_path, + "name": name} + config_path = config_interface.path_join(config_path, self.name) if not all([subreq.validate(context, config_path) for subreq in self.requirements.values() if not subreq.optional]): return False - cls = self.requirements["class"].cls - node_config = context.config.branch(config_path) - - # Determine the layer name - layer_name = self.name - counter = 2 - while layer_name in context.memory: - layer_name = self.name + str(counter) - counter += 1 - - # Construct the layer - requirement_dict = {} - for req in cls.get_requirements(): - if req.name in node_config.data and req.name != "class": - requirement_dict[req.name] = node_config.data[req.name] - # Fulfillment must happen, exceptions happening here mean the requirements aren't correct - # and these need to be raised and fixed, rather than caught and ignored - layer = cls(context, config_path, layer_name, **requirement_dict) - context.add_layer(layer) - context.config[config_path] = layer_name + obj = self._construct_class(context, config_path, args) + if obj is None: + return False + context.add_layer(obj) return True -class SymbolRequirement(config_interface.RequirementInterface): +class SymbolRequirement(config_interface.ConstructableRequirementInterface): """Class maintaining the limitations on what sort of symbol spaces are acceptable""" - def __init__(self, name, description = None, default = None, optional = False, constraints = None): - config_interface.RequirementInterface.__init__(self, name, description, default, optional) - def validate(self, context, config_path): """Validate that the value is a valid within the symbol space of the provided context""" value = self.config_value(context, config_path, None) @@ -148,13 +123,24 @@ class SymbolRequirement(config_interface.RequirementInterface): return False return True + def construct(self, context, config_path): + """Constructs the symbol space within the context based on the subrequirements""" + # Determine the space name + name = self.name + if name in context.symbol_space: + raise ValueError("Symbol space already contains a SymbolTable by the same name") -class NativeSymbolRequirement(SymbolRequirement): - def validate(self, context, config_path): - value = self.config_value(context, config_path) - if not isinstance(value, str): - vollog.debug("TypeError - SymbolRequirement only accepts string labels") + args = {"name": name} + + config_path = config_interface.path_join(config_path, self.name) + if not all([subreq.validate(context, config_path) for subreq in self.requirements.values() if + not subreq.optional]): return False + + obj = self._construct_class(context, config_path, args) + if obj is None: + return False + context.symbol_space.append(obj) return True diff --git a/volatility/framework/interfaces/configuration.py b/volatility/framework/interfaces/configuration.py index 8de7d53ad..19f55367f 100644 --- a/volatility/framework/interfaces/configuration.py +++ b/volatility/framework/interfaces/configuration.py @@ -1,3 +1,4 @@ +import sys from abc import ABCMeta, abstractmethod from volatility.framework import validity diff --git a/volatility/framework/interfaces/symbols.py b/volatility/framework/interfaces/symbols.py index 4898c86f5..ce48150b9 100644 --- a/volatility/framework/interfaces/symbols.py +++ b/volatility/framework/interfaces/symbols.py @@ -5,8 +5,7 @@ Created on 4 May 2013 """ import bisect -from volatility.framework import validity, exceptions, constants -from volatility.framework.interfaces import configuration +from volatility.framework import constants, exceptions, validity class Symbol(validity.ValidityRoutines): @@ -142,7 +141,3 @@ class NativeTableInterface(SymbolTableInterface): @property def symbols(self): return [] - - -class SymbolTableProviderInterface(configuration.ConfigurableInterface): - pass diff --git a/volatility/framework/layers/lime.py b/volatility/framework/layers/lime.py index 79d93728d..92f504036 100644 --- a/volatility/framework/layers/lime.py +++ b/volatility/framework/layers/lime.py @@ -6,7 +6,7 @@ Created on 6 Apr 2016 import struct -from volatility.framework import interfaces, exceptions +from volatility.framework import exceptions, interfaces from volatility.framework.configuration import requirements diff --git a/volatility/framework/symbols/vtypes.py b/volatility/framework/symbols/vtypes.py index 19affc3eb..043b68a39 100644 --- a/volatility/framework/symbols/vtypes.py +++ b/volatility/framework/symbols/vtypes.py @@ -5,8 +5,9 @@ Created on 10 Apr 2013 """ import copy +import importlib -from volatility.framework import exceptions, objects, interfaces, constants +from volatility.framework import constants, exceptions, interfaces, objects # ## TODO @@ -38,7 +39,13 @@ from volatility.framework import exceptions, objects, interfaces, constants class VTypeSymbolTable(interfaces.symbols.SymbolTableInterface): """Symbol Table that handles vtype datatypes""" - def __init__(self, name, vtype_dictionary, native_types = None): + def __init__(self, name, vtype_pymodule, vtype_variable, native_types = None): + try: + module = importlib.import_module(vtype_pymodule) + except ImportError: + raise TypeError("VType Provider interface cannot be used to fulfill a requirement") + vtype_dictionary = getattr(module, vtype_variable) + interfaces.symbols.SymbolTableInterface.__init__(self, name, native_types) self._vtypedict = vtype_dictionary self._overrides = {} diff --git a/volatility/framework/symbols/windows/__init__.py b/volatility/framework/symbols/windows/__init__.py index 7e417215f..9eb9e7ea4 100644 --- a/volatility/framework/symbols/windows/__init__.py +++ b/volatility/framework/symbols/windows/__init__.py @@ -1,5 +1,24 @@ -from volatility.framework.symbols.windows import xp_sp2 +from volatility.framework.configuration import requirements +from volatility.framework.symbols import vtypes +from volatility.framework.symbols.windows import extensions __author__ = 'mike' +class WindowsKernelVTypeSymbols(vtypes.VTypeSymbolTable): + provides = {"type": "interface"} + + def __init__(self, context, config_path, name, vtype_pymodule, vtype_variable): + # FIXME: Make natives another requirement, or in some way hand it in when building the vtype_table + vtypes.VTypeSymbolTable.__init__(self, name, vtype_pymodule, vtype_variable, + context.context.symbol_space.natives) + + # Set-up windows specific types + self.set_type_class('_ETHREAD', extensions._ETHREAD) + self.set_type_class('_LIST_ENTRY', extensions._LIST_ENTRY) + + @classmethod + def get_requirements(cls): + return [requirements.StringRequirement("vtype_pymodule", description = "Python module containing the vtypes"), + requirements.StringRequirement("vtype_variable", + description = "Python vtypes variable within the module")] diff --git a/volatility/framework/symbols/windows/xp_sp2.py b/volatility/framework/symbols/windows/xp_sp2.py deleted file mode 100644 index ac380a7dc..000000000 --- a/volatility/framework/symbols/windows/xp_sp2.py +++ /dev/null @@ -1,65 +0,0 @@ -import importlib - -from volatility.framework import interfaces -from volatility.framework.configuration import requirements -from volatility.framework.symbols import vtypes, native -from volatility.framework.symbols.windows import extensions - - -class X86NativeSymbolProvider(interfaces.symbols.SymbolTableProviderInterface): - provides = {"type": "natives", - "architecture": ["ia32", "pae"]} - - @classmethod - def fulfill(cls, context, requirement, config_path): - context.symbol_space.natives = native.x86NativeTable - context.config[config_path] = "natives" - - -class WindowsKernelSymbolProvider(interfaces.symbols.SymbolTableProviderInterface): - provides = {"type": "interface"} - - vtype_pymodule = "" - vtype_variable = "" - space_name = "" - - @classmethod - def fulfill(cls, context, requirement, config_path): - # Delay importing to reduce unnecessary memory and time wastage - try: - module = importlib.import_module("volatility.framework.symbols.windows." + cls.vtype_pymodule) - except ImportError: - raise TypeError("VType Provider interface cannot be used to fulfill a requirement") - virtual_types = getattr(module, cls.vtype_variable) - - # Check the space_name isn't already in use - if cls.space_name in context.symbol_space: - raise KeyError("Symbol space " + cls.space_name + " already exists") - vtype_table = vtypes.VTypeSymbolTable(cls.space_name, virtual_types, context.symbol_space.natives) - - # Set-up windows specific types - vtype_table.set_type_class('_ETHREAD', extensions._ETHREAD) - vtype_table.set_type_class('_LIST_ENTRY', extensions._LIST_ENTRY) - - context.symbol_space.append(vtype_table) - context.config[config_path] = cls.space_name - - -class XPSP2WindowsKernelSymbolProvider(WindowsKernelSymbolProvider): - provides = {"type": "symbols", - "os": "windows", - "major": 5, - "minor": 1, - "build": 1500, - "architecture": ["ia32", "pae"], - } - - vtype_pymodule = "xp_sp2_x86_vtypes" - vtype_variable = "ntkrnlmp_types" - space_name = 'ntkrnlmp' - - @classmethod - def get_requirements(cls): - return [requirements.NativeSymbolRequirement("natives", description = "Native Symbols for x86", - constraints = {"type": "natives", - "architecture": "ia32"})]