From e133509ea853d16e8795a3fa030288934533c4ac Mon Sep 17 00:00:00 2001 From: Mike Auty Date: Wed, 21 Mar 2018 15:32:09 +0000 Subject: [PATCH] Fix broken type resolution The introduction of symbol resolution required subresolving "unnamed" (symbol named) types. The resolution system was changed to pass constructed objects rather than names, which prevented the referencing from working properly. This commit changes that bit back and creates a temporary *type* in the _resolved list for the symbol, then restores whatever was there before. We restore it so that people don't get used to looking up symbols using get_type (we may revisit this decision). --- volatility/framework/symbols/__init__.py | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/volatility/framework/symbols/__init__.py b/volatility/framework/symbols/__init__.py index 31598265c..d6af6c3d0 100644 --- a/volatility/framework/symbols/__init__.py +++ b/volatility/framework/symbols/__init__.py @@ -5,7 +5,6 @@ import logging import typing from volatility.framework import constants, exceptions, interfaces, objects, validity -from volatility.framework.objects import templates from volatility.framework.symbols import native, windows, linux vollog = logging.getLogger(__name__) @@ -35,6 +34,7 @@ class SymbolSpace(interfaces.symbols.SymbolSpaceInterface, validity.ValidityRout self._dict = collections.OrderedDict() # type: typing.Dict[str, interfaces.symbols.BaseSymbolTableInterface] # Permanently cache all resolved symbols self._resolved = {} # type: typing.Dict[str, interfaces.objects.Template] + self._resolved_symbols = set() # type: typing.Set[str] def free_table_name(self, prefix: str = "layer") -> str: """Returns an unused table name to ensure no collision occurs when inserting a symbol table""" @@ -131,12 +131,12 @@ class SymbolSpace(interfaces.symbols.SymbolSpaceInterface, validity.ValidityRout raise exceptions.SymbolError('Type {} references missing Type/Symbol/Enum: {}'.format(name, e)) raise exceptions.SymbolError("Malformed name: {}".format(name)) - def _recursive_resolve(self, traverse_list): - """Recursively resolves a type, populating linked child ReferenceTemplates with their properly resolved counterparts""" + def _iterative_resolve(self, traverse_list): + """Iteratively resolves a type, populating linked child ReferenceTemplates with their properly resolved counterparts""" replacements = set() # Whole Symbols that still need traversing while traverse_list: - template_traverse_list, traverse_list = [traverse_list[0]], traverse_list[1:] + template_traverse_list, traverse_list = [self._resolved[traverse_list[0]]], traverse_list[1:] # Traverse a single symbol looking for any ReferenceTemplate objects while template_traverse_list: traverser, template_traverse_list = template_traverse_list[0], template_traverse_list[1:] @@ -145,7 +145,7 @@ class SymbolSpace(interfaces.symbols.SymbolSpaceInterface, validity.ValidityRout # If we haven't seen it before, subresolve it and also add it # to the "symbols that still need traversing" list if child.vol.type_name not in self._resolved: - traverse_list.append(child) + traverse_list.append(child.vol.type_name) try: self._resolved[child.vol.type_name] = self._weak_resolve(SymbolType.TYPE, child.vol.type_name) @@ -167,7 +167,7 @@ class SymbolSpace(interfaces.symbols.SymbolSpaceInterface, validity.ValidityRout # Traverse down any resolutions if type_name not in self._resolved: self._resolved[type_name] = self._weak_resolve(SymbolType.TYPE, type_name) # type: ignore - self._recursive_resolve([self._resolved[type_name]]) + self._iterative_resolve([type_name]) if isinstance(self._resolved[type_name], objects.templates.ReferenceTemplate): raise exceptions.SymbolError("Unresolvable symbol requested: {}".format(type_name)) return self._resolved[type_name] @@ -175,8 +175,16 @@ class SymbolSpace(interfaces.symbols.SymbolSpaceInterface, validity.ValidityRout def get_symbol(self, symbol_name: str) -> interfaces.symbols.Symbol: """Look-up a symbol name across all the contained symbol spaces""" retval = self._weak_resolve(SymbolType.SYMBOL, symbol_name) - if isinstance(retval.type, templates.ObjectTemplate): - self._recursive_resolve([retval.type]) + if symbol_name not in self._resolved_symbols and retval.type is not None: + # Stash the old resolved type if it exists + old_resolved = self._resolved.get(symbol_name, None) + try: + self._resolved[symbol_name] = retval.type + self._iterative_resolve([symbol_name]) + self._resolved_symbols.add(symbol_name) + finally: + if old_resolved is not None: + self._resolved[symbol_name] = old_resolved if not isinstance(retval, interfaces.symbols.Symbol): raise exceptions.SymbolError("Unresolvable Symbol: {}".format(symbol_name)) return retval