From 5362e2094edbe2fce8b9256577a0753e175b9dcb Mon Sep 17 00:00:00 2001 From: Mike Auty Date: Sat, 10 Aug 2019 03:15:30 +0100 Subject: [PATCH] Initial attempt at cleaning up the API Context.object accepts a template or a string name (and now a type flag). Module.object only accepts a string (because a template already has most of the stuff built in and might as well be passed to the Context.object constructor). The gotcha here is the absolute flag, which must now be set appropriately in all cases *except* where the module is constructed with an offset of 0 (whereby it will have no impact). --- volatility/cli/volshell/windows.py | 4 +- volatility/framework/automagic/linux.py | 2 +- volatility/framework/constants/__init__.py | 7 ++ volatility/framework/contexts/__init__.py | 79 +++++++++++-------- volatility/framework/interfaces/context.py | 13 +-- volatility/framework/layers/msf.py | 11 ++- .../framework/plugins/linux/check_afinfo.py | 2 +- .../framework/plugins/linux/check_syscall.py | 2 +- volatility/framework/plugins/linux/lsmod.py | 6 +- volatility/framework/plugins/linux/pslist.py | 6 +- .../framework/plugins/mac/check_syscall.py | 7 +- .../framework/plugins/mac/check_sysctl.py | 21 ++--- .../framework/plugins/mac/check_trap_table.py | 5 +- volatility/framework/plugins/mac/lsmod.py | 6 +- volatility/framework/plugins/mac/pslist.py | 6 +- .../framework/plugins/mac/trustedbsd.py | 8 +- .../framework/plugins/windows/handles.py | 4 +- volatility/framework/plugins/windows/info.py | 9 +-- .../framework/plugins/windows/modules.py | 4 +- .../framework/plugins/windows/poolscanner.py | 3 +- .../framework/plugins/windows/pslist.py | 4 +- .../plugins/windows/registry/hivelist.py | 4 +- volatility/framework/plugins/windows/ssdt.py | 8 +- .../framework/plugins/windows/vadinfo.py | 3 +- volatility/framework/symbols/__init__.py | 9 +-- .../symbols/windows/extensions/__init__.py | 2 +- .../framework/symbols/windows/pdbconv.py | 42 +++++----- 27 files changed, 146 insertions(+), 131 deletions(-) diff --git a/volatility/cli/volshell/windows.py b/volatility/cli/volshell/windows.py index 37931fa74..2005c5813 100644 --- a/volatility/cli/volshell/windows.py +++ b/volatility/cli/volshell/windows.py @@ -44,7 +44,7 @@ class Volshell(shellplugin.Volshell): ntkrnlmp = self.context.module(self.config['nt_symbols'], layer_name = layer_name, offset = kvo) ps_aph_offset = ntkrnlmp.get_symbol("PsActiveProcessHead").address - list_entry = ntkrnlmp.object(type_name = "_LIST_ENTRY", offset = kvo + ps_aph_offset) + list_entry = ntkrnlmp.object(symbol = "_LIST_ENTRY", offset = ps_aph_offset) # This is example code to demonstrate how to use symbol_space directly, rather than through a module: # @@ -58,7 +58,7 @@ class Volshell(shellplugin.Volshell): # having been present. Strictly, the value of the requirement should be joined with the BANG character # defined in the constants file reloff = ntkrnlmp.get_type("_EPROCESS").relative_child_offset("ActiveProcessLinks") - eproc = ntkrnlmp.object(type_name = "_EPROCESS", offset = list_entry.vol.offset - reloff) + eproc = ntkrnlmp.object(symbol = "_EPROCESS", offset = list_entry.vol.offset - reloff, absolute = True) for proc in eproc.ActiveProcessLinks: yield proc diff --git a/volatility/framework/automagic/linux.py b/volatility/framework/automagic/linux.py index 14e347127..a4594dfd1 100644 --- a/volatility/framework/automagic/linux.py +++ b/volatility/framework/automagic/linux.py @@ -303,7 +303,7 @@ class LinuxUtilities(object): progress_callback = progress_callback): task_symbol = module.get_type('task_struct') init_task_address = offset - task_symbol.relative_child_offset('comm') - init_task = module.object(type_name = 'task_struct', offset = init_task_address) + init_task = module.object(symbol = 'task_struct', offset = init_task_address, absolute = True) if init_task.pid != 0: continue elif init_task.has_member('state') and init_task.state.cast('unsigned int') != 0: diff --git a/volatility/framework/constants/__init__.py b/volatility/framework/constants/__init__.py index 3ce11b671..0d94e4868 100644 --- a/volatility/framework/constants/__init__.py +++ b/volatility/framework/constants/__init__.py @@ -21,6 +21,7 @@ Stores all the constant values that are generally fixed throughout volatility This includes default scanning block sizes, etc.""" +import enum import os.path import sys from typing import Optional, Callable @@ -61,3 +62,9 @@ PARALLELISM_THREADING = 1 PARALLELISM_MULTIPROCESSING = 2 PARALLELISM = PARALLELISM_OFF + + +class SymbolType(enum.Enum): + TYPE = 1 + SYMBOL = 2 + ENUM = 3 diff --git a/volatility/framework/contexts/__init__.py b/volatility/framework/contexts/__init__.py index 719837f8c..d52eca6e9 100644 --- a/volatility/framework/contexts/__init__.py +++ b/volatility/framework/contexts/__init__.py @@ -93,6 +93,7 @@ class Context(interfaces.context.ContextInterface): symbol: Union[str, interfaces.objects.Template], layer_name: str, offset: int, + symbol_type: Optional[constants.SymbolType] = None, native_layer_name: Optional[str] = None, **arguments) -> interfaces.objects.ObjectInterface: """Object factory, takes a context, symbol, offset and optional layername @@ -110,11 +111,20 @@ class Context(interfaces.context.ContextInterface): A fully constructed object """ if not isinstance(symbol, interfaces.objects.Template): - object_template = self._symbol_space.get_type(symbol) + if symbol_type == constants.SymbolType.SYMBOL: + symbol_obj = self._symbol_space.get_symbol(symbol) + if symbol_obj.type is None: + raise ValueError("Symbol {} has no associated type information".format(symbol_obj.name)) + object_template = symbol_obj.type + elif symbol_type == constants.SymbolType.ENUM: + object_template = self._symbol_space.get_enumeration(symbol) + else: + object_template = self._symbol_space.get_type(symbol) else: object_template = symbol # Ensure that if a pre-constructed type is provided we just instantiate it arguments.update(object_template.vol) + object_template = object_template.clone() object_template.update_vol(**arguments) return object_template( @@ -149,9 +159,11 @@ def get_module_wrapper(method: str) -> Callable: """Returns a symbol using the symbol_table_name of the Module""" def wrapper(self, name: str) -> Callable: - if constants.BANG in name: - raise ValueError("Name cannot reference another module") - return getattr(self._context.symbol_space, method)(self._module_name + constants.BANG + name) + if constants.BANG not in name: + name = self._module_name + constants.BANG + name + else: + raise ValueError("Cannot reference another module when calling {}".format(method)) + return getattr(self._context.symbol_space, method)(name) for entry in ['__annotations__', '__doc__', '__module__', '__name__', '__qualname__']: proxy_interface = getattr(interfaces.context.ModuleInterface, method) @@ -164,40 +176,45 @@ def get_module_wrapper(method: str) -> Callable: class Module(interfaces.context.ModuleInterface): def object(self, - symbol_name: Optional[str] = None, - type_name: Optional[str] = None, - offset: Optional[int] = None, + symbol: str, + symbol_type: Optional[constants.SymbolType] = None, + offset: int = None, native_layer_name: Optional[str] = None, - **kwargs) -> interfaces.objects.ObjectInterface: + absolute: bool = False, + **kwargs) -> 'interfaces.objects.ObjectInterface': """Returns an object created using the symbol_table_name and layer_name of the Module Args: - symbol_name: Name of the symbol (within the module) to construct, type_name and offset must not be specified - type_name: Name of the type (within the module) to construct, offset must be specified and symbol_name must not - offset: The location (absolute within memory), type_name must be specified and symbol_name must not + symbol: Name of the type/symbol/enumeration (within the module) to construct + symbol_type: One of the SymbolType enumeratino (Type/Symbol/Enum), defaults to Type + offset: The location of the object, ignored when symbol_type is SYMBOL native_layer_name: Name of the layer in which constructed objects are made (for pointers) """ - type_arg = None # type: Optional[Union[str, interfaces.objects.Template]] - if symbol_name is not None: - if constants.BANG in symbol_name: - raise ValueError("Symbol_name cannot reference another module") - symbol = self._context.symbol_space.get_symbol(self.symbol_table_name + constants.BANG + symbol_name) - if symbol.type is None: - raise ValueError("Symbol {} has no associated type information".format(symbol.name)) - type_arg = symbol.type - offset = symbol.address - if not self._absolute_symbol_addresses: - offset += self._offset - elif type_name is not None and offset is not None: - if constants.BANG in type_name: - raise ValueError("Type_name cannot reference another module") - type_arg = self.symbol_table_name + constants.BANG + type_name + if constants.BANG not in symbol: + symbol = self.symbol_table_name + constants.BANG + symbol else: - raise ValueError("One of symbol_name, or type_name & offset, must be specified to construct a module") + raise ValueError("Cannot reference another module when constructing an object") + + # Only set the offset if type is Symbol and we were given a name, not a template + if symbol_type == constants.SymbolType.SYMBOL: + offset = self._context.symbol_space.get_symbol(symbol).address + + if offset is None: + raise ValueError("Offset must not be None for non-symbol objects") + + if not absolute: + offset += self._offset + # Ensure we don't use a layer_name other than the module's, why would anyone do that? if 'layer_name' in kwargs: del kwargs['layer_name'] - return self._context.object(type_arg, self._layer_name, offset, native_layer_name, **kwargs) + return self._context.object( + symbol = symbol, + symbol_type = symbol_type, + layer_name = self._layer_name, + offset = offset, + native_layer_name = native_layer_name, + **kwargs) get_symbol = get_module_wrapper('get_symbol') get_type = get_module_wrapper('get_type') @@ -216,16 +233,14 @@ class SizedModule(Module): offset: int, size: int, symbol_table_name: Optional[str] = None, - native_layer_name: Optional[str] = None, - absolute_symbol_addresses: bool = False) -> None: + native_layer_name: Optional[str] = None) -> None: super().__init__( context, module_name = module_name, layer_name = layer_name, offset = offset, native_layer_name = native_layer_name, - symbol_table_name = symbol_table_name, - absolute_symbol_addresses = absolute_symbol_addresses) + symbol_table_name = symbol_table_name) self._size = size @property diff --git a/volatility/framework/interfaces/context.py b/volatility/framework/interfaces/context.py index 965bde39a..9f1399a9c 100644 --- a/volatility/framework/interfaces/context.py +++ b/volatility/framework/interfaces/context.py @@ -27,7 +27,7 @@ import copy from abc import ABCMeta, abstractmethod from typing import Optional, Union -from volatility.framework import interfaces +from volatility.framework import interfaces, constants class ContextInterface(object, metaclass = ABCMeta): @@ -115,8 +115,7 @@ class ModuleInterface(metaclass = ABCMeta): layer_name: str, offset: int, symbol_table_name: Optional[str] = None, - native_layer_name: Optional[str] = None, - absolute_symbol_addresses: bool = False) -> None: + native_layer_name: Optional[str] = None) -> None: self._context = context self._module_name = module_name self._layer_name = layer_name @@ -125,7 +124,6 @@ class ModuleInterface(metaclass = ABCMeta): if native_layer_name: self._native_layer_name = native_layer_name self.symbol_table_name = symbol_table_name or self._module_name - self._absolute_symbol_addresses = absolute_symbol_addresses super().__init__() @property @@ -148,7 +146,12 @@ class ModuleInterface(metaclass = ABCMeta): return self._context @abstractmethod - def object(self, symbol_name: str = None, type_name: str = None, offset: int = None, + def object(self, + symbol: Union[str, 'interfaces.objects.Template'], + symbol_type: Optional[constants.SymbolType] = None, + offset: int = None, + native_layer_name: Optional[str] = None, + absolute: bool = False, **kwargs) -> 'interfaces.objects.ObjectInterface': """Returns an object created using the symbol_table_name and layer_name of the Module""" diff --git a/volatility/framework/layers/msf.py b/volatility/framework/layers/msf.py index 1caad67b6..99e04ce27 100644 --- a/volatility/framework/layers/msf.py +++ b/volatility/framework/layers/msf.py @@ -63,8 +63,7 @@ class PdbMultiStreamFormat(interfaces.layers.TranslationLayerInterface): root_table_num_pages = math.ceil(self._header.StreamInfo.StreamInfoSize / self._header.PageSize) root_index_size = math.ceil((root_table_num_pages * entry_size) / self._header.PageSize) root_index = module.object( - type_name = "array", - layer_name = self._base_layer, + symbol = "array", offset = self._header.vol.size, count = root_index_size, subtype = module.get_type("unsigned long")) @@ -73,14 +72,14 @@ class PdbMultiStreamFormat(interfaces.layers.TranslationLayerInterface): module = self.context.module(self.pdb_symbol_table, root_index_layer_name, offset = 0) root_pages = module.object( - type_name = "array", offset = 0, count = root_table_num_pages, subtype = module.get_type("unsigned long")) + symbol = "array", offset = 0, count = root_table_num_pages, subtype = module.get_type("unsigned long")) root_layer_name = self.create_stream_from_pages("root", self._header.StreamInfo.StreamInfoSize, [x for x in root_pages]) module = self.context.module(self.pdb_symbol_table, root_layer_name, offset = 0) - num_streams = module.object(type_name = "unsigned long", offset = 0) + num_streams = module.object(symbol = "unsigned long", offset = 0) stream_sizes = module.object( - type_name = "array", offset = entry_size, count = num_streams, subtype = module.get_type("unsigned long")) + symbol = "array", offset = entry_size, count = num_streams, subtype = module.get_type("unsigned long")) current_offset = (num_streams + 1) * entry_size @@ -90,7 +89,7 @@ class PdbMultiStreamFormat(interfaces.layers.TranslationLayerInterface): self._streams[stream] = None else: stream_page_list = module.object( - type_name = "array", + symbol = "array", offset = current_offset, count = list_size, subtype = module.get_type("unsigned long")) diff --git a/volatility/framework/plugins/linux/check_afinfo.py b/volatility/framework/plugins/linux/check_afinfo.py index 014b4c2fb..946588556 100644 --- a/volatility/framework/plugins/linux/check_afinfo.py +++ b/volatility/framework/plugins/linux/check_afinfo.py @@ -98,7 +98,7 @@ class Check_afinfo(plugins.PluginInterface): except exceptions.SymbolError: continue - global_var = vmlinux.object(type_name = struct_type, offset = global_var.address) + global_var = vmlinux.object(symbol = struct_type, offset = global_var.address) for name, member, address in self._check_afinfo(global_var_name, global_var, op_members, seq_members): yield 0, (name, member, format_hints.Hex(address)) diff --git a/volatility/framework/plugins/linux/check_syscall.py b/volatility/framework/plugins/linux/check_syscall.py index 92ea98872..94ea1953f 100644 --- a/volatility/framework/plugins/linux/check_syscall.py +++ b/volatility/framework/plugins/linux/check_syscall.py @@ -176,7 +176,7 @@ class Check_syscall(plugins.PluginInterface): for (table_name, (tableaddr, tblsz)) in tables: table = vmlinux.object( - type_name = "array", subtype = vmlinux.get_type("pointer"), offset = tableaddr, count = tblsz) + symbol = "array", subtype = vmlinux.get_type("pointer"), offset = tableaddr, count = tblsz) for (i, call_addr) in enumerate(table): if not call_addr: diff --git a/volatility/framework/plugins/linux/lsmod.py b/volatility/framework/plugins/linux/lsmod.py index 9b0df9055..841506b4f 100644 --- a/volatility/framework/plugins/linux/lsmod.py +++ b/volatility/framework/plugins/linux/lsmod.py @@ -23,8 +23,8 @@ typically found in Linux's /proc file system. from typing import List +from volatility.framework import contexts from volatility.framework import renderers, constants, interfaces -from volatility.framework import exceptions, contexts from volatility.framework.automagic import linux from volatility.framework.configuration import requirements from volatility.framework.interfaces import plugins @@ -48,9 +48,9 @@ class Lsmod(plugins.PluginInterface): """Lists all the modules in the primary layer""" linux.LinuxUtilities.aslr_mask_symbol_table(context, vmlinux_symbols, layer_name) - vmlinux = contexts.Module(context, vmlinux_symbols, layer_name, 0, absolute_symbol_addresses = True) + vmlinux = contexts.Module(context, vmlinux_symbols, layer_name, 0) - modules = vmlinux.object(symbol_name = "modules").cast("list_head") + modules = vmlinux.object(symbol = "modules", symbol_type = constants.SymbolType.SYMBOL).cast("list_head") table_name = modules.vol.type_name.split(constants.BANG)[0] diff --git a/volatility/framework/plugins/linux/pslist.py b/volatility/framework/plugins/linux/pslist.py index 03b91f452..0d9dccfd0 100644 --- a/volatility/framework/plugins/linux/pslist.py +++ b/volatility/framework/plugins/linux/pslist.py @@ -21,7 +21,7 @@ from typing import Callable, Iterable, List import volatility.framework.interfaces.plugins as interfaces_plugins -from volatility.framework import renderers, interfaces, contexts +from volatility.framework import renderers, interfaces, contexts, constants from volatility.framework.automagic import linux from volatility.framework.configuration import requirements from volatility.framework.objects import utility @@ -75,9 +75,9 @@ class PsList(interfaces_plugins.PluginInterface): """Lists all the tasks in the primary layer""" linux.LinuxUtilities.aslr_mask_symbol_table(context, vmlinux_symbols, layer_name) - vmlinux = contexts.Module(context, vmlinux_symbols, layer_name, 0, absolute_symbol_addresses = True) + vmlinux = contexts.Module(context, vmlinux_symbols, layer_name, 0) - init_task = vmlinux.object(symbol_name = "init_task") + init_task = vmlinux.object(symbol = "init_task", symbol_type = constants.SymbolType.SYMBOL) for task in init_task.tasks: if not filter_func(task): diff --git a/volatility/framework/plugins/mac/check_syscall.py b/volatility/framework/plugins/mac/check_syscall.py index 49cd6964a..04b30dc48 100644 --- a/volatility/framework/plugins/mac/check_syscall.py +++ b/volatility/framework/plugins/mac/check_syscall.py @@ -25,11 +25,10 @@ class Check_syscall(plugins.PluginInterface): def _generator(self): mac.MacUtilities.aslr_mask_symbol_table(self.context, self.config['darwin'], self.config['primary']) - kernel = contexts.Module( - self._context, self.config['darwin'], self.config['primary'], 0, absolute_symbol_addresses = True) + kernel = contexts.Module(self._context, self.config['darwin'], self.config['primary'], 0) - nsysent = kernel.object(symbol_name = "nsysent") - table = kernel.object(symbol_name = "sysent") + nsysent = kernel.object(symbol = "nsysent", symbol_type = constants.SymbolType.SYMBOL) + table = kernel.object(symbol = "sysent", symbol_type = constants.SymbolType.SYMBOL) # smear help num_ents = min(nsysent, table.count) diff --git a/volatility/framework/plugins/mac/check_sysctl.py b/volatility/framework/plugins/mac/check_sysctl.py index 4f5966941..4c50087e2 100644 --- a/volatility/framework/plugins/mac/check_sysctl.py +++ b/volatility/framework/plugins/mac/check_sysctl.py @@ -12,6 +12,7 @@ from volatility.framework.objects import utility vollog = logging.getLogger(__name__) + class Check_sysctl(plugins.PluginInterface): """Check sysctl handlers for hooks""" @@ -25,17 +26,17 @@ class Check_sysctl(plugins.PluginInterface): def _parse_global_variable_sysctls(self, kernel, name): known_sysctls = { - "hostname" : "hostname", - "nisdomainname" : "domainname", + "hostname": "hostname", + "nisdomainname": "domainname", } - + var_str = "" if name in known_sysctls: var_name = known_sysctls[name] try: - var_array = kernel.object(symbol_name = var_name) + var_array = kernel.object(symbol = var_name) except exceptions.SymbolError: var_array = None @@ -61,7 +62,7 @@ class Check_sysctl(plugins.PluginInterface): name = utility.pointer_to_string(sysctl.oid_name, 128) except exceptions.PagedInvalidAddressException: name = "" - + if len(name) == 0: break @@ -103,14 +104,13 @@ class Check_sysctl(plugins.PluginInterface): sysctl = sysctl.oid_link.sle_next except exceptions.PagedInvalidAddressException: break - + def _generator(self): mac.MacUtilities.aslr_mask_symbol_table(self.context, self.config['darwin'], self.config['primary']) - kernel = contexts.Module( - self._context, self.config['darwin'], self.config['primary'], 0, absolute_symbol_addresses = True) + kernel = contexts.Module(self._context, self.config['darwin'], self.config['primary'], 0) - sysctl_list = kernel.object(symbol_name = "sysctl__children") + sysctl_list = kernel.object(symbo = "sysctl__children", symbol_type = constants.SymbolType.SYMBOL) for sysctl, name, val in self._process_sysctl_list(kernel, sysctl_list): check_addr = sysctl.oid_handler @@ -130,4 +130,5 @@ class Check_sysctl(plugins.PluginInterface): def run(self): return renderers.TreeGrid([("Name", str), ("Number", int), ("Perms", str), - ("Handler Address", format_hints.Hex), ("Value", str), ("Handler Symbol", str)], self._generator()) + ("Handler Address", format_hints.Hex), ("Value", str), ("Handler Symbol", str)], + self._generator()) diff --git a/volatility/framework/plugins/mac/check_trap_table.py b/volatility/framework/plugins/mac/check_trap_table.py index 8df977d35..7b659ff75 100644 --- a/volatility/framework/plugins/mac/check_trap_table.py +++ b/volatility/framework/plugins/mac/check_trap_table.py @@ -25,10 +25,9 @@ class Check_trap_table(plugins.PluginInterface): def _generator(self): mac.MacUtilities.aslr_mask_symbol_table(self.context, self.config['darwin'], self.config['primary']) - kernel = contexts.Module( - self._context, self.config['darwin'], self.config['primary'], 0, absolute_symbol_addresses = True) + kernel = contexts.Module(self._context, self.config['darwin'], self.config['primary'], 0) - table = kernel.object(symbol_name = "mach_trap_table") + table = kernel.object(symbol = "mach_trap_table", symbol_type = constants.SymbolType.SYMBOL) for i, ent in enumerate(table): try: diff --git a/volatility/framework/plugins/mac/lsmod.py b/volatility/framework/plugins/mac/lsmod.py index 4ead29f93..cdcacc579 100644 --- a/volatility/framework/plugins/mac/lsmod.py +++ b/volatility/framework/plugins/mac/lsmod.py @@ -21,7 +21,7 @@ typically found in Mac's lsmod command. """ -from volatility.framework import renderers, interfaces, contexts +from volatility.framework import renderers, interfaces, contexts, constants from volatility.framework.automagic import mac from volatility.framework.configuration import requirements from volatility.framework.interfaces import plugins @@ -45,9 +45,9 @@ class Lsmod(plugins.PluginInterface): """Lists all the modules in the primary layer""" mac.MacUtilities.aslr_mask_symbol_table(context, darwin_symbols, layer_name) - kernel = contexts.Module(context, darwin_symbols, layer_name, 0, absolute_symbol_addresses = True) + kernel = contexts.Module(context, darwin_symbols, layer_name, 0) - kmod_ptr = kernel.object(symbol_name = "kmod") + kmod_ptr = kernel.object(symbol = "kmod", symbol_type = constants.SymbolType.SYMBOL) # TODO - use smear-proof list walking API after dev release kmod = kmod_ptr.dereference().cast("kmod_info") diff --git a/volatility/framework/plugins/mac/pslist.py b/volatility/framework/plugins/mac/pslist.py index ed95e0d1b..84be3b539 100644 --- a/volatility/framework/plugins/mac/pslist.py +++ b/volatility/framework/plugins/mac/pslist.py @@ -22,7 +22,7 @@ import logging from typing import Callable, Iterable, List import volatility.framework.interfaces.plugins as interfaces_plugins -from volatility.framework import renderers, interfaces, contexts +from volatility.framework import renderers, interfaces, contexts, constants from volatility.framework.automagic import mac from volatility.framework.configuration import requirements from volatility.framework.objects import utility @@ -78,9 +78,9 @@ class PsList(interfaces_plugins.PluginInterface): mac.MacUtilities.aslr_mask_symbol_table(context, darwin_symbols, layer_name) - kernel = contexts.Module(context, darwin_symbols, layer_name, 0, absolute_symbol_addresses = True) + kernel = contexts.Module(context, darwin_symbols, layer_name, 0) - proc = kernel.object(symbol_name = "allproc").lh_first + proc = kernel.object(symbol = "allproc", symbol_type = constants.SymbolType.SYMBOL).lh_first seen = {} while proc is not None and proc.vol.offset != 0: diff --git a/volatility/framework/plugins/mac/trustedbsd.py b/volatility/framework/plugins/mac/trustedbsd.py index 83470ea2f..37697ae80 100644 --- a/volatility/framework/plugins/mac/trustedbsd.py +++ b/volatility/framework/plugins/mac/trustedbsd.py @@ -47,13 +47,13 @@ class Check_syscall(plugins.PluginInterface): def _generator(self, mods: Iterator[Any]): mac.MacUtilities.aslr_mask_symbol_table(self.context, self.config['darwin'], self.config['primary']) - kernel = contexts.Module( - self._context, self.config['darwin'], self.config['primary'], 0, absolute_symbol_addresses = True) + kernel = contexts.Module(self._context, self.config['darwin'], self.config['primary'], 0) - policy_list = kernel.object(symbol_name = "_mac_policy_list").cast("mac_policy_list") + policy_list = kernel.object( + symbol = "_mac_policy_list", symbol_type = constants.SymbolType.SYMBOL).cast("mac_policy_list") entries = kernel.object( - type_name = "array", + symbol = "array", offset = policy_list.entries.dereference().vol.offset, subtype = kernel.get_type('mac_policy_list_element'), count = policy_list.staticmax + 1) diff --git a/volatility/framework/plugins/windows/handles.py b/volatility/framework/plugins/windows/handles.py index 3ffe2e291..d68435c28 100644 --- a/volatility/framework/plugins/windows/handles.py +++ b/volatility/framework/plugins/windows/handles.py @@ -162,7 +162,7 @@ class Handles(interfaces_plugins.PluginInterface): table_addr = ntkrnlmp.get_symbol("ObpObjectTypes").address ptrs = ntkrnlmp.object( - type_name = "array", offset = kvo + table_addr, subtype = ntkrnlmp.get_type("pointer"), count = 100) + symbol = "array", offset = table_addr, subtype = ntkrnlmp.get_type("pointer"), count = 100) for i, ptr in enumerate(ptrs): #type: ignore # the first entry in the table is always null. break the @@ -214,7 +214,7 @@ class Handles(interfaces_plugins.PluginInterface): if not self.context.layers[virtual].is_valid(offset): return - table = ntkrnlmp.object(type_name = "array", offset = offset, subtype = subtype, count = int(count)) + table = ntkrnlmp.object(symbol = "array", offset = offset, subtype = subtype, count = int(count)) layer_object = self.context.layers[virtual] masked_offset = (offset & layer_object.maximum_address) diff --git a/volatility/framework/plugins/windows/info.py b/volatility/framework/plugins/windows/info.py index 4411df4f6..fca45026e 100644 --- a/volatility/framework/plugins/windows/info.py +++ b/volatility/framework/plugins/windows/info.py @@ -105,8 +105,7 @@ class Info(plugins.PluginInterface): vers_offset = ntkrnlmp.get_symbol("KdVersionBlock").address - vers = ntkrnlmp.object( - type_name = "_DBGKD_GET_VERSION64", layer_name = virtual_layer_name, offset = kvo + vers_offset) + vers = ntkrnlmp.object(symbol = "_DBGKD_GET_VERSION64", layer_name = virtual_layer_name, offset = vers_offset) yield (0, ("KdVersionBlock", hex(vers.vol.offset))) yield (0, ("Major/Minor", "{0}.{1}".format(vers.MajorVersion, vers.MinorVersion))) @@ -114,8 +113,7 @@ class Info(plugins.PluginInterface): cpu_count_offset = ntkrnlmp.get_symbol("KeNumberProcessors").address - cpu_count = ntkrnlmp.object( - type_name = "unsigned int", layer_name = virtual_layer_name, offset = kvo + cpu_count_offset) + cpu_count = ntkrnlmp.object(symbol = "unsigned int", layer_name = virtual_layer_name, offset = cpu_count_offset) yield (0, ("KeNumberProcessors", str(cpu_count))) @@ -125,7 +123,8 @@ class Info(plugins.PluginInterface): else: kuser_addr = 0xFFFFF78000000000 - kuser = ntkrnlmp.object(type_name = "_KUSER_SHARED_DATA", layer_name = virtual_layer_name, offset = kuser_addr) + kuser = ntkrnlmp.object( + symbol = "_KUSER_SHARED_DATA", layer_name = virtual_layer_name, offset = kuser_addr, absolute = True) yield (0, ("SystemTime", str(kuser.SystemTime.get_time()))) yield (0, ("NtSystemRoot", diff --git a/volatility/framework/plugins/windows/modules.py b/volatility/framework/plugins/windows/modules.py index 106ba308f..b0ed1f4e0 100644 --- a/volatility/framework/plugins/windows/modules.py +++ b/volatility/framework/plugins/windows/modules.py @@ -75,9 +75,9 @@ class Modules(interfaces.plugins.PluginInterface): type_name = ldr_entry_type.type_name.split(constants.BANG)[1] list_head = ntkrnlmp.get_symbol("PsLoadedModuleList").address - list_entry = ntkrnlmp.object(type_name = "_LIST_ENTRY", offset = kvo + list_head) + list_entry = ntkrnlmp.object(symbol = "_LIST_ENTRY", offset = list_head) reloff = ldr_entry_type.relative_child_offset("InLoadOrderLinks") - module = ntkrnlmp.object(type_name = type_name, offset = list_entry.vol.offset - reloff) + module = ntkrnlmp.object(symbol = type_name, offset = list_entry.vol.offset - reloff, absolute = True) for mod in module.InLoadOrderLinks: yield mod diff --git a/volatility/framework/plugins/windows/poolscanner.py b/volatility/framework/plugins/windows/poolscanner.py index 9e9eaf5f6..d2d342910 100644 --- a/volatility/framework/plugins/windows/poolscanner.py +++ b/volatility/framework/plugins/windows/poolscanner.py @@ -87,7 +87,8 @@ class PoolHeaderScanner(interfaces.layers.ScannerInterface): def __call__(self, data: bytes, data_offset: int): for offset, pattern in self._subscanner(data, data_offset): - header = self._module.object(type_name = "_POOL_HEADER", offset = offset - self._header_offset) + header = self._module.object( + symbol = "_POOL_HEADER", offset = offset - self._header_offset, absolute = True) constraint = self._constraint_lookup[pattern] try: # Size check diff --git a/volatility/framework/plugins/windows/pslist.py b/volatility/framework/plugins/windows/pslist.py index b3a7a50e7..6b2500974 100644 --- a/volatility/framework/plugins/windows/pslist.py +++ b/volatility/framework/plugins/windows/pslist.py @@ -87,7 +87,7 @@ class PsList(plugins.PluginInterface, timeliner.TimeLinerInterface): ntkrnlmp = context.module(symbol_table, layer_name = layer_name, offset = kvo) ps_aph_offset = ntkrnlmp.get_symbol("PsActiveProcessHead").address - list_entry = ntkrnlmp.object(type_name = "_LIST_ENTRY", offset = kvo + ps_aph_offset) + list_entry = ntkrnlmp.object(symbol = "_LIST_ENTRY", offset = ps_aph_offset) # This is example code to demonstrate how to use symbol_space directly, rather than through a module: # @@ -101,7 +101,7 @@ class PsList(plugins.PluginInterface, timeliner.TimeLinerInterface): # having been present. Strictly, the value of the requirement should be joined with the BANG character # defined in the constants file reloff = ntkrnlmp.get_type("_EPROCESS").relative_child_offset("ActiveProcessLinks") - eproc = ntkrnlmp.object(type_name = "_EPROCESS", offset = list_entry.vol.offset - reloff) + eproc = ntkrnlmp.object(symbol = "_EPROCESS", offset = list_entry.vol.offset - reloff, absolute = True) for proc in eproc.ActiveProcessLinks: if not filter_func(proc): diff --git a/volatility/framework/plugins/windows/registry/hivelist.py b/volatility/framework/plugins/windows/registry/hivelist.py index 37a2e9e0d..d97b3c6ab 100644 --- a/volatility/framework/plugins/windows/registry/hivelist.py +++ b/volatility/framework/plugins/windows/registry/hivelist.py @@ -63,9 +63,9 @@ class HiveList(plugins.PluginInterface): ntkrnlmp = context.module(symbol_table, layer_name = layer_name, offset = kvo) list_head = ntkrnlmp.get_symbol("CmpHiveListHead").address - list_entry = ntkrnlmp.object(type_name = "_LIST_ENTRY", offset = kvo + list_head) + list_entry = ntkrnlmp.object(symbol = "_LIST_ENTRY", offset = list_head) reloff = ntkrnlmp.get_type("_CMHIVE").relative_child_offset("HiveList") - cmhive = ntkrnlmp.object(type_name = "_CMHIVE", offset = list_entry.vol.offset - reloff) + cmhive = ntkrnlmp.object(symbol = "_CMHIVE", offset = list_entry.vol.offset - reloff, absolute = True) # Run through the list fowards seen = set() diff --git a/volatility/framework/plugins/windows/ssdt.py b/volatility/framework/plugins/windows/ssdt.py index 35f32d7f5..53cbbf045 100644 --- a/volatility/framework/plugins/windows/ssdt.py +++ b/volatility/framework/plugins/windows/ssdt.py @@ -19,7 +19,7 @@ # import os -from typing import Any, Iterator, List, Tuple, Sequence +from typing import Any, Iterator, List, Tuple from volatility.framework import constants, interfaces from volatility.framework import contexts @@ -85,7 +85,7 @@ class SSDT(plugins.PluginInterface): ## we could also find nt!KeServiceDescriptorTable (NT) and KeServiceDescriptorTableShadow (NT, Win32K) service_table_address = ntkrnlmp.get_symbol("KiServiceTable").address service_limit_address = ntkrnlmp.get_symbol("KiServiceLimit").address - service_limit = ntkrnlmp.object(type_name = "int", offset = kvo + service_limit_address) + service_limit = ntkrnlmp.object(symbol = "int", offset = service_limit_address) # on 32-bit systems the table indexes are 32-bits and contain pointers (unsigned) # on 64-bit systems the indexes are also 32-bits but they're offsets from the @@ -107,8 +107,8 @@ class SSDT(plugins.PluginInterface): find_address = passthrough functions = ntkrnlmp.object( - type_name = "array", - offset = kvo + service_table_address, + symbol = "array", + offset = service_table_address, subtype = ntkrnlmp.get_type(array_subtype), count = service_limit) diff --git a/volatility/framework/plugins/windows/vadinfo.py b/volatility/framework/plugins/windows/vadinfo.py index 6c7c559c7..d88ec0b93 100644 --- a/volatility/framework/plugins/windows/vadinfo.py +++ b/volatility/framework/plugins/windows/vadinfo.py @@ -78,8 +78,7 @@ class VadInfo(interfaces.plugins.PluginInterface): kvo = context.layers[virtual_layer].config["kernel_virtual_offset"] ntkrnlmp = context.module(nt_symbols, layer_name = virtual_layer, offset = kvo) addr = ntkrnlmp.get_symbol("MmProtectToValue").address - values = ntkrnlmp.object( - type_name = "array", offset = kvo + addr, subtype = ntkrnlmp.get_type("int"), count = 32) + values = ntkrnlmp.object(symbol = "array", offset = addr, subtype = ntkrnlmp.get_type("int"), count = 32) return values # type: ignore @classmethod diff --git a/volatility/framework/symbols/__init__.py b/volatility/framework/symbols/__init__.py index 15a4b3c4e..13c66c4d8 100644 --- a/volatility/framework/symbols/__init__.py +++ b/volatility/framework/symbols/__init__.py @@ -20,21 +20,14 @@ import collections import collections.abc -import enum import logging from typing import Any, Dict, Iterable, Iterator, TypeVar from volatility.framework import constants, exceptions, interfaces, objects +from volatility.framework.constants import SymbolType vollog = logging.getLogger(__name__) - -class SymbolType(enum.Enum): - TYPE = 1 - SYMBOL = 2 - ENUM = 3 - - SymbolSpaceReturnType = TypeVar("SymbolSpaceReturnType", interfaces.objects.Template, interfaces.symbols.SymbolInterface, Dict[str, Any]) diff --git a/volatility/framework/symbols/windows/extensions/__init__.py b/volatility/framework/symbols/windows/extensions/__init__.py index 242d55d7f..5ea03aa76 100644 --- a/volatility/framework/symbols/windows/extensions/__init__.py +++ b/volatility/framework/symbols/windows/extensions/__init__.py @@ -700,7 +700,7 @@ class _EPROCESS(generic.GenericIntelProcess, ExecutiveObject): layer_name = self.vol.native_layer_name, offset = kvo, native_layer_name = self.vol.native_layer_name) - session = ntkrnlmp.object(type_name = "_MM_SESSION_SPACE", offset = self.Session) + session = ntkrnlmp.object(symbol = "_MM_SESSION_SPACE", offset = self.Session, absolute = True) if session.has_member("SessionId"): return session.SessionId diff --git a/volatility/framework/symbols/windows/pdbconv.py b/volatility/framework/symbols/windows/pdbconv.py index f2d250e69..1bfb9febb 100644 --- a/volatility/framework/symbols/windows/pdbconv.py +++ b/volatility/framework/symbols/windows/pdbconv.py @@ -353,7 +353,7 @@ class PdbReader: if not tpi_layer: raise ValueError("No TPI stream available") module = self._context.module(module_name = tpi_layer.pdb_symbol_table, layer_name = tpi_layer.name, offset = 0) - header = module.object(type_name = "TPI_HEADER", offset = 0) + header = module.object(symbol = "TPI_HEADER", offset = 0) # Check the header if not (56 <= header.header_size < 1024): @@ -375,7 +375,7 @@ class PdbReader: type_index = 1 while tpi_layer.maximum_address - offset > 0: self._progress_callback(offset * 100 / tpi_layer.maximum_address, "Reading TPI layer") - length = module.object(type_name = length_type, offset = offset) + length = module.object(symbol = length_type, offset = offset) if not isinstance(length, int): raise ValueError("Non-integer length provided") offset += length_len @@ -401,7 +401,7 @@ class PdbReader: if not dbi_layer: raise ValueError("No DBI stream available") module = self._context.module(module_name = dbi_layer.pdb_symbol_table, layer_name = dbi_layer.name, offset = 0) - self._dbiheader = module.object(type_name = "DBI_HEADER", offset = 0) + self._dbiheader = module.object(symbol = "DBI_HEADER", offset = 0) if not self._dbiheader: raise ValueError("DBI Header could not be read") @@ -410,7 +410,7 @@ class PdbReader: dbg_hdr_offset = (self._dbiheader.vol.size + self._dbiheader.module_size + self._dbiheader.secconSize + self._dbiheader.secmapSize + self._dbiheader.filinfSize + self._dbiheader.tsmapSize + self._dbiheader.ecinfoSize) - self._dbidbgheader = module.object(type_name = "DBI_DBG_HEADER", offset = dbg_hdr_offset) + self._dbidbgheader = module.object(symbol = "DBI_DBG_HEADER", offset = dbg_hdr_offset) self._sections = [] self._omap_mapping = [] @@ -465,8 +465,8 @@ class PdbReader: while offset < max_address: self._progress_callback(offset * 100 / max_address, "Reading Symbol layer") - sym = module.object(type_name = "GLOBAL_SYMBOL", offset = offset) - leaf_type = module.object(type_name = "unsigned short", offset = sym.leaf_type.vol.offset) + sym = module.object(symbol = "GLOBAL_SYMBOL", offset = offset) + leaf_type = module.object(symbol = "unsigned short", offset = sym.leaf_type.vol.offset) name = None address = None if sym.segment < len(self._sections): @@ -500,7 +500,7 @@ class PdbReader: raise ValueError("No PDB Info Stream available") module = self._context.module( module_name = pdb_info_layer.pdb_symbol_table, layer_name = pdb_info_layer.name, offset = 0) - pdb_info = module.object(type_name = "PDB_INFORMATION", offset = 0) + pdb_info = module.object(symbol = "PDB_INFORMATION", offset = 0) self.metadata['windows']['pdb'] = { "GUID": self.convert_bytes_to_guid(pdb_info.GUID), @@ -726,7 +726,7 @@ class PdbReader: leaf_type.LF_CLASS, leaf_type.LF_CLASS_ST, leaf_type.LF_STRUCTURE, leaf_type.LF_STRUCTURE_ST, leaf_type.LF_INTERFACE ]: - structure = module.object(type_name = "LF_STRUCTURE", offset = offset + consumed) + structure = module.object(symbol = "LF_STRUCTURE", offset = offset + consumed) name_offset = structure.name.vol.offset - structure.vol.offset name, value, excess = self.determine_extended_value(leaf_type, structure.size, module, remaining - name_offset) @@ -735,7 +735,7 @@ class PdbReader: consumed += remaining result = leaf_type, name, structure elif leaf_type in [leaf_type.LF_MEMBER, leaf_type.LF_MEMBER_ST]: - member = module.object(type_name = "LF_MEMBER", offset = offset + consumed) + member = module.object(symbol = "LF_MEMBER", offset = offset + consumed) name_offset = member.name.vol.offset - member.vol.offset name, value, excess = self.determine_extended_value(leaf_type, member.offset, module, remaining - name_offset) @@ -744,7 +744,7 @@ class PdbReader: result = leaf_type, name, member consumed += member.vol.size + len(name) + 1 + excess elif leaf_type in [leaf_type.LF_ARRAY, leaf_type.LF_ARRAY_ST, leaf_type.LF_STRIDED_ARRAY]: - array = module.object(type_name = "LF_ARRAY", offset = offset + consumed) + array = module.object(symbol = "LF_ARRAY", offset = offset + consumed) name_offset = array.name.vol.offset - array.vol.offset name, value, excess = self.determine_extended_value(leaf_type, array.size, module, remaining - name_offset) array.size = value @@ -752,7 +752,7 @@ class PdbReader: result = leaf_type, name, array consumed += remaining elif leaf_type in [leaf_type.LF_ENUMERATE]: - enum = module.object(type_name = 'LF_ENUMERATE', offset = offset + consumed) + enum = module.object(symbol = 'LF_ENUMERATE', offset = offset + consumed) name_offset = enum.name.vol.offset - enum.vol.offset name, value, excess = self.determine_extended_value(leaf_type, enum.value, module, remaining - name_offset) enum.value = value @@ -760,20 +760,20 @@ class PdbReader: result = leaf_type, name, enum consumed += enum.vol.size + len(name) + 1 + excess elif leaf_type in [leaf_type.LF_ARGLIST, leaf_type.LF_ENUM]: - enum = module.object(type_name = "LF_ENUM", offset = offset + consumed) + enum = module.object(symbol = "LF_ENUM", offset = offset + consumed) name_offset = enum.name.vol.offset - enum.vol.offset name = self.parse_string(enum.name, leaf_type < leaf_type.LF_ST_MAX, size = remaining - name_offset) enum.name = name result = leaf_type, name, enum consumed += remaining elif leaf_type in [leaf_type.LF_UNION]: - union = module.object(type_name = "LF_UNION", offset = offset + consumed) + union = module.object(symbol = "LF_UNION", offset = offset + consumed) name_offset = union.name.vol.offset - union.vol.offset name = self.parse_string(union.name, leaf_type < leaf_type.LF_ST_MAX, size = remaining - name_offset) result = leaf_type, name, union consumed += remaining elif leaf_type in [leaf_type.LF_MODIFIER, leaf_type.LF_POINTER, leaf_type.LF_PROCEDURE]: - obj = module.object(type_name = leaf_type.lookup(), offset = offset + consumed) + obj = module.object(symbol = leaf_type.lookup(), offset = offset + consumed) result = leaf_type, None, obj consumed += remaining elif leaf_type in [leaf_type.LF_FIELDLIST]: @@ -789,7 +789,7 @@ class PdbReader: fields.append(subfield) result = leaf_type, None, fields elif leaf_type in [leaf_type.LF_BITFIELD]: - bitfield = module.object(type_name = "LF_BITFIELD", offset = offset + consumed) + bitfield = module.object(symbol = "LF_BITFIELD", offset = offset + consumed) result = leaf_type, None, bitfield consumed += remaining else: @@ -873,20 +873,20 @@ class PdbReader: # Set the offset at just after the previous size type offset = value.vol.offset + value.vol.data_format.length if sub_leaf_type in [leaf_type.LF_CHAR]: - value = module.object(type_name = 'char', offset = offset) + value = module.object(symbol = 'char', offset = offset) elif sub_leaf_type in [leaf_type.LF_SHORT]: - value = module.object(type_name = 'short', offset = offset) + value = module.object(symbol = 'short', offset = offset) elif sub_leaf_type in [leaf_type.LF_USHORT]: - value = module.object(type_name = 'unsigned short', offset = offset) + value = module.object(symbol = 'unsigned short', offset = offset) elif sub_leaf_type in [leaf_type.LF_LONG]: - value = module.object(type_name = 'long', offset = offset) + value = module.object(symbol = 'long', offset = offset) elif sub_leaf_type in [leaf_type.LF_ULONG]: - value = module.object(type_name = 'unsigned long', offset = offset) + value = module.object(symbol = 'unsigned long', offset = offset) else: raise TypeError("Unexpected extended value type") excess = value.vol.data_format.length # Updated the consume/offset counters - name = module.object(type_name = "string", offset = value.vol.offset + value.vol.data_format.length) + name = module.object(symbol = "string", offset = value.vol.offset + value.vol.data_format.length) name_str = self.parse_string(name, leaf_type < leaf_type.LF_ST_MAX, size = length - excess) return name_str, value, excess