mirror of
https://github.com/volatilityfoundation/volatility3.git
synced 2026-09-02 14:28:58 +02:00
Plugins: categorize linux.modxview as a malware plugin
This commit is contained in:
@@ -0,0 +1,181 @@
|
||||
# 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 List, Dict, Iterator
|
||||
|
||||
import volatility3.framework.symbols.linux.utilities.modules as linux_utilities_modules
|
||||
|
||||
from volatility3.framework import interfaces, deprecation, renderers
|
||||
from volatility3.framework.configuration import requirements
|
||||
from volatility3.framework.renderers import format_hints
|
||||
from volatility3.framework.symbols.linux import extensions
|
||||
from volatility3.framework.constants import architectures
|
||||
from volatility3.framework.symbols.linux.utilities import tainting
|
||||
|
||||
vollog = logging.getLogger(__name__)
|
||||
|
||||
|
||||
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)
|
||||
|
||||
@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,
|
||||
),
|
||||
]
|
||||
|
||||
@classmethod
|
||||
@deprecation.deprecated_method(
|
||||
replacement=linux_utilities_modules.Modules.flatten_run_modules_results,
|
||||
replacement_version=(3, 0, 0),
|
||||
removal_date="2025-09-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
|
||||
)
|
||||
|
||||
@classmethod
|
||||
@deprecation.deprecated_method(
|
||||
replacement=linux_utilities_modules.Modules.run_modules_scanners,
|
||||
replacement_version=(3, 0, 0),
|
||||
removal_date="2025-09-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(),
|
||||
),
|
||||
)
|
||||
|
||||
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(),
|
||||
)
|
||||
@@ -1,181 +1,22 @@
|
||||
# This file is Copyright 2024 Volatility Foundation and licensed under the Volatility Software License 1.0
|
||||
# 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, Dict, Iterator
|
||||
|
||||
import volatility3.framework.symbols.linux.utilities.modules as linux_utilities_modules
|
||||
|
||||
from volatility3.framework import interfaces, deprecation, renderers
|
||||
from volatility3.framework.configuration import requirements
|
||||
from volatility3.framework.renderers import format_hints
|
||||
from volatility3.framework.symbols.linux import extensions
|
||||
from volatility3.framework.constants import architectures
|
||||
from volatility3.framework.symbols.linux.utilities import tainting
|
||||
from volatility3.framework import interfaces, deprecation
|
||||
from volatility3.plugins.linux.malware import modxview
|
||||
|
||||
vollog = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Modxview(interfaces.plugins.PluginInterface):
|
||||
class Modxview(
|
||||
interfaces.plugins.PluginInterface,
|
||||
deprecation.PluginRenameClass,
|
||||
replacement_class=modxview.Modxview,
|
||||
removal_date="2026-06-07",
|
||||
):
|
||||
|
||||
"""Centralize lsmod, check_modules and hidden_modules results to efficiently \
|
||||
spot modules presence and taints."""
|
||||
spot modules presence and taints (deprecated)."""
|
||||
|
||||
_version = (1, 0, 0)
|
||||
_required_framework_version = (2, 17, 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=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,
|
||||
),
|
||||
]
|
||||
|
||||
@classmethod
|
||||
@deprecation.deprecated_method(
|
||||
replacement=linux_utilities_modules.Modules.flatten_run_modules_results,
|
||||
replacement_version=(3, 0, 0),
|
||||
removal_date="2025-09-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
|
||||
)
|
||||
|
||||
@classmethod
|
||||
@deprecation.deprecated_method(
|
||||
replacement=linux_utilities_modules.Modules.run_modules_scanners,
|
||||
replacement_version=(3, 0, 0),
|
||||
removal_date="2025-09-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(),
|
||||
),
|
||||
)
|
||||
|
||||
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(),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user