Skip to content

Commit

Permalink
Merge pull request #1601 from volatilityfoundation/issues/kvo-optional
Browse files Browse the repository at this point in the history
Issues/kvo optional
  • Loading branch information
ikelos authored Feb 9, 2025
2 parents f744d03 + 444376c commit 7e94d76
Show file tree
Hide file tree
Showing 14 changed files with 135 additions and 63 deletions.
8 changes: 6 additions & 2 deletions volatility3/framework/plugins/windows/bigpools.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class BigPools(interfaces.plugins.PluginInterface):
"""List big page pools."""

_required_framework_version = (2, 0, 0)
_version = (1, 1, 0)
_version = (1, 1, 1)

@classmethod
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
Expand Down Expand Up @@ -66,7 +66,11 @@ def list_big_pools(
Yields:
A big page pool object
"""
kvo = context.layers[layer_name].config["kernel_virtual_offset"]
kvo = context.layers[layer_name].config.get("kernel_virtual_offset", None)
if not kvo:
raise ValueError(
"Intel layer does not have an associated kernel virtual offset, failing"
)
ntkrnlmp = context.module(symbol_table, layer_name=layer_name, offset=kvo)

big_page_table_offset = ntkrnlmp.get_symbol("PoolBigPageTable").address
Expand Down
38 changes: 31 additions & 7 deletions volatility3/framework/plugins/windows/callbacks.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class Callbacks(interfaces.plugins.PluginInterface):
"""Lists kernel callbacks and notification routines."""

_required_framework_version = (2, 0, 0)
_version = (2, 0, 0)
_version = (2, 0, 1)

@classmethod
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
Expand Down Expand Up @@ -361,7 +361,11 @@ def list_notify_routines(
A name, location and optional detail string
"""

kvo = context.layers[layer_name].config["kernel_virtual_offset"]
kvo = context.layers[layer_name].config.get("kernel_virtual_offset", None)
if not kvo:
raise ValueError(
"Intel layer does not have an associated kernel virtual offset, failing"
)
ntkrnlmp = context.module(symbol_table, layer_name=layer_name, offset=kvo)

is_vista_or_later = versions.is_vista_or_later(
Expand Down Expand Up @@ -418,7 +422,11 @@ def _list_registry_callbacks_legacy(
Lists all registry callbacks from the old format via the CmpCallBackVector.
"""

kvo = context.layers[layer_name].config["kernel_virtual_offset"]
kvo = context.layers[layer_name].config.get("kernel_virtual_offset", None)
if not kvo:
raise ValueError(
"Intel layer does not have an associated kernel virtual offset, failing"
)
ntkrnlmp = context.module(symbol_table, layer_name=layer_name, offset=kvo)
full_type_name = (
callback_table_name + constants.BANG + "_EX_CALLBACK_ROUTINE_BLOCK"
Expand Down Expand Up @@ -465,7 +473,11 @@ def _list_registry_callbacks_new(
Lists all registry callbacks via the CallbackListHead.
"""

kvo = context.layers[layer_name].config["kernel_virtual_offset"]
kvo = context.layers[layer_name].config.get("kernel_virtual_offset", None)
if not kvo:
raise ValueError(
"Intel layer does not have an associated kernel virtual offset, failing"
)
ntkrnlmp = context.module(symbol_table, layer_name=layer_name, offset=kvo)
full_type_name = callback_table_name + constants.BANG + "_CM_CALLBACK_ENTRY"

Expand Down Expand Up @@ -506,7 +518,11 @@ def list_registry_callbacks(
A name, location and optional detail string
"""

kvo = context.layers[layer_name].config["kernel_virtual_offset"]
kvo = context.layers[layer_name].config.get("kernel_virtual_offset", None)
if not kvo:
raise ValueError(
"Intel layer does not have an associated kernel virtual offset, failing"
)
ntkrnlmp = context.module(symbol_table, layer_name=layer_name, offset=kvo)

if ntkrnlmp.has_symbol("CmpCallBackVector") and ntkrnlmp.has_symbol(
Expand Down Expand Up @@ -562,7 +578,11 @@ def list_bugcheck_reason_callbacks(
A name, location and optional detail string
"""

kvo = context.layers[layer_name].config["kernel_virtual_offset"]
kvo = context.layers[layer_name].config.get("kernel_virtual_offset", None)
if not kvo:
raise ValueError(
"Intel layer does not have an associated kernel virtual offset, failing"
)
ntkrnlmp = context.module(symbol_table, layer_name=layer_name, offset=kvo)

try:
Expand Down Expand Up @@ -626,7 +646,11 @@ def list_bugcheck_callbacks(
A name, location and optional detail string
"""

kvo = context.layers[layer_name].config["kernel_virtual_offset"]
kvo = context.layers[layer_name].config.get("kernel_virtual_offset", None)
if not kvo:
raise ValueError(
"Intel layer does not have an associated kernel virtual offset, failing"
)
ntkrnlmp = context.module(symbol_table, layer_name=layer_name, offset=kvo)

try:
Expand Down
16 changes: 12 additions & 4 deletions volatility3/framework/plugins/windows/handles.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class Handles(interfaces.plugins.PluginInterface):
"""Lists process open handles."""

_required_framework_version = (2, 0, 0)
_version = (2, 0, 0)
_version = (2, 0, 1)

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
Expand Down Expand Up @@ -144,7 +144,11 @@ def get_type_map(

type_map: Dict[int, str] = {}

kvo = context.layers[layer_name].config["kernel_virtual_offset"]
kvo = context.layers[layer_name].config.get("kernel_virtual_offset", None)
if not kvo:
raise ValueError(
"Intel layer does not have an associated kernel virtual offset, failing"
)
ntkrnlmp = context.module(symbol_table, layer_name=layer_name, offset=kvo)

try:
Expand Down Expand Up @@ -202,7 +206,11 @@ def find_cookie(
except exceptions.SymbolError:
return None

kvo = context.layers[layer_name].config["kernel_virtual_offset"]
kvo = context.layers[layer_name].config.get("kernel_virtual_offset", None)
if not kvo:
raise ValueError(
"Intel layer does not have an associated kernel virtual offset, failing"
)
return context.object(
symbol_table + constants.BANG + "unsigned int",
layer_name,
Expand All @@ -216,7 +224,7 @@ def _make_handle_array(self, offset, level, depth=0):
kernel = self.context.modules[self.config["kernel"]]

virtual = kernel.layer_name
kvo = self.context.layers[virtual].config["kernel_virtual_offset"]
kvo = kernel.offset

ntkrnlmp = self.context.module(
kernel.symbol_table_name, layer_name=virtual, offset=kvo
Expand Down
10 changes: 7 additions & 3 deletions volatility3/framework/plugins/windows/info.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class Info(plugins.PluginInterface):
"""Show OS & kernel details of the memory sample being analyzed."""

_required_framework_version = (2, 0, 0)
_version = (1, 0, 0)
_version = (1, 0, 1)

@classmethod
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
Expand Down Expand Up @@ -68,7 +68,9 @@ def get_kernel_module(
if not isinstance(virtual_layer, layers.intel.Intel):
raise TypeError("Virtual Layer is not an intel layer")

kvo = virtual_layer.config["kernel_virtual_offset"]
kvo = virtual_layer.config.get("kernel_virtual_offset", None)
if not kvo:
raise ValueError("Intel layer has no kernel virtual offset defined")

ntkrnlmp = context.module(symbol_table, layer_name=layer_name, offset=kvo)
return ntkrnlmp
Expand Down Expand Up @@ -166,7 +168,9 @@ def get_ntheader_structure(
if not isinstance(virtual_layer, layers.intel.Intel):
raise TypeError("Virtual Layer is not an intel layer")

kvo = virtual_layer.config["kernel_virtual_offset"]
kvo = virtual_layer.config.get("kernel_virtual_offset", None)
if not kvo:
raise ValueError("Intel layer has no kernel virtual offset defined")

pe_table_name = intermed.IntermediateSymbolTable.create(
context,
Expand Down
8 changes: 6 additions & 2 deletions volatility3/framework/plugins/windows/modules.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class Modules(interfaces.plugins.PluginInterface):
"""Lists the loaded kernel modules."""

_required_framework_version = (2, 0, 0)
_version = (2, 0, 0)
_version = (2, 0, 1)

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
Expand Down Expand Up @@ -247,7 +247,11 @@ def list_modules(
A list of Modules as retrieved from PsLoadedModuleList
"""

kvo = context.layers[layer_name].config["kernel_virtual_offset"]
kvo = context.layers[layer_name].config.get("kernel_virtual_offset", None)
if not kvo:
raise ValueError(
"Intel layer does not have an associated kernel virtual offset, failing"
)
ntkrnlmp = context.module(symbol_table, layer_name=layer_name, offset=kvo)

try:
Expand Down
8 changes: 6 additions & 2 deletions volatility3/framework/plugins/windows/pslist.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class PsList(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
"""Lists the processes present in a particular windows memory image."""

_required_framework_version = (2, 0, 0)
_version = (2, 0, 0)
_version = (2, 0, 1)
PHYSICAL_DEFAULT = False

@classmethod
Expand Down Expand Up @@ -226,7 +226,11 @@ def list_processes(
"""

# We only use the object factory to demonstrate how to use one
kvo = context.layers[layer_name].config["kernel_virtual_offset"]
kvo = context.layers[layer_name].config.get("kernel_virtual_offset", None)
if not kvo:
raise ValueError(
"Intel layer does not have an associated kernel virtual offset, failing"
)
ntkrnlmp = context.module(symbol_table, layer_name=layer_name, offset=kvo)

ps_aph_offset = ntkrnlmp.get_symbol("PsActiveProcessHead").address
Expand Down
9 changes: 6 additions & 3 deletions volatility3/framework/plugins/windows/psscan.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class PsScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
"""Scans for processes present in a particular windows memory image."""

_required_framework_version = (2, 3, 1)
_version = (1, 1, 0)
_version = (1, 1, 1)

@classmethod
def get_requirements(cls):
Expand Down Expand Up @@ -194,9 +194,12 @@ def virtual_process_from_physical(

# If it's WinXP->8.1 we have now a physical process address.
# We'll use the first thread to bounce back to the virtual process
kvo = context.layers[layer_name].config["kernel_virtual_offset"]
kvo = context.layers[layer_name].config.get("kernel_virtual_offset", None)
if not kvo:
raise ValueError(
"Intel layer does not have an associated kernel virtual offset, failing"
)
ntkrnlmp = context.module(symbol_table, layer_name=layer_name, offset=kvo)

tleoffset = ntkrnlmp.get_type("_ETHREAD").relative_child_offset(
"ThreadListEntry"
)
Expand Down
14 changes: 8 additions & 6 deletions volatility3/framework/plugins/windows/registry/hivelist.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def invalid(self) -> Optional[int]:
class HiveList(interfaces.plugins.PluginInterface):
"""Lists the registry hives present in a particular memory image."""

_version = (1, 0, 0)
_version = (1, 0, 1)
_required_framework_version = (2, 0, 0)

@classmethod
Expand All @@ -59,7 +59,7 @@ def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]
default=None,
),
requirements.PluginRequirement(
name="hivescan", plugin=hivescan.HiveScan, version=(1, 0, 0)
name="hivescan", plugin=hivescan.HiveScan, version=(2, 0, 0)
),
requirements.BooleanRequirement(
name="dump",
Expand Down Expand Up @@ -215,7 +215,11 @@ def list_hive_objects(
"""

# We only use the object factory to demonstrate how to use one
kvo = context.layers[layer_name].config["kernel_virtual_offset"]
kvo = context.layers[layer_name].config.get("kernel_virtual_offset", None)
if not kvo:
raise ValueError(
"Intel layer does not have an associated kernel virtual offset, failing"
)
ntkrnlmp = context.module(symbol_table, layer_name=layer_name, offset=kvo)

list_head = ntkrnlmp.get_symbol("CmpHiveListHead").address
Expand Down Expand Up @@ -278,9 +282,7 @@ def list_hive_objects(
f"Hivelist failed traversing backwards at {hex(backward_invalid)}, a different "
"location from forwards, revert to scanning"
)
for hive in hivescan.HiveScan.scan_hives(
context, layer_name, symbol_table
):
for hive in hivescan.HiveScan.scan_hives(context, ntkrnlmp.name):
try:
if hive.HiveList.Flink:
start_hive_offset = hive.HiveList.Flink - reloff
Expand Down
31 changes: 14 additions & 17 deletions volatility3/framework/plugins/windows/registry/hivescan.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class HiveScan(interfaces.plugins.PluginInterface):
"""Scans for registry hives present in a particular windows memory image."""

_required_framework_version = (2, 0, 0)
_version = (1, 0, 0)
_version = (2, 0, 0)

@classmethod
def get_requirements(cls):
Expand All @@ -35,10 +35,7 @@ def get_requirements(cls):

@classmethod
def scan_hives(
cls,
context: interfaces.context.ContextInterface,
layer_name: str,
symbol_table: str,
cls, context: interfaces.context.ContextInterface, kernel_name: str
) -> Iterable[interfaces.objects.ObjectInterface]:
"""Scans for hives using the poolscanner module and constraints or bigpools module with tag.
Expand All @@ -51,17 +48,21 @@ def scan_hives(
A list of Hive objects as found from the `layer_name` layer based on Hive pool signatures
"""

is_64bit = symbols.symbol_table_is_64bit(context, symbol_table)
kernel = context.modules[kernel_name]

is_64bit = symbols.symbol_table_is_64bit(context, kernel.symbol_table_name)
is_windows_8_1_or_later = versions.is_windows_8_1_or_later(
context=context, symbol_table=symbol_table
context=context, symbol_table=kernel.symbol_table_name
)

if is_windows_8_1_or_later and is_64bit:
kvo = context.layers[layer_name].config["kernel_virtual_offset"]
ntkrnlmp = context.module(symbol_table, layer_name=layer_name, offset=kvo)
ntkrnlmp = kernel

for pool in bigpools.BigPools.list_big_pools(
context, layer_name=layer_name, symbol_table=symbol_table, tags=["CM10"]
context,
layer_name=kernel.layer_name,
symbol_table=kernel.symbol_table_name,
tags=["CM10"],
):
cmhive = ntkrnlmp.object(
object_type="_CMHIVE", offset=pool.Va, absolute=True
Expand All @@ -70,21 +71,17 @@ def scan_hives(

else:
constraints = poolscanner.PoolScanner.builtin_constraints(
symbol_table, [b"CM10"]
kernel.symbol_table_name, [b"CM10"]
)

for result in poolscanner.PoolScanner.generate_pool_scan(
context, layer_name, symbol_table, constraints
context, kernel.layer_name, kernel.symbol_table_name, constraints
):
_constraint, mem_object, _header = result
yield mem_object

def _generator(self):
kernel = self.context.modules[self.config["kernel"]]

for hive in self.scan_hives(
self.context, kernel.layer_name, kernel.symbol_table_name
):
for hive in self.scan_hives(self.context, self.config["kernel"]):
yield (0, (format_hints.Hex(hive.vol.offset),))

def run(self):
Expand Down
8 changes: 3 additions & 5 deletions volatility3/framework/plugins/windows/ssdt.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class SSDT(plugins.PluginInterface):
"""Lists the system call table."""

_required_framework_version = (2, 0, 0)
_version = (1, 0, 0)
_version = (1, 0, 1)

@classmethod
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
Expand Down Expand Up @@ -89,10 +89,8 @@ def _generator(self) -> Iterator[Tuple[int, Tuple[int, int, Any, Any]]]:
self.context, layer_name, kernel.symbol_table_name
)

kvo = self.context.layers[layer_name].config["kernel_virtual_offset"]
ntkrnlmp = self.context.module(
kernel.symbol_table_name, layer_name=layer_name, offset=kvo
)
ntkrnlmp = kernel
kvo = kernel.offset

# this is just one way to enumerate the native (NT) service table.
# to do the same thing for the Win32K service table, we would need Win32K.sys symbol support
Expand Down
Loading

0 comments on commit 7e94d76

Please sign in to comment.