diff --git a/volatility/framework/interfaces/objects.py b/volatility/framework/interfaces/objects.py index 4b77646b7..d6c887605 100644 --- a/volatility/framework/interfaces/objects.py +++ b/volatility/framework/interfaces/objects.py @@ -132,6 +132,30 @@ class Template(validity.ValidityRoutines): """Returns a volatility information object, much like the ObjectInterface provides""" return ReadOnlyMapping(self._vol) + @property + def children(self): + """A function that returns a list of child templates of a template + + This is used to traverse the template tree + """ + return [] + + @property + @abstractmethod + def size(self): + """Returns the size of the template""" + + @abstractmethod + def relative_child_offset(self, child): + """A function that returns the relative offset of a child from its parent offset + + This may throw exceptions including ChildNotFoundException and NotImplementedError + """ + + @abstractmethod + def replace_child(self, old_child, new_child): + """A function for replacing one child with another""" + def update_vol(self, **new_arguments): """Updates the keyword arguments""" self._vol.update(new_arguments) diff --git a/volatility/framework/objects/templates.py b/volatility/framework/objects/templates.py index dce80baf1..8be3dc31c 100644 --- a/volatility/framework/objects/templates.py +++ b/volatility/framework/objects/templates.py @@ -3,8 +3,12 @@ Created on 1 Mar 2013 @author: mike """ +import logging from volatility.framework import interfaces, validity +from volatility.framework.exceptions import SymbolError + +vollog = logging.getLogger(__name__) class ObjectTemplate(interfaces.objects.Template, validity.ValidityRoutines): @@ -44,8 +48,6 @@ class ObjectTemplate(interfaces.objects.Template, validity.ValidityRoutines): def replace_child(self, old_child, new_child): """A function for replacing one child with another - - We pass in the kwargs directly so they can be changed """ return self.vol.object_class.VolTemplateProxy.replace_child(self, old_child, new_child) @@ -68,6 +70,20 @@ class ReferenceTemplate(interfaces.objects.Template): It should not return any attributes """ + @property + def children(self): + return [] + + @property + def _unresolved(self, *args, **kwargs): + """Referenced symbols must be appropriately resolved before they can provide information such as size + This is because the size request has no context within which to determine the actual symbol structure. + """ + raise SymbolError("Template {0} contains no information about its structure".format(self.vol.type_name)) + + size = property(_unresolved) + replace_child = relative_child_offset = _unresolved + def __call__(self, context, object_info): template = context.symbol_space.get_type(self.vol.type_name) return template(context = context, object_info = object_info) diff --git a/volatility/framework/symbols/__init__.py b/volatility/framework/symbols/__init__.py index 20ba03943..88abea657 100644 --- a/volatility/framework/symbols/__init__.py +++ b/volatility/framework/symbols/__init__.py @@ -6,11 +6,14 @@ Created on 7 Feb 2013 import collections import collections.abc +import logging import warnings -from volatility.framework import objects, interfaces, exceptions, constants +from volatility.framework import constants, exceptions, interfaces, objects from volatility.framework.symbols import native, vtypes, windows +vollog = logging.getLogger(__name__) + class SymbolType(object): # Suitably random values until we make this an Enum and require python >= 3.4 @@ -33,6 +36,8 @@ class SymbolSpace(collections.abc.Mapping): # Permanently cache all resolved symbols self._resolved = {} + ### Symbol functions + def get_symbols_by_type(self, type_name): """Returns all symbols based """ for table in self._dict.keys(): @@ -51,6 +56,8 @@ class SymbolSpace(collections.abc.Mapping): for symbol_name in self._dict[table].get_symbols_by_location(address = address): yield table + constants.BANG + symbol_name + ### Native functions + @property def natives(self): """Returns the native_types for this symbol space""" @@ -63,6 +70,8 @@ class SymbolSpace(collections.abc.Mapping): "Resetting the native type can cause have drastic effects on memory analysis using this space") self._native_types = native_types + ### Space functions + def __len__(self): """Returns the number of tables within the space""" return len(self._dict) @@ -89,6 +98,23 @@ class SymbolSpace(collections.abc.Mapping): self._resolved = {} del self._dict[key] + ### Resolution functions + + class _UnresolvedTemplate(objects.templates.ReferenceTemplate): + """Class to highlight when missing symbols are present + + This class is identical to a reference template, but differentiable by its classname. + It will output a debug log to indicate when it has been instantiated and with what name. + + This class is designed to be output ONLY as part of the SymbolSpace resolution system. + Individual SymbolTables that cannot resolve a symbol should still return a SymbolError to + indicate this failure in resolution. + """ + + def __init__(self, type_name = None, **kwargs): + vollog.debug("Unresolved symbol referenced: {0}".format(type_name)) + super().__init__(type_name = type_name, **kwargs) + def _weak_resolve(self, resolve_type, name): """Takes a symbol name and resolves it with ReferentialTemplates""" if resolve_type == SymbolType.TYPE: @@ -102,7 +128,10 @@ class SymbolSpace(collections.abc.Mapping): if len(name_array) == 2: table_name = name_array[0] component_name = name_array[1] - return getattr(self._dict[table_name], get_function)(component_name) + try: + return getattr(self._dict[table_name], get_function)(component_name) + except (exceptions.SymbolError, KeyError): + return self._UnresolvedTemplate(name) elif name in self.natives.types: return getattr(self.natives, get_function)(name) raise exceptions.SymbolError("Malformed symbol name: " + repr(name))