Merge pull request #1801 from volatilityfoundation/issues/do-not-inherit-pseudoplugins

Issues/do not inherit pseudoplugins
This commit is contained in:
ikelos
2025-11-20 09:26:59 +00:00
committed by GitHub
4 changed files with 142 additions and 69 deletions
+35 -6
View File
@@ -7,7 +7,7 @@ import logging
from typing import Iterable, List
import volatility3.framework.symbols.linux.utilities.modules as linux_utilities_modules
from volatility3.framework import deprecation, interfaces
from volatility3.framework import constants, deprecation, interfaces, renderers
from volatility3.framework.configuration import requirements
from volatility3.framework.interfaces import plugins
@@ -18,21 +18,35 @@ class Lsmod(plugins.PluginInterface):
"""Lists loaded kernel modules."""
_required_framework_version = (2, 0, 0)
_version = (3, 0, 1)
_version = (3, 0, 3)
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=constants.architectures.LINUX_ARCHS,
),
requirements.VersionRequirement(
name="linux_utilities_modules",
component=linux_utilities_modules.Modules,
version=(3, 0, 0),
),
requirements.VersionRequirement(
name="linux_utilities_modules_module_display_plugin",
component=linux_utilities_modules.ModuleDisplayPlugin,
version=(1, 0, 0),
version=(2, 0, 0),
),
] + linux_utilities_modules.ModuleDisplayPlugin.get_requirements()
requirements.BooleanRequirement(
name="dump",
description="Extract listed modules",
default=False,
optional=True,
),
]
@classmethod
@deprecation.deprecated_method(
@@ -46,3 +60,18 @@ class Lsmod(plugins.PluginInterface):
return linux_utilities_modules.Modules.list_modules(
context, vmlinux_module_name
)
def run(self):
return renderers.TreeGrid(
linux_utilities_modules.ModuleDisplayPlugin.columns_results,
self._generator(),
)
def _generator(self):
yield from linux_utilities_modules.ModuleDisplayPlugin.generate_results(
self.context,
self.implementation,
self.config["kernel"],
self.config["dump"],
self.open,
)
@@ -6,16 +6,15 @@ import logging
from typing import Dict, Generator, List
import volatility3.framework.symbols.linux.utilities.modules as linux_utilities_modules
from volatility3.framework import deprecation, interfaces
from volatility3.framework import constants, deprecation, interfaces, renderers
from volatility3.framework.configuration import requirements
from volatility3.framework.interfaces import plugins
from volatility3.framework.objects import utility
from volatility3.framework.symbols.linux import extensions
vollog = logging.getLogger(__name__)
class Check_modules(plugins.PluginInterface):
class Check_modules(interfaces.plugins.PluginInterface):
"""Compares module list to sysfs info, if available"""
_version = (3, 0, 1)
@@ -23,7 +22,7 @@ class Check_modules(plugins.PluginInterface):
@classmethod
def compare_kset_and_lsmod(
cls, context: str, vmlinux_name: str
cls, context: interfaces.context.ContextInterface, vmlinux_name: str
) -> Generator[extensions.module, None, None]:
kset_modules = linux_utilities_modules.Modules.get_kset_modules(
context=context, vmlinux_name=vmlinux_name
@@ -39,13 +38,16 @@ class Check_modules(plugins.PluginInterface):
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 [
requirements.ModuleRequirement(
name="kernel",
description="Linux kernel",
architectures=constants.architectures.LINUX_ARCHS,
),
requirements.VersionRequirement(
name="modules",
component=linux_utilities_modules.Modules,
@@ -54,9 +56,15 @@ class Check_modules(plugins.PluginInterface):
requirements.VersionRequirement(
name="linux_utilities_modules_module_display_plugin",
component=linux_utilities_modules.ModuleDisplayPlugin,
version=(1, 0, 0),
version=(2, 0, 0),
),
] + linux_utilities_modules.ModuleDisplayPlugin.get_requirements()
requirements.BooleanRequirement(
name="dump",
description="Extract listed modules",
default=False,
optional=True,
),
]
@classmethod
@deprecation.deprecated_method(
@@ -68,3 +76,18 @@ class Check_modules(plugins.PluginInterface):
cls, context: interfaces.context.ContextInterface, vmlinux_name: str
) -> Dict[str, extensions.module]:
return linux_utilities_modules.Modules.get_kset_modules(context, vmlinux_name)
def run(self):
return renderers.TreeGrid(
linux_utilities_modules.ModuleDisplayPlugin.columns_results,
self._generator(),
)
def _generator(self):
yield from linux_utilities_modules.ModuleDisplayPlugin.generate_results(
self.context,
self.implementation,
self.config["kernel"],
self.config["dump"],
self.open,
)
@@ -2,9 +2,15 @@
# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0
#
import logging
from typing import Iterable, List, Set, Tuple
from typing import Generator, Iterable, List, Set, Tuple
from volatility3.framework import deprecation, exceptions, interfaces
from volatility3.framework import (
constants,
deprecation,
exceptions,
interfaces,
renderers,
)
from volatility3.framework.configuration import requirements
from volatility3.framework.interfaces import plugins
from volatility3.framework.symbols.linux import extensions
@@ -19,12 +25,12 @@ class Hidden_modules(plugins.PluginInterface):
"""Carves memory to find hidden kernel modules"""
_required_framework_version = (2, 25, 0)
_version = (3, 0, 2)
_version = (3, 0, 3)
@classmethod
def find_hidden_modules(
cls, context, vmlinux_module_name: str
) -> extensions.module:
) -> Generator[extensions.module, None, None]:
if context.symbol_space.verify_table_versions(
"dwarf2json", lambda version, _: (not version) or version < (0, 8, 0)
):
@@ -82,24 +88,33 @@ class Hidden_modules(plugins.PluginInterface):
vmlinux_module_name, known_module_addresses, modules_memory_boundaries
)
run = linux_utilities_modules.ModuleDisplayPlugin.run
_generator = linux_utilities_modules.ModuleDisplayPlugin.generator
implementation = find_hidden_modules
@classmethod
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
return [
requirements.ModuleRequirement(
name="kernel",
description="Linux kernel",
architectures=constants.architectures.LINUX_ARCHS,
),
requirements.VersionRequirement(
name="linux_utilities_modules_module_display_plugin",
component=linux_utilities_modules.ModuleDisplayPlugin,
version=(1, 0, 0),
version=(2, 0, 0),
),
requirements.VersionRequirement(
name="linux_utilities_modules",
component=linux_utilities_modules.Modules,
version=(3, 0, 1),
),
] + linux_utilities_modules.ModuleDisplayPlugin.get_requirements()
requirements.BooleanRequirement(
name="dump",
description="Extract listed modules",
default=False,
optional=True,
),
]
@staticmethod
@deprecation.deprecated_method(
@@ -196,3 +211,18 @@ class Hidden_modules(plugins.PluginInterface):
)
}
return known_module_addresses
def run(self):
return renderers.TreeGrid(
linux_utilities_modules.ModuleDisplayPlugin.columns_results,
self._generator(),
)
def _generator(self):
yield from linux_utilities_modules.ModuleDisplayPlugin.generate_results(
self.context,
self.implementation,
self.config["kernel"],
self.config["dump"],
self.open,
)
@@ -1,37 +1,36 @@
import logging
import warnings
from abc import ABCMeta, abstractmethod
from typing import (
Callable,
Dict,
Generator,
Iterable,
Iterator,
List,
Optional,
Tuple,
NamedTuple,
Dict,
Optional,
Set,
Generator,
Tuple,
Union,
)
from abc import ABCMeta, abstractmethod
import volatility3.framework.symbols.linux.utilities.module_extract as linux_utilities_module_extract
from volatility3 import framework
from volatility3.framework import (
constants,
interfaces,
deprecation,
exceptions,
interfaces,
objects,
renderers,
)
from volatility3.framework.constants import architectures
from volatility3.framework.renderers import format_hints
from volatility3.framework.configuration import requirements
from volatility3.framework.objects import utility
from volatility3.framework.renderers import format_hints
from volatility3.framework.symbols.linux import extensions
from volatility3.framework.symbols.linux.utilities import tainting
import volatility3.framework.symbols.linux.utilities.module_extract as linux_utilities_module_extract
vollog = logging.getLogger(__name__)
@@ -382,7 +381,7 @@ class Modules(interfaces.configuration.VersionableInterface):
vmlinux_module_name: str,
known_module_addresses: Set[int],
modules_memory_boundaries: Tuple,
) -> Iterable[interfaces.objects.ObjectInterface]:
) -> Iterable[extensions.module]:
"""Enumerate hidden modules by taking advantage of memory address alignment patterns
This technique is much faster and uses less memory than the traditional scan method
@@ -919,19 +918,11 @@ class ModuleDisplayPlugin(interfaces.configuration.VersionableInterface):
The constructor of the plugin must call super() with the `implementation` set
"""
_version = (1, 0, 1)
_required_framework_version = (2, 0, 0)
framework.require_interface_version(*_required_framework_version)
_version = (2, 0, 0)
@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",
component=Modules,
@@ -940,25 +931,29 @@ class ModuleDisplayPlugin(interfaces.configuration.VersionableInterface):
requirements.VersionRequirement(
name="linux-tainting", component=tainting.Tainting, version=(1, 0, 0)
),
requirements.BooleanRequirement(
name="dump",
description="Extract listed modules",
default=False,
optional=True,
),
]
def generator(self):
@classmethod
def generate_results(
cls,
context: interfaces.context.ContextInterface,
implementation: Callable[
[interfaces.context.ContextInterface, str], Iterable[extensions.module]
],
kernel_module_name: str,
dump: bool,
open_implementation: Optional[interfaces.plugins.FileHandlerInterface],
):
"""
Uses the implementation set in the constructor call to produce consistent output fields
across module gathering plugins
"""
for module in self.implementation(self.context, self.config["kernel"]):
for module in implementation(context, kernel_module_name):
try:
name = utility.array_to_string(module.name)
except exceptions.InvalidAddressException:
vollog.debug(
f"Unable to recover name for module {module.vol.offset:#x} from implementation {self.implementation}"
f"Unable to recover name for module {module.vol.offset:#x} from implementation {implementation}"
)
continue
@@ -968,21 +963,21 @@ class ModuleDisplayPlugin(interfaces.configuration.VersionableInterface):
taints = ",".join(
tainting.Tainting.get_taints_parsed(
self.context, self.config["kernel"], module.taints, True
context, kernel_module_name, module.taints, True
)
)
parameters_iter = Modules.get_load_parameters(
self.context, self.config["kernel"], module
context, kernel_module_name, module
)
parameters = ", ".join([f"{key}={value}" for key, value in parameters_iter])
file_name = renderers.NotApplicableValue()
if self.config["dump"]:
if dump and open_implementation:
elf_data = linux_utilities_module_extract.ModuleExtract.extract_module(
self.context, self.config["kernel"], module
context, kernel_module_name, module
)
if not elf_data:
vollog.warning(
@@ -990,11 +985,11 @@ class ModuleDisplayPlugin(interfaces.configuration.VersionableInterface):
)
file_name = renderers.NotAvailableValue()
else:
file_name = self.open.sanitize_filename(
file_name = open_implementation.sanitize_filename(
f"kernel_module.{name}.{module.vol.offset:#x}.elf"
)
with self.open(file_name) as file_handle:
with open_implementation(file_name) as file_handle:
file_handle.write(elf_data)
yield (
@@ -1009,15 +1004,11 @@ class ModuleDisplayPlugin(interfaces.configuration.VersionableInterface):
),
)
def run(self):
return renderers.TreeGrid(
[
("Offset", format_hints.Hex),
("Module Name", str),
("Code Size", format_hints.Hex),
("Taints", str),
("Load Arguments", str),
("File Output", str),
],
self._generator(),
)
columns_results = [
("Offset", format_hints.Hex),
("Module Name", str),
("Code Size", format_hints.Hex),
("Taints", str),
("Load Arguments", str),
("File Output", str),
]