Source code for volatility3.plugins.linux.malware.modxview

# This file is Copyright 2024 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 Dict, Iterator, List

import volatility3.framework.symbols.linux.utilities.modules as linux_utilities_modules
from volatility3.framework import deprecation, interfaces, renderers
from volatility3.framework.configuration import requirements
from volatility3.framework.constants import architectures
from volatility3.framework.renderers import format_hints
from volatility3.framework.symbols.linux import extensions
from volatility3.framework.symbols.linux.utilities import tainting

vollog = logging.getLogger(__name__)


[docs] class Modxview(interfaces.plugins.PluginInterface): """Centralize lsmod, check_modules and hidden_modules results to efficiently \ spot modules presence and taints.""" _version = (1, 0, 0) _required_framework_version = (2, 17, 0)
[docs] @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=linux_utilities_modules.Modules, 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) ), requirements.BooleanRequirement( name="plain_taints", description="Display the plain taints string for each module.", optional=True, default=False, ), ]
[docs] @classmethod @deprecation.deprecated_method( replacement=linux_utilities_modules.Modules.flatten_run_modules_results, replacement_version=(3, 0, 0), removal_date="2026-03-25", ) def flatten_run_modules_results( cls, run_results: Dict[str, List[extensions.module]], deduplicate: bool = True ) -> Iterator[extensions.module]: """Flatten a dictionary mapping plugin names and modules list, to a single merged list. This is useful to get a generic lookup list of all the detected modules. Args: run_results: dictionary of plugin names mapping a list of detected modules deduplicate: remove duplicate modules, based on their offsets Returns: Iterator of modules objects """ return linux_utilities_modules.Modules.flatten_run_modules_results( run_results, deduplicate )
[docs] @classmethod @deprecation.deprecated_method( replacement=linux_utilities_modules.Modules.run_modules_scanners, replacement_version=(3, 0, 0), removal_date="2026-03-25", ) def run_modules_scanners( cls, context: interfaces.context.ContextInterface, kernel_name: str, run_hidden_modules: bool = True, ) -> Dict[str, List[extensions.module]]: """Run module scanning plugins and aggregate the results. It is designed to not operate any inter-plugin results triage.""" return linux_utilities_modules.Modules.run_modules_scanners( context, kernel_name, run_hidden_modules )
def _generator(self): kernel = self.context.modules[self.config["kernel"]] wanted_gatherers = [ linux_utilities_modules.ModuleGathererLsmod, linux_utilities_modules.ModuleGathererSysFs, linux_utilities_modules.ModuleGathererScanner, ] run_results = linux_utilities_modules.Modules.run_modules_scanners( 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 gatherer in wanted_gatherers: # Iterate over each recovered module 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(gatherer.name) else: aggregated_modules[mod_info.offset] = [gatherer.name] 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, self.config["kernel"], module.taints, True, ) else: taints = ",".join( tainting.Tainting.get_taints_parsed( self.context, self.config["kernel"], module.taints, True, ) ) yield ( 0, ( module.get_name() or renderers.NotAvailableValue(), format_hints.Hex(module_offset), linux_utilities_modules.ModuleGathererLsmod.name in gatherers, linux_utilities_modules.ModuleGathererSysFs.name in gatherers, linux_utilities_modules.ModuleGathererScanner.name in gatherers, taints or renderers.NotAvailableValue(), ), )
[docs] def run(self): columns = [ ("Name", str), ("Address", format_hints.Hex), ("In procfs", bool), ("In sysfs", bool), ("In scan", bool), ("Taints", str), ] return renderers.TreeGrid( columns, self._generator(), )