From 0a55a7c3f26ac45b8408df1982edb89aa7c6bbc3 Mon Sep 17 00:00:00 2001 From: Mike Auty Date: Thu, 9 Aug 2018 14:42:18 +0100 Subject: [PATCH] Introduced SizedModules to simplify when we just don't care about the size. --- volatility/framework/contexts/__init__.py | 44 +++++++++++++++++++--- volatility/framework/interfaces/context.py | 30 --------------- 2 files changed, 38 insertions(+), 36 deletions(-) diff --git a/volatility/framework/contexts/__init__.py b/volatility/framework/contexts/__init__.py index fef1bf15d..49b2308d5 100644 --- a/volatility/framework/contexts/__init__.py +++ b/volatility/framework/contexts/__init__.py @@ -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) diff --git a/volatility/framework/interfaces/context.py b/volatility/framework/interfaces/context.py index a12369cc5..330e6e015 100644 --- a/volatility/framework/interfaces/context.py +++ b/volatility/framework/interfaces/context.py @@ -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,