mirror of
https://github.com/volatilityfoundation/volatility3.git
synced 2026-09-02 14:28:58 +02:00
Merge branch 'develop' into additional_windows_testing
This commit is contained in:
@@ -9,7 +9,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: astral-sh/ruff-action@v1
|
||||
- uses: astral-sh/ruff-action@v3.2.1
|
||||
with:
|
||||
args: check
|
||||
src: "."
|
||||
|
||||
@@ -53,9 +53,9 @@ to be able to run properly. Any that are defined as optional need not necessari
|
||||
description = "Process IDs to include (all other processes are excluded)",
|
||||
optional = True
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
requirements.VersionRequirement(
|
||||
name = 'pslist',
|
||||
plugin = pslist.PsList,
|
||||
component = pslist.PsList,
|
||||
version = (2, 0, 0)
|
||||
),
|
||||
]
|
||||
|
||||
@@ -8,6 +8,7 @@ import random
|
||||
import string
|
||||
import struct
|
||||
import sys
|
||||
import textwrap
|
||||
from typing import Any, Dict, Iterable, List, Optional, Tuple, Type, Union
|
||||
from urllib import parse, request
|
||||
|
||||
@@ -23,6 +24,14 @@ try:
|
||||
except ImportError:
|
||||
has_capstone = False
|
||||
|
||||
try:
|
||||
from IPython import terminal
|
||||
from traitlets import config as traitlets_config
|
||||
|
||||
has_ipython = True
|
||||
except ImportError:
|
||||
has_ipython = False
|
||||
|
||||
|
||||
class Volshell(interfaces.plugins.PluginInterface):
|
||||
"""Shell environment to directly interact with a memory image."""
|
||||
@@ -51,7 +60,13 @@ class Volshell(interfaces.plugins.PluginInterface):
|
||||
description="File to load and execute at start",
|
||||
default=None,
|
||||
optional=True,
|
||||
)
|
||||
),
|
||||
requirements.BooleanRequirement(
|
||||
name="script-only",
|
||||
description="Exit volshell after the script specified in --script completes",
|
||||
default=False,
|
||||
optional=True,
|
||||
),
|
||||
]
|
||||
return reqs + [
|
||||
requirements.TranslationLayerRequirement(
|
||||
@@ -69,43 +84,70 @@ class Volshell(interfaces.plugins.PluginInterface):
|
||||
"""
|
||||
|
||||
# Try to enable tab completion
|
||||
try:
|
||||
import readline
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
import rlcompleter
|
||||
if not has_ipython:
|
||||
try:
|
||||
import readline
|
||||
import rlcompleter
|
||||
|
||||
completer = rlcompleter.Completer(namespace=self._construct_locals_dict())
|
||||
readline.set_completer(completer.complete)
|
||||
readline.parse_and_bind("tab: complete")
|
||||
print("Readline imported successfully")
|
||||
completer = rlcompleter.Completer(
|
||||
namespace=self._construct_locals_dict()
|
||||
)
|
||||
readline.set_completer(completer.complete)
|
||||
readline.parse_and_bind("tab: complete")
|
||||
print("Readline imported successfully")
|
||||
except ImportError:
|
||||
print(
|
||||
"Readline or rlcompleter module could not be imported. Tab completion will not be available."
|
||||
)
|
||||
|
||||
# TODO: provide help, consider generic functions (pslist?) and/or providing windows/linux functions
|
||||
|
||||
mode = self.__module__.split(".")[-1]
|
||||
mode = mode[0].upper() + mode[1:]
|
||||
|
||||
banner = f"""
|
||||
Call help() to see available functions
|
||||
banner = textwrap.dedent(
|
||||
f"""
|
||||
Call help() to see available functions
|
||||
|
||||
Volshell mode : {mode}
|
||||
Current Layer : {self.current_layer}
|
||||
Current Symbol Table : {self.current_symbol_table}
|
||||
Current Kernel Name : {self.current_kernel_name}
|
||||
"""
|
||||
Volshell mode : {mode}
|
||||
Current Layer : {self.current_layer}
|
||||
Current Symbol Table : {self.current_symbol_table}
|
||||
Current Kernel Name : {self.current_kernel_name}
|
||||
"""
|
||||
)
|
||||
|
||||
sys.ps1 = f"({self.current_layer}) >>> "
|
||||
# Dict self._construct_locals_dict() will have priority on keys
|
||||
combined_locals = additional_locals.copy()
|
||||
combined_locals.update(self._construct_locals_dict())
|
||||
self.__console = code.InteractiveConsole(locals=combined_locals)
|
||||
if has_ipython:
|
||||
|
||||
class LayerNamePrompt(terminal.prompts.Prompts):
|
||||
def in_prompt_tokens(self, cli=None):
|
||||
slf = self.shell.user_ns.get("self")
|
||||
layer_name = slf.current_layer if slf else "no_layer"
|
||||
return [(terminal.prompts.Token.Prompt, f"[{layer_name}]> ")]
|
||||
|
||||
c = traitlets_config.Config()
|
||||
c.TerminalInteractiveShell.prompts_class = LayerNamePrompt
|
||||
c.InteractiveShellEmbed.banner2 = banner
|
||||
self.__console = terminal.embed.InteractiveShellEmbed(
|
||||
config=c, user_ns=combined_locals
|
||||
)
|
||||
else:
|
||||
self.__console = code.InteractiveConsole(locals=combined_locals)
|
||||
# Since we have to do work to add the option only once for all different modes of volshell, we can't
|
||||
# rely on the default having been set
|
||||
if self.config.get("script", None) is not None:
|
||||
self.run_script(location=self.config["script"])
|
||||
|
||||
self.__console.interact(banner=banner)
|
||||
if self.config.get("script-only"):
|
||||
exit()
|
||||
|
||||
if has_ipython:
|
||||
self.__console()
|
||||
else:
|
||||
self.__console.interact(banner=banner)
|
||||
|
||||
return renderers.TreeGrid([("Terminating", str)], None)
|
||||
|
||||
@@ -277,23 +319,25 @@ class Volshell(interfaces.plugins.PluginInterface):
|
||||
self._display_data(offset, remaining_data)
|
||||
|
||||
def display_quadwords(
|
||||
self, offset, count=DEFAULT_NUM_DISPLAY_BYTES, layer_name=None
|
||||
self, offset, count=DEFAULT_NUM_DISPLAY_BYTES, layer_name=None, byteorder="@"
|
||||
):
|
||||
"""Displays quad-word values (8 bytes) and corresponding ASCII characters"""
|
||||
remaining_data = self._read_data(offset, count=count, layer_name=layer_name)
|
||||
self._display_data(offset, remaining_data, format_string="Q")
|
||||
self._display_data(offset, remaining_data, format_string=f"{byteorder}Q")
|
||||
|
||||
def display_doublewords(
|
||||
self, offset, count=DEFAULT_NUM_DISPLAY_BYTES, layer_name=None
|
||||
self, offset, count=DEFAULT_NUM_DISPLAY_BYTES, layer_name=None, byteorder="@"
|
||||
):
|
||||
"""Displays double-word values (4 bytes) and corresponding ASCII characters"""
|
||||
remaining_data = self._read_data(offset, count=count, layer_name=layer_name)
|
||||
self._display_data(offset, remaining_data, format_string="I")
|
||||
self._display_data(offset, remaining_data, format_string=f"{byteorder}I")
|
||||
|
||||
def display_words(self, offset, count=DEFAULT_NUM_DISPLAY_BYTES, layer_name=None):
|
||||
def display_words(
|
||||
self, offset, count=DEFAULT_NUM_DISPLAY_BYTES, layer_name=None, byteorder="@"
|
||||
):
|
||||
"""Displays word values (2 bytes) and corresponding ASCII characters"""
|
||||
remaining_data = self._read_data(offset, count=count, layer_name=layer_name)
|
||||
self._display_data(offset, remaining_data, format_string="H")
|
||||
self._display_data(offset, remaining_data, format_string=f"{byteorder}H")
|
||||
|
||||
def regex_scan(self, pattern, count=DEFAULT_NUM_DISPLAY_BYTES, layer_name=None):
|
||||
"""Scans for regex pattern in layer using RegExScanner."""
|
||||
@@ -508,10 +552,13 @@ class Volshell(interfaces.plugins.PluginInterface):
|
||||
location = "file:" + request.pathname2url(location)
|
||||
print(f"Running code from {location}\n")
|
||||
accessor = resources.ResourceAccessor()
|
||||
with accessor.open(url=location) as fp:
|
||||
self.__console.runsource(
|
||||
io.TextIOWrapper(fp, encoding="utf-8").read(), symbol="exec"
|
||||
)
|
||||
with accessor.open(url=location) as handle, io.TextIOWrapper(
|
||||
handle, encoding="utf-8"
|
||||
) as fp:
|
||||
if has_ipython:
|
||||
self.__console.ex(fp.read())
|
||||
else:
|
||||
self.__console.runsource(fp.read(), symbol="exec")
|
||||
print("\nCode complete")
|
||||
|
||||
def load_file(self, location: str):
|
||||
|
||||
@@ -30,8 +30,8 @@ class Volshell(generic.Volshell):
|
||||
requirements.ModuleRequirement(
|
||||
name="kernel", description="Linux kernel module"
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="pslist", plugin=pslist.PsList, version=(4, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="pslist", component=pslist.PsList, version=(4, 0, 0)
|
||||
),
|
||||
requirements.IntRequirement(
|
||||
name="pid", description="Process ID", optional=True
|
||||
|
||||
@@ -19,8 +19,8 @@ class Volshell(generic.Volshell):
|
||||
requirements.ModuleRequirement(
|
||||
name="kernel", description="Darwin kernel module"
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="pslist", plugin=pslist.PsList, version=(3, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="pslist", component=pslist.PsList, version=(3, 0, 0)
|
||||
),
|
||||
requirements.IntRequirement(
|
||||
name="pid", description="Process ID", optional=True
|
||||
|
||||
@@ -17,8 +17,8 @@ class Volshell(generic.Volshell):
|
||||
def get_requirements(cls):
|
||||
return [
|
||||
requirements.ModuleRequirement(name="kernel", description="Windows kernel"),
|
||||
requirements.PluginRequirement(
|
||||
name="pslist", plugin=pslist.PsList, version=(3, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="pslist", component=pslist.PsList, version=(3, 0, 0)
|
||||
),
|
||||
requirements.IntRequirement(
|
||||
name="pid", description="Process ID", optional=True
|
||||
|
||||
@@ -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 = 23 # Number of changes that only add to the interface
|
||||
VERSION_MINOR = 25 # Number of changes that only add to the interface
|
||||
VERSION_PATCH = 0 # Number of changes that do not change the interface
|
||||
VERSION_SUFFIX = ""
|
||||
|
||||
|
||||
@@ -402,13 +402,35 @@ class Pointer(Integer):
|
||||
pointer should be recast. The "pointer" must always live within
|
||||
the space (even if the data provided is invalid).
|
||||
"""
|
||||
mask = context.layers[object_info.native_layer_name].address_mask
|
||||
new = (
|
||||
cls._get_raw_value(
|
||||
context, data_format, object_info.layer_name, object_info.offset
|
||||
)
|
||||
& mask
|
||||
)
|
||||
return new
|
||||
|
||||
@classmethod
|
||||
def _get_raw_value(
|
||||
cls,
|
||||
context: interfaces.context.ContextInterface,
|
||||
data_format: DataFormatInfo,
|
||||
layer_name: str,
|
||||
offset: int,
|
||||
) -> int:
|
||||
length, endian, signed = data_format
|
||||
if signed:
|
||||
raise ValueError("Pointers cannot have signed values")
|
||||
mask = context.layers[object_info.native_layer_name].address_mask
|
||||
data = context.layers.read(object_info.layer_name, object_info.offset, length)
|
||||
data = context.layers.read(layer_name, offset, length)
|
||||
value = int.from_bytes(data, byteorder=endian, signed=signed)
|
||||
return value & mask
|
||||
return value
|
||||
|
||||
def get_raw_value(self) -> int:
|
||||
raw = self._get_raw_value(
|
||||
self._context, self.vol.data_format, self.vol.layer_name, self.vol.offset
|
||||
)
|
||||
return raw
|
||||
|
||||
def dereference(
|
||||
self, layer_name: Optional[str] = None
|
||||
|
||||
@@ -2,9 +2,11 @@
|
||||
# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0
|
||||
#
|
||||
|
||||
import re
|
||||
|
||||
from typing import Optional, Union
|
||||
|
||||
from volatility3.framework import interfaces, objects, constants
|
||||
from volatility3.framework import interfaces, objects, constants, exceptions
|
||||
|
||||
|
||||
def rol(value: int, count: int, max_bits: int = 64) -> int:
|
||||
@@ -33,6 +35,7 @@ def array_to_string(
|
||||
count: Optional[int] = None,
|
||||
errors: str = "replace",
|
||||
block_size=32,
|
||||
encoding="utf-8",
|
||||
) -> str:
|
||||
"""Takes a Volatility 'Array' of characters and returns a Python string.
|
||||
|
||||
@@ -60,6 +63,7 @@ def array_to_string(
|
||||
count=count,
|
||||
errors=errors,
|
||||
block_size=block_size,
|
||||
encoding=encoding,
|
||||
)
|
||||
|
||||
|
||||
@@ -68,6 +72,7 @@ def pointer_to_string(
|
||||
count: int,
|
||||
errors: str = "replace",
|
||||
block_size=32,
|
||||
encoding="utf-8",
|
||||
) -> str:
|
||||
"""Takes a Volatility 'Pointer' to characters and returns a Python string.
|
||||
|
||||
@@ -94,9 +99,101 @@ def pointer_to_string(
|
||||
count=count,
|
||||
errors=errors,
|
||||
block_size=block_size,
|
||||
encoding=encoding,
|
||||
)
|
||||
|
||||
|
||||
def gather_contiguous_bytes_from_address(
|
||||
context, data_layer, starting_address: int, count: int
|
||||
) -> bytes:
|
||||
"""
|
||||
This method reconstructs a string from memory while also carefully examining each page
|
||||
|
||||
It goes page-by-page reading the bytes. This is done by calculating page boundaries
|
||||
and then only reading one page at a time.
|
||||
|
||||
If a page is missing, the code initially catches the exception.
|
||||
If data is non-empty (meaning at least one read succeeded), then we return what was read
|
||||
If the first page fails, then we re-raise the exception
|
||||
"""
|
||||
|
||||
data = b""
|
||||
|
||||
if isinstance(data_layer, interfaces.layers.TranslationLayerInterface):
|
||||
last_address = starting_address
|
||||
|
||||
for address, length, _, _, _ in data_layer.mapping(
|
||||
offset=starting_address, length=count, ignore_errors=True
|
||||
):
|
||||
# we hit a swapped out page
|
||||
if last_address != address:
|
||||
break
|
||||
|
||||
data += data_layer.read(address, length)
|
||||
|
||||
last_address = address + length
|
||||
|
||||
elif starting_address + count < data_layer.maximum_address:
|
||||
data = data_layer.read(starting_address, count)
|
||||
|
||||
# if we were able to read from the first page, we want to try and construct the string
|
||||
# if the first page fails -> throw exception
|
||||
if data:
|
||||
return data
|
||||
else:
|
||||
raise exceptions.InvalidAddressException(
|
||||
layer_name=data_layer, invalid_address=starting_address
|
||||
)
|
||||
|
||||
|
||||
def bytes_to_decoded_string(
|
||||
data: bytes, encoding: str, errors: str, return_truncated: bool = True
|
||||
) -> str:
|
||||
"""
|
||||
Args:
|
||||
data: The `bytes` buffer containing the string of a string at offset 0
|
||||
encoding: An encoding value for the encoding paramater of `bytes.decode`
|
||||
errors: An errors value for the errors parameter of `bytes.decode`
|
||||
return_truncated: Dictates whether truncated strings should be returned or
|
||||
if a ValueError should be thrown if a truncated (broken) string was decoded
|
||||
Returns:
|
||||
bytes: The decoded string starting at offset of data
|
||||
|
||||
This function takes a bytes buffer that contains at a string of unknown
|
||||
length starting at the first byte, and returns the properly decoded string
|
||||
|
||||
It starts by using Python's `bytes.decode` to attempt to decode the entire string
|
||||
It then finds the termination character (\ufffd or \x00) and splices the string
|
||||
Finally, it returns this spliced string after its been decoded with the
|
||||
caller-specified encoding
|
||||
"""
|
||||
# this is the standard byte used to replace bad unicode characters
|
||||
unicode_replacement_char = "\ufffd"
|
||||
|
||||
# used to find the terminating byte
|
||||
termination_re = re.compile(f"{unicode_replacement_char}|\x00")
|
||||
|
||||
# run over the entire string, letting Python replace invalid characters
|
||||
full_decoded_string = data.decode(encoding=encoding, errors="replace")
|
||||
|
||||
# stop at the first terminating character or get the whole string if not found
|
||||
try:
|
||||
idx = termination_re.search(full_decoded_string).start()
|
||||
except AttributeError:
|
||||
if return_truncated:
|
||||
idx = len(full_decoded_string)
|
||||
else:
|
||||
raise ValueError(
|
||||
"return_truncated set to False and truncated string decoded."
|
||||
)
|
||||
|
||||
# cut at terminating byte, if found
|
||||
data = bytes(full_decoded_string[:idx], encoding=encoding)
|
||||
|
||||
# return with caller-specified encoding and errors
|
||||
return data.decode(encoding=encoding, errors=errors)
|
||||
|
||||
|
||||
def address_to_string(
|
||||
context: interfaces.context.ContextInterface,
|
||||
layer_name: str,
|
||||
@@ -104,6 +201,7 @@ def address_to_string(
|
||||
count: int,
|
||||
errors: str = "replace",
|
||||
block_size=32,
|
||||
encoding="utf-8",
|
||||
) -> str:
|
||||
"""Reads a null-terminated string from a given specified memory address, processing
|
||||
it in blocks for efficiency.
|
||||
@@ -126,18 +224,10 @@ def address_to_string(
|
||||
raise ValueError("Count must be greater than 0")
|
||||
|
||||
layer = context.layers[layer_name]
|
||||
text = b""
|
||||
while len(text) < count:
|
||||
current_block_size = min(count - len(text), block_size)
|
||||
temp_text = layer.read(address + len(text), current_block_size)
|
||||
idx = temp_text.find(b"\x00")
|
||||
if idx != -1:
|
||||
temp_text = temp_text[:idx]
|
||||
text += temp_text
|
||||
break
|
||||
text += temp_text
|
||||
|
||||
return text.decode(errors=errors)
|
||||
data = gather_contiguous_bytes_from_address(context, layer, address, count)
|
||||
|
||||
return bytes_to_decoded_string(data=data, errors=errors, encoding=encoding)
|
||||
|
||||
|
||||
def array_of_pointers(
|
||||
|
||||
@@ -32,8 +32,13 @@ class Bash(plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
description="Linux kernel",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="pslist", plugin=pslist.PsList, version=(4, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="pslist", component=pslist.PsList, version=(4, 0, 0)
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="timeliner",
|
||||
component=timeliner.TimeLinerInterface,
|
||||
version=(1, 0, 0),
|
||||
),
|
||||
requirements.ListRequirement(
|
||||
name="pid",
|
||||
|
||||
@@ -25,8 +25,13 @@ class Boottime(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface)
|
||||
description="Linux kernel",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="pslist", plugin=pslist.PsList, version=(4, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="timeliner",
|
||||
component=timeliner.TimeLinerInterface,
|
||||
version=(1, 0, 0),
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="pslist", component=pslist.PsList, version=(4, 0, 0)
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -60,8 +60,8 @@ class Capabilities(plugins.PluginInterface):
|
||||
description="Linux kernel",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="pslist", plugin=pslist.PsList, version=(4, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="pslist", component=pslist.PsList, version=(4, 0, 0)
|
||||
),
|
||||
requirements.ListRequirement(
|
||||
name="pids",
|
||||
|
||||
@@ -22,8 +22,8 @@ class Check_creds(interfaces.plugins.PluginInterface):
|
||||
description="Linux kernel",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="pslist", plugin=pslist.PsList, version=(4, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="pslist", component=pslist.PsList, version=(4, 0, 0)
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ from volatility3.framework import interfaces, renderers, symbols
|
||||
from volatility3.framework.configuration import requirements
|
||||
from volatility3.framework.renderers import format_hints
|
||||
from volatility3.framework.symbols import linux
|
||||
from volatility3.plugins.linux import lsmod
|
||||
|
||||
vollog = logging.getLogger(__name__)
|
||||
|
||||
@@ -34,14 +33,16 @@ class Check_idt(interfaces.plugins.PluginInterface):
|
||||
requirements.VersionRequirement(
|
||||
name="linux_utilities_modules",
|
||||
component=linux_utilities_modules.Modules,
|
||||
version=(2, 0, 0),
|
||||
version=(3, 0, 0),
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="linux_utilities_module_gatherers",
|
||||
component=linux_utilities_modules.ModuleGatherers,
|
||||
version=(1, 0, 0),
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="linuxutils", component=linux.LinuxUtilities, version=(2, 0, 0)
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="lsmod", plugin=lsmod.Lsmod, version=(2, 0, 0)
|
||||
),
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
@@ -82,10 +83,10 @@ class Check_idt(interfaces.plugins.PluginInterface):
|
||||
|
||||
vmlinux = self.context.modules[self.config["kernel"]]
|
||||
|
||||
modules = lsmod.Lsmod.list_modules(self.context, vmlinux.name)
|
||||
|
||||
handlers = linux.LinuxUtilities.generate_kernel_handler_info(
|
||||
self.context, vmlinux.name, modules
|
||||
known_modules = linux_utilities_modules.Modules.run_modules_scanners(
|
||||
context=self.context,
|
||||
kernel_module_name=self.config["kernel"],
|
||||
caller_wanted_gatherers=linux_utilities_modules.ModuleGatherers.all_gatherers_identifier,
|
||||
)
|
||||
|
||||
idt_table_size = 256
|
||||
@@ -134,19 +135,24 @@ class Check_idt(interfaces.plugins.PluginInterface):
|
||||
module_name = renderers.NotAvailableValue()
|
||||
symbol_name = renderers.NotAvailableValue()
|
||||
else:
|
||||
module_name, symbol_name = (
|
||||
linux_utilities_modules.Modules.lookup_module_address(
|
||||
self.context, vmlinux.name, handlers, idt_addr
|
||||
module_info, symbol_name = (
|
||||
linux_utilities_modules.Modules.module_lookup_by_address(
|
||||
self.context, vmlinux.name, known_modules, idt_addr
|
||||
)
|
||||
)
|
||||
|
||||
if module_info:
|
||||
module_name = module_info.name
|
||||
else:
|
||||
module_name = renderers.NotAvailableValue()
|
||||
|
||||
yield (
|
||||
0,
|
||||
[
|
||||
format_hints.Hex(i),
|
||||
format_hints.Hex(idt_addr),
|
||||
module_name,
|
||||
symbol_name,
|
||||
symbol_name or renderers.NotAvailableValue(),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -3,15 +3,14 @@
|
||||
#
|
||||
|
||||
import logging
|
||||
from typing import List, Dict
|
||||
from typing import List, Dict, Generator
|
||||
|
||||
import volatility3.framework.symbols.linux.utilities.modules as linux_utilities_modules
|
||||
from volatility3.framework import interfaces, renderers, deprecation
|
||||
from volatility3.framework import interfaces, deprecation
|
||||
from volatility3.framework.configuration import requirements
|
||||
from volatility3.framework.interfaces import plugins
|
||||
from volatility3.framework.objects import utility
|
||||
from volatility3.framework.renderers import format_hints
|
||||
from volatility3.framework.symbols.linux import extensions
|
||||
from volatility3.framework.interfaces import plugins
|
||||
|
||||
vollog = logging.getLogger(__name__)
|
||||
|
||||
@@ -19,9 +18,31 @@ vollog = logging.getLogger(__name__)
|
||||
class Check_modules(plugins.PluginInterface):
|
||||
"""Compares module list to sysfs info, if available"""
|
||||
|
||||
_version = (2, 0, 0)
|
||||
_version = (3, 0, 0)
|
||||
_required_framework_version = (2, 0, 0)
|
||||
|
||||
@classmethod
|
||||
def compare_kset_and_lsmod(
|
||||
cls, context: str, vmlinux_name: str
|
||||
) -> Generator[extensions.module, None, None]:
|
||||
kset_modules = linux_utilities_modules.Modules.get_kset_modules(
|
||||
context=context, vmlinux_name=vmlinux_name
|
||||
)
|
||||
|
||||
lsmod_modules = set(
|
||||
str(utility.array_to_string(modules.name))
|
||||
for modules in linux_utilities_modules.Modules.list_modules(
|
||||
context=context, vmlinux_module_name=vmlinux_name
|
||||
)
|
||||
)
|
||||
|
||||
for mod_name in set(kset_modules.keys()).difference(lsmod_modules):
|
||||
yield kset_modules[mod_name]
|
||||
|
||||
run = linux_utilities_modules.ModuleDisplayPlugin.run
|
||||
_generator = linux_utilities_modules.ModuleDisplayPlugin.generator
|
||||
implementation = compare_kset_and_lsmod
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
|
||||
return [
|
||||
@@ -31,9 +52,9 @@ class Check_modules(plugins.PluginInterface):
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="linux_utilities_modules",
|
||||
component=linux_utilities_modules.Modules,
|
||||
version=(2, 0, 0),
|
||||
name="linux_utilities_modules_module_display_plugin",
|
||||
component=linux_utilities_modules.ModuleDisplayPlugin,
|
||||
version=(1, 0, 0),
|
||||
),
|
||||
]
|
||||
|
||||
@@ -41,30 +62,9 @@ class Check_modules(plugins.PluginInterface):
|
||||
@deprecation.deprecated_method(
|
||||
replacement=linux_utilities_modules.Modules.get_kset_modules,
|
||||
removal_date="2025-09-25",
|
||||
replacement_version=(2, 0, 0),
|
||||
replacement_version=(3, 0, 0),
|
||||
)
|
||||
def get_kset_modules(
|
||||
cls, context: interfaces.context.ContextInterface, vmlinux_name: str
|
||||
) -> Dict[str, extensions.module]:
|
||||
return linux_utilities_modules.Modules.get_kset_modules(context, vmlinux_name)
|
||||
|
||||
def _generator(self):
|
||||
kset_modules = linux_utilities_modules.Modules.get_kset_modules(
|
||||
self.context, self.config["kernel"]
|
||||
)
|
||||
|
||||
lsmod_modules = set(
|
||||
str(utility.array_to_string(modules.name))
|
||||
for modules in linux_utilities_modules.Modules.list_modules(
|
||||
self.context, self.config["kernel"]
|
||||
)
|
||||
)
|
||||
|
||||
for mod_name in set(kset_modules.keys()).difference(lsmod_modules):
|
||||
yield (0, (format_hints.Hex(kset_modules[mod_name]), str(mod_name)))
|
||||
|
||||
def run(self):
|
||||
return renderers.TreeGrid(
|
||||
[("Module Address", format_hints.Hex), ("Module Name", str)],
|
||||
self._generator(),
|
||||
)
|
||||
|
||||
@@ -172,8 +172,11 @@ class Check_syscall(plugins.PluginInterface):
|
||||
count=tblsz,
|
||||
)
|
||||
|
||||
for i, call_addr in enumerate(table):
|
||||
if not call_addr:
|
||||
for i in range(len(table)):
|
||||
try:
|
||||
call_addr = table[i]
|
||||
except exceptions.InvalidAddressException:
|
||||
vollog.debug(f"Failed to get system call table entry at index {i}")
|
||||
continue
|
||||
|
||||
symbols = list(vmlinux.get_symbols_by_absolute_location(call_addr))
|
||||
|
||||
@@ -35,8 +35,8 @@ class Elfs(plugins.PluginInterface):
|
||||
description="Linux kernel",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="pslist", plugin=pslist.PsList, version=(4, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="pslist", component=pslist.PsList, version=(4, 0, 0)
|
||||
),
|
||||
requirements.ListRequirement(
|
||||
name="pid",
|
||||
|
||||
@@ -29,8 +29,8 @@ class Envars(plugins.PluginInterface):
|
||||
description="Linux kernel",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="pslist", plugin=pslist.PsList, version=(4, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="pslist", component=pslist.PsList, version=(4, 0, 0)
|
||||
),
|
||||
requirements.ListRequirement(
|
||||
name="pid",
|
||||
|
||||
@@ -6,86 +6,21 @@ from typing import List, Set, Tuple, Iterable
|
||||
from volatility3.framework.symbols.linux.utilities import (
|
||||
modules as linux_utilities_modules,
|
||||
)
|
||||
from volatility3.framework import renderers, interfaces, exceptions, deprecation
|
||||
from volatility3.framework import interfaces, exceptions, deprecation
|
||||
from volatility3.framework.constants import architectures
|
||||
from volatility3.framework.renderers import format_hints
|
||||
from volatility3.framework.configuration import requirements
|
||||
from volatility3.plugins.linux import lsmod
|
||||
from volatility3.framework.symbols.linux import extensions
|
||||
from volatility3.framework.interfaces import plugins
|
||||
|
||||
vollog = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Hidden_modules(interfaces.plugins.PluginInterface):
|
||||
class Hidden_modules(plugins.PluginInterface):
|
||||
"""Carves memory to find hidden kernel modules"""
|
||||
|
||||
_required_framework_version = (2, 10, 0)
|
||||
_version = (2, 0, 0)
|
||||
_version = (3, 0, 0)
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
|
||||
return [
|
||||
requirements.ModuleRequirement(
|
||||
name="kernel",
|
||||
description="Linux kernel",
|
||||
architectures=architectures.LINUX_ARCHS,
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="lsmod", plugin=lsmod.Lsmod, version=(2, 0, 0)
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="linux_utilities_modules",
|
||||
component=linux_utilities_modules.Modules,
|
||||
version=(2, 0, 0),
|
||||
),
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
@deprecation.deprecated_method(
|
||||
replacement=linux_utilities_modules.Modules.get_modules_memory_boundaries,
|
||||
removal_date="2025-09-25",
|
||||
replacement_version=(2, 0, 0),
|
||||
)
|
||||
def get_modules_memory_boundaries(
|
||||
context: interfaces.context.ContextInterface,
|
||||
vmlinux_module_name: str,
|
||||
) -> Tuple[int, int]:
|
||||
return linux_utilities_modules.Modules.get_modules_memory_boundaries(
|
||||
context, vmlinux_module_name
|
||||
)
|
||||
|
||||
@deprecation.deprecated_method(
|
||||
replacement=linux_utilities_modules.Modules.get_module_address_alignment,
|
||||
removal_date="2025-09-25",
|
||||
replacement_version=(2, 0, 0),
|
||||
)
|
||||
@classmethod
|
||||
def _get_module_address_alignment(
|
||||
cls,
|
||||
context: interfaces.context.ContextInterface,
|
||||
vmlinux_module_name: str,
|
||||
) -> int:
|
||||
"""Obtain the module memory address alignment.
|
||||
|
||||
struct module is aligned to the L1 cache line, which is typically 64 bytes for most
|
||||
common i386/AMD64/ARM64 configurations. In some cases, it can be 128 bytes, but this
|
||||
will still work.
|
||||
|
||||
Args:
|
||||
context: The context to retrieve required elements (layers, symbol tables) from
|
||||
vmlinux_module_name: The name of the kernel module on which to operate
|
||||
|
||||
Returns:
|
||||
The struct module alignment
|
||||
"""
|
||||
return linux_utilities_modules.get_module_address_alignment(
|
||||
context, vmlinux_module_name
|
||||
)
|
||||
|
||||
@deprecation.deprecated_method(
|
||||
replacement=linux_utilities_modules.Modules.get_hidden_modules,
|
||||
removal_date="2025-09-25",
|
||||
replacement_version=(2, 0, 0),
|
||||
)
|
||||
@classmethod
|
||||
def get_hidden_modules(
|
||||
cls,
|
||||
@@ -120,11 +55,77 @@ class Hidden_modules(interfaces.plugins.PluginInterface):
|
||||
vmlinux_module_name, known_module_addresses, modules_memory_boundaries
|
||||
)
|
||||
|
||||
run = linux_utilities_modules.ModuleDisplayPlugin.run
|
||||
_generator = linux_utilities_modules.ModuleDisplayPlugin.generator
|
||||
implementation = linux_utilities_modules.Modules.list_modules
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
|
||||
return [
|
||||
requirements.ModuleRequirement(
|
||||
name="kernel",
|
||||
description="Linux kernel",
|
||||
architectures=architectures.LINUX_ARCHS,
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="linux_utilities_modules_module_display_plugin",
|
||||
component=linux_utilities_modules.ModuleDisplayPlugin,
|
||||
version=(1, 0, 0),
|
||||
),
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
@deprecation.deprecated_method(
|
||||
replacement=linux_utilities_modules.Modules.get_modules_memory_boundaries,
|
||||
removal_date="2025-09-25",
|
||||
replacement_version=(3, 0, 0),
|
||||
)
|
||||
def get_modules_memory_boundaries(
|
||||
context: interfaces.context.ContextInterface,
|
||||
vmlinux_module_name: str,
|
||||
) -> Tuple[int, int]:
|
||||
return linux_utilities_modules.Modules.get_modules_memory_boundaries(
|
||||
context, vmlinux_module_name
|
||||
)
|
||||
|
||||
@deprecation.deprecated_method(
|
||||
replacement=linux_utilities_modules.Modules.get_module_address_alignment,
|
||||
removal_date="2025-09-25",
|
||||
replacement_version=(3, 0, 0),
|
||||
)
|
||||
@classmethod
|
||||
def _get_module_address_alignment(
|
||||
cls,
|
||||
context: interfaces.context.ContextInterface,
|
||||
vmlinux_module_name: str,
|
||||
) -> int:
|
||||
"""Obtain the module memory address alignment.
|
||||
|
||||
struct module is aligned to the L1 cache line, which is typically 64 bytes for most
|
||||
common i386/AMD64/ARM64 configurations. In some cases, it can be 128 bytes, but this
|
||||
will still work.
|
||||
|
||||
Args:
|
||||
context: The context to retrieve required elements (layers, symbol tables) from
|
||||
vmlinux_module_name: The name of the kernel module on which to operate
|
||||
|
||||
Returns:
|
||||
The struct module alignment
|
||||
"""
|
||||
return linux_utilities_modules.get_module_address_alignment(
|
||||
context, vmlinux_module_name
|
||||
)
|
||||
|
||||
@deprecation.deprecated_method(
|
||||
replacement=linux_utilities_modules.Modules.get_hidden_modules,
|
||||
removal_date="2025-09-25",
|
||||
replacement_version=(3, 0, 0),
|
||||
)
|
||||
@staticmethod
|
||||
@deprecation.deprecated_method(
|
||||
replacement=linux_utilities_modules.Modules.validate_alignment_patterns,
|
||||
removal_date="2025-09-25",
|
||||
replacement_version=(2, 0, 0),
|
||||
replacement_version=(3, 0, 0),
|
||||
)
|
||||
def _validate_alignment_patterns(
|
||||
addresses: Iterable[int],
|
||||
@@ -163,42 +164,35 @@ class Hidden_modules(interfaces.plugins.PluginInterface):
|
||||
|
||||
known_module_addresses = {
|
||||
vmlinux_layer.canonicalize(module.vol.offset)
|
||||
for module in lsmod.Lsmod.list_modules(context, vmlinux_module_name)
|
||||
for module in linux_utilities_modules.Modules.list_modules(
|
||||
context, vmlinux_module_name
|
||||
)
|
||||
}
|
||||
return known_module_addresses
|
||||
|
||||
def _generator(self):
|
||||
vmlinux_module_name = self.config["kernel"]
|
||||
known_module_addresses = self.get_lsmod_module_addresses(
|
||||
self.context, vmlinux_module_name
|
||||
)
|
||||
modules_memory_boundaries = (
|
||||
linux_utilities_modules.Modules.get_modules_memory_boundaries(
|
||||
self.context, vmlinux_module_name
|
||||
)
|
||||
)
|
||||
|
||||
for module in linux_utilities_modules.Modules.get_hidden_modules(
|
||||
self.context,
|
||||
vmlinux_module_name,
|
||||
known_module_addresses,
|
||||
modules_memory_boundaries,
|
||||
):
|
||||
module_addr = module.vol.offset
|
||||
module_name = module.get_name() or renderers.NotAvailableValue()
|
||||
fields = (format_hints.Hex(module_addr), module_name)
|
||||
yield (0, fields)
|
||||
|
||||
def run(self):
|
||||
if self.context.symbol_space.verify_table_versions(
|
||||
@classmethod
|
||||
def find_hidden_modules(
|
||||
cls, context, vmlinux_module_name: str
|
||||
) -> extensions.module:
|
||||
if context.symbol_space.verify_table_versions(
|
||||
"dwarf2json", lambda version, _: (not version) or version < (0, 8, 0)
|
||||
):
|
||||
raise exceptions.SymbolSpaceError(
|
||||
"Invalid symbol table, please ensure the ISF table produced by dwarf2json was created with version 0.8.0 or later"
|
||||
)
|
||||
|
||||
headers = [
|
||||
("Address", format_hints.Hex),
|
||||
("Name", str),
|
||||
]
|
||||
return renderers.TreeGrid(headers, self._generator())
|
||||
known_module_addresses = cls.get_lsmod_module_addresses(
|
||||
context, vmlinux_module_name
|
||||
)
|
||||
modules_memory_boundaries = (
|
||||
linux_utilities_modules.Modules.get_modules_memory_boundaries(
|
||||
context, vmlinux_module_name
|
||||
)
|
||||
)
|
||||
|
||||
yield from linux_utilities_modules.Modules.get_hidden_modules(
|
||||
context,
|
||||
vmlinux_module_name,
|
||||
known_module_addresses,
|
||||
modules_memory_boundaries,
|
||||
)
|
||||
|
||||
@@ -59,7 +59,7 @@ class IOMem(interfaces.plugins.PluginInterface):
|
||||
f"Unable to create resource object at {resource_offset:#x}. This resource, "
|
||||
"its sibling, and any of it's children and will be missing from the output."
|
||||
)
|
||||
return None
|
||||
return
|
||||
|
||||
# get name with protection against smear as following a pointer
|
||||
try:
|
||||
@@ -71,6 +71,15 @@ class IOMem(interfaces.plugins.PluginInterface):
|
||||
)
|
||||
name = renderers.UnreadableValue()
|
||||
|
||||
try:
|
||||
start = resource.start
|
||||
end = resource.end
|
||||
except exceptions.InvalidAddressException:
|
||||
vollog.warning(
|
||||
f"Unable to follow pointer to start and end for resource object at {resource_offset:#x}. Skipping entry."
|
||||
)
|
||||
return
|
||||
|
||||
# mark this resource as seen in the seen set. Normally this should not be needed but will protect
|
||||
# against possible infinite loops. Warn the user if an infinite loop would have happened.
|
||||
if resource_offset in seen:
|
||||
@@ -79,12 +88,12 @@ class IOMem(interfaces.plugins.PluginInterface):
|
||||
"this should not normally occur. No further results from related resources will be "
|
||||
"displayed to protect against infinite loops."
|
||||
)
|
||||
return None
|
||||
return
|
||||
else:
|
||||
seen.add(resource_offset)
|
||||
|
||||
# yield information on this resource
|
||||
yield depth, (name, resource.start, resource.end)
|
||||
yield depth, (name, start, end)
|
||||
|
||||
# process child resource if this exists
|
||||
if resource.child != 0:
|
||||
|
||||
@@ -73,6 +73,9 @@ class Kallsyms(plugins.PluginInterface):
|
||||
# resulting in incorrect values. Unfortunately, there isn't much that can be done
|
||||
# in such cases.
|
||||
# See comments on .init.scratch in arch/x86/kernel/vmlinux.lds.S for details
|
||||
if not kassymbol or not kassymbol.size:
|
||||
return renderers.NotAvailableValue()
|
||||
|
||||
return kassymbol.size if kassymbol.size >= 0 else renderers.NotAvailableValue()
|
||||
|
||||
def _generator(self):
|
||||
@@ -95,6 +98,7 @@ class Kallsyms(plugins.PluginInterface):
|
||||
include_core = include_modules = include_ftrace = include_bpf = True
|
||||
|
||||
symbol_generators = []
|
||||
|
||||
if include_core:
|
||||
symbol_generators.append(kas.get_core_symbols())
|
||||
if include_modules:
|
||||
@@ -106,17 +110,25 @@ class Kallsyms(plugins.PluginInterface):
|
||||
|
||||
for symbols_generator in symbol_generators:
|
||||
for kassymbol in symbols_generator:
|
||||
if not kassymbol:
|
||||
continue
|
||||
# Symbol sizes are calculated using the address of the next non-aliased
|
||||
# symbol or the end of the kernel text area _end/_etext. However, some kernel
|
||||
# symbols are located beyond that area, which causes this method to fail for
|
||||
# the last symbol, resulting in a negative size.
|
||||
# See comments on .init.scratch in arch/x86/kernel/vmlinux.lds.S for details
|
||||
symbol_size = self._get_symbol_size(kassymbol)
|
||||
|
||||
if kassymbol.exported is None:
|
||||
exported = renderers.NotAvailableValue()
|
||||
else:
|
||||
exported = kassymbol.exported
|
||||
|
||||
fields = (
|
||||
format_hints.Hex(kassymbol.address),
|
||||
kassymbol.type,
|
||||
kassymbol.type or renderers.NotAvailableValue(),
|
||||
symbol_size,
|
||||
kassymbol.exported,
|
||||
exported,
|
||||
kassymbol.subsystem,
|
||||
kassymbol.module_name,
|
||||
kassymbol.name,
|
||||
|
||||
@@ -9,7 +9,6 @@ from volatility3.framework import interfaces, renderers, exceptions
|
||||
from volatility3.framework.configuration import requirements
|
||||
from volatility3.framework.renderers import format_hints
|
||||
from volatility3.framework.symbols import linux
|
||||
from volatility3.plugins.linux import lsmod
|
||||
|
||||
vollog = logging.getLogger(__name__)
|
||||
|
||||
@@ -30,10 +29,12 @@ class Keyboard_notifiers(interfaces.plugins.PluginInterface):
|
||||
requirements.VersionRequirement(
|
||||
name="linux_utilities_modules",
|
||||
component=linux_utilities_modules.Modules,
|
||||
version=(2, 0, 0),
|
||||
version=(3, 0, 0),
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="lsmod", plugin=lsmod.Lsmod, version=(2, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="linux_utilities_module_gatherers",
|
||||
component=linux_utilities_modules.ModuleGatherers,
|
||||
version=(1, 0, 0),
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="linuxutils", component=linux.LinuxUtilities, version=(2, 0, 0)
|
||||
@@ -43,12 +44,6 @@ class Keyboard_notifiers(interfaces.plugins.PluginInterface):
|
||||
def _generator(self):
|
||||
vmlinux = self.context.modules[self.config["kernel"]]
|
||||
|
||||
modules = lsmod.Lsmod.list_modules(self.context, vmlinux.name)
|
||||
|
||||
handlers = linux.LinuxUtilities.generate_kernel_handler_info(
|
||||
self.context, vmlinux.name, modules
|
||||
)
|
||||
|
||||
try:
|
||||
knl_addr = vmlinux.object_from_symbol("keyboard_notifier_list")
|
||||
except exceptions.SymbolError:
|
||||
@@ -65,6 +60,12 @@ class Keyboard_notifiers(interfaces.plugins.PluginInterface):
|
||||
vollog.error("The head of the keyboard notifier list is paged out.")
|
||||
return
|
||||
|
||||
known_modules = linux_utilities_modules.Modules.run_modules_scanners(
|
||||
context=self.context,
|
||||
kernel_module_name=self.config["kernel"],
|
||||
caller_wanted_gatherers=linux_utilities_modules.ModuleGatherers.all_gatherers_identifier,
|
||||
)
|
||||
|
||||
knl = vmlinux.object(
|
||||
object_type="atomic_notifier_head",
|
||||
offset=knl_addr.vol.offset,
|
||||
@@ -76,13 +77,25 @@ class Keyboard_notifiers(interfaces.plugins.PluginInterface):
|
||||
):
|
||||
call_addr = call_back.notifier_call
|
||||
|
||||
module_name, symbol_name = (
|
||||
linux_utilities_modules.Modules.lookup_module_address(
|
||||
self.context, vmlinux.name, handlers, call_addr
|
||||
module_info, symbol_name = (
|
||||
linux_utilities_modules.Modules.module_lookup_by_address(
|
||||
self.context, vmlinux.name, known_modules, call_addr
|
||||
)
|
||||
)
|
||||
|
||||
yield (0, [format_hints.Hex(call_addr), module_name, symbol_name])
|
||||
if module_info:
|
||||
module_name = module_info.name
|
||||
else:
|
||||
module_name = renderers.NotAvailableValue()
|
||||
|
||||
yield (
|
||||
0,
|
||||
[
|
||||
format_hints.Hex(call_addr),
|
||||
module_name,
|
||||
symbol_name or renderers.NotAvailableValue(),
|
||||
],
|
||||
)
|
||||
|
||||
def run(self):
|
||||
return renderers.TreeGrid(
|
||||
|
||||
@@ -5,14 +5,14 @@ import logging
|
||||
from typing import List
|
||||
|
||||
import volatility3.framework.symbols.linux.utilities.modules as linux_utilities_modules
|
||||
from volatility3.framework import constants, exceptions, interfaces, renderers
|
||||
from volatility3.framework import exceptions, interfaces, renderers
|
||||
from volatility3.framework.configuration import requirements
|
||||
from volatility3.framework.interfaces import plugins
|
||||
from volatility3.framework.renderers import format_hints
|
||||
from volatility3.framework.symbols import linux
|
||||
from volatility3.framework.constants import architectures
|
||||
from volatility3.framework.objects import utility
|
||||
from volatility3.plugins.linux import pslist, lsmod
|
||||
from volatility3.plugins.linux import pslist
|
||||
|
||||
vollog = logging.getLogger(__name__)
|
||||
|
||||
@@ -34,36 +34,37 @@ class Kthreads(plugins.PluginInterface):
|
||||
requirements.VersionRequirement(
|
||||
name="linux_utilities_modules",
|
||||
component=linux_utilities_modules.Modules,
|
||||
version=(2, 0, 0),
|
||||
version=(3, 0, 0),
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="linux_utilities_module_gatherers",
|
||||
component=linux_utilities_modules.ModuleGatherers,
|
||||
version=(1, 0, 0),
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="linuxutils", component=linux.LinuxUtilities, version=(2, 1, 0)
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="pslist", plugin=pslist.PsList, version=(4, 0, 0)
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="lsmod", plugin=lsmod.Lsmod, version=(2, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="pslist", component=pslist.PsList, version=(4, 0, 0)
|
||||
),
|
||||
]
|
||||
|
||||
def _generator(self):
|
||||
vmlinux = self.context.modules[self.config["kernel"]]
|
||||
|
||||
modules = lsmod.Lsmod.list_modules(self.context, vmlinux.name)
|
||||
handlers = linux.LinuxUtilities.generate_kernel_handler_info(
|
||||
self.context, vmlinux.name, modules
|
||||
)
|
||||
|
||||
kthread_type = vmlinux.get_type(
|
||||
vmlinux.symbol_table_name + constants.BANG + "kthread"
|
||||
)
|
||||
kthread_type = vmlinux.get_type("kthread")
|
||||
|
||||
if not kthread_type.has_member("threadfn"):
|
||||
raise exceptions.VolatilityException(
|
||||
"Unsupported kthread implementation. This plugin only works with kernels >= 5.8"
|
||||
)
|
||||
|
||||
known_modules = linux_utilities_modules.Modules.run_modules_scanners(
|
||||
context=self.context,
|
||||
kernel_module_name=self.config["kernel"],
|
||||
caller_wanted_gatherers=linux_utilities_modules.ModuleGatherers.all_gatherers_identifier,
|
||||
)
|
||||
|
||||
for task in pslist.PsList.list_tasks(
|
||||
self.context, vmlinux.name, include_threads=True
|
||||
):
|
||||
@@ -86,9 +87,7 @@ class Kthreads(plugins.PluginInterface):
|
||||
if not (threadfn and threadfn.is_readable()):
|
||||
continue
|
||||
|
||||
task_name = utility.array_to_string(task.comm)
|
||||
|
||||
thread_name = task_name
|
||||
thread_name = utility.array_to_string(task.comm)
|
||||
|
||||
# kernels >= 5.17 in d6986ce24fc00b0638bd29efe8fb7ba7619ed2aa full_name was added to kthread
|
||||
if kthread.has_member("full_name"):
|
||||
@@ -101,18 +100,23 @@ class Kthreads(plugins.PluginInterface):
|
||||
f"full_name pointer for thread at {kthread.vol.offset:#x} is paged out."
|
||||
)
|
||||
|
||||
module_name, symbol_name = (
|
||||
linux_utilities_modules.Modules.lookup_module_address(
|
||||
self.context, vmlinux.name, handlers, threadfn
|
||||
module_info, symbol_name = (
|
||||
linux_utilities_modules.Modules.module_lookup_by_address(
|
||||
self.context, vmlinux.name, known_modules, threadfn
|
||||
)
|
||||
)
|
||||
|
||||
if module_info:
|
||||
module_name = module_info.name
|
||||
else:
|
||||
module_name = renderers.NotAvailableValue()
|
||||
|
||||
fields = [
|
||||
task.pid,
|
||||
thread_name,
|
||||
format_hints.Hex(threadfn),
|
||||
module_name,
|
||||
symbol_name,
|
||||
symbol_name or renderers.NotAvailableValue(),
|
||||
]
|
||||
yield 0, fields
|
||||
|
||||
|
||||
@@ -31,8 +31,8 @@ class LibraryList(interfaces.plugins.PluginInterface):
|
||||
description="Linux kernel",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="pslist", plugin=pslist.PsList, version=(4, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="pslist", component=pslist.PsList, version=(4, 0, 0)
|
||||
),
|
||||
requirements.ListRequirement(
|
||||
name="pids",
|
||||
|
||||
@@ -7,11 +7,9 @@ import logging
|
||||
from typing import List, Iterable
|
||||
|
||||
import volatility3.framework.symbols.linux.utilities.modules as linux_utilities_modules
|
||||
from volatility3.framework import exceptions, renderers, interfaces, deprecation
|
||||
from volatility3.framework import interfaces, deprecation
|
||||
from volatility3.framework.configuration import requirements
|
||||
from volatility3.framework.interfaces import plugins
|
||||
from volatility3.framework.objects import utility
|
||||
from volatility3.framework.renderers import format_hints
|
||||
|
||||
vollog = logging.getLogger(__name__)
|
||||
|
||||
@@ -20,7 +18,11 @@ class Lsmod(plugins.PluginInterface):
|
||||
"""Lists loaded kernel modules."""
|
||||
|
||||
_required_framework_version = (2, 0, 0)
|
||||
_version = (2, 0, 0)
|
||||
_version = (3, 0, 0)
|
||||
|
||||
run = linux_utilities_modules.ModuleDisplayPlugin.run
|
||||
_generator = linux_utilities_modules.ModuleDisplayPlugin.generator
|
||||
implementation = linux_utilities_modules.Modules.list_modules
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
|
||||
@@ -33,14 +35,19 @@ class Lsmod(plugins.PluginInterface):
|
||||
requirements.VersionRequirement(
|
||||
name="linux_utilities_modules",
|
||||
component=linux_utilities_modules.Modules,
|
||||
version=(2, 0, 0),
|
||||
version=(3, 0, 0),
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="linux_utilities_modules_module_display_plugin",
|
||||
component=linux_utilities_modules.ModuleDisplayPlugin,
|
||||
version=(1, 0, 0),
|
||||
),
|
||||
]
|
||||
|
||||
@classmethod
|
||||
@deprecation.deprecated_method(
|
||||
replacement=linux_utilities_modules.Modules.list_modules,
|
||||
replacement_version=(2, 0, 0),
|
||||
replacement_version=(3, 0, 0),
|
||||
removal_date="2025-09-25",
|
||||
)
|
||||
def list_modules(
|
||||
@@ -49,25 +56,3 @@ class Lsmod(plugins.PluginInterface):
|
||||
return linux_utilities_modules.Modules.list_modules(
|
||||
context, vmlinux_module_name
|
||||
)
|
||||
|
||||
def _generator(self):
|
||||
try:
|
||||
for module in linux_utilities_modules.Modules.list_modules(
|
||||
self.context, self.config["kernel"]
|
||||
):
|
||||
mod_size = module.get_init_size() + module.get_core_size()
|
||||
|
||||
mod_name = utility.array_to_string(module.name)
|
||||
|
||||
yield 0, (format_hints.Hex(module.vol.offset), mod_name, mod_size)
|
||||
|
||||
except exceptions.SymbolError:
|
||||
vollog.warning(
|
||||
"The required symbol 'module' is not present in symbol table. Please check that kernel modules are enabled for the system under analysis."
|
||||
)
|
||||
|
||||
def run(self):
|
||||
return renderers.TreeGrid(
|
||||
[("Offset", format_hints.Hex), ("Name", str), ("Size", int)],
|
||||
self._generator(),
|
||||
)
|
||||
|
||||
@@ -120,8 +120,13 @@ class Lsof(plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
description="Linux kernel",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="pslist", plugin=pslist.PsList, version=(4, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="pslist", component=pslist.PsList, version=(4, 0, 0)
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="timeliner",
|
||||
component=timeliner.TimeLinerInterface,
|
||||
version=(1, 0, 0),
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="linuxutils", component=linux.LinuxUtilities, version=(2, 0, 0)
|
||||
|
||||
@@ -28,8 +28,8 @@ class Malfind(interfaces.plugins.PluginInterface):
|
||||
description="Linux kernel",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="pslist", plugin=pslist.PsList, version=(4, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="pslist", component=pslist.PsList, version=(4, 0, 0)
|
||||
),
|
||||
requirements.ListRequirement(
|
||||
name="pid",
|
||||
|
||||
@@ -34,7 +34,22 @@ spot modules presence and taints."""
|
||||
requirements.VersionRequirement(
|
||||
name="linux_utilities_modules",
|
||||
component=linux_utilities_modules.Modules,
|
||||
version=(2, 0, 0),
|
||||
version=(3, 0, 0),
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="linux_utilities_module_gatherer_lsmod",
|
||||
component=linux_utilities_modules.ModuleGathererLsmod,
|
||||
version=(1, 0, 0),
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="linux_utilities_module_gatherer_sysfs",
|
||||
component=linux_utilities_modules.ModuleGathererSysFs,
|
||||
version=(1, 0, 0),
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="linux_utilities_module_gatherer_scanner",
|
||||
component=linux_utilities_modules.ModuleGathererScanner,
|
||||
version=(1, 0, 0),
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="linux-tainting", component=tainting.Tainting, version=(1, 0, 0)
|
||||
@@ -50,7 +65,7 @@ spot modules presence and taints."""
|
||||
@classmethod
|
||||
@deprecation.deprecated_method(
|
||||
replacement=linux_utilities_modules.Modules.flatten_run_modules_results,
|
||||
replacement_version=(2, 0, 0),
|
||||
replacement_version=(3, 0, 0),
|
||||
removal_date="2025-09-25",
|
||||
)
|
||||
def flatten_run_modules_results(
|
||||
@@ -73,7 +88,7 @@ spot modules presence and taints."""
|
||||
@classmethod
|
||||
@deprecation.deprecated_method(
|
||||
replacement=linux_utilities_modules.Modules.run_modules_scanners,
|
||||
replacement_version=(2, 0, 0),
|
||||
replacement_version=(3, 0, 0),
|
||||
removal_date="2025-09-25",
|
||||
)
|
||||
def run_modules_scanners(
|
||||
@@ -89,35 +104,42 @@ spot modules presence and taints."""
|
||||
)
|
||||
|
||||
def _generator(self):
|
||||
kernel_name = self.config["kernel"]
|
||||
kernel = self.context.modules[self.config["kernel"]]
|
||||
|
||||
kernel = self.context.modules[kernel_name]
|
||||
wanted_gatherers = [
|
||||
linux_utilities_modules.ModuleGathererLsmod,
|
||||
linux_utilities_modules.ModuleGathererSysFs,
|
||||
linux_utilities_modules.ModuleGathererScanner,
|
||||
]
|
||||
|
||||
run_results = linux_utilities_modules.Modules.run_modules_scanners(
|
||||
self.context, kernel_name, flatten=False
|
||||
context=self.context,
|
||||
kernel_module_name=self.config["kernel"],
|
||||
caller_wanted_gatherers=wanted_gatherers,
|
||||
flatten=False,
|
||||
)
|
||||
|
||||
aggregated_modules = {}
|
||||
# We want to be explicit on the plugins results we are interested in
|
||||
for plugin_name in ["lsmod", "check_modules", "hidden_modules"]:
|
||||
for gatherer in wanted_gatherers:
|
||||
# Iterate over each recovered module
|
||||
for mod_info in run_results[plugin_name]:
|
||||
for mod_info in run_results[gatherer.name]:
|
||||
# Use offsets as unique keys, whether a module
|
||||
# appears in many plugin runs or not
|
||||
if aggregated_modules.get(mod_info.offset, None) is not None:
|
||||
# Append the plugin to the list of originating plugins
|
||||
aggregated_modules[mod_info.offset].append(plugin_name)
|
||||
aggregated_modules[mod_info.offset].append(gatherer.name)
|
||||
else:
|
||||
aggregated_modules[mod_info.offset] = [plugin_name]
|
||||
aggregated_modules[mod_info.offset] = [gatherer.name]
|
||||
|
||||
for module_offset, originating_plugins in aggregated_modules.items():
|
||||
# Tainting parsing capabilities applied to the module
|
||||
for module_offset, gatherers in aggregated_modules.items():
|
||||
module = kernel.object("module", offset=module_offset, absolute=True)
|
||||
|
||||
# Tainting parsing capabilities applied to the module
|
||||
if self.config.get("plain_taints"):
|
||||
taints = tainting.Tainting.get_taints_as_plain_string(
|
||||
self.context,
|
||||
kernel_name,
|
||||
self.config["kernel"],
|
||||
module.taints,
|
||||
True,
|
||||
)
|
||||
@@ -125,7 +147,7 @@ spot modules presence and taints."""
|
||||
taints = ",".join(
|
||||
tainting.Tainting.get_taints_parsed(
|
||||
self.context,
|
||||
kernel_name,
|
||||
self.config["kernel"],
|
||||
module.taints,
|
||||
True,
|
||||
)
|
||||
@@ -136,9 +158,9 @@ spot modules presence and taints."""
|
||||
(
|
||||
module.get_name() or NotAvailableValue(),
|
||||
format_hints.Hex(module_offset),
|
||||
"lsmod" in originating_plugins,
|
||||
"check_modules" in originating_plugins,
|
||||
"hidden_modules" in originating_plugins,
|
||||
linux_utilities_modules.ModuleGathererLsmod.name in gatherers,
|
||||
linux_utilities_modules.ModuleGathererSysFs.name in gatherers,
|
||||
linux_utilities_modules.ModuleGathererScanner.name in gatherers,
|
||||
taints or NotAvailableValue(),
|
||||
),
|
||||
)
|
||||
@@ -149,7 +171,7 @@ spot modules presence and taints."""
|
||||
("Address", format_hints.Hex),
|
||||
("In procfs", bool),
|
||||
("In sysfs", bool),
|
||||
("Hidden", bool),
|
||||
("In scan", bool),
|
||||
("Taints", str),
|
||||
]
|
||||
|
||||
|
||||
@@ -46,8 +46,8 @@ class MountInfo(plugins.PluginInterface):
|
||||
description="Linux kernel",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="pslist", plugin=pslist.PsList, version=(4, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="pslist", component=pslist.PsList, version=(4, 0, 0)
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="linuxutils", component=linux.LinuxUtilities, version=(2, 1, 0)
|
||||
|
||||
@@ -13,12 +13,11 @@ from volatility3.framework import (
|
||||
interfaces,
|
||||
renderers,
|
||||
exceptions,
|
||||
deprecation,
|
||||
)
|
||||
from volatility3.framework.renderers import format_hints
|
||||
from volatility3.framework.configuration import requirements
|
||||
from volatility3.framework.symbols import linux
|
||||
from volatility3.framework.symbols.linux import network
|
||||
from volatility3.plugins.linux import lsmod
|
||||
|
||||
vollog = logging.getLogger(__name__)
|
||||
|
||||
@@ -82,22 +81,18 @@ class AbstractNetfilter(ABC):
|
||||
self.ptr_size = self.vmlinux.get_type("pointer").size
|
||||
self.list_head_size = self.vmlinux.get_type("list_head").size
|
||||
|
||||
lsmod_required_version = Netfilter._required_lsmod_version
|
||||
lsmod_current_version = lsmod.Lsmod.version
|
||||
linuxutils_modulegatherers_required_version = (
|
||||
Netfilter._required_linuxutils_gatherers_version
|
||||
)
|
||||
linuxutils_modulegatherers_current_version = (
|
||||
linux_utilities_modules.ModuleGatherers.version
|
||||
)
|
||||
if not requirements.VersionRequirement.matches_required(
|
||||
lsmod_required_version, lsmod_current_version
|
||||
linuxutils_modulegatherers_required_version,
|
||||
linuxutils_modulegatherers_current_version,
|
||||
):
|
||||
raise exceptions.PluginRequirementException(
|
||||
f"linux.lsmod.Lsmod version not suitable: required {lsmod_required_version} found {lsmod_current_version}"
|
||||
)
|
||||
|
||||
linuxutils_required_version = Netfilter._required_linuxutils_version
|
||||
linuxutils_current_version = linux.LinuxUtilities.version
|
||||
if not requirements.VersionRequirement.matches_required(
|
||||
linuxutils_required_version, linuxutils_current_version
|
||||
):
|
||||
raise exceptions.PluginRequirementException(
|
||||
f"linux.LinuxUtilities version not suitable: required {linuxutils_required_version} found {linuxutils_current_version}"
|
||||
f"linux_utilities_modules.ModuleGatherer version not suitable: required {linuxutils_modulegatherers_required_version} found {linuxutils_modulegatherers_current_version}"
|
||||
)
|
||||
|
||||
linux_net_required_version = Netfilter._required_linuxnet_version
|
||||
@@ -123,12 +118,13 @@ class AbstractNetfilter(ABC):
|
||||
f"linux_utilities_modules.Modules version not suitable: required {linux_utilities_modules_required_version} found {linux_utilities_modules_current_version}"
|
||||
)
|
||||
|
||||
symbol_table = self._context.symbol_space[self.vmlinux.symbol_table_name]
|
||||
symbol_table = context.symbol_space[self.vmlinux.symbol_table_name]
|
||||
network.NetSymbols.apply(symbol_table)
|
||||
|
||||
modules = lsmod.Lsmod.list_modules(context, kernel_module_name)
|
||||
self.handlers = linux.LinuxUtilities.generate_kernel_handler_info(
|
||||
context, kernel_module_name, modules
|
||||
self.handlers = linux_utilities_modules.Modules.run_modules_scanners(
|
||||
context=context,
|
||||
kernel_module_name=kernel_module_name,
|
||||
caller_wanted_gatherers=linux_utilities_modules.ModuleGatherers.all_gatherers_identifier,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
@@ -217,10 +213,17 @@ class AbstractNetfilter(ABC):
|
||||
|
||||
priority = int(hook_ops.priority)
|
||||
hook_ops_hook = hook_ops.hook
|
||||
module_name = self.get_module_name_for_address(hook_ops_hook)
|
||||
hooked = module_name is None
|
||||
module_info, symbol_name = (
|
||||
linux_utilities_modules.Modules.module_lookup_by_address(
|
||||
self._context,
|
||||
self.vmlinux.name,
|
||||
self.handlers,
|
||||
hook_ops_hook,
|
||||
)
|
||||
)
|
||||
hooked = module_info is None
|
||||
|
||||
yield netns, proto_name, hook_name, priority, hook_ops_hook, module_name, hooked
|
||||
yield netns, proto_name, hook_name, priority, hook_ops_hook, module_info, symbol_name, hooked
|
||||
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
@@ -300,6 +303,10 @@ class AbstractNetfilter(ABC):
|
||||
# in other parts of the kernel source code.
|
||||
return ("IPV4", "ARP", "BRIDGE", "IPV6", "DECNET")
|
||||
|
||||
@deprecation.method_being_removed(
|
||||
removal_date="2025-09-25",
|
||||
message="Callers to this method should adapt `linux_utilities_modules.Modules.run_module_scanners`",
|
||||
)
|
||||
def get_module_name_for_address(self, addr) -> str:
|
||||
"""Helper to obtain the module and symbol name in the format needed for the
|
||||
output of this plugin.
|
||||
@@ -724,11 +731,10 @@ class Netfilter(interfaces.plugins.PluginInterface):
|
||||
|
||||
_required_framework_version = (2, 22, 0)
|
||||
|
||||
_version = (1, 1, 1)
|
||||
_version = (2, 0, 0)
|
||||
|
||||
_required_linux_utilities_modules_version = (2, 0, 0)
|
||||
_required_linuxutils_version = (2, 1, 0)
|
||||
_required_lsmod_version = (2, 0, 0)
|
||||
_required_linux_utilities_modules_version = (3, 0, 0)
|
||||
_required_linuxutils_gatherers_version = (1, 0, 0)
|
||||
_required_linuxnet_version = (1, 0, 0)
|
||||
|
||||
@classmethod
|
||||
@@ -740,17 +746,9 @@ class Netfilter(interfaces.plugins.PluginInterface):
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="linux_utilities_modules",
|
||||
component=linux_utilities_modules.Modules,
|
||||
version=cls._required_linux_utilities_modules_version,
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="lsmod", plugin=lsmod.Lsmod, version=cls._required_lsmod_version
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="linuxutils",
|
||||
component=linux.LinuxUtilities,
|
||||
version=cls._required_linuxutils_version,
|
||||
name="linux_utilities_module_gatherers",
|
||||
component=linux_utilities_modules.ModuleGatherers,
|
||||
version=cls._required_linuxutils_gatherers_version,
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="linuxnet",
|
||||
@@ -766,16 +764,24 @@ class Netfilter(interfaces.plugins.PluginInterface):
|
||||
hook_name,
|
||||
priority,
|
||||
hook_func,
|
||||
module_name,
|
||||
module_info,
|
||||
symbol_name,
|
||||
hooked,
|
||||
) = fields
|
||||
|
||||
if module_info:
|
||||
module_name = module_info.name
|
||||
else:
|
||||
module_name = renderers.NotAvailableValue()
|
||||
|
||||
return (
|
||||
netns,
|
||||
proto_name,
|
||||
hook_name,
|
||||
priority,
|
||||
format_hints.Hex(hook_func),
|
||||
module_name or renderers.NotAvailableValue(),
|
||||
module_name,
|
||||
symbol_name or renderers.NotAvailableValue(),
|
||||
str(hooked),
|
||||
)
|
||||
|
||||
@@ -794,6 +800,7 @@ class Netfilter(interfaces.plugins.PluginInterface):
|
||||
("Priority", int),
|
||||
("Handler", format_hints.Hex),
|
||||
("Module", str),
|
||||
("Symbol", str),
|
||||
("Is Hooked", str),
|
||||
]
|
||||
return renderers.TreeGrid(headers, self._generator())
|
||||
|
||||
@@ -126,8 +126,13 @@ class Files(plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
description="Linux kernel",
|
||||
architectures=architectures.LINUX_ARCHS,
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="mountinfo", plugin=mountinfo.MountInfo, version=(1, 2, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="mountinfo", component=mountinfo.MountInfo, version=(1, 2, 0)
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="timeliner",
|
||||
component=timeliner.TimeLinerInterface,
|
||||
version=(1, 0, 0),
|
||||
),
|
||||
requirements.ListRequirement(
|
||||
name="type",
|
||||
@@ -431,8 +436,8 @@ class InodePages(plugins.PluginInterface):
|
||||
description="Linux kernel",
|
||||
architectures=architectures.LINUX_ARCHS,
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="files", plugin=Files, version=(1, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="files", component=Files, version=(1, 0, 0)
|
||||
),
|
||||
requirements.StringRequirement(
|
||||
name="find",
|
||||
@@ -650,11 +655,11 @@ class RecoverFs(plugins.PluginInterface):
|
||||
description="Linux kernel",
|
||||
architectures=architectures.LINUX_ARCHS,
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="files", plugin=Files, version=(1, 1, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="files", component=Files, version=(1, 1, 0)
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="inodepages", plugin=InodePages, version=(3, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="inodepages", component=InodePages, version=(3, 0, 0)
|
||||
),
|
||||
requirements.BooleanRequirement(
|
||||
name="tmpfs_only",
|
||||
|
||||
@@ -29,8 +29,8 @@ class PIDHashTable(plugins.PluginInterface):
|
||||
description="Linux kernel",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="pslist", plugin=pslist.PsList, version=(4, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="pslist", component=pslist.PsList, version=(4, 0, 0)
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="linuxutils", component=linux.LinuxUtilities, version=(2, 1, 0)
|
||||
|
||||
@@ -34,8 +34,8 @@ class Maps(plugins.PluginInterface):
|
||||
description="Linux kernel",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="pslist", plugin=pslist.PsList, version=(4, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="pslist", component=pslist.PsList, version=(4, 0, 0)
|
||||
),
|
||||
requirements.ListRequirement(
|
||||
name="pid",
|
||||
|
||||
@@ -26,8 +26,8 @@ class PsAux(plugins.PluginInterface):
|
||||
description="Linux kernel",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="pslist", plugin=pslist.PsList, version=(4, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="pslist", component=pslist.PsList, version=(4, 0, 0)
|
||||
),
|
||||
requirements.ListRequirement(
|
||||
name="pid",
|
||||
|
||||
@@ -45,8 +45,8 @@ class PsCallStack(plugins.PluginInterface):
|
||||
requirements.VersionRequirement(
|
||||
name="Kallsyms", component=kallsyms.Kallsyms, version=(1, 0, 0)
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="pslist", plugin=pslist.PsList, version=(4, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="pslist", component=pslist.PsList, version=(4, 0, 0)
|
||||
),
|
||||
requirements.ListRequirement(
|
||||
name="pid",
|
||||
@@ -118,9 +118,15 @@ class PsCallStack(plugins.PluginInterface):
|
||||
current_sp = rsp_start
|
||||
idx = 0
|
||||
while current_sp < task_top_of_stack:
|
||||
stack_value_bytes = task_layer.read(current_sp, pointer_size)
|
||||
try:
|
||||
stack_value_bytes = task_layer.read(current_sp, pointer_size)
|
||||
except exceptions.InvalidAddressException:
|
||||
break
|
||||
stack_value = int.from_bytes(stack_value_bytes, byteorder=byte_order)
|
||||
|
||||
if not stack_value:
|
||||
idx += 1
|
||||
current_sp += pointer_size
|
||||
continue
|
||||
kassymbol = kas.lookup_address(stack_value)
|
||||
sp_address = current_sp & vmlinux_layer.address_mask
|
||||
stack_value &= vmlinux_layer.address_mask
|
||||
|
||||
@@ -44,8 +44,8 @@ class PsList(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
description="Linux kernel",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="elfs", plugin=elfs.Elfs, version=(2, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="elfs", component=elfs.Elfs, version=(2, 0, 0)
|
||||
),
|
||||
requirements.ListRequirement(
|
||||
name="pid",
|
||||
@@ -53,6 +53,11 @@ class PsList(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
element_type=int,
|
||||
optional=True,
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="timeliner",
|
||||
component=timeliner.TimeLinerInterface,
|
||||
version=(1, 0, 0),
|
||||
),
|
||||
requirements.BooleanRequirement(
|
||||
name="threads",
|
||||
description="Include user threads",
|
||||
|
||||
@@ -38,8 +38,8 @@ class PsScan(interfaces.plugins.PluginInterface):
|
||||
description="Linux kernel",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="pslist", plugin=pslist.PsList, version=(4, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="pslist", component=pslist.PsList, version=(4, 0, 0)
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -27,8 +27,8 @@ class PsTree(interfaces.plugins.PluginInterface):
|
||||
description="Linux kernel",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="pslist", plugin=pslist.PsList, version=(4, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="pslist", component=pslist.PsList, version=(4, 0, 0)
|
||||
),
|
||||
requirements.ListRequirement(
|
||||
name="pid",
|
||||
|
||||
@@ -29,8 +29,8 @@ class Ptrace(plugins.PluginInterface):
|
||||
description="Linux kernel",
|
||||
architectures=architectures.LINUX_ARCHS,
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="pslist", plugin=pslist.PsList, version=(4, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="pslist", component=pslist.PsList, version=(4, 0, 0)
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -463,11 +463,11 @@ class Sockstat(plugins.PluginInterface):
|
||||
requirements.VersionRequirement(
|
||||
name="SockHandlers", component=SockHandlers, version=(4, 0, 0)
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="lsof", plugin=lsof.Lsof, version=(2, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="lsof", component=lsof.Lsof, version=(2, 0, 0)
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="pslist", plugin=pslist.PsList, version=(4, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="pslist", component=pslist.PsList, version=(4, 0, 0)
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="linuxutils", component=linux.LinuxUtilities, version=(2, 0, 0)
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
# Public researches: https://i.blackhat.com/USA21/Wednesday-Handouts/us-21-Fixing-A-Memory-Forensics-Blind-Spot-Linux-Kernel-Tracing-wp.pdf
|
||||
|
||||
import logging
|
||||
from typing import Dict, List, Generator
|
||||
from typing import List, Generator
|
||||
from enum import Enum
|
||||
from dataclasses import dataclass
|
||||
|
||||
@@ -65,7 +65,7 @@ class CheckFtrace(interfaces.plugins.PluginInterface):
|
||||
Investigate the ftrace infrastructure to uncover kernel attached callbacks, which can be leveraged
|
||||
to hook kernel functions and modify their behaviour."""
|
||||
|
||||
_version = (3, 0, 0)
|
||||
_version = (4, 0, 0)
|
||||
_required_framework_version = (2, 19, 0)
|
||||
|
||||
@classmethod
|
||||
@@ -79,7 +79,12 @@ class CheckFtrace(interfaces.plugins.PluginInterface):
|
||||
requirements.VersionRequirement(
|
||||
name="linux_utilities_modules",
|
||||
component=linux_utilities_modules.Modules,
|
||||
version=(2, 0, 0),
|
||||
version=(3, 0, 0),
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="linux_utilities_module_gatherers",
|
||||
component=linux_utilities_modules.ModuleGatherers,
|
||||
version=(1, 0, 0),
|
||||
),
|
||||
requirements.BooleanRequirement(
|
||||
name="show_ftrace_flags",
|
||||
@@ -127,9 +132,8 @@ class CheckFtrace(interfaces.plugins.PluginInterface):
|
||||
cls,
|
||||
context: interfaces.context.ContextInterface,
|
||||
kernel_module_name: str,
|
||||
known_modules: Dict[str, List[linux_utilities_modules.Modules.ModuleInfo]],
|
||||
known_modules: List[linux_utilities_modules.ModuleInfo],
|
||||
ftrace_ops: interfaces.objects.ObjectInterface,
|
||||
run_hidden_modules: bool = True,
|
||||
) -> Generator[ParsedFtraceOps, None, None]:
|
||||
"""Parse an ftrace_ops struct to highlight ftrace kernel hooking.
|
||||
Iterates over embedded ftrace_func_entry entries, which point to hooked memory areas.
|
||||
@@ -137,8 +141,6 @@ class CheckFtrace(interfaces.plugins.PluginInterface):
|
||||
Args:
|
||||
known_modules: A dict of known modules, used to locate callbacks origin. Typically obtained through run_modules_scanners().
|
||||
ftrace_ops: The ftrace_ops struct to parse
|
||||
run_hidden_modules: Whether to run the hidden_modules plugin or not. Note: it won't be run, even if specified, \
|
||||
if the "hidden_modules" key is present in known_modules.
|
||||
|
||||
Yields:
|
||||
An iterable of ParsedFtraceOps dataclasses, containing a selection of useful fields (callback, hook, module) related to an ftrace_ops struct
|
||||
@@ -223,7 +225,9 @@ class CheckFtrace(interfaces.plugins.PluginInterface):
|
||||
return
|
||||
|
||||
known_modules = linux_utilities_modules.Modules.run_modules_scanners(
|
||||
self.context, kernel_name, run_hidden_modules=True
|
||||
context=self.context,
|
||||
kernel_module_name=self.config["kernel"],
|
||||
caller_wanted_gatherers=linux_utilities_modules.ModuleGatherers.all_gatherers_identifier,
|
||||
)
|
||||
|
||||
for ftrace_ops in self.iterate_ftrace_ops_list(self.context, kernel_name):
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
# This file is Copyright 2025 Volatility Foundation and licensed under the Volatility Software License 1.0
|
||||
# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0
|
||||
#
|
||||
import logging
|
||||
from typing import List, Tuple, Generator, Optional
|
||||
|
||||
from volatility3.framework import renderers, interfaces, constants, exceptions
|
||||
from volatility3.framework.renderers import format_hints
|
||||
from volatility3.framework.configuration import requirements
|
||||
from volatility3.framework.interfaces import plugins
|
||||
from volatility3.framework.objects import utility
|
||||
from volatility3.plugins.linux import pslist
|
||||
|
||||
vollog = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class PerfEvents(plugins.PluginInterface):
|
||||
"""Lists performance events for each process."""
|
||||
|
||||
_required_framework_version = (2, 0, 0)
|
||||
_version = (1, 0, 0)
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
|
||||
return [
|
||||
requirements.ModuleRequirement(
|
||||
name="kernel",
|
||||
description="Linux kernel",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="pslist", plugin=pslist.PsList, version=(4, 0, 0)
|
||||
),
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def list_perf_events(cls, context, vmlinux_module_name: str) -> Generator[
|
||||
Tuple[
|
||||
interfaces.objects.ObjectInterface,
|
||||
interfaces.objects.ObjectInterface,
|
||||
Optional[str],
|
||||
Optional[str],
|
||||
Optional[str],
|
||||
Optional[int],
|
||||
],
|
||||
None,
|
||||
None,
|
||||
]:
|
||||
"""
|
||||
Walks the `perf_event_list` of each `task_struct` and reports valid event structures found
|
||||
This plugin is one of several to detect eBPF based malware
|
||||
|
||||
Args:
|
||||
context:
|
||||
vmlinux_module_name:
|
||||
|
||||
Returns:
|
||||
A tuple of the task struct, performance event object, event name, program name, full name, and program address
|
||||
"""
|
||||
vmlinux = context.modules[vmlinux_module_name]
|
||||
|
||||
if not vmlinux.has_type("perf_event") or not vmlinux.get_type(
|
||||
"perf_event"
|
||||
).has_member("owner_entry"):
|
||||
vollog.warning(
|
||||
"This kernel does not have performance events enabled (CONFIG_PERF_EVENTS). Cannot proceed."
|
||||
)
|
||||
return
|
||||
|
||||
for task in pslist.PsList.list_tasks(
|
||||
context, vmlinux_module_name, include_threads=True
|
||||
):
|
||||
|
||||
# walk the list of perf_event entries for this process
|
||||
for event in task.perf_event_list.to_list(
|
||||
vmlinux.symbol_table_name + constants.BANG + "perf_event", "owner_entry"
|
||||
):
|
||||
# if the names are smeared then bail
|
||||
try:
|
||||
event_name = utility.pointer_to_string(event.pmu.name, count=64)
|
||||
try:
|
||||
full_name = utility.array_to_string(
|
||||
event.prog.aux.ksym.name, count=512
|
||||
)
|
||||
except AttributeError:
|
||||
full_name = None
|
||||
|
||||
program_name = utility.array_to_string(event.prog.aux.name)
|
||||
except exceptions.InvalidAddressException:
|
||||
continue
|
||||
|
||||
# if the kernel has the prog member then ensure it is not 0
|
||||
if hasattr(event, "prog"):
|
||||
program_address = event.prog
|
||||
if program_address == 0:
|
||||
continue
|
||||
|
||||
else:
|
||||
program_address = None
|
||||
|
||||
yield task, event_name, program_name, full_name, program_address
|
||||
|
||||
def _generator(self):
|
||||
for (
|
||||
task,
|
||||
event_name,
|
||||
program_name,
|
||||
full_name,
|
||||
program_address,
|
||||
) in self.list_perf_events(self.context, self.config["kernel"]):
|
||||
task_name = utility.array_to_string(task.comm)
|
||||
|
||||
# We at least need one useful string...
|
||||
if event_name is None and program_name is None and full_name is None:
|
||||
continue
|
||||
|
||||
if program_address is not None:
|
||||
program_address = format_hints.Hex(program_address)
|
||||
else:
|
||||
program_address = renderers.NotAvailableValue()
|
||||
|
||||
yield (
|
||||
0,
|
||||
(
|
||||
task.pid,
|
||||
task_name,
|
||||
event_name or renderers.NotAvailableValue(),
|
||||
program_name or renderers.NotAvailableValue(),
|
||||
full_name or renderers.NotAvailableValue(),
|
||||
program_address,
|
||||
),
|
||||
)
|
||||
|
||||
def run(self) -> renderers.TreeGrid:
|
||||
return renderers.TreeGrid(
|
||||
[
|
||||
("PID", int),
|
||||
("Process", str),
|
||||
("Event", str),
|
||||
("Short Program Name", str),
|
||||
("Full Name", str),
|
||||
("Address", format_hints.Hex),
|
||||
],
|
||||
self._generator(),
|
||||
)
|
||||
@@ -5,7 +5,7 @@
|
||||
# Public researches: https://i.blackhat.com/USA21/Wednesday-Handouts/us-21-Fixing-A-Memory-Forensics-Blind-Spot-Linux-Kernel-Tracing-wp.pdf
|
||||
|
||||
import logging
|
||||
from typing import Dict, Iterable, List, Optional
|
||||
from typing import Iterable, List, Optional
|
||||
from dataclasses import dataclass
|
||||
|
||||
import volatility3.framework.symbols.linux.utilities.modules as linux_utilities_modules
|
||||
@@ -38,7 +38,7 @@ class CheckTracepoints(interfaces.plugins.PluginInterface):
|
||||
Investigate the tracepoints subsystem to uncover kernel attached probes, which can be leveraged
|
||||
to hook kernel functions and modify their behaviour."""
|
||||
|
||||
_version = (1, 0, 0)
|
||||
_version = (2, 0, 0)
|
||||
_required_framework_version = (2, 19, 0)
|
||||
|
||||
@classmethod
|
||||
@@ -52,7 +52,12 @@ class CheckTracepoints(interfaces.plugins.PluginInterface):
|
||||
requirements.VersionRequirement(
|
||||
name="linux_utilities_modules",
|
||||
component=linux_utilities_modules.Modules,
|
||||
version=(2, 0, 0),
|
||||
version=(3, 0, 0),
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="linux_utilities_module_gatherers",
|
||||
component=linux_utilities_modules.ModuleGatherers,
|
||||
version=(1, 0, 0),
|
||||
),
|
||||
]
|
||||
|
||||
@@ -96,7 +101,7 @@ class CheckTracepoints(interfaces.plugins.PluginInterface):
|
||||
cls,
|
||||
context: interfaces.context.ContextInterface,
|
||||
kernel_module_name: str,
|
||||
known_modules: Dict[str, List[linux_utilities_modules.Modules.ModuleInfo]],
|
||||
known_modules: List[linux_utilities_modules.ModuleInfo],
|
||||
tracepoint: interfaces.objects.ObjectInterface,
|
||||
run_hidden_modules: bool = True,
|
||||
) -> Optional[Iterable[ParsedTracepointFunc]]:
|
||||
@@ -229,7 +234,9 @@ class CheckTracepoints(interfaces.plugins.PluginInterface):
|
||||
return
|
||||
|
||||
known_modules = linux_utilities_modules.Modules.run_modules_scanners(
|
||||
self.context, kernel_name, run_hidden_modules=False
|
||||
context=self.context,
|
||||
kernel_module_name=self.config["kernel"],
|
||||
caller_wanted_gatherers=linux_utilities_modules.ModuleGatherers.all_gatherers_identifier,
|
||||
)
|
||||
tracepoints = self.iterate_tracepoints_array(self.context, kernel_name)
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ from volatility3.framework.interfaces import plugins
|
||||
from volatility3.framework.objects import utility
|
||||
from volatility3.framework.renderers import format_hints
|
||||
from volatility3.framework.symbols import linux
|
||||
from volatility3.plugins.linux import lsmod
|
||||
|
||||
vollog = logging.getLogger(__name__)
|
||||
|
||||
@@ -33,10 +32,12 @@ class tty_check(plugins.PluginInterface):
|
||||
requirements.VersionRequirement(
|
||||
name="linux_utilities_modules",
|
||||
component=linux_utilities_modules.Modules,
|
||||
version=(2, 0, 0),
|
||||
version=(3, 0, 0),
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="lsmod", plugin=lsmod.Lsmod, version=(2, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="linux_utilities_module_gatherers",
|
||||
component=linux_utilities_modules.ModuleGatherers,
|
||||
version=(1, 0, 0),
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="linuxutils", component=linux.LinuxUtilities, version=(2, 0, 0)
|
||||
@@ -46,12 +47,6 @@ class tty_check(plugins.PluginInterface):
|
||||
def _generator(self):
|
||||
vmlinux = self.context.modules[self.config["kernel"]]
|
||||
|
||||
modules = lsmod.Lsmod.list_modules(self.context, vmlinux.name)
|
||||
|
||||
handlers = linux.LinuxUtilities.generate_kernel_handler_info(
|
||||
self.context, vmlinux.name, modules
|
||||
)
|
||||
|
||||
try:
|
||||
tty_drivers = vmlinux.object_from_symbol("tty_drivers").cast("list_head")
|
||||
except exceptions.SymbolError:
|
||||
@@ -64,6 +59,12 @@ class tty_check(plugins.PluginInterface):
|
||||
"This means you are either analyzing an unsupported kernel version or that your symbol table is corrupt."
|
||||
)
|
||||
|
||||
known_modules = linux_utilities_modules.Modules.run_modules_scanners(
|
||||
context=self.context,
|
||||
kernel_module_name=self.config["kernel"],
|
||||
caller_wanted_gatherers=linux_utilities_modules.ModuleGatherers.all_gatherers_identifier,
|
||||
)
|
||||
|
||||
for tty in tty_drivers.to_list(
|
||||
vmlinux.symbol_table_name + constants.BANG + "tty_driver", "tty_drivers"
|
||||
):
|
||||
@@ -87,13 +88,23 @@ class tty_check(plugins.PluginInterface):
|
||||
except exceptions.InvalidAddressException:
|
||||
continue
|
||||
|
||||
module_name, symbol_name = (
|
||||
linux_utilities_modules.Modules.lookup_module_address(
|
||||
self.context, vmlinux.name, handlers, recv_buf
|
||||
module_info, symbol_name = (
|
||||
linux_utilities_modules.Modules.module_lookup_by_address(
|
||||
self.context, vmlinux.name, known_modules, recv_buf
|
||||
)
|
||||
)
|
||||
|
||||
yield (0, (name, format_hints.Hex(recv_buf), module_name, symbol_name))
|
||||
if module_info:
|
||||
module_name = module_info.name
|
||||
else:
|
||||
module_name = renderers.NotAvailableValue()
|
||||
|
||||
yield 0, (
|
||||
name,
|
||||
format_hints.Hex(recv_buf),
|
||||
module_name,
|
||||
symbol_name or renderers.NotAvailableValue(),
|
||||
)
|
||||
|
||||
def run(self):
|
||||
return renderers.TreeGrid(
|
||||
|
||||
@@ -34,8 +34,8 @@ class VmaRegExScan(plugins.PluginInterface):
|
||||
description="Linux kernel",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="pslist", plugin=pslist.PsList, version=(4, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="pslist", component=pslist.PsList, version=(4, 0, 0)
|
||||
),
|
||||
requirements.ListRequirement(
|
||||
name="pid",
|
||||
|
||||
@@ -30,11 +30,11 @@ class VmaYaraScan(interfaces.plugins.PluginInterface):
|
||||
description="Process IDs to include (all other processes are excluded)",
|
||||
optional=True,
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="pslist", plugin=pslist.PsList, version=(4, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="pslist", component=pslist.PsList, version=(4, 0, 0)
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="yarascan", plugin=yarascan.YaraScan, version=(2, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="yarascan", component=yarascan.YaraScan, version=(2, 0, 0)
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="yarascanner", component=yarascan.YaraScanner, version=(2, 0, 0)
|
||||
|
||||
@@ -30,8 +30,13 @@ class Bash(plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
description="Kernel module for the OS",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="pslist", plugin=pslist.PsList, version=(3, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="pslist", component=pslist.PsList, version=(3, 0, 0)
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="timeliner",
|
||||
component=timeliner.TimeLinerInterface,
|
||||
version=(1, 0, 0),
|
||||
),
|
||||
requirements.ListRequirement(
|
||||
name="pid",
|
||||
|
||||
@@ -31,8 +31,8 @@ class Check_syscall(plugins.PluginInterface):
|
||||
requirements.VersionRequirement(
|
||||
name="macutils", component=mac.MacUtilities, version=(1, 0, 0)
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="lsmod", plugin=lsmod.Lsmod, version=(2, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="lsmod", component=lsmod.Lsmod, version=(2, 0, 0)
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -33,8 +33,8 @@ class Check_sysctl(plugins.PluginInterface):
|
||||
requirements.VersionRequirement(
|
||||
name="macutils", component=mac.MacUtilities, version=(1, 0, 0)
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="lsmod", plugin=lsmod.Lsmod, version=(2, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="lsmod", component=lsmod.Lsmod, version=(2, 0, 0)
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -29,8 +29,8 @@ class Check_trap_table(plugins.PluginInterface):
|
||||
description="Kernel module for the OS",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="lsmod", plugin=lsmod.Lsmod, version=(2, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="lsmod", component=lsmod.Lsmod, version=(2, 0, 0)
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="macutils", component=mac.MacUtilities, version=(1, 0, 0)
|
||||
|
||||
@@ -26,11 +26,13 @@ class Kauth_listeners(interfaces.plugins.PluginInterface):
|
||||
requirements.VersionRequirement(
|
||||
name="macutils", component=mac.MacUtilities, version=(1, 1, 0)
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="lsmod", plugin=lsmod.Lsmod, version=(2, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="lsmod", component=lsmod.Lsmod, version=(2, 0, 0)
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="kauth_scopes", plugin=kauth_scopes.Kauth_scopes, version=(2, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="kauth_scopes",
|
||||
component=kauth_scopes.Kauth_scopes,
|
||||
version=(2, 0, 0),
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -31,8 +31,8 @@ class Kauth_scopes(interfaces.plugins.PluginInterface):
|
||||
requirements.VersionRequirement(
|
||||
name="macutils", component=mac.MacUtilities, version=(1, 1, 0)
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="lsmod", plugin=lsmod.Lsmod, version=(2, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="lsmod", component=lsmod.Lsmod, version=(2, 0, 0)
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -71,8 +71,8 @@ class Kevents(interfaces.plugins.PluginInterface):
|
||||
description="Kernel module for the OS",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="pslist", plugin=pslist.PsList, version=(3, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="pslist", component=pslist.PsList, version=(3, 0, 0)
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="macutils", component=mac.MacUtilities, version=(1, 2, 0)
|
||||
|
||||
@@ -28,8 +28,8 @@ class List_Files(plugins.PluginInterface):
|
||||
description="Kernel module for the OS",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="mount", plugin=mount.Mount, version=(2, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="mount", component=mount.Mount, version=(2, 0, 0)
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -29,8 +29,8 @@ class Lsof(plugins.PluginInterface):
|
||||
requirements.VersionRequirement(
|
||||
name="macutils", component=mac.MacUtilities, version=(1, 0, 0)
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="pslist", plugin=pslist.PsList, version=(3, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="pslist", component=pslist.PsList, version=(3, 0, 0)
|
||||
),
|
||||
requirements.ListRequirement(
|
||||
name="pid",
|
||||
|
||||
@@ -23,8 +23,8 @@ class Malfind(interfaces.plugins.PluginInterface):
|
||||
description="Kernel module for the OS",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="pslist", plugin=pslist.PsList, version=(3, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="pslist", component=pslist.PsList, version=(3, 0, 0)
|
||||
),
|
||||
requirements.ListRequirement(
|
||||
name="pid",
|
||||
|
||||
@@ -29,8 +29,8 @@ class Netstat(plugins.PluginInterface):
|
||||
description="Kernel module for the OS",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="pslist", plugin=pslist.PsList, version=(3, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="pslist", component=pslist.PsList, version=(3, 0, 0)
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="macutils", component=mac.MacUtilities, version=(1, 0, 0)
|
||||
|
||||
@@ -28,8 +28,8 @@ class Maps(interfaces.plugins.PluginInterface):
|
||||
description="Kernel module for the OS",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="pslist", plugin=pslist.PsList, version=(3, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="pslist", component=pslist.PsList, version=(3, 0, 0)
|
||||
),
|
||||
requirements.ListRequirement(
|
||||
name="pid",
|
||||
|
||||
@@ -24,8 +24,8 @@ class Psaux(plugins.PluginInterface):
|
||||
description="Kernel module for the OS",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="pslist", plugin=pslist.PsList, version=(3, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="pslist", component=pslist.PsList, version=(3, 0, 0)
|
||||
),
|
||||
requirements.ListRequirement(
|
||||
name="pid",
|
||||
|
||||
@@ -28,8 +28,8 @@ class PsTree(plugins.PluginInterface):
|
||||
description="Kernel module for the OS",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="pslist", plugin=pslist.PsList, version=(3, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="pslist", component=pslist.PsList, version=(3, 0, 0)
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -32,8 +32,8 @@ class Socket_filters(plugins.PluginInterface):
|
||||
requirements.VersionRequirement(
|
||||
name="macutils", component=mac.MacUtilities, version=(1, 0, 0)
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="lsmod", plugin=lsmod.Lsmod, version=(2, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="lsmod", component=lsmod.Lsmod, version=(2, 0, 0)
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -33,8 +33,8 @@ class Trustedbsd(plugins.PluginInterface):
|
||||
requirements.VersionRequirement(
|
||||
name="macutils", component=mac.MacUtilities, version=(1, 3, 0)
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="lsmod", plugin=lsmod.Lsmod, version=(2, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="lsmod", component=lsmod.Lsmod, version=(2, 0, 0)
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -25,10 +25,14 @@ class TimeLinerType(enum.IntEnum):
|
||||
CHANGED = 4
|
||||
|
||||
|
||||
class TimeLinerInterface(metaclass=abc.ABCMeta):
|
||||
class TimeLinerInterface(
|
||||
interfaces.configuration.VersionableInterface, metaclass=abc.ABCMeta
|
||||
):
|
||||
"""Interface defining methods that timeliner will use to generate a body
|
||||
file."""
|
||||
|
||||
_version = (1, 0, 0)
|
||||
|
||||
@abc.abstractmethod
|
||||
def generate_timeline(
|
||||
self,
|
||||
|
||||
@@ -231,8 +231,13 @@ class Amcache(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
description="Windows kernel",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="hivelist", plugin=hivelist.HiveList, version=(2, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="hivelist", component=hivelist.HiveList, version=(2, 0, 0)
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="timeliner",
|
||||
component=timeliner.TimeLinerInterface,
|
||||
version=(1, 0, 0),
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -32,14 +32,14 @@ class Cachedump(interfaces.plugins.PluginInterface):
|
||||
description="Windows kernel",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="hivelist", plugin=hivelist.HiveList, version=(2, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="hivelist", component=hivelist.HiveList, version=(2, 0, 0)
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="lsadump", plugin=lsadump.Lsadump, version=(1, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="lsadump", component=lsadump.Lsadump, version=(1, 0, 0)
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="hashdump", plugin=hashdump.Hashdump, version=(1, 1, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="hashdump", component=hashdump.Hashdump, version=(1, 1, 0)
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -38,17 +38,17 @@ class Callbacks(interfaces.plugins.PluginInterface):
|
||||
description="Windows kernel",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="ssdt", plugin=ssdt.SSDT, version=(2, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="ssdt", component=ssdt.SSDT, version=(2, 0, 0)
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="poolscanner", plugin=poolscanner.PoolScanner, version=(3, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="poolscanner", component=poolscanner.PoolScanner, version=(3, 0, 0)
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="driverirp", plugin=driverirp.DriverIrp, version=(1, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="driverirp", component=driverirp.DriverIrp, version=(1, 0, 0)
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="handles", plugin=handles.Handles, version=(3, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="handles", component=handles.Handles, version=(3, 0, 0)
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -27,8 +27,8 @@ class CmdLine(interfaces.plugins.PluginInterface):
|
||||
description="Windows kernel",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="pslist", plugin=pslist.PsList, version=(3, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="pslist", component=pslist.PsList, version=(3, 0, 0)
|
||||
),
|
||||
requirements.ListRequirement(
|
||||
name="pid",
|
||||
|
||||
@@ -38,8 +38,8 @@ class CmdScan(interfaces.plugins.PluginInterface):
|
||||
requirements.VersionRequirement(
|
||||
name="pslist", component=pslist.PsList, version=(3, 0, 0)
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="consoles", plugin=consoles.Consoles, version=(3, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="consoles", component=consoles.Consoles, version=(3, 0, 0)
|
||||
),
|
||||
requirements.BooleanRequirement(
|
||||
name="no_registry",
|
||||
|
||||
@@ -46,10 +46,13 @@ class Consoles(interfaces.plugins.PluginInterface):
|
||||
name="pslist", component=pslist.PsList, version=(3, 0, 0)
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="verinfo", component=verinfo.VerInfo, version=(1, 0, 0)
|
||||
name="verinfo", component=verinfo.VerInfo, version=(2, 0, 0)
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="hivelist", plugin=hivelist.HiveList, version=(2, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="info", component=info.Info, version=(1, 0, 0)
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="hivelist", component=hivelist.HiveList, version=(2, 0, 0)
|
||||
),
|
||||
requirements.BooleanRequirement(
|
||||
name="no_registry",
|
||||
|
||||
@@ -31,12 +31,12 @@ class DeskScan(desktops.Desktops):
|
||||
description="Windows kernel",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="desktops", plugin=desktops.Desktops, version=(1, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="desktops", component=desktops.Desktops, version=(1, 0, 0)
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
requirements.VersionRequirement(
|
||||
name="windowstations",
|
||||
plugin=windowstations.WindowStations,
|
||||
component=windowstations.WindowStations,
|
||||
version=(1, 0, 0),
|
||||
),
|
||||
]
|
||||
|
||||
@@ -31,9 +31,9 @@ class Desktops(interfaces.plugins.PluginInterface):
|
||||
description="Windows kernel",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
requirements.VersionRequirement(
|
||||
name="windowstations",
|
||||
plugin=windowstations.WindowStations,
|
||||
component=windowstations.WindowStations,
|
||||
version=(1, 0, 0),
|
||||
),
|
||||
]
|
||||
|
||||
@@ -89,8 +89,8 @@ class DeviceTree(interfaces.plugins.PluginInterface):
|
||||
description="Windows kernel",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="driverscan", plugin=driverscan.DriverScan, version=(2, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="driverscan", component=driverscan.DriverScan, version=(2, 0, 0)
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -91,14 +91,14 @@ class DirectSystemCalls(interfaces.plugins.PluginInterface):
|
||||
description="Windows kernel",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="pslist", plugin=pslist.PsList, version=(3, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="pslist", component=pslist.PsList, version=(3, 0, 0)
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="yarascanner", component=yarascan.YaraScanner, version=(2, 1, 0)
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="yarascan", plugin=yarascan.YaraScan, version=(2, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="yarascan", component=yarascan.YaraScan, version=(2, 0, 0)
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -36,6 +36,11 @@ class DllList(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
requirements.VersionRequirement(
|
||||
name="pslist", component=pslist.PsList, version=(3, 0, 0)
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="timeliner",
|
||||
component=timeliner.TimeLinerInterface,
|
||||
version=(1, 0, 0),
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="psscan", component=psscan.PsScan, version=(2, 0, 0)
|
||||
),
|
||||
|
||||
@@ -58,14 +58,14 @@ class DriverIrp(interfaces.plugins.PluginInterface):
|
||||
description="Windows kernel",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="ssdt", plugin=ssdt.SSDT, version=(2, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="ssdt", component=ssdt.SSDT, version=(2, 0, 0)
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="driverscan", plugin=driverscan.DriverScan, version=(2, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="driverscan", component=driverscan.DriverScan, version=(2, 0, 0)
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="modules", plugin=modules.Modules, version=(3, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="modules", component=modules.Modules, version=(3, 0, 0)
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -25,14 +25,14 @@ class DriverModule(interfaces.plugins.PluginInterface):
|
||||
description="Windows kernel",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="ssdt", plugin=ssdt.SSDT, version=(2, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="ssdt", component=ssdt.SSDT, version=(2, 0, 0)
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="driverscan", plugin=driverscan.DriverScan, version=(2, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="driverscan", component=driverscan.DriverScan, version=(2, 0, 0)
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="modules", plugin=modules.Modules, version=(3, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="modules", component=modules.Modules, version=(3, 0, 0)
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -24,8 +24,11 @@ class DriverScan(interfaces.plugins.PluginInterface):
|
||||
description="Windows kernel",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="poolscanner", plugin=poolscanner.PoolScanner, version=(3, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="poolscanner", component=poolscanner.PoolScanner, version=(3, 0, 0)
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="modules", component=modules.Modules, version=(3, 0, 0)
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -39,11 +39,11 @@ class Envars(interfaces.plugins.PluginInterface):
|
||||
description="Suppress common and non-persistent variables",
|
||||
optional=True,
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="pslist", plugin=pslist.PsList, version=(3, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="pslist", component=pslist.PsList, version=(3, 0, 0)
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="hivelist", plugin=hivelist.HiveList, version=(2, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="hivelist", component=hivelist.HiveList, version=(2, 0, 0)
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -24,8 +24,8 @@ class FileScan(interfaces.plugins.PluginInterface):
|
||||
description="Windows kernel",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="poolscanner", plugin=poolscanner.PoolScanner, version=(3, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="poolscanner", component=poolscanner.PoolScanner, version=(3, 0, 0)
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -68,8 +68,8 @@ class GetServiceSIDs(interfaces.plugins.PluginInterface):
|
||||
description="Windows kernel",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="hivelist", plugin=hivelist.HiveList, version=(2, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="hivelist", component=hivelist.HiveList, version=(2, 0, 0)
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -83,11 +83,11 @@ class GetSIDs(interfaces.plugins.PluginInterface):
|
||||
element_type=int,
|
||||
optional=True,
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="pslist", plugin=pslist.PsList, version=(3, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="pslist", component=pslist.PsList, version=(3, 0, 0)
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="hivelist", plugin=hivelist.HiveList, version=(2, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="hivelist", component=hivelist.HiveList, version=(2, 0, 0)
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -35,8 +35,8 @@ class Handles(interfaces.plugins.PluginInterface):
|
||||
description="Windows kernel",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="pslist", plugin=pslist.PsList, version=(3, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="pslist", component=pslist.PsList, version=(3, 0, 0)
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="psscan", component=psscan.PsScan, version=(2, 0, 0)
|
||||
|
||||
@@ -33,8 +33,8 @@ class Hashdump(interfaces.plugins.PluginInterface):
|
||||
description="Windows kernel",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="hivelist", plugin=hivelist.HiveList, version=(2, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="hivelist", component=hivelist.HiveList, version=(2, 0, 0)
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -46,12 +46,12 @@ class IndirectSystemCalls(direct_system_calls.DirectSystemCalls):
|
||||
requirements.VersionRequirement(
|
||||
name="yarascanner", component=yarascan.YaraScanner, version=(2, 1, 0)
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="yarascan", plugin=yarascan.YaraScan, version=(2, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="yarascan", component=yarascan.YaraScan, version=(2, 0, 0)
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
requirements.VersionRequirement(
|
||||
name="direct_system_calls",
|
||||
plugin=direct_system_calls.DirectSystemCalls,
|
||||
component=direct_system_calls.DirectSystemCalls,
|
||||
version=(2, 0, 0),
|
||||
),
|
||||
]
|
||||
|
||||
@@ -27,8 +27,8 @@ class Memmap(interfaces.plugins.PluginInterface):
|
||||
description="Windows kernel",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="pslist", plugin=pslist.PsList, version=(3, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="pslist", component=pslist.PsList, version=(3, 0, 0)
|
||||
),
|
||||
requirements.IntRequirement(
|
||||
name="pid",
|
||||
|
||||
@@ -32,9 +32,17 @@ class MFTScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
description="Memory layer for the kernel",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="timeliner",
|
||||
component=timeliner.TimeLinerInterface,
|
||||
version=(1, 0, 0),
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="yarascanner", component=yarascan.YaraScanner, version=(2, 1, 0)
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="yarascan", component=yarascan.YaraScan, version=(2, 0, 0)
|
||||
),
|
||||
]
|
||||
|
||||
@classmethod
|
||||
@@ -333,8 +341,8 @@ class ADS(interfaces.plugins.PluginInterface):
|
||||
@classmethod
|
||||
def get_requirements(cls):
|
||||
return [
|
||||
requirements.PluginRequirement(
|
||||
name="MFTScan", plugin=MFTScan, version=(2, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="MFTScan", component=MFTScan, version=(2, 0, 0)
|
||||
),
|
||||
requirements.TranslationLayerRequirement(
|
||||
name="primary",
|
||||
@@ -403,8 +411,8 @@ class ResidentData(interfaces.plugins.PluginInterface):
|
||||
@classmethod
|
||||
def get_requirements(cls):
|
||||
return [
|
||||
requirements.PluginRequirement(
|
||||
name="MFTScan", plugin=MFTScan, version=(2, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="MFTScan", component=MFTScan, version=(2, 0, 0)
|
||||
),
|
||||
requirements.TranslationLayerRequirement(
|
||||
name="primary",
|
||||
|
||||
@@ -24,8 +24,8 @@ class MutantScan(interfaces.plugins.PluginInterface):
|
||||
description="Windows kernel",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="poolscanner", plugin=poolscanner.PoolScanner, version=(3, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="poolscanner", component=poolscanner.PoolScanner, version=(3, 0, 0)
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -39,6 +39,11 @@ class NetScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
requirements.VersionRequirement(
|
||||
name="info", component=info.Info, version=(2, 0, 0)
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="timeliner",
|
||||
component=timeliner.TimeLinerInterface,
|
||||
version=(1, 0, 0),
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="verinfo", component=verinfo.VerInfo, version=(1, 0, 0)
|
||||
),
|
||||
|
||||
@@ -39,6 +39,11 @@ class NetStat(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
requirements.VersionRequirement(
|
||||
name="modules", component=modules.Modules, version=(3, 0, 0)
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="timeliner",
|
||||
component=timeliner.TimeLinerInterface,
|
||||
version=(1, 0, 0),
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="pdbutil", component=pdbutil.PDBUtility, version=(1, 0, 0)
|
||||
),
|
||||
|
||||
@@ -33,14 +33,14 @@ class Threads(thrdscan.ThrdScan):
|
||||
description="Windows kernel",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="thrdscan", plugin=thrdscan.ThrdScan, version=(1, 1, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="thrdscan", component=thrdscan.ThrdScan, version=(2, 0, 0)
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="ssdt", plugin=ssdt.SSDT, version=(2, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="ssdt", component=ssdt.SSDT, version=(2, 0, 0)
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="modules", plugin=modules.Modules, version=(3, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="modules", component=modules.Modules, version=(3, 0, 0)
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -229,7 +229,6 @@ class ExportSymbolFinder(PESymbolFinder):
|
||||
Returns:
|
||||
address: the address of the symbol, if found
|
||||
"""
|
||||
|
||||
for export in self._symbol_module:
|
||||
sym_name = self._get_name(export)
|
||||
if sym_name and sym_name == name:
|
||||
@@ -413,8 +412,10 @@ class PESymbols(interfaces.plugins.PluginInterface):
|
||||
)
|
||||
|
||||
for mod_name, unresolved_symbols in missing_symbols.items():
|
||||
for symbol in unresolved_symbols:
|
||||
vollog.debug(f"Unable to resolve symbol {symbol} in module {mod_name}")
|
||||
for symbol_key, symbols in unresolved_symbols.items():
|
||||
vollog.debug(
|
||||
f"Unable to resolve symbols {symbols} of type {symbol_key} in module {mod_name}"
|
||||
)
|
||||
|
||||
return found_symbols
|
||||
|
||||
@@ -632,7 +633,7 @@ class PESymbols(interfaces.plugins.PluginInterface):
|
||||
def _get_symbol_value(
|
||||
wanted_symbols: filter_module_info,
|
||||
symbol_resolver: PESymbolFinder,
|
||||
) -> Generator[Tuple[str, int, str, int], None, None]:
|
||||
) -> Generator[Tuple[str, str, int], None, None]:
|
||||
"""
|
||||
Enumerates the symbols specified as wanted by the calling plugin
|
||||
|
||||
@@ -641,7 +642,7 @@ class PESymbols(interfaces.plugins.PluginInterface):
|
||||
symbol_resolver: method in a layer to resolve the symbols
|
||||
|
||||
Returns:
|
||||
Tuple[str, int, str, int]: the index and value of the found symbol in the wanted list, and the name and address of resolved symbol
|
||||
Tuple[str, str, int]: the symbol identifier (key) of the found symbol in the wanted list, and the name and address of resolved symbol
|
||||
"""
|
||||
if (
|
||||
wanted_names_identifier not in wanted_symbols
|
||||
@@ -661,15 +662,25 @@ class PESymbols(interfaces.plugins.PluginInterface):
|
||||
# address or name
|
||||
if symbol_key in wanted_symbols:
|
||||
# walk each wanted address or name
|
||||
for value_index, wanted_value in enumerate(wanted_symbols[symbol_key]):
|
||||
symbol_value = symbol_getter(wanted_value)
|
||||
|
||||
# build dict in this function for debugging and tracking
|
||||
all_wanted = []
|
||||
for wanted_value in wanted_symbols[symbol_key]:
|
||||
all_wanted.append(wanted_value)
|
||||
|
||||
for value_index, wanted_value in enumerate(all_wanted):
|
||||
symbol_value = symbol_getter(wanted_value)
|
||||
if symbol_value:
|
||||
# yield out deleteion key, deletion index, symbol name, symbol address
|
||||
if symbol_key == wanted_names_identifier:
|
||||
yield symbol_key, value_index, wanted_value, symbol_value # type: ignore
|
||||
yield symbol_key, wanted_value, symbol_value
|
||||
else:
|
||||
yield symbol_key, value_index, symbol_value, wanted_value # type: ignore
|
||||
yield symbol_key, symbol_value, wanted_value
|
||||
|
||||
for value in all_wanted:
|
||||
vollog.debug(
|
||||
f"Unable to resolve value {value} using getter {symbol_getter}"
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def _validate_wanted_modules(
|
||||
@@ -742,7 +753,7 @@ class PESymbols(interfaces.plugins.PluginInterface):
|
||||
PESymbols._find_symbols_through_exports,
|
||||
]
|
||||
|
||||
found: found_symbols_module = []
|
||||
found_symbols: found_symbols_module = []
|
||||
|
||||
# the symbols wanted from this module by the caller
|
||||
wanted = wanted_modules[mod_name]
|
||||
@@ -760,12 +771,17 @@ class PESymbols(interfaces.plugins.PluginInterface):
|
||||
vollog.debug(f"Have resolver for method {method}")
|
||||
for (
|
||||
symbol_key,
|
||||
value_index,
|
||||
symbol_name,
|
||||
symbol_address,
|
||||
) in PESymbols._get_symbol_value(remaining, symbol_resolver):
|
||||
found.append((symbol_name, symbol_address))
|
||||
del remaining[symbol_key][value_index]
|
||||
found_symbols.append((symbol_name, symbol_address))
|
||||
|
||||
if symbol_key == wanted_names_identifier:
|
||||
to_remove = symbol_name
|
||||
else:
|
||||
to_remove = symbol_address
|
||||
|
||||
remaining[symbol_key].remove(to_remove)
|
||||
|
||||
# everything was resolved, stop this resolver
|
||||
# remove this key from the remaining symbols to resolve
|
||||
@@ -781,7 +797,7 @@ class PESymbols(interfaces.plugins.PluginInterface):
|
||||
if done_processing:
|
||||
break
|
||||
|
||||
return found, remaining
|
||||
return found_symbols, remaining
|
||||
|
||||
@classmethod
|
||||
def find_symbols(
|
||||
@@ -970,7 +986,8 @@ class PESymbols(interfaces.plugins.PluginInterface):
|
||||
Generator[Tuple[interfaces.objects.ObjectInterface, str, ranges_type]]: Yields tuple of process objects, layers, and VADs mapping files
|
||||
"""
|
||||
procs = pslist.PsList.list_processes(
|
||||
context=context, kernel_module_name=kernel_module_name
|
||||
context=context,
|
||||
kernel_module_name=kernel_module_name,
|
||||
)
|
||||
|
||||
for proc in procs:
|
||||
|
||||
@@ -139,8 +139,8 @@ class PoolScanner(plugins.PluginInterface):
|
||||
description="Windows kernel",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="handles", plugin=handles.Handles, version=(3, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="handles", component=handles.Handles, version=(3, 0, 0)
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -60,8 +60,8 @@ class Privs(interfaces.plugins.PluginInterface):
|
||||
element_type=int,
|
||||
optional=True,
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="pslist", plugin=pslist.PsList, version=(3, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="pslist", component=pslist.PsList, version=(3, 0, 0)
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -2,21 +2,23 @@
|
||||
# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0
|
||||
#
|
||||
import logging
|
||||
import contextlib
|
||||
|
||||
from typing import Optional, Tuple, Generator, Dict
|
||||
|
||||
from volatility3.framework import interfaces, exceptions
|
||||
from volatility3.framework import renderers
|
||||
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, vadinfo
|
||||
|
||||
vollog = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ProcessGhosting(interfaces.plugins.PluginInterface):
|
||||
"""Lists processes whose DeletePending bit is set or whose FILE_OBJECT is set to 0"""
|
||||
"""Lists processes whose DeletePending bit is set or whose FILE_OBJECT is set to 0 or Vads that are DeleteOnClose"""
|
||||
|
||||
_version = (1, 0, 0)
|
||||
_required_framework_version = (2, 4, 0)
|
||||
|
||||
@classmethod
|
||||
@@ -31,54 +33,168 @@ class ProcessGhosting(interfaces.plugins.PluginInterface):
|
||||
requirements.VersionRequirement(
|
||||
name="pslist", component=pslist.PsList, version=(3, 0, 0)
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="vadinfo", component=vadinfo.VadInfo, version=(2, 0, 1)
|
||||
),
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def _process_checks(
|
||||
cls,
|
||||
proc: interfaces.objects.ObjectInterface,
|
||||
mapped_files: Dict[int, Tuple[str, interfaces.objects.ObjectInterface]],
|
||||
) -> Generator[
|
||||
Tuple[int, Optional[int], Optional[int], int, Optional[str]], None, None
|
||||
]:
|
||||
"""
|
||||
Checks the EPROCESS for signs of ghosting
|
||||
"""
|
||||
if not proc.has_member("ImageFilePointer"):
|
||||
return
|
||||
|
||||
delete_pending = None
|
||||
|
||||
# if it is 0 then its a side effect of process ghosting
|
||||
if proc.ImageFilePointer.vol.offset != 0:
|
||||
try:
|
||||
file_object = proc.ImageFilePointer
|
||||
delete_pending = file_object.DeletePending
|
||||
file_object = file_object.dereference().vol.offset
|
||||
except exceptions.InvalidAddressException:
|
||||
file_object = 0
|
||||
|
||||
# ImageFilePointer equal to 0 means process ghosting or similar techniques were used
|
||||
else:
|
||||
file_object = 0
|
||||
|
||||
# delete_pending besides 0 or 1 = smear
|
||||
if isinstance(delete_pending, int) and delete_pending not in [0, 1]:
|
||||
vollog.debug(
|
||||
f"Invalid delete_pending value {delete_pending} found for process {proc.UniqueProcessId}"
|
||||
)
|
||||
delete_pending = None
|
||||
|
||||
if file_object == 0 or delete_pending == 1:
|
||||
yield file_object, delete_pending, None, proc.SectionBaseAddress
|
||||
|
||||
@classmethod
|
||||
def _vad_checks(
|
||||
cls, control_area: interfaces.objects.ObjectInterface, vad_path: str
|
||||
) -> Generator[Tuple[int, Optional[int], Optional[int]], None, None]:
|
||||
"""
|
||||
Checks the control area for delete on close or delete pending being set
|
||||
"""
|
||||
try:
|
||||
file_object = control_area.FilePointer.dereference().cast("_FILE_OBJECT")
|
||||
except exceptions.InvalidAddressException:
|
||||
return
|
||||
|
||||
try:
|
||||
delete_on_close = control_area.u.Flags.DeleteOnClose
|
||||
except exceptions.InvalidAddressException:
|
||||
delete_on_close = None
|
||||
|
||||
if delete_on_close and vad_path.lower().endswith((".exe", ".dll")):
|
||||
yield file_object.vol.offset, None, delete_on_close
|
||||
|
||||
try:
|
||||
delete_pending = file_object.DeletePending
|
||||
except exceptions.InvalidAddressException:
|
||||
delete_pending = None
|
||||
|
||||
if delete_pending == 1:
|
||||
yield file_object.vol.offset, delete_pending, None
|
||||
|
||||
@classmethod
|
||||
def check_for_ghosting(
|
||||
cls,
|
||||
proc: interfaces.objects.ObjectInterface,
|
||||
mapped_files: Dict[int, Tuple[str, interfaces.objects.ObjectInterface]],
|
||||
) -> Generator[
|
||||
Tuple[int, Optional[int], Optional[int], int, Optional[str]], None, None
|
||||
]:
|
||||
"""
|
||||
Returns process or vad info for ghosting files
|
||||
|
||||
Args:
|
||||
proc:
|
||||
mapped_files: A dictionary mapping vad base addreses to the path and vad instance for the process
|
||||
|
||||
Return:
|
||||
A Generator of tuples of the file object address, the delete pending state, delete on close state, base address of the VAD, and the path
|
||||
"""
|
||||
# check the direct file object of the process
|
||||
yield from cls._process_checks(proc, mapped_files)
|
||||
|
||||
# walk each vad, check if it is pending delete or has its delete on close bit set
|
||||
for vad_base, (path, vad) in mapped_files.items():
|
||||
# these checks have no meaning for private memory areas
|
||||
if vad.get_private_memory() == 1:
|
||||
continue
|
||||
|
||||
try:
|
||||
if vad.has_member("ControlArea"):
|
||||
control_area = vad.ControlArea
|
||||
elif vad.has_member("Subsection"):
|
||||
control_area = vad.Subsection.ControlArea
|
||||
# We got here from a short vad, likely smear
|
||||
else:
|
||||
continue
|
||||
except exceptions.InvalidAddressException:
|
||||
vollog.debug(
|
||||
f"Unable to get control area for vad at base {vad_base:#x} for process with pid {proc.UniqueProcessId}"
|
||||
)
|
||||
continue
|
||||
|
||||
for file_object_address, delete_pending, delete_on_close in cls._vad_checks(
|
||||
control_area, path
|
||||
):
|
||||
yield format_hints.Hex(
|
||||
file_object_address
|
||||
), delete_pending, delete_on_close, vad_base
|
||||
|
||||
def _generator(self, procs):
|
||||
kernel = self.context.modules[self.config["kernel"]]
|
||||
|
||||
if not kernel.get_type("_EPROCESS").has_member("ImageFilePointer"):
|
||||
has_imagefilepointer = kernel.get_type("_EPROCESS").has_member(
|
||||
"ImageFilePointer"
|
||||
)
|
||||
if not has_imagefilepointer:
|
||||
vollog.warning(
|
||||
"This plugin only supports Windows 10 builds when the ImageFilePointer member of _EPROCESS is present"
|
||||
"ImageFilePointer checks are only supported on Windows 10+ builds when the ImageFilePointer member of _EPROCESS is present"
|
||||
)
|
||||
return
|
||||
|
||||
for proc in procs:
|
||||
delete_pending = renderers.UnreadableValue()
|
||||
process_name = utility.array_to_string(proc.ImageFileName)
|
||||
pid = proc.UniqueProcessId
|
||||
|
||||
# if it is 0 then its a side effect of process ghosting
|
||||
if proc.ImageFilePointer.vol.offset != 0:
|
||||
try:
|
||||
file_object = proc.ImageFilePointer
|
||||
delete_pending = file_object.DeletePending
|
||||
except exceptions.InvalidAddressException:
|
||||
file_object = 0
|
||||
# base address -> (file path, VAD instance)
|
||||
mapped_files: Dict[int, Tuple[str, interfaces.objects.ObjectInterface]] = {}
|
||||
for vad in vadinfo.VadInfo.list_vads(proc):
|
||||
path = vad.get_file_name()
|
||||
if isinstance(path, str):
|
||||
mapped_files[vad.get_start()] = (path, vad)
|
||||
|
||||
# ImageFilePointer equal to 0 means process ghosting or similar techniques were used
|
||||
else:
|
||||
file_object = 0
|
||||
for (
|
||||
file_object_address,
|
||||
delete_pending,
|
||||
delete_on_close,
|
||||
base_address,
|
||||
) in self.check_for_ghosting(proc, mapped_files):
|
||||
vad_info = mapped_files.get(base_address)
|
||||
if vad_info:
|
||||
path = vad_info[0]
|
||||
else:
|
||||
path = renderers.NotAvailableValue()
|
||||
|
||||
if isinstance(delete_pending, int) and delete_pending not in [0, 1]:
|
||||
vollog.debug(
|
||||
f"Invalid delete_pending value {delete_pending} found for {process_name} {proc.UniqueProcessId}"
|
||||
)
|
||||
|
||||
# delete_pending besides 0 or 1 = smear
|
||||
if file_object == 0 or delete_pending == 1:
|
||||
path = renderers.UnreadableValue()
|
||||
if file_object:
|
||||
with contextlib.suppress(exceptions.InvalidAddressException):
|
||||
path = file_object.FileName.String
|
||||
|
||||
yield (
|
||||
0,
|
||||
(
|
||||
proc.UniqueProcessId,
|
||||
process_name,
|
||||
format_hints.Hex(file_object),
|
||||
delete_pending,
|
||||
path,
|
||||
),
|
||||
yield 0, (
|
||||
pid,
|
||||
process_name,
|
||||
format_hints.Hex(base_address),
|
||||
format_hints.Hex(file_object_address),
|
||||
delete_pending or renderers.NotApplicableValue(),
|
||||
delete_on_close or renderers.NotApplicableValue(),
|
||||
path,
|
||||
)
|
||||
|
||||
def run(self):
|
||||
@@ -88,8 +204,10 @@ class ProcessGhosting(interfaces.plugins.PluginInterface):
|
||||
[
|
||||
("PID", int),
|
||||
("Process", str),
|
||||
("Base", format_hints.Hex),
|
||||
("FILE_OBJECT", format_hints.Hex),
|
||||
("DeletePending", str),
|
||||
("DeletePending", int),
|
||||
("DeleteOnClose", int),
|
||||
("Path", str),
|
||||
],
|
||||
self._generator(
|
||||
|
||||
@@ -41,6 +41,11 @@ class PsList(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
default=cls.PHYSICAL_DEFAULT,
|
||||
optional=True,
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="timeliner",
|
||||
component=timeliner.TimeLinerInterface,
|
||||
version=(1, 0, 0),
|
||||
),
|
||||
requirements.ListRequirement(
|
||||
name="pid",
|
||||
element_type=int,
|
||||
|
||||
@@ -33,8 +33,13 @@ class PsScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
description="Windows kernel",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="pslist", plugin=pslist.PsList, version=(3, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="pslist", component=pslist.PsList, version=(3, 0, 0)
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="timeliner",
|
||||
component=timeliner.TimeLinerInterface,
|
||||
version=(1, 0, 0),
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="info", component=info.Info, version=(2, 0, 0)
|
||||
|
||||
@@ -55,7 +55,7 @@ We recommend using -r pretty if you are looking at this plugin's output in a ter
|
||||
name="psscan", component=psscan.PsScan, version=(2, 0, 0)
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="thrdscan", component=thrdscan.ThrdScan, version=(1, 0, 0)
|
||||
name="thrdscan", component=thrdscan.ThrdScan, version=(2, 0, 0)
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="handles", component=handles.Handles, version=(3, 0, 0)
|
||||
|
||||
@@ -27,11 +27,11 @@ class GetCellRoutine(interfaces.plugins.PluginInterface):
|
||||
description="Windows kernel",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="hivelist", plugin=hivelist.HiveList, version=(2, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="hivelist", component=hivelist.HiveList, version=(2, 0, 0)
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="ssdt", plugin=ssdt.SSDT, version=(2, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="ssdt", component=ssdt.SSDT, version=(2, 0, 0)
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -60,8 +60,8 @@ class HiveList(interfaces.plugins.PluginInterface):
|
||||
optional=True,
|
||||
default=None,
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="hivescan", plugin=hivescan.HiveScan, version=(2, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="hivescan", component=hivescan.HiveScan, version=(2, 0, 0)
|
||||
),
|
||||
requirements.BooleanRequirement(
|
||||
name="dump",
|
||||
|
||||
@@ -25,11 +25,11 @@ class HiveScan(interfaces.plugins.PluginInterface):
|
||||
description="Windows kernel",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="poolscanner", plugin=poolscanner.PoolScanner, version=(3, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="poolscanner", component=poolscanner.PoolScanner, version=(3, 0, 0)
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="bigpools", plugin=bigpools.BigPools, version=(2, 0, 0)
|
||||
requirements.VersionRequirement(
|
||||
name="bigpools", component=bigpools.BigPools, version=(2, 0, 0)
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user