diff --git a/volatility/cli/__init__.py b/volatility/cli/__init__.py index de877ba95..8801bb861 100644 --- a/volatility/cli/__init__.py +++ b/volatility/cli/__init__.py @@ -288,35 +288,36 @@ class CommandLine(interfaces.plugins.FileConsumerInterface): if isinstance(excp, exceptions.InvalidAddressException): if isinstance(excp, exceptions.SwappedInvalidAddressException): print("\nVolatility was unable to read a requested page from swap:\n" - "{} in layer {}\n\n" + "{} in layer {}: {}\n\n" "This is likely caused by:\n" "\tNo suitable swap file having been provided (locate and provide the correct swap file)\n" "\tAn intentionally invalid page (operating system protection)".format( - hex(excp.invalid_address), excp.layer_name)) + hex(excp.invalid_address), excp.layer_name, excp)) elif isinstance(excp, exceptions.PagedInvalidAddressException): print("\nVolatility was unable to read a requested page:\n" - "{} in layer {}\n\n" + "{} in layer {}: {}\n\n" "This could be caused by:\n" "\tMemory smear during acquisition (try re-acquiring if possible)\n" "\tAn intentionally invalid page lookup (operating system protection)\n" "\tA bug in the plugin/volatility (re-run with -vvv and file a bug)".format( - hex(excp.invalid_address), excp.layer_name)) + hex(excp.invalid_address), excp.layer_name, excp)) else: print("\nVolatility was unable to read a requested page:\n" - "{} in layer {}\n\n" + "{} in layer {}: {}\n\n" "This could be caused by:\n" "\tThe base memory file being incomplete (try re-acquiring if possible)\n" "\tMemory smear during acquisition (try re-acquiring if possible)\n" "\tAn intentionally invalid page lookup (operating system protection)\n" "\tA bug in the plugin/volatility (re-run with -vvv and file a bug)".format( - hex(excp.invalid_address), excp.layer_name)) + hex(excp.invalid_address), excp.layer_name, excp)) elif isinstance(excp, exceptions.SymbolError): print("\nVolatility experienced a symbol-related issue:\n" - "{}\n\n" + "{}{}{}: {}\n\n" "This is likely caused by:\n" "\tAn invalid symbol table\n" "\tA plugin requesting a bad symbol\n" - "\tA plugin requesting a symbol from the wrong table\n".format(excp)) + "\tA plugin requesting a symbol from the wrong table\n".format(excp.table_name, constants.BANG, + excp.symbol_name, excp)) elif isinstance(excp, exceptions.SymbolSpaceError): print("\nVolatility experienced an issue related to a symbol table:\n " "{}\n\n" diff --git a/volatility/framework/exceptions.py b/volatility/framework/exceptions.py index 43227719b..9f2ef4c69 100644 --- a/volatility/framework/exceptions.py +++ b/volatility/framework/exceptions.py @@ -8,7 +8,7 @@ space or symbol tables, and by layers when an address is invalid. The :class:`PagedInvalidAddressException` contains information about the size of the invalid page. """ -from typing import Dict +from typing import Dict, Optional from volatility.framework import interfaces @@ -30,6 +30,11 @@ class PluginRequirementException(VolatilityException): class SymbolError(VolatilityException): """Thrown when a symbol lookup has failed.""" + def __init__(self, symbol_name: Optional[str], table_name: Optional[str], *args) -> None: + super().__init__(*args) + self.symbol_name = symbol_name + self.table_name = table_name + class LayerException(VolatilityException): """Thrown when an error occurs dealing with memory and layers.""" diff --git a/volatility/framework/interfaces/symbols.py b/volatility/framework/interfaces/symbols.py index 3224633fa..ad570b559 100644 --- a/volatility/framework/interfaces/symbols.py +++ b/volatility/framework/interfaces/symbols.py @@ -295,14 +295,14 @@ class NativeTableInterface(BaseSymbolTableInterface): """Class to distinguish NativeSymbolLists from other symbol lists.""" def get_symbol(self, name: str) -> SymbolInterface: - raise exceptions.SymbolError("NativeTables never hold symbols") + raise exceptions.SymbolError(name, self.name, "NativeTables never hold symbols") @property def symbols(self) -> Iterable[str]: return [] def get_enumeration(self, name: str) -> objects.Template: - raise exceptions.SymbolError("NativeTables never hold enumerations") + raise exceptions.SymbolError(name, self.name, "NativeTables never hold enumerations") @property def enumerations(self) -> Iterable[str]: diff --git a/volatility/framework/objects/templates.py b/volatility/framework/objects/templates.py index 4bb7da5dd..acdc459ac 100644 --- a/volatility/framework/objects/templates.py +++ b/volatility/framework/objects/templates.py @@ -5,7 +5,7 @@ import functools import logging from typing import Any, ClassVar, Dict, List, Type -from volatility.framework import interfaces, exceptions +from volatility.framework import interfaces, exceptions, constants vollog = logging.getLogger(__name__) @@ -87,8 +87,14 @@ class ReferenceTemplate(interfaces.objects.Template): """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 exceptions.SymbolError("Template contains no information about its structure: {}".format( - self.vol.type_name)) + type_name = self.vol.type_name.split(constants.BANG) + table_name = None + if len(type_name) == 2: + table_name = type_name[0] + symbol_name = type_name[-1] + raise exceptions.SymbolError( + symbol_name, table_name, + "Template contains no information about its structure: {}".format(self.vol.type_name)) size = property(_unresolved) # type: ClassVar[Any] replace_child = _unresolved # type: ClassVar[Any] diff --git a/volatility/framework/plugins/windows/virtmap.py b/volatility/framework/plugins/windows/virtmap.py index 26a469058..9fc759501 100644 --- a/volatility/framework/plugins/windows/virtmap.py +++ b/volatility/framework/plugins/windows/virtmap.py @@ -43,11 +43,8 @@ class VirtMap(interfaces.plugins.PluginInterface): raise result = {} # type: Dict[str, List[Tuple[int, int]]] - try: - system_va_type = module.get_enumeration('_MI_SYSTEM_VA_TYPE') - large_page_size = (layer.page_size ** 2) // module.get_type("_MMPTE").size - except exceptions.SymbolError: - raise exceptions.SymbolError("Required structures not found") + system_va_type = module.get_enumeration('_MI_SYSTEM_VA_TYPE') + large_page_size = (layer.page_size ** 2) // module.get_type("_MMPTE").size if module.has_symbol('MiVisibleState'): symbol = module.get_symbol('MiVisibleState') @@ -67,7 +64,7 @@ class VirtMap(interfaces.plugins.PluginInterface): result = cls._enumerate_system_va_type(large_page_size, system_range_start, module, visible_state.SystemVaType) else: - raise exceptions.SymbolError("Required structures not found") + raise exceptions.SymbolError(None, module.name, "Required structures not found") elif module.has_symbol('MiSystemVaType'): system_range_start = module.object(object_type = "pointer", offset = module.get_symbol("MmSystemRangeStart").address) @@ -80,7 +77,7 @@ class VirtMap(interfaces.plugins.PluginInterface): result = cls._enumerate_system_va_type(large_page_size, system_range_start, module, type_array) else: - raise exceptions.SymbolError("Required structures not found") + raise exceptions.SymbolError(None, module.name, "Required structures not found") return result diff --git a/volatility/framework/symbols/__init__.py b/volatility/framework/symbols/__init__.py index 8bf118b2e..ac58c1f65 100644 --- a/volatility/framework/symbols/__init__.py +++ b/volatility/framework/symbols/__init__.py @@ -127,8 +127,9 @@ class SymbolSpace(interfaces.symbols.SymbolSpaceInterface): try: return getattr(self._dict[table_name], get_function)(component_name) except KeyError as e: - raise exceptions.SymbolError('Type {} references missing Type/Symbol/Enum: {}'.format(name, e)) - raise exceptions.SymbolError("Malformed name: {}".format(name)) + raise exceptions.SymbolError(component_name, table_name, + 'Type {} references missing Type/Symbol/Enum: {}'.format(name, e)) + raise exceptions.SymbolError(name, None, "Malformed name: {}".format(name)) def _iterative_resolve(self, traverse_list): """Iteratively resolves a type, populating linked child @@ -169,7 +170,11 @@ class SymbolSpace(interfaces.symbols.SymbolSpaceInterface): self._resolved[type_name] = self._weak_resolve(SymbolType.TYPE, type_name) # type: ignore self._iterative_resolve([type_name]) if isinstance(self._resolved[type_name], objects.templates.ReferenceTemplate): - raise exceptions.SymbolError("Unresolvable symbol requested: {}".format(type_name)) + table_name = None + index = type_name.find(constants.BANG) + if index > 0: + table_name, type_name = type_name[:index], type_name[index + 1:] + raise exceptions.SymbolError(type_name, table_name, "Unresolvable symbol requested: {}".format(type_name)) return self._resolved[type_name] def get_symbol(self, symbol_name: str) -> interfaces.symbols.SymbolInterface: @@ -189,7 +194,11 @@ class SymbolSpace(interfaces.symbols.SymbolSpaceInterface): if old_resolved is not None: self._resolved_symbols[symbol_name] = old_resolved if not isinstance(retval, interfaces.symbols.SymbolInterface): - raise exceptions.SymbolError("Unresolvable Symbol: {}".format(symbol_name)) + table_name = None + index = symbol_name.find(constants.BANG) + if index > 0: + table_name, symbol_name = symbol_name[:index], symbol_name[index + 1:] + raise exceptions.SymbolError(symbol_name, table_name, "Unresolvable Symbol: {}".format(symbol_name)) return retval def get_enumeration(self, enum_name: str) -> interfaces.objects.Template: @@ -197,7 +206,11 @@ class SymbolSpace(interfaces.symbols.SymbolSpaceInterface): table.""" retval = self._weak_resolve(SymbolType.ENUM, enum_name) if not isinstance(retval, interfaces.objects.Template): - raise exceptions.SymbolError("Unresolvable Enumeration: {}".format(enum_name)) + table_name = None + index = enum_name.find(constants.BANG) + if index > 0: + table_name, enum_name = enum_name[:index], enum_name[index + 1:] + raise exceptions.SymbolError(enum_name, table_name, "Unresolvable Enumeration: {}".format(enum_name)) return retval def _membership(self, member_type: SymbolType, name: str) -> bool: diff --git a/volatility/framework/symbols/intermed.py b/volatility/framework/symbols/intermed.py index 063bf7516..3ddf5715e 100644 --- a/volatility/framework/symbols/intermed.py +++ b/volatility/framework/symbols/intermed.py @@ -312,7 +312,7 @@ class Version1Format(ISFormatTable): return self._symbol_cache[name] symbol = self._json_object['symbols'].get(name, None) if not symbol: - raise exceptions.SymbolError("Unknown symbol: {}".format(name)) + raise exceptions.SymbolError(name, self.name, "Unknown symbol: {}".format(name)) self._symbol_cache[name] = interfaces.symbols.SymbolInterface(name = name, address = symbol['address']) return self._symbol_cache[name] @@ -402,10 +402,12 @@ class Version1Format(ISFormatTable): def get_enumeration(self, enum_name: str) -> interfaces.objects.Template: """Resolves an individual enumeration.""" if constants.BANG in enum_name: - raise exceptions.SymbolError("Enumeration for a different table requested: {}".format(enum_name)) + raise exceptions.SymbolError(enum_name, self.name, + "Enumeration for a different table requested: {}".format(enum_name)) if enum_name not in self._json_object['enums']: # Fall back to the natives table - raise exceptions.SymbolError("Enumeration not found in {} table: {}".format(self.name, enum_name)) + raise exceptions.SymbolError(enum_name, self.name, + "Enumeration not found in {} table: {}".format(self.name, enum_name)) curdict = self._json_object['enums'][enum_name] base_type = self.natives.get_type(curdict['base']) # The size isn't actually used, the base-type defines it. @@ -417,7 +419,13 @@ class Version1Format(ISFormatTable): def get_type(self, type_name: str) -> interfaces.objects.Template: """Resolves an individual symbol.""" if constants.BANG in type_name: - raise exceptions.SymbolError("Symbol for a different table requested: {}".format(type_name)) + table_name = None + index = type_name.find(constants.BANG) + if index > 0: + table_name, type_name = type_name[:index], type_name[index + 1:] + raise exceptions.SymbolError( + type_name, table_name, + "Symbol for a different table requested: {}".format(table_name + constants.BANG + type_name)) if type_name not in self._json_object['user_types']: # Fall back to the natives table return self.natives.get_type(self.name + constants.BANG + type_name) @@ -463,13 +471,19 @@ class Version2Format(Version1Format): def get_type(self, type_name: str) -> interfaces.objects.Template: """Resolves an individual symbol.""" if constants.BANG in type_name: - raise exceptions.SymbolError("Symbol for a different table requested: {}".format(type_name)) + table_name = None + index = type_name.find(constants.BANG) + if index > 0: + table_name, type_name = type_name[:index], type_name[index + 1:] + raise exceptions.SymbolError( + type_name, table_name, + "Symbol for a different table requested: {}".format(table_name + constants.BANG + type_name)) if type_name not in self._json_object['user_types']: # Fall back to the natives table if type_name in self.natives.types: return self.natives.get_type(self.name + constants.BANG + type_name) else: - raise exceptions.SymbolError("Unknown symbol: {}".format(type_name)) + raise exceptions.SymbolError(type_name, self.name, "Unknown symbol: {}".format(type_name)) curdict = self._json_object['user_types'][type_name] members = {} for member_name in curdict['fields']: @@ -497,7 +511,7 @@ class Version3Format(Version2Format): return self._symbol_cache[name] symbol = self._json_object['symbols'].get(name, None) if not symbol: - raise exceptions.SymbolError("Unknown symbol: {}".format(name)) + raise exceptions.SymbolError(name, self.name, "Unknown symbol: {}".format(name)) symbol_type = None if 'type' in symbol: symbol_type = self._interdict_to_template(symbol['type']) @@ -549,7 +563,7 @@ class Version5Format(Version4Format): return self._symbol_cache[name] symbol = self._json_object['symbols'].get(name, None) if not symbol: - raise exceptions.SymbolError("Unknown symbol: {}".format(name)) + raise exceptions.SymbolError(name, self.name, "Unknown symbol: {}".format(name)) symbol_type = None if 'type' in symbol: symbol_type = self._interdict_to_template(symbol['type'])