Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add APIs and initial plugins for GUI support and fit Windows major APIs to current design flow #1640

Open
wants to merge 50 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
8cacdaf
Windows: Adds windows GUI vtypes
dgmcdona Sep 3, 2024
412233a
Windows: Adds windows OS version checks
dgmcdona Sep 4, 2024
406b8af
Windows: Adds GUI plugin
dgmcdona Sep 4, 2024
c534dd4
Windows PsList: Add method for listing procs from kernel
dgmcdona Feb 27, 2025
f6273ef
Windows Modules/Modscan: Clean up APIs
dgmcdona Feb 27, 2025
adf1dcb
Windows SSDT: Simplify `build_module_collection` signature
dgmcdona Feb 27, 2025
6c6113f
Windows SSDT: Updates plugin consumers
dgmcdona Feb 27, 2025
33243a0
Windows HiveList: Update list_hives method signature
dgmcdona Feb 27, 2025
8804907
Windows Hivelist: Update dependents
dgmcdona Feb 27, 2025
42f7bdd
Windows Amcache: Update dependency and change method signature
dgmcdona Feb 27, 2025
6a7bee4
Windows PoolScan: Adds method
dgmcdona Feb 27, 2025
c16987a
Windows SuspiciousThreads: Adds missing requirement, updates other
dgmcdona Feb 27, 2025
1f0da45
Windows UnhookedSystemCalls: Update reqs, add breaking change
dgmcdona Feb 27, 2025
e1083da
Windows Strings: Update pslist req and add breaking change
dgmcdona Feb 27, 2025
3771d74
Windows Orphan Kernel Threads: Update modules dep, add breaking change
dgmcdona Feb 27, 2025
f81cd07
Windows svclist: Update svcscan dependency
dgmcdona Feb 27, 2025
87d05a7
Windows SvcScan: Update reqs, add breaking change
dgmcdona Feb 27, 2025
d576e79
Windows SvcDiff: Update reqs, adds breaking change
dgmcdona Feb 27, 2025
08a2e61
Windows Netstat: Update modules req, adds breaking change
dgmcdona Feb 27, 2025
42b5f5c
Windows Extensions: Fix traceback when accessing peb.Ldr
dgmcdona Feb 27, 2025
4204a19
Windows ScheduledTasks: update hivelist dep, breaking change
dgmcdona Feb 27, 2025
6d23cbd
Windows Shimcachemem: Updates req's, new major version
dgmcdona Feb 27, 2025
8bd2a2e
Windows Indirect Syscalls: Remove unneeded pslist dep
dgmcdona Feb 27, 2025
38333de
Windows Modules: Update dependents
dgmcdona Feb 27, 2025
38677ac
Windows PESymbols: Updates requirements, changes interface
dgmcdona Feb 27, 2025
55e98f2
Windows Suspended Threads: Updates pe_symbols req
dgmcdona Feb 27, 2025
8fdc065
Windows Threads: Change list_process_threads signature
dgmcdona Feb 27, 2025
34e1c98
Windows Threads: Update dependents
dgmcdona Feb 27, 2025
097cdca
Windows Consoles: Update hivelist dep and change method signature
dgmcdona Feb 27, 2025
bf5e791
Windows PsList: Update dependents
dgmcdona Feb 27, 2025
5fbbd45
Windows PEDump: Update PsList dep and change method signature
dgmcdona Feb 27, 2025
27317d1
Windows PEDump: Update dependents
dgmcdona Feb 27, 2025
0993fd1
Windows Scheduled Tasks: Prevent backtraces
atcuno Feb 25, 2025
5422ed3
Windows Versions: Sort version checks for readability
dgmcdona Feb 25, 2025
7f99438
Windows Versions: Add version check for win10 17735 or later
dgmcdona Feb 25, 2025
edafcde
Windows DeskScan: Update pool extension
atcuno Feb 25, 2025
965a2c7
Windows GUI Plugins: Adds three plugins
atcuno Feb 27, 2025
16b4452
Windows WindowStations: Fix issue with native types
dgmcdona Feb 25, 2025
051de2a
Windows GUI Symbols: JSON Lint
dgmcdona Feb 28, 2025
8eb0f24
Windows DeskScan: Add version to class
dgmcdona Feb 27, 2025
434dfcb
Code Review: Fix pslist param
dgmcdona Feb 27, 2025
fc3d76f
Code Review: Simplify dictionary construction
dgmcdona Feb 27, 2025
7db67cc
Code Review: Parameter renaming
dgmcdona Feb 27, 2025
f67e45b
Code Review (style): Use keyword args for clarity
dgmcdona Feb 27, 2025
1cdb17e
Code Review: PluginRequirement -> VersionRequirement
dgmcdona Feb 27, 2025
be16b84
CodeQL Fix: Unused variable
dgmcdona Feb 28, 2025
b534e74
Framework: Minor version bump
dgmcdona Feb 28, 2025
b4228dd
Code Review: Get rid of 'kvo' in favor of kernel.offset
dgmcdona Feb 28, 2025
9d2b0c5
Code Review: Remove redundant kernel module reconstruction
dgmcdona Feb 27, 2025
a553ee3
Code Review: Remove unneeded kernel module reconstruction
dgmcdona Feb 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions doc/source/simple-plugin.rst
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,6 @@ that will be output as part of the :py:class:`~volatility3.framework.interfaces.
def run(self):

filter_func = pslist.PsList.create_pid_filter(self.config.get('pid', None))
kernel = self.context.modules[self.config['kernel']]

return renderers.TreeGrid(
[
Expand All @@ -211,9 +210,8 @@ that will be output as part of the :py:class:`~volatility3.framework.interfaces.
],
self._generator(
pslist.PsList.list_processes(
self.context,
kernel.layer_name,
kernel.symbol_table_name,
context=self.context,
kernel_module_name=self.config['kernel'],
filter_func = filter_func
)
)
Expand All @@ -235,7 +233,7 @@ the :py:class:`~volatility3.plugins.windows.pslist.PsList` plugin. That plugin
so that other plugins can call it. As such, it takes all the necessary parameters rather than accessing them
from a configuration. Since it must be portable code, it takes a context, as well as the layer name,
symbol table and optionally a filter. In this instance we unconditionally
pass it the values from the configuration for the layer and symbol table from the kernel module object, constructed from
pass it the value from the configuration for the kernel module name, constructed from
the ``kernel`` configuration requirement. This will generate a list
of :py:class:`~volatility3.framework.symbols.windows.extensions.EPROCESS` objects, as provided by the :py:class:`~volatility.plugins.windows.pslist.PsList` plugin,
and is not covered here but is used as an example for how to share code across plugins
Expand Down
6 changes: 2 additions & 4 deletions volatility3/cli/volshell/windows.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def get_requirements(cls):
return [
requirements.ModuleRequirement(name="kernel", description="Windows kernel"),
requirements.PluginRequirement(
name="pslist", plugin=pslist.PsList, version=(2, 0, 0)
name="pslist", plugin=pslist.PsList, version=(3, 0, 0)
),
requirements.IntRequirement(
name="pid", description="Process ID", optional=True
Expand All @@ -39,9 +39,7 @@ def list_processes(self):
"""Returns a list of EPROCESS objects from the primary layer"""
# We always use the main kernel memory and associated symbols
return list(
pslist.PsList.list_processes(
self.context, self.current_layer, self.current_symbol_table
)
pslist.PsList.list_processes(self.context, self.current_kernel_name)
)

def get_process(self, pid=None, virtaddr=None, physaddr=None):
Expand Down
2 changes: 1 addition & 1 deletion volatility3/framework/constants/_version.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# We use the SemVer 2.0.0 versioning scheme
VERSION_MAJOR = 2 # Number of releases of the library with a breaking change
VERSION_MINOR = 22 # Number of changes that only add to the interface
VERSION_MINOR = 23 # Number of changes that only add to the interface
VERSION_PATCH = 0 # Number of changes that do not change the interface
VERSION_SUFFIX = ""

Expand Down
2 changes: 1 addition & 1 deletion volatility3/framework/layers/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def __init__(
# Win10 17063 introduced the Registry process to map most hives. Check
# if it exists and update RegistryHive._base_layer
for proc in pslist.PsList.list_processes(
self.context, self.config["base_layer"], self.config["nt_symbols"]
context=self.context, kernel_module_name=self.config["kernel_module_name"]
):
proc_name = proc.ImageFileName.cast(
"string", max_length=proc.ImageFileName.vol.count, errors="replace"
Expand Down
2 changes: 1 addition & 1 deletion volatility3/framework/plugins/linux/bash.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]
def _generator(self, tasks):
vmlinux = self.context.modules[self.config["kernel"]]
is_32bit = not symbols.symbol_table_is_64bit(
self.context, vmlinux.symbol_table_name
context=self.context, symbol_table_name=vmlinux.symbol_table_name
)
if is_32bit:
pack_format = "I"
Expand Down
2 changes: 1 addition & 1 deletion volatility3/framework/plugins/linux/check_idt.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def _generator(self):
)

is_32bit = not symbols.symbol_table_is_64bit(
self.context, vmlinux.symbol_table_name
context=self.context, symbol_table_name=vmlinux.symbol_table_name
)

idt_table_size = 256
Expand Down
2 changes: 1 addition & 1 deletion volatility3/framework/plugins/linux/malfind.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def _generator(self, tasks):
# determine if we're on a 32 or 64 bit kernel
vmlinux = self.context.modules[self.config["kernel"]]
is_32bit_arch = not symbols.symbol_table_is_64bit(
self.context, vmlinux.symbol_table_name
context=self.context, symbol_table_name=vmlinux.symbol_table_name
)

for task in tasks:
Expand Down
4 changes: 3 additions & 1 deletion volatility3/framework/plugins/linux/psscan.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,9 @@ def scan_tasks(
vmlinux = context.modules[vmlinux_module_name]

# check if this image is 32bit or 64bit
is_32bit = not symbols.symbol_table_is_64bit(context, vmlinux.symbol_table_name)
is_32bit = not symbols.symbol_table_is_64bit(
context=context, symbol_table_name=vmlinux.symbol_table_name
)
if is_32bit:
pack_format = "I"
else:
Expand Down
2 changes: 1 addition & 1 deletion volatility3/framework/plugins/mac/bash.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def get_requirements(cls):
def _generator(self, tasks):
darwin = self.context.modules[self.config["kernel"]]
is_32bit = not symbols.symbol_table_is_64bit(
self.context, darwin.symbol_table_name
context=self.context, symbol_table_name=darwin.symbol_table_name
)
if is_32bit:
pack_format = "I"
Expand Down
17 changes: 9 additions & 8 deletions volatility3/framework/plugins/windows/amcache.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,9 @@ class Amcache(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
"""Extract information on executed applications from the AmCache."""

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

# 2.0.0 - changed the signature of get_amcache_hive
_version = (2, 0, 0)

@classmethod
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
Expand All @@ -230,7 +232,7 @@ def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]
architectures=["Intel32", "Intel64"],
),
requirements.PluginRequirement(
name="hivelist", plugin=hivelist.HiveList, version=(1, 0, 0)
name="hivelist", plugin=hivelist.HiveList, version=(2, 0, 0)
),
]

Expand All @@ -252,7 +254,7 @@ def get_amcache_hive(
cls,
context: interfaces.context.ContextInterface,
config_path: str,
kernel: interfaces.context.ModuleInterface,
kernel_module_name: str,
) -> Optional[registry.RegistryHive]:
"""Retrieves the `Amcache.hve` registry hive from the kernel module, if it can be located."""
return next(
Expand All @@ -261,8 +263,7 @@ def get_amcache_hive(
base_config_path=interfaces.configuration.path_join(
config_path, "hivelist"
),
layer_name=kernel.layer_name,
symbol_table=kernel.symbol_table_name,
kernel_module_name=kernel_module_name,
filter_string="amcache",
),
None,
Expand Down Expand Up @@ -523,8 +524,6 @@ def parse_driver_binary_key(
)

def _generator(self) -> Iterator[Tuple[int, _AmcacheEntry]]:
kernel = self.context.modules[self.config["kernel"]]

def indented(
entry_gen: Iterable[_AmcacheEntry], indent: int = 0
) -> Iterator[Tuple[int, _AmcacheEntry]]:
Expand All @@ -533,7 +532,9 @@ def indented(

# Building the dictionary ahead of time is much better for performance
# vs looking up each service's DLL individually.
amcache = self.get_amcache_hive(self.context, self.config_path, kernel)
amcache = self.get_amcache_hive(
self.context, self.config_path, self.config["kernel"]
)
if amcache is None:
return

Expand Down
10 changes: 4 additions & 6 deletions volatility3/framework/plugins/windows/cachedump.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def get_requirements(cls):
architectures=["Intel32", "Intel64"],
),
requirements.PluginRequirement(
name="hivelist", plugin=hivelist.HiveList, version=(1, 0, 0)
name="hivelist", plugin=hivelist.HiveList, version=(2, 0, 0)
),
requirements.PluginRequirement(
name="lsadump", plugin=lsadump.Lsadump, version=(1, 0, 0)
Expand Down Expand Up @@ -169,13 +169,11 @@ def run(self):
offset = self.config.get("offset", None)

syshive = sechive = None
kernel = self.context.modules[self.config["kernel"]]

for hive in hivelist.HiveList.list_hives(
self.context,
self.config_path,
kernel.layer_name,
kernel.symbol_table_name,
context=self.context,
base_config_path=self.config_path,
kernel_module_name=self.config["kernel"],
hive_offsets=None if offset is None else [offset],
):
if hive.get_name().split("\\")[-1].upper() == "SYSTEM":
Expand Down
9 changes: 6 additions & 3 deletions volatility3/framework/plugins/windows/callbacks.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]
architectures=["Intel32", "Intel64"],
),
requirements.PluginRequirement(
name="ssdt", plugin=ssdt.SSDT, version=(1, 0, 0)
name="ssdt", plugin=ssdt.SSDT, version=(2, 0, 0)
),
requirements.PluginRequirement(
name="poolscanner", plugin=poolscanner.PoolScanner, version=(1, 0, 0)
Expand Down Expand Up @@ -187,7 +187,9 @@ def create_callback_symbol_table(
The name of the constructed symbol table
"""
native_types = context.symbol_space[nt_symbol_table].natives
is_64bit = symbols.symbol_table_is_64bit(context, nt_symbol_table)
is_64bit = symbols.symbol_table_is_64bit(
context=context, symbol_table_name=nt_symbol_table
)
table_mapping = {"nt_symbols": nt_symbol_table}

if is_64bit:
Expand Down Expand Up @@ -691,7 +693,8 @@ def _generator(self):
)

collection = ssdt.SSDT.build_module_collection(
self.context, kernel.layer_name, kernel.symbol_table_name
context=self.context,
kernel_module_name=self.config["kernel"],
)

callback_methods = (
Expand Down
15 changes: 7 additions & 8 deletions volatility3/framework/plugins/windows/cmdline.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0
#
import logging
from typing import List
from typing import List, Optional

from volatility3.framework import constants, exceptions, renderers, interfaces
from volatility3.framework.configuration import requirements
Expand All @@ -28,7 +28,7 @@ def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]
architectures=["Intel32", "Intel64"],
),
requirements.PluginRequirement(
name="pslist", plugin=pslist.PsList, version=(2, 0, 0)
name="pslist", plugin=pslist.PsList, version=(3, 0, 0)
),
requirements.ListRequirement(
name="pid",
Expand All @@ -41,7 +41,7 @@ def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]
@classmethod
def get_cmdline(
cls, context: interfaces.context.ContextInterface, kernel_table_name: str, proc
):
) -> Optional[str]:
"""Extracts the cmdline from PEB

Args:
Expand All @@ -54,15 +54,16 @@ def get_cmdline(
"""

proc_layer_name = proc.add_process_layer()
if not proc_layer_name:
return None

peb = context.object(
kernel_table_name + constants.BANG + "_PEB",
layer_name=proc_layer_name,
offset=proc.Peb,
)
result_text = peb.ProcessParameters.CommandLine.get_string()

return result_text
return peb.ProcessParameters.CommandLine.get_string()

def _generator(self, procs):
kernel = self.context.modules[self.config["kernel"]]
Expand Down Expand Up @@ -99,16 +100,14 @@ def _generator(self, procs):
yield (0, (proc.UniqueProcessId, process_name, result_text))

def run(self):
kernel = self.context.modules[self.config["kernel"]]
filter_func = pslist.PsList.create_pid_filter(self.config.get("pid", None))

return renderers.TreeGrid(
[("PID", int), ("Process", str), ("Args", str)],
self._generator(
pslist.PsList.list_processes(
context=self.context,
layer_name=kernel.layer_name,
symbol_table=kernel.symbol_table_name,
kernel_module_name=self.config["kernel"],
filter_func=filter_func,
)
),
Expand Down
20 changes: 8 additions & 12 deletions volatility3/framework/plugins/windows/cmdscan.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,10 @@ def get_requirements(cls):
architectures=["Intel32", "Intel64"],
),
requirements.VersionRequirement(
name="pslist", component=pslist.PsList, version=(2, 0, 0)
name="pslist", component=pslist.PsList, version=(3, 0, 0)
),
requirements.PluginRequirement(
name="consoles", plugin=consoles.Consoles, version=(1, 0, 0)
name="consoles", plugin=consoles.Consoles, version=(2, 0, 0)
),
requirements.BooleanRequirement(
name="no_registry",
Expand Down Expand Up @@ -286,12 +286,11 @@ def _generator(

if no_registry is False:
max_history, _ = consoles.Consoles.get_console_settings_from_registry(
self.context,
self.config_path,
kernel.layer_name,
kernel.symbol_table_name,
max_history,
[],
context=self.context,
config_path=self.config_path,
kernel_module_name=self.config["kernel"],
max_history=max_history,
max_buffers=[],
)

vollog.debug(f"Possible CommandHistorySize values: {max_history}")
Expand Down Expand Up @@ -360,8 +359,6 @@ def _conhost_proc_filter(self, proc: interfaces.objects.ObjectInterface):
return process_name != "conhost.exe"

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

return renderers.TreeGrid(
[
("PID", int),
Expand All @@ -374,8 +371,7 @@ def run(self):
self._generator(
pslist.PsList.list_processes(
context=self.context,
layer_name=kernel.layer_name,
symbol_table=kernel.symbol_table_name,
kernel_module_name=self.config["kernel"],
filter_func=self._conhost_proc_filter,
)
),
Expand Down
Loading
Loading