Skip to content

Commit

Permalink
Merge branch 'develop' into modxview_plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
Abyss-W4tcher authored Jan 16, 2025
2 parents cd8690a + a677714 commit cf4389e
Show file tree
Hide file tree
Showing 15 changed files with 61 additions and 42 deletions.
1 change: 1 addition & 0 deletions volatility3/cli/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,7 @@ def run(self):
plugin,
help=plugin_list[plugin].__doc__,
description=plugin_list[plugin].__doc__,
epilog=plugin_list[plugin].additional_description,
)
self.populate_requirements_argparse(plugin_parser, plugin_list[plugin])

Expand Down
2 changes: 2 additions & 0 deletions volatility3/framework/interfaces/plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ class PluginInterface(
# Be careful with inheritance around this (We default to requiring a version which doesn't exist, so it must be set)
_required_framework_version: Tuple[int, int, int] = (0, 0, 0)
"""The _version variable is a quick way for plugins to define their current interface, it should follow SemVer rules"""
additional_description: str = None
"""Display additional description of the plugin after the description of the arguments. See: https://docs.python.org/3/library/argparse.html#epilog"""

def __init__(
self,
Expand Down
6 changes: 3 additions & 3 deletions volatility3/framework/layers/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,9 +192,9 @@ def get_key(
while key_array and node_key:
subkeys = node_key[-1].get_subkeys()
for subkey in subkeys:
# registry keys are not case sensitive so compare lowercase
# https://msdn.microsoft.com/en-us/library/windows/desktop/ms724946(v=vs.85).aspx
if subkey.get_name().lower() == key_array[0].lower():
# registry keys are not case sensitive so compare likewise
# https://learn.microsoft.com/en-us/windows/win32/sysinfo/structure-of-the-registry
if subkey.get_name().casefold() == key_array[0].casefold():
node_key = node_key + [subkey]
found_key, key_array = found_key + [key_array[0]], key_array[1:]
break
Expand Down
4 changes: 2 additions & 2 deletions volatility3/framework/plugins/linux/bash.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# This file is Copyright 2019 Volatility Foundation and licensed under the Volatility Software License 1.0
# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0
#
"""A module containing a collection of plugins that produce data typically
found in Linux's /proc file system."""
"""A module containing a plugin that recovers bash command history
from bash process memory."""

import datetime
import struct
Expand Down
4 changes: 2 additions & 2 deletions volatility3/framework/plugins/linux/check_afinfo.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# This file is Copyright 2019 Volatility Foundation and licensed under the Volatility Software License 1.0
# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0
#
"""A module containing a collection of plugins that produce data typically
found in Linux's /proc file system."""
"""A module containing a plugin that verifies the operation function
pointers of network protocols."""
import logging
from typing import List

Expand Down
3 changes: 1 addition & 2 deletions volatility3/framework/plugins/linux/check_syscall.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
# This file is Copyright 2019 Volatility Foundation and licensed under the Volatility Software License 1.0
# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0
#
"""A module containing a collection of plugins that produce data typically
found in Linux's /proc file system."""
"""A module containing a plugin that checks the system call table for hooks."""
import contextlib
import logging
from typing import List
Expand Down
4 changes: 2 additions & 2 deletions volatility3/framework/plugins/linux/elfs.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# This file is Copyright 2019 Volatility Foundation and licensed under the Volatility Software License 1.0
# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0
#
"""A module containing a collection of plugins that produce data typically
found in Linux's /proc file system."""
"""A module containing a plugin for enumerating memory-mapped
ELF files across all processes."""

import logging
from typing import List, Optional, Type
Expand Down
14 changes: 10 additions & 4 deletions volatility3/framework/plugins/linux/envars.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import logging
from typing import Iterable, Tuple

from volatility3.framework import renderers, interfaces
from volatility3.framework import renderers, interfaces, exceptions
from volatility3.framework.configuration import requirements
from volatility3.framework.interfaces import plugins
from volatility3.framework.objects import utility
Expand Down Expand Up @@ -58,10 +58,16 @@ def get_task_env_variables(
Tuples of (key, value) representing each environment variable.
"""

task_name = utility.array_to_string(task.comm)
# This ensures the `task` is valid as well as its
# memory mapping structures
try:
task_name = utility.array_to_string(task.comm)
env_start = task.mm.env_start
env_end = task.mm.env_end
except exceptions.InvalidAddressException:
return None

task_pid = task.pid
env_start = task.mm.env_start
env_end = task.mm.env_end
env_area_size = env_end - env_start
if not (0 < env_area_size <= env_area_max_size):
vollog.debug(
Expand Down
3 changes: 1 addition & 2 deletions volatility3/framework/plugins/linux/lsmod.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
# This file is Copyright 2019 Volatility Foundation and licensed under the Volatility Software License 1.0
# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0
#
"""A module containing a collection of plugins that produce data typically
found in Linux's /proc file system."""
"""A module containing a plugin that lists loaded kernel modules."""

import logging
from typing import List, Iterable
Expand Down
9 changes: 5 additions & 4 deletions volatility3/framework/plugins/windows/cmdscan.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ def get_filtered_vads(
Args:
conhost_proc: the process object for conhost.exe
size_filter: size above which vads will not be returned
Returns:
A list of tuples of:
Expand Down Expand Up @@ -99,8 +100,8 @@ def get_command_history(
kernel_layer_name: The name of the layer on which to operate
kernel_symbol_table_name: The name of the table containing the kernel symbols
config_path: The config path where to find symbol files
procs: list of process objects
max_history: an initial set of CommandHistorySize values
procs: List of process objects
max_history: An initial set of CommandHistorySize values
Returns:
The conhost process object, the command history structure, a dictionary of properties for
Expand Down Expand Up @@ -227,7 +228,6 @@ def get_command_history(
"data": command_history.CommandCountMax,
}
)

command_history_properties.append(
{
"level": 1,
Expand All @@ -236,6 +236,7 @@ def get_command_history(
"data": "",
}
)

for (
cmd_index,
bucket_cmd,
Expand Down Expand Up @@ -352,7 +353,7 @@ def _generator(

def _conhost_proc_filter(self, proc: interfaces.objects.ObjectInterface):
"""
Used to filter to only conhost.exe processes
Used to filter only conhost.exe processes
"""
process_name = utility.array_to_string(proc.ImageFileName)

Expand Down
2 changes: 1 addition & 1 deletion volatility3/framework/plugins/windows/driverscan.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def get_names_for_driver(cls, driver):
names associated with a driver
Args:
driver: A Eriver object
driver: A Driver object
Returns:
A tuple of strings of (driver name, service key, driver alt. name)
Expand Down
18 changes: 9 additions & 9 deletions volatility3/framework/plugins/windows/shimcachemem.py
Original file line number Diff line number Diff line change
Expand Up @@ -305,14 +305,14 @@ def try_get_shim_head_at_offset(
If a number of validity checks are passed, this method will return the `SHIM_CACHE_HEAD`
object. Otherwise, `None` is returned.
"""
# print("checking RTL_AVL_TABLE at offset %s" % hex(offset))
# Check RTL_AVL_TABLE at offset
rtl_avl_table = context.object(
symbol_table + constants.BANG + "_RTL_AVL_TABLE", layer_name, offset
)
if not rtl_avl_table.is_valid(mod_page_start, mod_page_end):
return None

vollog.debug(f"Candidate RTL_AVL_TABLE found at offset {hex(offset)}")
vollog.debug(f"Candidate RTL_AVL_TABLE found at offset {offset:#x}")

ersrc_size = context.symbol_space.get_type(
kernel_symbol_table + constants.BANG + "_ERESOURCE"
Expand All @@ -324,13 +324,13 @@ def try_get_shim_head_at_offset(
# 0x20 if context.symbol_space.get_type("pointer").size == 8 else 0x10
)
vollog.debug(
f"ERESOURCE size: {hex(ersrc_size)}, ERESOURCE alignment: {hex(ersrc_alignment)}"
f"ERESOURCE size: {ersrc_size:#x}, ERESOURCE alignment: {ersrc_alignment:#x}"
)

eresource_rel_off = ersrc_size + ((offset - ersrc_size) % ersrc_alignment)
eresource_offset = offset - eresource_rel_off

vollog.debug(f"Constructing ERESOURCE at {hex(eresource_offset)}")
vollog.debug(f"Constructing ERESOURCE at {eresource_offset:#x}")
eresource = context.object(
kernel_symbol_table + constants.BANG + "_ERESOURCE",
layer_name,
Expand Down Expand Up @@ -408,8 +408,8 @@ def find_shimcache_win_8_or_later(
# iterate over ahcache kernel module's .data section in search of *two* SHIM handles
shim_heads = []

vollog.debug(f"PAGE offset: {hex(mod_page_offset)}")
vollog.debug(f".data offset: {hex(data_sec_offset)}")
vollog.debug(f"PAGE offset: {mod_page_offset:#x}")
vollog.debug(f".data offset: {data_sec_offset:#x}")

handle_type = context.symbol_space.get_type(
shimcache_symbol_table + constants.BANG + "SHIM_CACHE_HANDLE"
Expand All @@ -419,7 +419,7 @@ def find_shimcache_win_8_or_later(
data_sec_offset + data_sec_size,
8 if symbols.symbol_table_is_64bit(context, nt_symbol_table) else 4,
):
vollog.debug(f"Building shim handle pointer at {hex(offset)}")
vollog.debug(f"Building shim handle pointer at {offset:#x}")
shim_handle = context.object(
object_type=shimcache_symbol_table + constants.BANG + "pointer",
layer_name=kernel_layer_name,
Expand All @@ -430,7 +430,7 @@ def find_shimcache_win_8_or_later(
if shim_handle.is_valid(mod_page_offset, mod_page_offset + mod_page_size):
if shim_handle.head is not None:
vollog.debug(
f"Found valid shim handle @ {hex(shim_handle.vol.offset)}"
f"Found valid shim handle @ {shim_handle.vol.offset:#x}"
)
shim_heads.append(shim_handle.head)
if len(shim_heads) == 2:
Expand All @@ -440,7 +440,7 @@ def find_shimcache_win_8_or_later(
vollog.debug("Failed to identify two valid SHIM_CACHE_HANDLE structures")
return

# On Windows 8 x64, the frist cache contains the shim cache
# On Windows 8 x64, the first cache contains the shim cache.
# On Windows 8 x86, 8.1 x86/x64, and 10, the second cache contains the shim cache.
if (
not symbols.symbol_table_is_64bit(context, nt_symbol_table)
Expand Down
11 changes: 6 additions & 5 deletions volatility3/framework/renderers/conversion.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def wintime_to_datetime(
unix_time = wintime // 10000000
if unix_time == 0:
return renderers.NotApplicableValue()
unix_time = unix_time - 11644473600
unix_time -= 11644473600
try:
return datetime.datetime.fromtimestamp(unix_time, datetime.timezone.utc)
# Windows sometimes throws OSErrors rather than ValueError/OverflowError when it can't convert a value
Expand Down Expand Up @@ -71,7 +71,7 @@ def round(addr: int, align: int, up: bool = False) -> int:
Args:
addr: the address
align: the alignment value
up: Whether to round up or not
up: whether to round up or not
Returns:
The aligned address
Expand Down Expand Up @@ -122,11 +122,12 @@ def convert_port(port_as_integer):


def convert_network_four_tuple(family, four_tuple):
"""Converts the connection four_tuple: (source ip, source port, dest ip,
dest port)
"""Converts the connection four_tuple:
(source ip, source port, dest ip, dest port)
into their string equivalents. IP addresses are expected as a tuple
of unsigned shorts Ports are converted to proper endianness as well
of unsigned shorts. Ports are converted to proper endianness as well.
"""

if family == socket.AF_INET:
Expand Down
6 changes: 4 additions & 2 deletions volatility3/framework/symbols/linux/extensions/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -323,9 +323,11 @@ def add_process_layer(
raise TypeError(
"Parent layer is not a translation layer, unable to construct process layer"
)
dtb, layer_name = parent_layer.translate(pgd)
if not dtb:
try:
dtb, layer_name = parent_layer.translate(pgd)
except exceptions.InvalidAddressException:
return None

if preferred_name is None:
preferred_name = self.vol.layer_name + f"_Process{self.pid}"
# Add the constructed layer and return the name
Expand Down
16 changes: 12 additions & 4 deletions volatility3/plugins/windows/registry/certificates.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import contextlib
import logging
import struct
from typing import List, Iterator, Optional, Tuple, Type
from typing import Iterator, List, Optional, Tuple, Type

from volatility3.framework import exceptions, interfaces, renderers
from volatility3.framework.configuration import requirements
from volatility3.framework.symbols.windows.extensions.registry import RegValueTypes
from volatility3.framework.symbols.windows.extensions import registry
from volatility3.plugins.windows.registry import hivelist, printkey

vollog = logging.getLogger(__name__)
Expand Down Expand Up @@ -81,7 +81,11 @@ def _generator(self) -> Iterator[Tuple[int, Tuple[str, str, str, str]]]:
"Microsoft\\SystemCertificates",
"Software\\Microsoft\\SystemCertificates",
]:
with contextlib.suppress(KeyError, exceptions.InvalidAddressException):
with contextlib.suppress(
KeyError,
registry.RegistryFormatException,
exceptions.InvalidAddressException,
):
# Walk it
node_path = hive.get_key(top_key, return_list=True)
for (
Expand All @@ -92,7 +96,11 @@ def _generator(self) -> Iterator[Tuple[int, Tuple[str, str, str, str]]]:
_volatility,
node,
) in printkey.PrintKey.key_iterator(hive, node_path, recurse=True):
if not is_key and RegValueTypes(node.Type).name == "REG_BINARY":
if (
not is_key
and registry.RegValueTypes(node.Type)
== registry.RegValueTypes.REG_BINARY
):
name, certificate_data = self.parse_data(node.decode_data())
unique_key_offset = (
key_path.casefold().index(top_key.casefold())
Expand Down

0 comments on commit cf4389e

Please sign in to comment.