From 5e96327cb0851fe75d1c7a4cb9ef27641bf119f7 Mon Sep 17 00:00:00 2001 From: Mike Auty Date: Sun, 21 Jul 2024 22:58:43 +0100 Subject: [PATCH 1/3] Add in threads that only provides an implmentation method --- .../framework/plugins/windows/thrdscan.py | 32 +++++++++++------ .../framework/plugins/windows/threads.py | 34 +++++++++++++------ 2 files changed, 45 insertions(+), 21 deletions(-) diff --git a/volatility3/framework/plugins/windows/thrdscan.py b/volatility3/framework/plugins/windows/thrdscan.py index bbf65cd6c..be7097347 100644 --- a/volatility3/framework/plugins/windows/thrdscan.py +++ b/volatility3/framework/plugins/windows/thrdscan.py @@ -3,7 +3,7 @@ ## import logging import datetime -from typing import Iterable +from typing import Callable, Iterable from volatility3.framework import renderers, interfaces, exceptions from volatility3.framework.configuration import requirements @@ -21,6 +21,10 @@ class ThrdScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface) _required_framework_version = (2, 6, 0) _version = (1, 0, 0) + def __init__(self, *args, **kwargs): + self.implementation = self.scan_threads + super().__init__(*args, **kwargs) + @classmethod def get_requirements(cls): return [ @@ -38,8 +42,7 @@ class ThrdScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface) def scan_threads( cls, context: interfaces.context.ContextInterface, - layer_name: str, - symbol_table: str, + module_name: str, ) -> Iterable[interfaces.objects.ObjectInterface]: """Scans for threads using the poolscanner module and constraints. @@ -52,6 +55,10 @@ class ThrdScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface) A list of _ETHREAD objects found by scanning memory for the "Thre" / "Thr\\xE5" pool signatures """ + module = context.modules[module_name] + layer_name = module.layer_name + symbol_table = module.symbol_table_name + constraints = poolscanner.PoolScanner.builtin_constraints( symbol_table, [b"Thr\xe5", b"Thre"] ) @@ -76,7 +83,7 @@ class ThrdScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface) ethread.get_exit_time() ) # datetime.datetime object / volatility3.framework.renderers.UnparsableValue object except exceptions.InvalidAddressException: - vollog.debug("Thread invalid address {:#x}".format(thread.vol.offset)) + vollog.debug("Thread invalid address {:#x}".format(ethread.vol.offset)) return None return ( @@ -88,12 +95,10 @@ class ThrdScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface) thread_exit_time, ) - def _generator(self): - kernel = self.context.modules[self.config["kernel"]] + def _generator(self, filter_func: Callable): + kernel_name = self.config["kernel"] - for ethread in self.scan_threads( - self.context, kernel.layer_name, kernel.symbol_table_name - ): + for ethread in self.implementation(self.context, kernel_name): info = self.gather_thread_info(ethread) if info: yield (0, info) @@ -126,7 +131,14 @@ class ThrdScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface) row_dict["ExitTime"], ) + @classmethod + def filter_func(cls, config: interfaces.configuration.HierarchicalDict) -> Callable: + """Returns a function that can filter this plugin's implementation method based on the config""" + return lambda x: False + def run(self): + filt_func = self.filter_func(self.config) + return renderers.TreeGrid( [ ("Offset", format_hints.Hex), @@ -136,5 +148,5 @@ class ThrdScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface) ("CreateTime", datetime.datetime), ("ExitTime", datetime.datetime), ], - self._generator(), + self._generator(filt_func), ) diff --git a/volatility3/framework/plugins/windows/threads.py b/volatility3/framework/plugins/windows/threads.py index 83d231abb..55720c6f3 100644 --- a/volatility3/framework/plugins/windows/threads.py +++ b/volatility3/framework/plugins/windows/threads.py @@ -3,7 +3,7 @@ # import logging -from typing import List, Generator +from typing import Callable, Iterable, List, Generator from volatility3.framework import interfaces, constants from volatility3.framework.configuration import requirements @@ -18,6 +18,9 @@ class Threads(thrdscan.ThrdScan): _required_framework_version = (2, 4, 0) _version = (1, 0, 0) + def __init__(self): + self.implementation = self.list_process_threads + @classmethod def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: # Since we're calling the plugin, make sure we have the plugin's requirements @@ -60,18 +63,27 @@ class Threads(thrdscan.ThrdScan): seen.add(thread.vol.offset) yield thread - def _generator(self): - kernel = self.context.modules[self.config["kernel"]] + @classmethod + def filter_func(cls, config: interfaces.configuration.HierarchicalDict) -> Callable: + return pslist.PsList.create_pid_filter(config.get("pid", None)) - filter_func = pslist.PsList.create_pid_filter(self.config.get("pid", None)) + @classmethod + def list_process_threads( + cls, + context: interfaces.context.ContextInterface, + module_name: str, + filter_func: Callable, + ) -> Iterable[interfaces.objects.ObjectInterface]: + """Runs through all processes and lists threads for each process""" + module = context.modules[module_name] + layer_name = module.layer_name + symbol_table_name = module.symbol_table_name for proc in pslist.PsList.list_processes( - context=self.context, - layer_name=kernel.layer_name, - symbol_table=kernel.symbol_table_name, + context=context, + layer_name=layer_name, + symbol_table=symbol_table_name, filter_func=filter_func, ): - for thread in self.list_threads(kernel, proc): - info = self.gather_thread_info(thread) - if info: - yield (0, info) + for thread in cls.list_threads(module, proc): + yield thread From e1065f9e788322faded83520da29cd5cbcd5d5ed Mon Sep 17 00:00:00 2001 From: Mike Auty Date: Wed, 24 Jul 2024 20:32:36 +0100 Subject: [PATCH 2/3] Fix up a missing super which @atcuno spotted --- volatility3/framework/plugins/windows/threads.py | 1 + 1 file changed, 1 insertion(+) diff --git a/volatility3/framework/plugins/windows/threads.py b/volatility3/framework/plugins/windows/threads.py index 55720c6f3..d57911650 100644 --- a/volatility3/framework/plugins/windows/threads.py +++ b/volatility3/framework/plugins/windows/threads.py @@ -20,6 +20,7 @@ class Threads(thrdscan.ThrdScan): def __init__(self): self.implementation = self.list_process_threads + super().__init__() @classmethod def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: From f4cbed856bcfb011707588d5563cd7144450ba1e Mon Sep 17 00:00:00 2001 From: Mike Auty Date: Wed, 24 Jul 2024 20:47:05 +0100 Subject: [PATCH 3/3] Fix up missing filter parameter --- volatility3/framework/plugins/windows/thrdscan.py | 7 +++++-- volatility3/framework/plugins/windows/threads.py | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/volatility3/framework/plugins/windows/thrdscan.py b/volatility3/framework/plugins/windows/thrdscan.py index be7097347..6e664e052 100644 --- a/volatility3/framework/plugins/windows/thrdscan.py +++ b/volatility3/framework/plugins/windows/thrdscan.py @@ -19,7 +19,7 @@ class ThrdScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface) # version 2.6.0 adds support for scanning for 'Ethread' structures by pool tags _required_framework_version = (2, 6, 0) - _version = (1, 0, 0) + _version = (1, 1, 0) def __init__(self, *args, **kwargs): self.implementation = self.scan_threads @@ -100,11 +100,14 @@ class ThrdScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface) for ethread in self.implementation(self.context, kernel_name): info = self.gather_thread_info(ethread) + if info: yield (0, info) def generate_timeline(self): - for row in self._generator(): + filt_func = self.filter_func(self.config) + + for row in self._generator(filt_func): _depth, row_data = row row_dict = {} ( diff --git a/volatility3/framework/plugins/windows/threads.py b/volatility3/framework/plugins/windows/threads.py index d57911650..ae70e717b 100644 --- a/volatility3/framework/plugins/windows/threads.py +++ b/volatility3/framework/plugins/windows/threads.py @@ -38,7 +38,7 @@ class Threads(thrdscan.ThrdScan): optional=True, ), requirements.PluginRequirement( - name="thrdscan", plugin=thrdscan.ThrdScan, version=(1, 0, 0) + name="thrdscan", plugin=thrdscan.ThrdScan, version=(1, 1, 0) ), ]