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).
This commit is contained in:
Mike Auty
2019-08-14 20:50:42 +01:00
committed by ikelos
parent 95ac651f7e
commit 5362e2094e
27 changed files with 146 additions and 131 deletions
+2 -2
View File
@@ -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
+1 -1
View File
@@ -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:
@@ -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
+47 -32
View File
@@ -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
+8 -5
View File
@@ -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"""
+5 -6
View File
@@ -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"))
@@ -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))
@@ -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:
+3 -3
View File
@@ -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]
+3 -3
View File
@@ -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):
@@ -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)
@@ -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())
@@ -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:
+3 -3
View File
@@ -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")
+3 -3
View File
@@ -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:
@@ -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)
@@ -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)
+4 -5
View File
@@ -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",
@@ -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
@@ -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
@@ -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):
@@ -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()
+4 -4
View File
@@ -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)
@@ -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
+1 -8
View File
@@ -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])
@@ -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
+21 -21
View File
@@ -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