mirror of
https://github.com/volatilityfoundation/volatility3.git
synced 2026-09-13 13:17:38 +02:00
Merge pull request #569 from volatilityfoundation/feature/coalese-module-objects
Core: Change Module to ConfigurableInterface
This commit is contained in:
@@ -22,7 +22,7 @@ class KernelModule(interfaces.automagic.AutomagicInterface):
|
||||
# The requirement is unfulfilled and is a ModuleRequirement
|
||||
|
||||
context.config[interfaces.configuration.path_join(
|
||||
new_config_path, 'class')] = 'volatility3.framework.contexts.ConfigurableModule'
|
||||
new_config_path, 'class')] = 'volatility3.framework.contexts.Module'
|
||||
|
||||
for req in requirement.requirements:
|
||||
if requirement.requirements[req].unsatisfied(context, new_config_path) and req != 'offset':
|
||||
|
||||
@@ -144,17 +144,17 @@ class Context(interfaces.context.ContextInterface):
|
||||
size: The size, in bytes, that the module occupys from offset location within the layer named layer_name
|
||||
"""
|
||||
if size:
|
||||
return SizedModule(self,
|
||||
module_name = module_name,
|
||||
layer_name = layer_name,
|
||||
offset = offset,
|
||||
size = size,
|
||||
native_layer_name = native_layer_name)
|
||||
return Module(self,
|
||||
module_name = module_name,
|
||||
layer_name = layer_name,
|
||||
offset = offset,
|
||||
native_layer_name = native_layer_name)
|
||||
return SizedModule.create(self,
|
||||
module_name = module_name,
|
||||
layer_name = layer_name,
|
||||
offset = offset,
|
||||
size = size,
|
||||
native_layer_name = native_layer_name)
|
||||
return Module.create(self,
|
||||
module_name = module_name,
|
||||
layer_name = layer_name,
|
||||
offset = offset,
|
||||
native_layer_name = native_layer_name)
|
||||
|
||||
|
||||
def get_module_wrapper(method: str) -> Callable:
|
||||
@@ -179,6 +179,33 @@ def get_module_wrapper(method: str) -> Callable:
|
||||
|
||||
class Module(interfaces.context.ModuleInterface):
|
||||
|
||||
@classmethod
|
||||
def create(cls,
|
||||
context: interfaces.context.ContextInterface,
|
||||
module_name: str,
|
||||
layer_name: str,
|
||||
offset: int,
|
||||
**kwargs) -> 'Module':
|
||||
pathjoin = interfaces.configuration.path_join
|
||||
# Check if config_path is None
|
||||
config_path = kwargs.get('config_path', None)
|
||||
if config_path is None:
|
||||
config_path = pathjoin('temporary', 'modules')
|
||||
# Populate the configuration
|
||||
context.config[pathjoin(config_path, 'layer_name')] = layer_name
|
||||
context.config[pathjoin(config_path, 'offset')] = offset
|
||||
# This is important, since the module_name may be changed in case it is already in use
|
||||
if 'symbol_table_name' not in kwargs:
|
||||
kwargs['symbol_table_name'] = module_name
|
||||
for arg in kwargs:
|
||||
context.config[pathjoin(config_path, arg)] = kwargs.get(arg, None)
|
||||
# Construct the object
|
||||
return_val = cls(context, config_path, context.modules.free_module_name(module_name))
|
||||
context.add_module(return_val)
|
||||
context.config[config_path] = return_val.name
|
||||
# Add the module to the context modules collection
|
||||
return return_val
|
||||
|
||||
def object(self,
|
||||
object_type: str,
|
||||
offset: int = None,
|
||||
@@ -280,26 +307,11 @@ class Module(interfaces.context.ModuleInterface):
|
||||
|
||||
class SizedModule(Module):
|
||||
|
||||
def __init__(self,
|
||||
context: interfaces.context.ContextInterface,
|
||||
module_name: str,
|
||||
layer_name: str,
|
||||
offset: int,
|
||||
size: int,
|
||||
symbol_table_name: Optional[str] = None,
|
||||
native_layer_name: Optional[str] = None) -> None:
|
||||
super().__init__(context,
|
||||
module_name = module_name,
|
||||
layer_name = layer_name,
|
||||
offset = offset,
|
||||
native_layer_name = native_layer_name,
|
||||
symbol_table_name = symbol_table_name)
|
||||
self._size = size
|
||||
|
||||
@property
|
||||
def size(self) -> int:
|
||||
"""Returns the size of the module (0 for unknown size)"""
|
||||
return self._size
|
||||
size = self.config.get('size', 0)
|
||||
return size or 0
|
||||
|
||||
@property # type: ignore # FIXME: mypy #5107
|
||||
@functools.lru_cache()
|
||||
@@ -346,6 +358,13 @@ class ModuleCollection(interfaces.context.ModuleContainer):
|
||||
seen.add(mod.hash) # type: ignore # FIXME: mypy #5107
|
||||
return ModuleCollection(new_modules)
|
||||
|
||||
def free_module_name(self, prefix: str = "module") -> str:
|
||||
"""Returns an unused module name"""
|
||||
count = 1
|
||||
while prefix + str(count) in self:
|
||||
count += 1
|
||||
return prefix + str(count)
|
||||
|
||||
@property
|
||||
def modules(self) -> 'ModuleCollection':
|
||||
"""A name indexed dictionary of modules using that name in this
|
||||
|
||||
@@ -192,7 +192,7 @@ class HierarchicalDict(collections.abc.Mapping):
|
||||
elif value is None:
|
||||
return None
|
||||
else:
|
||||
raise TypeError("Invalid type stored in configuration")
|
||||
raise TypeError(f"Invalid type stored in configuration: {type(value)}")
|
||||
|
||||
def __delitem__(self, key: str) -> None:
|
||||
"""Deletes an item from the hierarchical dict."""
|
||||
|
||||
@@ -136,7 +136,7 @@ class ContextInterface(metaclass = ABCMeta):
|
||||
"""
|
||||
|
||||
|
||||
class ModuleInterface(metaclass = ABCMeta):
|
||||
class ModuleInterface(interfaces.configuration.ConfigurableInterface):
|
||||
"""Maintains state concerning a particular loaded module in memory.
|
||||
|
||||
This object is OS-independent.
|
||||
@@ -144,31 +144,35 @@ class ModuleInterface(metaclass = ABCMeta):
|
||||
|
||||
def __init__(self,
|
||||
context: ContextInterface,
|
||||
module_name: str,
|
||||
layer_name: str,
|
||||
offset: int,
|
||||
symbol_table_name: Optional[str] = None,
|
||||
native_layer_name: Optional[str] = None) -> None:
|
||||
config_path: str,
|
||||
name: str) -> None:
|
||||
"""Constructs a new os-independent module.
|
||||
|
||||
Args:
|
||||
context: The context within which this module will exist
|
||||
config_path: The path within the context's configuration tree
|
||||
name: The name of the module
|
||||
layer_name: The layer within the context in which the module exists
|
||||
offset: The offset at which the module exists in the layer
|
||||
symbol_table_name: The name of an associated symbol table
|
||||
native_layer_name: The default native layer for objects constructed by the module
|
||||
"""
|
||||
self._context = context
|
||||
self._module_name = module_name
|
||||
self._layer_name = layer_name
|
||||
self._offset = offset
|
||||
# TODO: Figure out about storing/requesting the native_layer_name for a module in the configuration
|
||||
# The current module requirement does not ask for nor act upon this information
|
||||
self._native_layer_name = native_layer_name or layer_name
|
||||
self._symbol_table_name = symbol_table_name or self._module_name
|
||||
super().__init__(context, config_path)
|
||||
self._module_name = name
|
||||
|
||||
def build_configuration(self) -> 'configuration.HierarchicalDict':
|
||||
@property
|
||||
def _layer_name(self) -> str:
|
||||
return self.config['layer_name']
|
||||
|
||||
@property
|
||||
def _offset(self) -> int:
|
||||
return self.config['offset']
|
||||
|
||||
@property
|
||||
def _native_layer_name(self) -> str:
|
||||
return self.config.get('native_layer_name', self._layer_name)
|
||||
|
||||
@property
|
||||
def _symbol_table_name(self) -> str:
|
||||
return self.config.get('symbol_table_name', self._module_name)
|
||||
|
||||
def build_configuration(self) -> 'interfaces.configuration.HierarchicalDict':
|
||||
"""Builds the configuration dictionary for this specific Module"""
|
||||
|
||||
config = super().build_configuration()
|
||||
@@ -319,6 +323,10 @@ class ModuleContainer(collections.abc.Mapping):
|
||||
def __iter__(self):
|
||||
return iter(self._modules)
|
||||
|
||||
def free_module_name(self, prefix: str = "module") -> str:
|
||||
"""Returns an unused table name to ensure no collision occurs when
|
||||
inserting a symbol table."""
|
||||
|
||||
def get_modules_by_symbol_tables(self, symbol_table: str) -> Iterable[str]:
|
||||
"""Returns the modules which use the specified symbol table name"""
|
||||
for module_name in self._modules:
|
||||
|
||||
@@ -60,7 +60,7 @@ class ABCKmsg(ABC):
|
||||
vmlinux = context.modules[self._config['kernel']]
|
||||
self.layer_name = vmlinux.layer_name # type: ignore
|
||||
symbol_table_name = vmlinux.symbol_table_name # type: ignore
|
||||
self.vmlinux = contexts.Module(context, symbol_table_name, self.layer_name, 0) # type: ignore
|
||||
self.vmlinux = contexts.Module.create(context, symbol_table_name, self.layer_name, 0) # type: ignore
|
||||
self.long_unsigned_int_size = self.vmlinux.get_type('long unsigned int').size
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -60,12 +60,12 @@ class SSDT(plugins.PluginInterface):
|
||||
if module_name in constants.windows.KERNEL_MODULE_NAMES:
|
||||
symbol_table_name = symbol_table
|
||||
|
||||
context_module = contexts.SizedModule(context,
|
||||
module_name,
|
||||
layer_name,
|
||||
mod.DllBase,
|
||||
mod.SizeOfImage,
|
||||
symbol_table_name = symbol_table_name)
|
||||
context_module = contexts.SizedModule.create(context = context,
|
||||
module_name = module_name,
|
||||
layer_name = layer_name,
|
||||
offset = mod.DllBase,
|
||||
size = mod.SizeOfImage,
|
||||
symbol_table_name = symbol_table_name)
|
||||
|
||||
context_modules.append(context_module)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user