mirror of
https://github.com/volatilityfoundation/volatility3.git
synced 2026-09-11 04:07:39 +02:00
Rework Translation Layers to tie more closely to configurations
This change is quite signficant, and requires that TranslationLayers get all additional parameters that they need through their requirements. These are now automatically enumerated and populated on object construction based on the requirements, so should not require lots of repetitive filling out of fields. It does come with the downside that TranslationLayers can only be contructed with a context (and appropiate config), but TLs in particular always require a context (to contain the base layer) and blank configs can be constructed relatively easily (convenience functions can be added if necessary). This allows configuration trees to be built up, and their configs spliced into an existing config (as if it were being loaded from a file). Not all ConstructableRequirements use this method, since SymbolTables (for example) do not have access to the context or config_path in order to get to any parameters stored in the context's config. They therefore are still passed their requirement values as __init__ parameters instead.
This commit is contained in:
@@ -24,11 +24,11 @@ class LayerStacker(interfaces.automagic.AutomagicInterface):
|
||||
self.local_store = self.location.path
|
||||
|
||||
new_context = context.clone()
|
||||
current_layer = context.memory.free_layer_name()
|
||||
# This must be specific to get us started
|
||||
new_context.add_layer(
|
||||
physical.FileLayer(new_context, interfaces.configuration.path_join("automagic_general", current_layer),
|
||||
current_layer, self.local_store))
|
||||
current_layer_name = context.memory.free_layer_name()
|
||||
current_config_path = interfaces.configuration.path_join("automagic_general", current_layer_name)
|
||||
# This must be specific to get us started, setup the config and run
|
||||
new_context.config[interfaces.configuration.path_join(current_config_path, "filename")] = self.local_store
|
||||
new_context.add_layer(physical.FileLayer(new_context, current_config_path, current_layer_name))
|
||||
|
||||
# Repeatedly apply "determine what this is" code and build as much up as possible
|
||||
stacked = True
|
||||
@@ -42,15 +42,16 @@ class LayerStacker(interfaces.automagic.AutomagicInterface):
|
||||
for stacker_cls in stack_set:
|
||||
stacker = stacker_cls()
|
||||
try:
|
||||
new_layer = stacker.stack(new_context, current_layer)
|
||||
new_layer = stacker.stack(new_context, current_layer_name)
|
||||
new_context.memory.add_layer(new_layer)
|
||||
break
|
||||
except Exception as excp:
|
||||
pass
|
||||
else:
|
||||
stacked = False
|
||||
if new_layer and stacker_cls:
|
||||
stacked_layers = [new_layer] + stacked_layers
|
||||
current_layer = new_layer
|
||||
stacked_layers = [new_layer.name] + stacked_layers
|
||||
current_layer_name = new_layer.name
|
||||
stacked = True
|
||||
stack_set.remove(stacker_cls)
|
||||
|
||||
|
||||
@@ -183,15 +183,17 @@ class IntelHelper(interfaces.automagic.AutomagicInterface, interfaces.automagic.
|
||||
def stack(cls, context, layer_name):
|
||||
"""Attempts to determine and stack an intel layer on a physical layer where possible"""
|
||||
hits = context.memory[layer_name].scan(context, PageMapScanner(cls.tests))
|
||||
new_layer = None
|
||||
layer = None
|
||||
for test, dtb in hits:
|
||||
new_layer = context.memory.free_layer_name("IntelLayer")
|
||||
new_layer_name = context.memory.free_layer_name("IntelLayer")
|
||||
config_path = interfaces.configuration.path_join("IntelHelper", new_layer_name)
|
||||
context.config[interfaces.configuration.path_join(config_path, "memory_layer")] = layer_name
|
||||
context.config[interfaces.configuration.path_join(config_path, "page_map_offset")] = dtb
|
||||
layer = test.layer_type(context,
|
||||
config_path = interfaces.configuration.path_join("IntelHelper", new_layer),
|
||||
name = new_layer,
|
||||
page_map_offset = dtb)
|
||||
config_path = config_path,
|
||||
name = new_layer_name)
|
||||
break
|
||||
return new_layer
|
||||
return layer
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
@@ -215,10 +217,11 @@ if __name__ == '__main__':
|
||||
nativelst = native.x86NativeTable
|
||||
ctx = contexts.Context(nativelst)
|
||||
for filename in args.filenames:
|
||||
ctx.config[
|
||||
interfaces.configuration.path_join('config' + str(args.filenames.index(filename)), "filename")] = filename
|
||||
data = layers.physical.FileLayer(ctx,
|
||||
'config' + str(args.filenames.index(filename)),
|
||||
'data' + str(args.filenames.index(filename)),
|
||||
filename = filename)
|
||||
'data' + str(args.filenames.index(filename)))
|
||||
ctx.memory.add_layer(data)
|
||||
|
||||
tests = []
|
||||
|
||||
@@ -163,11 +163,6 @@ class ConstructableRequirementInterface(RequirementInterface):
|
||||
if requirement_dict is None:
|
||||
requirement_dict = {}
|
||||
|
||||
node_config = context.config.branch(config_path)
|
||||
# Construct the class
|
||||
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
|
||||
obj = cls(**requirement_dict)
|
||||
@@ -184,6 +179,12 @@ class ConfigurableInterface(validity.ValidityRoutines, metaclass = ABCMeta):
|
||||
self._context = self._check_type(context, ContextInterface)
|
||||
self._config_path = self._check_type(config_path, str)
|
||||
|
||||
# Store these programmatically, so we don't keep repreating the requirements
|
||||
# This also allows constructed objects to populate a configuration without too much trouble
|
||||
for requirement in self.get_requirements():
|
||||
# Create the (private) properties using the config as backend storage
|
||||
setattr(self, "_" + requirement.name, self.config.get(requirement.name, requirement.default))
|
||||
|
||||
@property
|
||||
def context(self):
|
||||
return self._context
|
||||
@@ -192,6 +193,10 @@ class ConfigurableInterface(validity.ValidityRoutines, metaclass = ABCMeta):
|
||||
def config_path(self):
|
||||
return self._config_path
|
||||
|
||||
@config_path.setter
|
||||
def config_path(self, value):
|
||||
self._config_path = self._check_type(value, str)
|
||||
|
||||
@property
|
||||
def config(self):
|
||||
return self._context.config.branch(self._config_path)
|
||||
|
||||
@@ -19,10 +19,10 @@ class Intel(interfaces.layers.TranslationLayerInterface):
|
||||
"architecture": "ia32"
|
||||
}
|
||||
|
||||
def __init__(self, context, config_path, name, page_map_offset, memory_layer, swap_layer = None):
|
||||
def __init__(self, context, config_path, name):
|
||||
super().__init__(context, config_path, name)
|
||||
self._base_layer = self._check_type(memory_layer, str)
|
||||
self._page_map_offset = self._check_type(page_map_offset, int)
|
||||
self._base_layer = self._check_type(self.config["memory_layer"], str)
|
||||
self._page_map_offset = self._check_type(self.config["page_map_offset"], int)
|
||||
# All Intel address spaces work on 4096 byte pages
|
||||
self._page_size_in_bits = 12
|
||||
|
||||
|
||||
@@ -63,16 +63,16 @@ class FileLayer(interfaces.layers.DataLayerInterface):
|
||||
provides = {"type": "physical"}
|
||||
priority = 20
|
||||
|
||||
def __init__(self, context, config_path, name, filename):
|
||||
def __init__(self, context, config_path, name):
|
||||
super().__init__(context, config_path, name)
|
||||
|
||||
self._filename = filename
|
||||
self._filename = self.config["filename"]
|
||||
self._file_ = None
|
||||
self._size = os.path.getsize(filename)
|
||||
self._size = os.path.getsize(self._filename)
|
||||
|
||||
@property
|
||||
def _file(self):
|
||||
"""Property to prevent the intializer storing an unserializable open file (for context cloning)"""
|
||||
"""Property to prevent the initializer storing an unserializable open file (for context cloning)"""
|
||||
# FIXME: Add "+" to the mode once we've determined whether write mode is enabled
|
||||
mode = "rb"
|
||||
if not self._file_:
|
||||
|
||||
Reference in New Issue
Block a user