diff --git a/volatility/framework/plugins/windows/registry/hivelist.py b/volatility/framework/plugins/windows/registry/hivelist.py index bea604a40..b6ac9e3b5 100644 --- a/volatility/framework/plugins/windows/registry/hivelist.py +++ b/volatility/framework/plugins/windows/registry/hivelist.py @@ -2,11 +2,12 @@ # which is available at https://www.volatilityfoundation.org/license/vsl_v1.0 # import logging -from typing import Iterator, List, Tuple +from typing import Iterator, List, Tuple, Iterable, Optional import volatility.framework.interfaces.plugins as plugins from volatility.framework import renderers, interfaces, exceptions from volatility.framework.configuration import requirements +from volatility.framework.layers import registry from volatility.framework.renderers import format_hints vollog = logging.getLogger(__name__) @@ -28,7 +29,7 @@ class HiveList(plugins.PluginInterface): ] def _generator(self) -> Iterator[Tuple[int, Tuple[int, str]]]: - for hive in self.list_hives( + for hive in self.list_hive_objects( context = self.context, layer_name = self.config["primary"], symbol_table = self.config["nt_symbols"], @@ -39,9 +40,52 @@ class HiveList(plugins.PluginInterface): @classmethod def list_hives(cls, context: interfaces.context.ContextInterface, + base_config_path: str, layer_name: str, symbol_table: str, - filter_string: str = None) -> Iterator[interfaces.objects.ObjectInterface]: + filter_string: Optional[str] = None, + hive_offsets: List[int] = None) -> Iterable[registry.RegistryHive]: + """Walks through a registry, hive by hive returning the constructed + registry layer name. + + Args: + context: The context to retrieve required elements (layers, symbol tables) from + layer_name: The name of the layer on which to operate + symbol_table: The name of the table containing the kernel symbols + filter_string: An optional string which must be present in the hive name if specified + offset: An optional offset to specify a specific hive to iterate over (takes precedence over filter_string) + + Yields: + A registry hive layer name + """ + if hive_offsets is None: + try: + hive_offsets = [ + hive.vol.offset for hive in cls.list_hive_objects(context, layer_name, symbol_table, filter_string) + ] + except ImportError: + vollog.warning("Unable to import windows.hivelist plugin, please provide a hive offset") + raise ValueError("Unable to import windows.hivelist plugin, please provide a hive offset") + + for hive_offset in hive_offsets: + # Construct the hive + reg_config_path = cls.make_subconfig( + context = context, + base_config_path = base_config_path, + hive_offset = hive_offset, + base_layer = layer_name, + nt_symbols = symbol_table) + + hive = registry.RegistryHive(context, reg_config_path, name = 'hive' + hex(hive_offset)) + context.layers.add_layer(hive) + yield hive + + @classmethod + def list_hive_objects(cls, + context: interfaces.context.ContextInterface, + layer_name: str, + symbol_table: str, + filter_string: str = None) -> Iterator[interfaces.objects.ObjectInterface]: """Lists all the hives in the primary layer. Args: diff --git a/volatility/framework/plugins/windows/registry/printkey.py b/volatility/framework/plugins/windows/registry/printkey.py index 5061f380b..954849ed2 100644 --- a/volatility/framework/plugins/windows/registry/printkey.py +++ b/volatility/framework/plugins/windows/registry/printkey.py @@ -4,7 +4,7 @@ import datetime import logging -from typing import Generator, List, Sequence, Iterable, Optional +from typing import List, Sequence, Iterable, Tuple from volatility.framework import objects, renderers, exceptions, interfaces, constants from volatility.framework.configuration import requirements @@ -37,7 +37,7 @@ class PrintKey(interfaces.plugins.PluginInterface): @classmethod def key_iterator(cls, hive: RegistryHive, node_path: Sequence[objects.StructType] = None, - recurse: bool = False) -> Iterable[int, bool, datetime.datetime, str, bool, bytes]: + recurse: bool = False) -> Iterable[Tuple[int, bool, datetime.datetime, str, bool, bytes]]: """Walks through a set of nodes from a given node (last one in node_path). Avoids loops by not traversing into nodes already present in the node_path. @@ -79,50 +79,6 @@ class PrintKey(interfaces.plugins.PluginInterface): result = (len(node_path), False, last_write_time, key_path, node.get_volatile(), value_node) yield result - @classmethod - def hive_iterator(cls, - context: interfaces.context.ContextInterface, - base_config_path: str, - layer_name: str, - symbol_table: str, - filter_string: Optional[str] = None, - hive_offsets: List[int] = None) -> Iterable[RegistryHive]: - """Walks through a registry, hive by hive returning the constructed - registry layer name. - - Args: - context: The context to retrieve required elements (layers, symbol tables) from - layer_name: The name of the layer on which to operate - symbol_table: The name of the table containing the kernel symbols - filter_string: An optional string which must be present in the hive name if specified - offset: An optional offset to specify a specific hive to iterate over (takes precedence over filter_string) - - Yields: - A registry hive layer name - """ - if hive_offsets is None: - try: - hive_offsets = [ - hive.vol.offset - for hive in hivelist.HiveList.list_hives(context, layer_name, symbol_table, filter_string) - ] - except ImportError: - vollog.warning("Unable to import windows.hivelist plugin, please provide a hive offset") - raise ValueError("Unable to import windows.hivelist plugin, please provide a hive offset") - - for hive_offset in hive_offsets: - # Construct the hive - reg_config_path = cls.make_subconfig( - context = context, - base_config_path = base_config_path, - hive_offset = hive_offset, - base_layer = layer_name, - nt_symbols = symbol_table) - - hive = RegistryHive(context, reg_config_path, name = 'hive' + hex(hive_offset)) - context.layers.add_layer(hive) - yield hive - def _printkey_iterator(self, hive: RegistryHive, node_path: Sequence[objects.StructType] = None, @@ -175,7 +131,7 @@ class PrintKey(interfaces.plugins.PluginInterface): key: str = None, recurse: bool = False): - for hive in self.hive_iterator( + for hive in hivelist.HiveList.list_hives( self.context, self.config_path, layer_name = layer_name, diff --git a/volatility/framework/plugins/windows/registry/userassist.py b/volatility/framework/plugins/windows/registry/userassist.py index 38cb617c3..b3548454e 100644 --- a/volatility/framework/plugins/windows/registry/userassist.py +++ b/volatility/framework/plugins/windows/registry/userassist.py @@ -9,7 +9,7 @@ import logging import os from typing import Any, List, Tuple, Generator -import volatility.plugins.windows.registry.printkey as printkey +import volatility.plugins.windows.registry.hivelist as hivelist from volatility.framework import exceptions, renderers, constants, interfaces from volatility.framework.configuration import requirements @@ -39,7 +39,8 @@ class UserAssist(interfaces.plugins.PluginInterface): requirements.TranslationLayerRequirement( name = 'primary', description = 'Memory layer for the kernel', architectures = ["Intel32", "Intel64"]), requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"), - requirements.IntRequirement(name = 'offset', description = "Hive Offset", default = None, optional = True) + requirements.IntRequirement(name = 'offset', description = "Hive Offset", default = None, optional = True), + requirements.PluginRequirement(name = 'hivelist', plugin = hivelist.HiveList, version = (1, 0, 0)) ] def parse_userassist_data(self, reg_val): @@ -209,14 +210,18 @@ class UserAssist(interfaces.plugins.PluginInterface): def _generator(self): + hive_offsets = None + if self.config.get('offset', None) is not None: + hive_offsets = [self.config.get('offset', None)] + # get all the user hive offsets or use the one specified - for hive in printkey.PrintKey.hive_iterator( + for hive in hivelist.HiveList.list_hives( context = self.context, base_config_path = self.config_path, layer_name = self.config['primary'], symbol_table = self.config['nt_symbols'], - filter_string = 'ntuser.data', - offsets = [self.config.get('offset', None)]): + filter_string = 'ntuser.dat', + hive_offsets = hive_offsets): try: yield from self.list_userassist(hive) continue @@ -235,6 +240,8 @@ class UserAssist(interfaces.plugins.PluginInterface): yield result def run(self): + self._reg_table_name = intermed.IntermediateSymbolTable.create(self.context, self._config_path, 'windows', + 'registry') return renderers.TreeGrid([("Hive Offset", renderers.format_hints.Hex), ("Hive Name", str), ("Path", str), ("Last Write Time", datetime.datetime), ("Type", str), ("Name", str), ("ID", int), diff --git a/volatility/plugins/windows/registry/certificates.py b/volatility/plugins/windows/registry/certificates.py index 52230c63b..8791fc034 100644 --- a/volatility/plugins/windows/registry/certificates.py +++ b/volatility/plugins/windows/registry/certificates.py @@ -4,7 +4,7 @@ from typing import List, Iterator, Tuple from volatility.framework import interfaces, renderers from volatility.framework.configuration import requirements from volatility.framework.symbols.windows.extensions.registry import RegValueTypes -from volatility.plugins.windows.registry import printkey +from volatility.plugins.windows.registry import hivelist, printkey class Certificates(interfaces.plugins.PluginInterface): @@ -16,6 +16,7 @@ class Certificates(interfaces.plugins.PluginInterface): requirements.TranslationLayerRequirement( name = 'primary', description = 'Memory layer for the kernel', architectures = ["Intel32", "Intel64"]), requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"), + requirements.PluginRequirement(name = 'hivelist', plugin = hivelist.HiveList, version = (1, 0, 0)), requirements.PluginRequirement(name = 'printkey', plugin = printkey.PrintKey, version = (1, 0, 0)) ] @@ -32,7 +33,7 @@ class Certificates(interfaces.plugins.PluginInterface): return (name, certificate_data) def _generator(self) -> Iterator[Tuple[int, Tuple[int, str]]]: - for hive in printkey.PrintKey.hive_iterator( + for hive in hivelist.HiveList.list_hives( self.context, base_config_path = self.config_path, layer_name = self.config['primary'],