Merge pull request #1100 from adiego8/windows-psscan-offset

Windows: Add filtering by offset to psscan
This commit is contained in:
ikelos
2024-02-22 10:59:47 +00:00
committed by GitHub
3 changed files with 129 additions and 20 deletions
@@ -13,7 +13,7 @@ from volatility3.framework.renderers import conversion, format_hints
from volatility3.framework.symbols import intermed
from volatility3.framework.symbols.windows.extensions import pe
from volatility3.plugins import timeliner
from volatility3.plugins.windows import info, pslist
from volatility3.plugins.windows import info, pslist, psscan
vollog = logging.getLogger(__name__)
@@ -36,6 +36,9 @@ class DllList(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
requirements.VersionRequirement(
name="pslist", component=pslist.PsList, version=(2, 0, 0)
),
requirements.VersionRequirement(
name="psscan", component=psscan.PsScan, version=(1, 1, 0)
),
requirements.VersionRequirement(
name="info", component=info.Info, version=(1, 0, 0)
),
@@ -45,6 +48,11 @@ class DllList(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
description="Process IDs to include (all other processes are excluded)",
optional=True,
),
requirements.IntRequirement(
name="offset",
description="Process offset in the physical address space",
optional=True,
),
requirements.BooleanRequirement(
name="dump",
description="Extract listed DLLs",
@@ -221,6 +229,25 @@ class DllList(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
filter_func = pslist.PsList.create_pid_filter(self.config.get("pid", None))
kernel = self.context.modules[self.config["kernel"]]
if self.config["offset"]:
procs = psscan.PsScan.scan_processes(
self.context,
kernel.layer_name,
kernel.symbol_table_name,
filter_func=psscan.PsScan.create_offset_filter(
self.context,
kernel.layer_name,
self.config["offset"],
),
)
else:
procs = pslist.PsList.list_processes(
context=self.context,
layer_name=kernel.layer_name,
symbol_table=kernel.symbol_table_name,
filter_func=filter_func,
)
return renderers.TreeGrid(
[
("PID", int),
@@ -232,12 +259,5 @@ class DllList(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
("LoadTime", datetime.datetime),
("File output", str),
],
self._generator(
pslist.PsList.list_processes(
context=self.context,
layer_name=kernel.layer_name,
symbol_table=kernel.symbol_table_name,
filter_func=filter_func,
)
),
self._generator(procs=procs),
)
@@ -9,7 +9,7 @@ from volatility3.framework import constants, exceptions, renderers, interfaces,
from volatility3.framework.configuration import requirements
from volatility3.framework.objects import utility
from volatility3.framework.renderers import format_hints
from volatility3.plugins.windows import pslist
from volatility3.plugins.windows import pslist, psscan
vollog = logging.getLogger(__name__)
@@ -43,14 +43,22 @@ class Handles(interfaces.plugins.PluginInterface):
description="Windows kernel",
architectures=["Intel32", "Intel64"],
),
requirements.PluginRequirement(
name="pslist", plugin=pslist.PsList, version=(2, 0, 0)
),
requirements.VersionRequirement(
name="psscan", component=psscan.PsScan, version=(1, 1, 0)
),
requirements.ListRequirement(
name="pid",
element_type=int,
description="Process IDs to include (all other processes are excluded)",
optional=True,
),
requirements.PluginRequirement(
name="pslist", plugin=pslist.PsList, version=(2, 0, 0)
requirements.IntRequirement(
name="offset",
description="Process offset in the physical address space",
optional=True,
),
]
@@ -416,6 +424,25 @@ class Handles(interfaces.plugins.PluginInterface):
filter_func = pslist.PsList.create_pid_filter(self.config.get("pid", None))
kernel = self.context.modules[self.config["kernel"]]
if self.config["offset"]:
procs = psscan.PsScan.scan_processes(
self.context,
kernel.layer_name,
kernel.symbol_table_name,
filter_func=psscan.PsScan.create_offset_filter(
self.context,
kernel.layer_name,
self.config["offset"],
),
)
else:
procs = pslist.PsList.list_processes(
context=self.context,
layer_name=kernel.layer_name,
symbol_table=kernel.symbol_table_name,
filter_func=filter_func,
)
return renderers.TreeGrid(
[
("PID", int),
@@ -426,12 +453,5 @@ class Handles(interfaces.plugins.PluginInterface):
("GrantedAccess", format_hints.Hex),
("Name", str),
],
self._generator(
pslist.PsList.list_processes(
self.context,
kernel.layer_name,
kernel.symbol_table_name,
filter_func=filter_func,
)
),
self._generator(procs=procs),
)
@@ -59,6 +59,75 @@ class PsScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
),
]
@classmethod
def physical_offset_from_virtual(cls, context, layer_name, proc):
"""Calculate the physical offset from the virtual offset of a process.
Args:
context: The context containing layers and modules information.
layer_name: The name of the layer containing the process memory.
proc: The process object for which to calculate the physical offset.
Returns:
int: The physical offset of the process.
Raises:
TypeError: If the primary layer is not an Intel layer.
"""
memory = context.layers[layer_name]
if not isinstance(memory, layers.intel.Intel):
raise TypeError("Primary layer is not an intel layer")
(_, _, ph_offset, _, _) = list(
memory.mapping(offset=proc.vol.offset, length=0)
)[0]
return ph_offset
@classmethod
def create_offset_filter(
cls,
context: interfaces.context.ContextInterface,
layer_name: str,
offset: int = None,
physical: bool = True,
exclude: bool = False,
) -> Callable[[interfaces.objects.ObjectInterface], bool]:
"""A factory for producing filter functions that filter based on the physical offset of the process.
Args:
offset: A number that is the physical offset to be filtered out
exclude: Accept only tasks that are not the offset argument
Returns:
Filter function to be passed to the list of processes.
"""
filter_func = lambda _: False
if offset:
if physical:
if exclude:
filter_func = (
lambda proc: cls.physical_offset_from_virtual(
context, layer_name, proc
)
== offset
)
else:
filter_func = (
lambda proc: cls.physical_offset_from_virtual(
context, layer_name, proc
)
!= offset
)
else:
if exclude:
filter_func = lambda proc: proc.vol.offset == offset
else:
filter_func = lambda proc: proc.vol.offset != offset
return filter_func
@classmethod
def scan_processes(
cls,