mirror of
https://github.com/volatilityfoundation/volatility3.git
synced 2026-09-10 03:37:39 +02:00
Introduced SizedModules to simplify when we just don't care about the size.
This commit is contained in:
@@ -4,6 +4,7 @@ This has been made an object to allow quick swapping and changing of contexts, t
|
||||
to act on multiple different contexts without them interfering eith each other.
|
||||
"""
|
||||
import functools
|
||||
import hashlib
|
||||
import typing
|
||||
|
||||
from volatility.framework import constants, interfaces, symbols, validity
|
||||
@@ -166,6 +167,37 @@ class Module(interfaces.context.ModuleInterface):
|
||||
has_type = get_module_wrapper('has_type')
|
||||
has_enum = get_module_wrapper('has_enum')
|
||||
|
||||
|
||||
class SizedModule(Module):
|
||||
|
||||
def __init__(self,
|
||||
context: interfaces.context.ContextInterface,
|
||||
module_name: str,
|
||||
layer_name: str,
|
||||
offset: int,
|
||||
size: int,
|
||||
symbol_table_name: typing.Optional[str] = None) -> None:
|
||||
super().__init__(context, module_name, layer_name, offset, symbol_table_name = symbol_table_name)
|
||||
self._size = self._check_type(size, int)
|
||||
|
||||
@property
|
||||
def size(self) -> int:
|
||||
"""Returns the size of the module (0 for unknown size)"""
|
||||
return self._size
|
||||
|
||||
@property # type: ignore # FIXME: mypy #5107
|
||||
@functools.lru_cache()
|
||||
def hash(self) -> str:
|
||||
"""Hashes the module for equality checks
|
||||
|
||||
The mapping should be sorted and should be quicker than reading the data
|
||||
We turn it into JSON to make a common string and use a quick hash, because collissions are unlikely"""
|
||||
layer = self._context.memory[self.layer_name]
|
||||
if not isinstance(layer, interfaces.layers.TranslationLayerInterface):
|
||||
raise TypeError("Hashing modules on non-TranslationLayers is not allowed")
|
||||
return hashlib.md5(
|
||||
bytes(str(list(layer.mapping(self.offset, self.size, ignore_errors = True))), 'utf-8')).hexdigest()
|
||||
|
||||
def get_symbols_by_absolute_location(self, offset: int, size: int = 0) -> typing.List[str]:
|
||||
"""Returns the symbols within this module that live at the specified absolute offset provided"""
|
||||
if size < 0:
|
||||
@@ -177,11 +209,11 @@ class Module(interfaces.context.ModuleInterface):
|
||||
|
||||
|
||||
class ModuleCollection(validity.ValidityRoutines):
|
||||
"""Class to contain a collection of modules and reason about their contents"""
|
||||
"""Class to contain a collection of SizedModules and reason about their contents"""
|
||||
|
||||
def __init__(self, modules: typing.List[Module]) -> None:
|
||||
def __init__(self, modules: typing.List[SizedModule]) -> None:
|
||||
for module in modules:
|
||||
self._check_type(module, Module)
|
||||
self._check_type(module, SizedModule)
|
||||
self._modules = modules
|
||||
|
||||
def deduplicate(self) -> 'ModuleCollection':
|
||||
@@ -198,13 +230,13 @@ class ModuleCollection(validity.ValidityRoutines):
|
||||
return ModuleCollection(new_modules)
|
||||
|
||||
@property
|
||||
def modules(self) -> typing.Dict[str, typing.List[Module]]:
|
||||
def modules(self) -> typing.Dict[str, typing.List[SizedModule]]:
|
||||
"""A name indexed dictionary of modules using that name in this collection"""
|
||||
return self._generate_module_dict(self._modules)
|
||||
|
||||
@classmethod
|
||||
def _generate_module_dict(cls, modules: typing.List[Module]) -> typing.Dict[str, typing.List[Module]]:
|
||||
result = {} # type: typing.Dict[str, typing.List[Module]]
|
||||
def _generate_module_dict(cls, modules: typing.List[SizedModule]) -> typing.Dict[str, typing.List[SizedModule]]:
|
||||
result = {} # type: typing.Dict[str, typing.List[SizedModule]]
|
||||
for module in modules:
|
||||
modlist = result.get(module.name, [])
|
||||
modlist.append(module)
|
||||
|
||||
@@ -94,19 +94,11 @@ class ModuleInterface(validity.ValidityRoutines, metaclass = ABCMeta):
|
||||
module_name: str,
|
||||
layer_name: str,
|
||||
offset: int,
|
||||
size: typing.Optional[int] = 0,
|
||||
symbol_table_name: typing.Optional[str] = None) -> None:
|
||||
self._context = self._check_type(context, ContextInterface)
|
||||
self._module_name = self._check_type(module_name, str)
|
||||
self._layer_name = self._check_type(layer_name, str)
|
||||
self._offset = self._check_type(offset, int)
|
||||
|
||||
# Size defaults to 0 (ie, we care about it), but will only calculate it on demand
|
||||
# If it's explicitly set to None, then we know we don't care about it
|
||||
if size is None:
|
||||
self._size = 0
|
||||
self._size_unimportant = (size is None)
|
||||
self._size = self._check_type(size, int)
|
||||
self.symbol_table_name = symbol_table_name or self._module_name
|
||||
super().__init__()
|
||||
|
||||
@@ -114,15 +106,6 @@ class ModuleInterface(validity.ValidityRoutines, metaclass = ABCMeta):
|
||||
def name(self) -> str:
|
||||
return self._module_name
|
||||
|
||||
@property
|
||||
def size(self) -> int:
|
||||
"""Returns the size of the module (0 for unknown size)"""
|
||||
if self._size <= 0 and not self._size_unimportant:
|
||||
symbol_table = self._context.symbol_space[self.symbol_table_name]
|
||||
self._size = max([0] + [symbol_table.get_symbol(s).address for s in symbol_table.symbols])
|
||||
self._size_unimportant = self._size_unimportant or self._size <= 0
|
||||
return self._size
|
||||
|
||||
@property
|
||||
def offset(self) -> int:
|
||||
"""Returns the offset that the module resides within the layer of layer_name """
|
||||
@@ -133,19 +116,6 @@ class ModuleInterface(validity.ValidityRoutines, metaclass = ABCMeta):
|
||||
"""Layer name in which the Module resides"""
|
||||
return self._layer_name
|
||||
|
||||
@property # type: ignore # FIXME: mypy #5107
|
||||
@functools.lru_cache()
|
||||
def hash(self) -> str:
|
||||
"""Hashes the module for equality checks
|
||||
|
||||
The mapping should be sorted and should be quicker than reading the data
|
||||
We turn it into JSON to make a common string and use a quick hash, because collissions are unlikely"""
|
||||
layer = self._context.memory[self.layer_name]
|
||||
if not isinstance(layer, interfaces.layers.TranslationLayerInterface):
|
||||
raise TypeError("Hashing modules on non-TranslationLayers is not allowed")
|
||||
return hashlib.md5(
|
||||
bytes(str(list(layer.mapping(self.offset, self.size, ignore_errors = True))), 'utf-8')).hexdigest()
|
||||
|
||||
@abstractmethod
|
||||
def object(self,
|
||||
symbol_name: str = None,
|
||||
|
||||
Reference in New Issue
Block a user