mirror of
https://github.com/volatilityfoundation/volatility3.git
synced 2026-08-21 05:52:22 +02:00
178 lines
9.1 KiB
Python
178 lines
9.1 KiB
Python
# This file is Copyright 2019 Volatility Foundation and licensed under the Volatility Software License 1.0
|
|
# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0
|
|
#
|
|
|
|
import datetime
|
|
import logging
|
|
from typing import List, Sequence, Iterable, Tuple, Union
|
|
|
|
from volatility.framework import objects, renderers, exceptions, interfaces, constants
|
|
from volatility.framework.configuration import requirements
|
|
from volatility.framework.layers.registry import RegistryHive, RegistryFormatException
|
|
from volatility.framework.renderers import TreeGrid, conversion, format_hints
|
|
from volatility.framework.symbols.windows.extensions.registry import RegValueTypes
|
|
from volatility.plugins.windows.registry import hivelist
|
|
|
|
vollog = logging.getLogger(__name__)
|
|
|
|
|
|
class PrintKey(interfaces.plugins.PluginInterface):
|
|
"""Lists the registry keys under a hive or specific key value."""
|
|
|
|
_version = (1, 0, 0)
|
|
|
|
@classmethod
|
|
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
|
|
return [
|
|
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.IntRequirement(name = 'offset', description = "Hive Offset", default = None, optional = True),
|
|
requirements.StringRequirement(name = 'key',
|
|
description = "Key to start from",
|
|
default = None,
|
|
optional = True),
|
|
requirements.BooleanRequirement(name = 'recurse',
|
|
description = 'Recurses through keys',
|
|
default = False,
|
|
optional = True)
|
|
]
|
|
|
|
@classmethod
|
|
def key_iterator(cls, hive: RegistryHive, node_path: Sequence[objects.StructType] = None, recurse: bool = False
|
|
) -> Iterable[Tuple[int, bool, datetime.datetime, str, bool, interfaces.objects.ObjectInterface]]:
|
|
"""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.
|
|
|
|
Args:
|
|
hive: The registry hive to walk
|
|
node_path: The list of nodes that make up the
|
|
recurse: Traverse down the node tree or stay only on the same level
|
|
|
|
Yields:
|
|
A tuple of results (depth, is_key, last write time, path, volatile, and the node).
|
|
"""
|
|
if not node_path:
|
|
node_path = [hive.get_node(hive.root_cell_offset)]
|
|
if not isinstance(node_path, list) or len(node_path) < 1:
|
|
vollog.warning("Hive walker was not passed a valid node_path (or None)")
|
|
return
|
|
node = node_path[-1]
|
|
if node.vol.type_name.endswith(constants.BANG + '_CELL_DATA'):
|
|
raise RegistryFormatException(hive.name, "Encountered _CELL_DATA instead of _CM_KEY_NODE")
|
|
key_path = node.get_key_path()
|
|
last_write_time = conversion.wintime_to_datetime(node.LastWriteTime.QuadPart)
|
|
|
|
for key_node in node.get_subkeys():
|
|
result = (len(node_path), True, last_write_time, key_path, key_node.get_volatile(), key_node)
|
|
yield result
|
|
|
|
if recurse:
|
|
if key_node.vol.offset not in [x.vol.offset for x in node_path]:
|
|
try:
|
|
sub_node_name = key_node.get_name()
|
|
except exceptions.InvalidAddressException as excp:
|
|
vollog.debug(excp)
|
|
continue
|
|
|
|
yield from cls.key_iterator(hive, node_path + [key_node], recurse = recurse)
|
|
|
|
for value_node in node.get_values():
|
|
result = (len(node_path), False, last_write_time, key_path, node.get_volatile(), value_node)
|
|
yield result
|
|
|
|
def _printkey_iterator(self,
|
|
hive: RegistryHive,
|
|
node_path: Sequence[objects.StructType] = None,
|
|
recurse: bool = False):
|
|
"""Method that wraps the more generic key_iterator, to provide output
|
|
for printkey specifically.
|
|
|
|
Args:
|
|
hive: The registry hive to walk
|
|
node_path: The list of nodes that make up the
|
|
recurse: Traverse down the node tree or stay only on the same level
|
|
|
|
Yields:
|
|
The depth, and a tuple of results (last write time, hive offset, type, path, name, data and volatile)
|
|
"""
|
|
for depth, is_key, last_write_time, key_path, volatile, node in self.key_iterator(hive, node_path, recurse):
|
|
if is_key:
|
|
try:
|
|
key_node_name = node.get_name()
|
|
except (exceptions.InvalidAddressException, RegistryFormatException) as excp:
|
|
vollog.debug(excp)
|
|
key_node_name = renderers.UnreadableValue()
|
|
|
|
yield (depth, (last_write_time, renderers.format_hints.Hex(hive.hive_offset), "Key", key_path,
|
|
key_node_name, "", volatile))
|
|
else:
|
|
try:
|
|
value_node_name = node.get_name() or "(Default)"
|
|
except (exceptions.InvalidAddressException, RegistryFormatException) as excp:
|
|
vollog.debug(excp)
|
|
value_node_name = renderers.UnreadableValue()
|
|
|
|
try:
|
|
value_data = str(node.decode_data()) # type: Union[interfaces.renderers.BaseAbsentValue, str]
|
|
except (ValueError, exceptions.InvalidAddressException, RegistryFormatException) as excp:
|
|
vollog.debug(excp)
|
|
value_data = renderers.UnreadableValue()
|
|
|
|
try:
|
|
value_type = RegValueTypes.get(node.Type).name
|
|
except (exceptions.InvalidAddressException, RegistryFormatException) as excp:
|
|
vollog.debug(excp)
|
|
value_type = renderers.UnreadableValue()
|
|
|
|
result = (depth, (last_write_time, renderers.format_hints.Hex(hive.hive_offset), value_type, key_path,
|
|
value_node_name, value_data, volatile))
|
|
yield result
|
|
|
|
def _registry_walker(self,
|
|
layer_name: str,
|
|
symbol_table: str,
|
|
hive_offsets: List[int] = None,
|
|
key: str = None,
|
|
recurse: bool = False):
|
|
|
|
for hive in hivelist.HiveList.list_hives(self.context,
|
|
self.config_path,
|
|
layer_name = layer_name,
|
|
symbol_table = symbol_table,
|
|
hive_offsets = hive_offsets):
|
|
|
|
try:
|
|
# Walk it
|
|
if key is not None:
|
|
node_path = hive.get_key(key, return_list = True)
|
|
else:
|
|
node_path = [hive.get_node(hive.root_cell_offset)]
|
|
for (x, y) in self._printkey_iterator(hive, node_path, recurse = recurse):
|
|
yield (x - len(node_path), y)
|
|
except (exceptions.InvalidAddressException, KeyError, RegistryFormatException) as excp:
|
|
if isinstance(excp, KeyError):
|
|
vollog.debug("Key '{}' not found in Hive at offset {}.".format(key, hex(hive.hive_offset)))
|
|
elif isinstance(excp, RegistryFormatException):
|
|
vollog.debug(excp)
|
|
elif isinstance(excp, exceptions.InvalidAddressException):
|
|
vollog.debug("Invalid address identified in Hive: {}".format(hex(excp.invalid_address)))
|
|
result = (0, (renderers.UnreadableValue(), format_hints.Hex(hive.hive_offset), "Key",
|
|
'?\\' + (key or ''), renderers.UnreadableValue(), renderers.UnreadableValue(),
|
|
renderers.UnreadableValue()))
|
|
yield result
|
|
|
|
def run(self):
|
|
offset = self.config.get('offset', None)
|
|
|
|
return TreeGrid(columns = [('Last Write Time', datetime.datetime), ('Hive Offset', format_hints.Hex),
|
|
('Type', str), ('Key', str), ('Name', str), ('Data', str), ('Volatile', bool)],
|
|
generator = self._registry_walker(self.config['primary'],
|
|
self.config['nt_symbols'],
|
|
hive_offsets = None if offset is None else [offset],
|
|
key = self.config.get('key', None),
|
|
recurse = self.config.get('recurse', None)))
|