From 7146b45fa7571da210be13c2c341f2a3a5c52133 Mon Sep 17 00:00:00 2001 From: Andrew Case Date: Mon, 17 Mar 2025 17:41:35 +0000 Subject: [PATCH 1/7] Create versioned parent class for all plugins that enumerate Linux kernel modules. Convert plugins to new method. --- .../framework/plugins/linux/check_modules.py | 36 ++++---- .../framework/plugins/linux/hidden_modules.py | 66 +++++++------- volatility3/framework/plugins/linux/lsmod.py | 45 +++------- .../symbols/linux/utilities/modules.py | 85 ++++++++++++++++++- 4 files changed, 145 insertions(+), 87 deletions(-) diff --git a/volatility3/framework/plugins/linux/check_modules.py b/volatility3/framework/plugins/linux/check_modules.py index 44cb568e6..246f2450d 100644 --- a/volatility3/framework/plugins/linux/check_modules.py +++ b/volatility3/framework/plugins/linux/check_modules.py @@ -3,25 +3,26 @@ # 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 vollog = logging.getLogger(__name__) -class Check_modules(plugins.PluginInterface): +class Check_modules(linux_utilities_modules.ModuleDisplayPlugin): """Compares module list to sysfs info, if available""" - _version = (2, 0, 0) + _version = (3, 0, 0) _required_framework_version = (2, 0, 0) + def __init__(self, *args, **kwargs): + super().__init__(self.compare_kset_and_lsmod, *args, **kwargs) + @classmethod def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: return [ @@ -31,9 +32,9 @@ class Check_modules(plugins.PluginInterface): architectures=["Intel32", "Intel64"], ), requirements.VersionRequirement( - name="linux_utilities_modules", - component=linux_utilities_modules.Modules, - version=(3, 0, 0), + name="linux_utilities_modules_module_display_plugin", + component=linux_utilities_modules.ModuleDisplayPlugin, + version=(1, 0, 0), ), ] @@ -48,23 +49,20 @@ class Check_modules(plugins.PluginInterface): ) -> Dict[str, extensions.module]: return linux_utilities_modules.Modules.get_kset_modules(context, vmlinux_name) - def _generator(self): + @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( - self.context, self.config["kernel"] + 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( - self.context, self.config["kernel"] + context=context, vmlinux_module_name=vmlinux_name ) ) 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(), - ) + yield kset_modules[mod_name] diff --git a/volatility3/framework/plugins/linux/hidden_modules.py b/volatility3/framework/plugins/linux/hidden_modules.py index 985d4cfcb..dd473a8f7 100644 --- a/volatility3/framework/plugins/linux/hidden_modules.py +++ b/volatility3/framework/plugins/linux/hidden_modules.py @@ -6,19 +6,22 @@ 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.framework.symbols.linux import extensions vollog = logging.getLogger(__name__) -class Hidden_modules(interfaces.plugins.PluginInterface): +class Hidden_modules(linux_utilities_modules.ModuleDisplayPlugin): """Carves memory to find hidden kernel modules""" _required_framework_version = (2, 10, 0) - _version = (2, 0, 0) + _version = (3, 0, 0) + + def __init__(self, *args, **kwargs): + super().__init__(self.find_hidden_modules, *args, **kwargs) @classmethod def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: @@ -29,9 +32,9 @@ class Hidden_modules(interfaces.plugins.PluginInterface): architectures=architectures.LINUX_ARCHS, ), requirements.VersionRequirement( - name="linux_utilities_modules", - component=linux_utilities_modules.Modules, - version=(3, 0, 0), + name="linux_utilities_modules_module_display_plugin", + component=linux_utilities_modules.ModuleDisplayPlugin, + version=(1, 0, 0), ), ] @@ -165,38 +168,29 @@ class Hidden_modules(interfaces.plugins.PluginInterface): } 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, + ) diff --git a/volatility3/framework/plugins/linux/lsmod.py b/volatility3/framework/plugins/linux/lsmod.py index 466bfa0b4..30d494d55 100644 --- a/volatility3/framework/plugins/linux/lsmod.py +++ b/volatility3/framework/plugins/linux/lsmod.py @@ -7,20 +7,20 @@ 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__) -class Lsmod(plugins.PluginInterface): +class Lsmod(linux_utilities_modules.ModuleDisplayPlugin): """Lists loaded kernel modules.""" _required_framework_version = (2, 0, 0) - _version = (2, 0, 0) + _version = (3, 0, 0) + + def __init__(self, *args, **kwargs): + super().__init__(linux_utilities_modules.ModuleGathererLsmod, *args, **kwargs) @classmethod def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: @@ -31,9 +31,14 @@ class Lsmod(plugins.PluginInterface): architectures=["Intel32", "Intel64"], ), requirements.VersionRequirement( - name="linux_utilities_modules", - component=linux_utilities_modules.Modules, - version=(3, 0, 0), + name="linux_utilities_modules_gatherers_lsmod", + component=linux_utilities_modules.ModuleGathererLsmod, + version=(1, 0, 0), + ), + requirements.VersionRequirement( + name="linux_utilities_modules_module_display_plugin", + component=linux_utilities_modules.ModuleDisplayPlugin, + version=(1, 0, 0), ), ] @@ -49,25 +54,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(), - ) diff --git a/volatility3/framework/symbols/linux/utilities/modules.py b/volatility3/framework/symbols/linux/utilities/modules.py index 8f1b5b67d..a2f6a942b 100644 --- a/volatility3/framework/symbols/linux/utilities/modules.py +++ b/volatility3/framework/symbols/linux/utilities/modules.py @@ -21,11 +21,15 @@ from volatility3.framework import ( deprecation, exceptions, 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.symbols.linux import extensions +from volatility3.framework.interfaces import plugins +from volatility3.framework.symbols.linux.utilities import tainting vollog = logging.getLogger(__name__) @@ -684,3 +688,82 @@ class ModuleGatherers( ) return reqs + + +class ModuleDisplayPlugin(plugins.PluginInterface): + """ + Plugins that enumerate kernel modules (lsmod, check_modules, etc.) + must inherit from this class to have unified output columns across plugins. + The constructor of the plugin must call super() with the `implementation` set + """ + + _version = (1, 0, 0) + _required_framework_version = (2, 0, 0) + + framework.require_interface_version(*_required_framework_version) + + def __init__(self, implementation, *args, **kwargs): + super().__init__(*args, **kwargs) + self.implementation = implementation + + @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, + version=(3, 0, 0), + ), + requirements.VersionRequirement( + name="linux-tainting", component=tainting.Tainting, version=(1, 0, 0) + ), + ] + + def _generator(self): + """ + 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"]): + 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}" + ) + continue + + code_size = format_hints.Hex( + module.get_init_size() + module.get_core_size() + ) + + taints = ",".join( + tainting.Tainting.get_taints_parsed( + self.context, self.config["kernel"], module.taints, True + ) + ) + + yield 0, ( + format_hints.Hex(module.vol.offset), + name, + format_hints.Hex(code_size), + taints, + renderers.NotAvailableValue(), # will become the load arguments after this inital conversion is merged + ) + + def run(self): + return renderers.TreeGrid( + [ + ("Offset", format_hints.Hex), + ("Module Name", str), + ("Code Size", format_hints.Hex), + ("Taints", str), + ("Load Arguments", str), + ], + self._generator(), + ) From 971f06996b54deda6cab6e0d48b01146c83ad519 Mon Sep 17 00:00:00 2001 From: Andrew Case Date: Mon, 17 Mar 2025 18:02:03 +0000 Subject: [PATCH 2/7] bump version on kallsyms --- volatility3/framework/symbols/linux/kallsyms.py | 1 + 1 file changed, 1 insertion(+) diff --git a/volatility3/framework/symbols/linux/kallsyms.py b/volatility3/framework/symbols/linux/kallsyms.py index 368169757..945342ea9 100644 --- a/volatility3/framework/symbols/linux/kallsyms.py +++ b/volatility3/framework/symbols/linux/kallsyms.py @@ -305,6 +305,7 @@ class Kallsyms(interfaces.configuration.VersionableInterface): def _assert_versions(cls) -> None: """Verify versions of shared dependencies""" linux_utilities_modules_version_required = (3, 0, 0) + if not requirements.VersionRequirement.matches_required( linux_utilities_modules_version_required, linux_utilities_modules.Modules.version, From f906bde338d8298c69d3e8db6faa6664f935a25b Mon Sep 17 00:00:00 2001 From: Andrew Case Date: Mon, 17 Mar 2025 18:22:19 +0000 Subject: [PATCH 3/7] change lmsod call --- volatility3/framework/plugins/linux/lsmod.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/volatility3/framework/plugins/linux/lsmod.py b/volatility3/framework/plugins/linux/lsmod.py index 30d494d55..d01a25afa 100644 --- a/volatility3/framework/plugins/linux/lsmod.py +++ b/volatility3/framework/plugins/linux/lsmod.py @@ -20,7 +20,7 @@ class Lsmod(linux_utilities_modules.ModuleDisplayPlugin): _version = (3, 0, 0) def __init__(self, *args, **kwargs): - super().__init__(linux_utilities_modules.ModuleGathererLsmod, *args, **kwargs) + super().__init__(linux_utilities_modules.Modules.list_modules, *args, **kwargs) @classmethod def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: @@ -31,9 +31,9 @@ class Lsmod(linux_utilities_modules.ModuleDisplayPlugin): architectures=["Intel32", "Intel64"], ), requirements.VersionRequirement( - name="linux_utilities_modules_gatherers_lsmod", - component=linux_utilities_modules.ModuleGathererLsmod, - version=(1, 0, 0), + name="linux_utilities_modules", + component=linux_utilities_modules.Modules, + version=(3, 0, 0), ), requirements.VersionRequirement( name="linux_utilities_modules_module_display_plugin", From 00c4a13567d2fb2bc14aa291bb9ab7c7aab02a75 Mon Sep 17 00:00:00 2001 From: Andrew Case Date: Mon, 17 Mar 2025 18:58:55 -0500 Subject: [PATCH 4/7] remove errant space --- volatility3/framework/symbols/linux/kallsyms.py | 1 - 1 file changed, 1 deletion(-) diff --git a/volatility3/framework/symbols/linux/kallsyms.py b/volatility3/framework/symbols/linux/kallsyms.py index 945342ea9..368169757 100644 --- a/volatility3/framework/symbols/linux/kallsyms.py +++ b/volatility3/framework/symbols/linux/kallsyms.py @@ -305,7 +305,6 @@ class Kallsyms(interfaces.configuration.VersionableInterface): def _assert_versions(cls) -> None: """Verify versions of shared dependencies""" linux_utilities_modules_version_required = (3, 0, 0) - if not requirements.VersionRequirement.matches_required( linux_utilities_modules_version_required, linux_utilities_modules.Modules.version, From 93be148534308a47e06ceefbecf64ccdeaba50ee Mon Sep 17 00:00:00 2001 From: Andrew Case Date: Mon, 17 Mar 2025 19:04:02 -0500 Subject: [PATCH 5/7] Change how the inheritance is performed --- volatility3/framework/plugins/linux/check_modules.py | 5 ++++- volatility3/framework/plugins/linux/hidden_modules.py | 5 ++++- volatility3/framework/plugins/linux/lsmod.py | 3 ++- volatility3/framework/symbols/linux/utilities/modules.py | 2 +- 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/volatility3/framework/plugins/linux/check_modules.py b/volatility3/framework/plugins/linux/check_modules.py index 246f2450d..55865deb8 100644 --- a/volatility3/framework/plugins/linux/check_modules.py +++ b/volatility3/framework/plugins/linux/check_modules.py @@ -10,11 +10,14 @@ from volatility3.framework import interfaces, deprecation from volatility3.framework.configuration import requirements from volatility3.framework.objects import utility from volatility3.framework.symbols.linux import extensions +from volatility3.framework.interfaces import plugins vollog = logging.getLogger(__name__) -class Check_modules(linux_utilities_modules.ModuleDisplayPlugin): +class Check_modules( + linux_utilities_modules.ModuleDisplayPlugin, plugins.PluginInterface +): """Compares module list to sysfs info, if available""" _version = (3, 0, 0) diff --git a/volatility3/framework/plugins/linux/hidden_modules.py b/volatility3/framework/plugins/linux/hidden_modules.py index dd473a8f7..56b36e2cb 100644 --- a/volatility3/framework/plugins/linux/hidden_modules.py +++ b/volatility3/framework/plugins/linux/hidden_modules.py @@ -10,11 +10,14 @@ from volatility3.framework import interfaces, exceptions, deprecation from volatility3.framework.constants import architectures from volatility3.framework.configuration import requirements from volatility3.framework.symbols.linux import extensions +from volatility3.framework.interfaces import plugins vollog = logging.getLogger(__name__) -class Hidden_modules(linux_utilities_modules.ModuleDisplayPlugin): +class Hidden_modules( + linux_utilities_modules.ModuleDisplayPlugin, plugins.PluginInterface +): """Carves memory to find hidden kernel modules""" _required_framework_version = (2, 10, 0) diff --git a/volatility3/framework/plugins/linux/lsmod.py b/volatility3/framework/plugins/linux/lsmod.py index d01a25afa..71f36ecc9 100644 --- a/volatility3/framework/plugins/linux/lsmod.py +++ b/volatility3/framework/plugins/linux/lsmod.py @@ -9,11 +9,12 @@ from typing import List, Iterable import volatility3.framework.symbols.linux.utilities.modules as linux_utilities_modules from volatility3.framework import interfaces, deprecation from volatility3.framework.configuration import requirements +from volatility3.framework.interfaces import plugins vollog = logging.getLogger(__name__) -class Lsmod(linux_utilities_modules.ModuleDisplayPlugin): +class Lsmod(linux_utilities_modules.ModuleDisplayPlugin, plugins.PluginInterface): """Lists loaded kernel modules.""" _required_framework_version = (2, 0, 0) diff --git a/volatility3/framework/symbols/linux/utilities/modules.py b/volatility3/framework/symbols/linux/utilities/modules.py index a2f6a942b..b5b5b28a2 100644 --- a/volatility3/framework/symbols/linux/utilities/modules.py +++ b/volatility3/framework/symbols/linux/utilities/modules.py @@ -690,7 +690,7 @@ class ModuleGatherers( return reqs -class ModuleDisplayPlugin(plugins.PluginInterface): +class ModuleDisplayPlugin(interfaces.configuration.VersionableInterface): """ Plugins that enumerate kernel modules (lsmod, check_modules, etc.) must inherit from this class to have unified output columns across plugins. From 0667a408364394dc56f7bcf080f5c26c92171c39 Mon Sep 17 00:00:00 2001 From: Andrew Case Date: Mon, 17 Mar 2025 19:06:02 -0500 Subject: [PATCH 6/7] Removed unused import --- volatility3/framework/symbols/linux/utilities/modules.py | 1 - 1 file changed, 1 deletion(-) diff --git a/volatility3/framework/symbols/linux/utilities/modules.py b/volatility3/framework/symbols/linux/utilities/modules.py index b5b5b28a2..b8466d097 100644 --- a/volatility3/framework/symbols/linux/utilities/modules.py +++ b/volatility3/framework/symbols/linux/utilities/modules.py @@ -28,7 +28,6 @@ from volatility3.framework.renderers import format_hints from volatility3.framework.configuration import requirements from volatility3.framework.objects import utility from volatility3.framework.symbols.linux import extensions -from volatility3.framework.interfaces import plugins from volatility3.framework.symbols.linux.utilities import tainting vollog = logging.getLogger(__name__) From 06a4c5639533657d32eda56b927aa0a826406829 Mon Sep 17 00:00:00 2001 From: Andrew Case Date: Mon, 17 Mar 2025 20:15:18 -0500 Subject: [PATCH 7/7] Update for new accessing method --- .../framework/plugins/linux/check_modules.py | 45 ++++++----- .../framework/plugins/linux/hidden_modules.py | 77 +++++++++---------- volatility3/framework/plugins/linux/lsmod.py | 7 +- .../symbols/linux/utilities/modules.py | 6 +- 4 files changed, 65 insertions(+), 70 deletions(-) diff --git a/volatility3/framework/plugins/linux/check_modules.py b/volatility3/framework/plugins/linux/check_modules.py index 55865deb8..5a43bf899 100644 --- a/volatility3/framework/plugins/linux/check_modules.py +++ b/volatility3/framework/plugins/linux/check_modules.py @@ -15,16 +15,33 @@ from volatility3.framework.interfaces import plugins vollog = logging.getLogger(__name__) -class Check_modules( - linux_utilities_modules.ModuleDisplayPlugin, plugins.PluginInterface -): +class Check_modules(plugins.PluginInterface): """Compares module list to sysfs info, if available""" _version = (3, 0, 0) _required_framework_version = (2, 0, 0) - def __init__(self, *args, **kwargs): - super().__init__(self.compare_kset_and_lsmod, *args, **kwargs) + @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]: @@ -51,21 +68,3 @@ class Check_modules( cls, context: interfaces.context.ContextInterface, vmlinux_name: str ) -> Dict[str, extensions.module]: return linux_utilities_modules.Modules.get_kset_modules(context, vmlinux_name) - - @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] diff --git a/volatility3/framework/plugins/linux/hidden_modules.py b/volatility3/framework/plugins/linux/hidden_modules.py index 56b36e2cb..c6f5d749e 100644 --- a/volatility3/framework/plugins/linux/hidden_modules.py +++ b/volatility3/framework/plugins/linux/hidden_modules.py @@ -15,16 +15,49 @@ from volatility3.framework.interfaces import plugins vollog = logging.getLogger(__name__) -class Hidden_modules( - linux_utilities_modules.ModuleDisplayPlugin, plugins.PluginInterface -): +class Hidden_modules(plugins.PluginInterface): """Carves memory to find hidden kernel modules""" _required_framework_version = (2, 10, 0) _version = (3, 0, 0) - def __init__(self, *args, **kwargs): - super().__init__(self.find_hidden_modules, *args, **kwargs) + @classmethod + def get_hidden_modules( + cls, + context: interfaces.context.ContextInterface, + vmlinux_module_name: str, + known_module_addresses: Set[int], + modules_memory_boundaries: Tuple, + ) -> Iterable[interfaces.objects.ObjectInterface]: + """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 + in Volatility2, but it doesn't work with older kernels. + + From kernels 4.2 struct module allocation are aligned to the L1 cache line size. + In i386/amd64/arm64 this is typically 64 bytes. However, this can be changed in + the Linux kernel configuration via CONFIG_X86_L1_CACHE_SHIFT. The alignment can + also be obtained from the DWARF info i.e. DW_AT_alignment<64>, but dwarf2json + doesn't support this feature yet. + In kernels < 4.2, alignment attributes are absent in the struct module, meaning + alignment cannot be guaranteed. Therefore, for older kernels, it's better to use + the traditional scan technique. + + 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 + known_module_addresses: Set with known module addresses + modules_memory_boundaries: Minimum and maximum address boundaries for module allocation. + Yields: + module objects + """ + return linux_utilities_modules.get_hidden_modules( + 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]: @@ -88,40 +121,6 @@ class Hidden_modules( removal_date="2025-09-25", replacement_version=(3, 0, 0), ) - @classmethod - def get_hidden_modules( - cls, - context: interfaces.context.ContextInterface, - vmlinux_module_name: str, - known_module_addresses: Set[int], - modules_memory_boundaries: Tuple, - ) -> Iterable[interfaces.objects.ObjectInterface]: - """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 - in Volatility2, but it doesn't work with older kernels. - - From kernels 4.2 struct module allocation are aligned to the L1 cache line size. - In i386/amd64/arm64 this is typically 64 bytes. However, this can be changed in - the Linux kernel configuration via CONFIG_X86_L1_CACHE_SHIFT. The alignment can - also be obtained from the DWARF info i.e. DW_AT_alignment<64>, but dwarf2json - doesn't support this feature yet. - In kernels < 4.2, alignment attributes are absent in the struct module, meaning - alignment cannot be guaranteed. Therefore, for older kernels, it's better to use - the traditional scan technique. - - 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 - known_module_addresses: Set with known module addresses - modules_memory_boundaries: Minimum and maximum address boundaries for module allocation. - Yields: - module objects - """ - return linux_utilities_modules.get_hidden_modules( - vmlinux_module_name, known_module_addresses, modules_memory_boundaries - ) - @staticmethod @deprecation.deprecated_method( replacement=linux_utilities_modules.Modules.validate_alignment_patterns, diff --git a/volatility3/framework/plugins/linux/lsmod.py b/volatility3/framework/plugins/linux/lsmod.py index 71f36ecc9..3029d2541 100644 --- a/volatility3/framework/plugins/linux/lsmod.py +++ b/volatility3/framework/plugins/linux/lsmod.py @@ -14,14 +14,15 @@ from volatility3.framework.interfaces import plugins vollog = logging.getLogger(__name__) -class Lsmod(linux_utilities_modules.ModuleDisplayPlugin, plugins.PluginInterface): +class Lsmod(plugins.PluginInterface): """Lists loaded kernel modules.""" _required_framework_version = (2, 0, 0) _version = (3, 0, 0) - def __init__(self, *args, **kwargs): - super().__init__(linux_utilities_modules.Modules.list_modules, *args, **kwargs) + 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]: diff --git a/volatility3/framework/symbols/linux/utilities/modules.py b/volatility3/framework/symbols/linux/utilities/modules.py index b8466d097..0b4dea997 100644 --- a/volatility3/framework/symbols/linux/utilities/modules.py +++ b/volatility3/framework/symbols/linux/utilities/modules.py @@ -701,10 +701,6 @@ class ModuleDisplayPlugin(interfaces.configuration.VersionableInterface): framework.require_interface_version(*_required_framework_version) - def __init__(self, implementation, *args, **kwargs): - super().__init__(*args, **kwargs) - self.implementation = implementation - @classmethod def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: return [ @@ -723,7 +719,7 @@ class ModuleDisplayPlugin(interfaces.configuration.VersionableInterface): ), ] - def _generator(self): + def generator(self): """ Uses the implementation set in the constructor call to produce consistent output fields across module gathering plugins