Update the list_threads API to current standards and update current callers to new form

This commit is contained in:
Andrew Case
2025-03-08 00:34:40 +00:00
parent 0b6203cf7a
commit 9fe4092e9f
4 changed files with 20 additions and 16 deletions
@@ -38,7 +38,7 @@ class DebugRegisters(interfaces.plugins.PluginInterface):
name="pslist", component=pslist.PsList, version=(3, 0, 0)
),
requirements.VersionRequirement(
name="threads", component=threads.Threads, version=(2, 0, 0)
name="threads", component=threads.Threads, version=(3, 0, 0)
),
requirements.VersionRequirement(
name="pe_symbols", component=pe_symbols.PESymbols, version=(2, 0, 0)
@@ -111,8 +111,6 @@ class DebugRegisters(interfaces.plugins.PluginInterface):
None,
None,
]:
kernel = self.context.modules[self.config["kernel"]]
vads_cache: Dict[int, pe_symbols.ranges_type] = {}
proc_modules = None
@@ -122,7 +120,9 @@ class DebugRegisters(interfaces.plugins.PluginInterface):
)
for proc in procs:
for thread in threads.Threads.list_threads(kernel, proc):
for thread in threads.Threads.list_threads(
self.context, self.config["kernel"], proc
):
debug_info = self._get_debug_info(thread)
if not debug_info:
continue
@@ -36,7 +36,7 @@ class SuspendedThreads(interfaces.plugins.PluginInterface):
name="pe_symbols", component=pe_symbols.PESymbols, version=(2, 0, 0)
),
requirements.VersionRequirement(
name="threads", component=threads.Threads, version=(2, 0, 0)
name="threads", component=threads.Threads, version=(3, 0, 0)
),
]
@@ -54,8 +54,6 @@ class SuspendedThreads(interfaces.plugins.PluginInterface):
https://www.volexity.com/wp-content/uploads/2024/08/Defcon24_EDR_Evasion_Detection_White-Paper_Andrew-Case.pdf
"""
kernel = self.context.modules[self.config["kernel"]]
vads_cache: Dict[int, pe_symbols.PESymbols.ranges_type] = {}
proc_modules = None
@@ -64,7 +62,9 @@ class SuspendedThreads(interfaces.plugins.PluginInterface):
for proc in pslist.PsList.list_processes(
context=self.context, kernel_module_name=self.config["kernel"]
):
for thread in threads.Threads.list_threads(kernel, proc):
for thread in threads.Threads.list_threads(
self.context, self.config["kernel"], proc
):
try:
# we only care if the thread is suspended
if thread.Tcb.SuspendCount == 0:
@@ -41,7 +41,7 @@ class SuspiciousThreads(interfaces.plugins.PluginInterface):
name="pslist", component=pslist.PsList, version=(3, 0, 0)
),
requirements.VersionRequirement(
name="threads", component=threads.Threads, version=(2, 0, 0)
name="threads", component=threads.Threads, version=(3, 0, 0)
),
requirements.VersionRequirement(
name="vadinfo", component=vadinfo.VadInfo, version=(2, 0, 0)
@@ -169,7 +169,9 @@ class SuspiciousThreads(interfaces.plugins.PluginInterface):
# there is no benefit to checking the same address more than once per process
checked = set()
for thread in threads.Threads.list_threads(kernel, proc):
for thread in threads.Threads.list_threads(
self.context, self.config["kernel"], proc
):
# do not process if a thread is exited or terminated (4 = Terminated)
if thread.ExitTime.QuadPart > 0 or thread.Tcb.State == 4:
continue
@@ -16,7 +16,7 @@ class Threads(thrdscan.ThrdScan):
"""Lists process threads"""
_required_framework_version = (2, 4, 0)
_version = (2, 0, 0)
_version = (3, 0, 0)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@@ -36,9 +36,11 @@ class Threads(thrdscan.ThrdScan):
),
]
@classmethod
@staticmethod
def list_threads(
cls, kernel, proc: interfaces.objects.ObjectInterface
context: interfaces.context.ContextInterface,
kernel_module_name: str,
proc: interfaces.objects.ObjectInterface,
) -> Generator[interfaces.objects.ObjectInterface, None, None]:
"""Lists the Threads of a specific process.
@@ -48,6 +50,8 @@ class Threads(thrdscan.ThrdScan):
Returns:
A list of threads based on the process and filtered based on the filter function
"""
kernel = context.modules[kernel_module_name]
seen = set()
for thread in proc.ThreadListHead.to_list(
f"{kernel.symbol_table_name}{constants.BANG}_ETHREAD", "ThreadListEntry"
@@ -64,8 +68,6 @@ class Threads(thrdscan.ThrdScan):
kernel_module_name: str,
) -> Iterable[interfaces.objects.ObjectInterface]:
"""Runs through all processes and lists threads for each process"""
module = context.modules[kernel_module_name]
filter_func = pslist.PsList.create_pid_filter(context.config.get("pid", None))
for proc in pslist.PsList.list_processes(
@@ -73,4 +75,4 @@ class Threads(thrdscan.ThrdScan):
kernel_module_name=kernel_module_name,
filter_func=filter_func,
):
yield from cls.list_threads(module, proc)
yield from cls.list_threads(context, kernel_module_name, proc)