diff --git a/volatility3/framework/plugins/linux/check_modules.py b/volatility3/framework/plugins/linux/check_modules.py index 7805bbd8a4..0844b3400a 100644 --- a/volatility3/framework/plugins/linux/check_modules.py +++ b/volatility3/framework/plugins/linux/check_modules.py @@ -6,16 +6,15 @@ from typing import List, Dict, Generator import volatility3.framework.symbols.linux.utilities.modules as linux_utilities_modules -from volatility3.framework import interfaces, deprecation +from volatility3.framework import constants, interfaces, deprecation, renderers 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(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 @@ def compare_kset_and_lsmod( 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 @@ def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface] 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 @@ 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 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, + ) diff --git a/volatility3/framework/plugins/linux/hidden_modules.py b/volatility3/framework/plugins/linux/hidden_modules.py index dcd602c5d3..66f27ff66f 100644 --- a/volatility3/framework/plugins/linux/hidden_modules.py +++ b/volatility3/framework/plugins/linux/hidden_modules.py @@ -2,11 +2,17 @@ # which is available at https://www.volatilityfoundation.org/license/vsl-v1.0 # import logging -from typing import List, Set, Tuple, Iterable +from typing import List, Set, Tuple, Iterable, Generator from volatility3.framework.symbols.linux.utilities import ( modules as linux_utilities_modules, ) -from volatility3.framework import interfaces, exceptions, deprecation +from volatility3.framework import ( + constants, + interfaces, + exceptions, + deprecation, + renderers, +) from volatility3.framework.configuration import requirements from volatility3.framework.symbols.linux import extensions from volatility3.framework.interfaces import plugins @@ -18,12 +24,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) ): @@ -81,24 +87,33 @@ def 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 = 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( @@ -195,3 +210,18 @@ def get_lsmod_module_addresses( ) } 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, + ) diff --git a/volatility3/framework/plugins/linux/lsmod.py b/volatility3/framework/plugins/linux/lsmod.py index 8ed52e3b7a..8db47cb955 100644 --- a/volatility3/framework/plugins/linux/lsmod.py +++ b/volatility3/framework/plugins/linux/lsmod.py @@ -7,7 +7,7 @@ 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 import constants, interfaces, deprecation, 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), + ), + requirements.BooleanRequirement( + name="dump", + description="Extract listed modules", + default=False, + optional=True, ), - ] + linux_utilities_modules.ModuleDisplayPlugin.get_requirements() + ] @classmethod @deprecation.deprecated_method( @@ -46,3 +60,18 @@ def list_modules( 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, + ) diff --git a/volatility3/framework/symbols/linux/utilities/modules.py b/volatility3/framework/symbols/linux/utilities/modules.py index 1c675a2838..0e5f8ac03d 100644 --- a/volatility3/framework/symbols/linux/utilities/modules.py +++ b/volatility3/framework/symbols/linux/utilities/modules.py @@ -1,6 +1,7 @@ import logging import warnings from typing import ( + Callable, Iterable, Iterator, List, @@ -23,7 +24,6 @@ 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 @@ -383,7 +383,7 @@ def get_hidden_modules( 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 @@ -920,19 +920,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, @@ -941,25 +933,29 @@ def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface] 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 @@ -969,21 +965,21 @@ def generator(self): 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 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( @@ -991,11 +987,11 @@ def generator(self): ) 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 0, ( @@ -1007,15 +1003,11 @@ def generator(self): file_name, ) - 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), + ]