mirror of
https://github.com/volatilityfoundation/volatility3.git
synced 2026-09-28 04:24:53 +02:00
Linux: pslist: Add the boottime plugin
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
# 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 datetime
|
||||
from typing import List, Tuple, Iterable
|
||||
|
||||
|
||||
from volatility3.framework import interfaces, renderers
|
||||
from volatility3.framework.configuration import requirements
|
||||
from volatility3.plugins import timeliner
|
||||
from volatility3.plugins.linux import pslist
|
||||
|
||||
|
||||
class Boottime(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
"""Shows the time the system was started"""
|
||||
|
||||
_required_framework_version = (2, 11, 0)
|
||||
|
||||
_version = (1, 0, 0)
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
|
||||
return [
|
||||
requirements.ModuleRequirement(
|
||||
name="kernel",
|
||||
description="Linux kernel",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="pslist", plugin=pslist.PsList, version=(2, 3, 0)
|
||||
),
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def get_time_namespaces_bootime(
|
||||
cls,
|
||||
context: interfaces.context.ContextInterface,
|
||||
vmlinux_module_name: str,
|
||||
) -> Iterable[Tuple[int, int, int, str, datetime.datetime]]:
|
||||
"""Enumerates tasks' boot times based on their time namespaces.
|
||||
|
||||
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
|
||||
pids: Pid list
|
||||
unique: Filter unique time namespaces
|
||||
|
||||
Yields:
|
||||
A tuple with the fields to show in the plugin output.
|
||||
"""
|
||||
time_namespace_ids = set()
|
||||
for task in pslist.PsList.list_tasks(context, vmlinux_module_name):
|
||||
time_namespace_id = task.get_time_namespace_id()
|
||||
# If it cannot get the time namespace i.e. kernels < 5.6, this still works
|
||||
# using None to just get the first tasks
|
||||
if time_namespace_id in time_namespace_ids:
|
||||
continue
|
||||
time_namespace_ids.add(time_namespace_id)
|
||||
boottime = task.get_boottime(root_time_namespace=False)
|
||||
|
||||
fields = (
|
||||
time_namespace_id,
|
||||
boottime,
|
||||
)
|
||||
yield fields
|
||||
|
||||
def _generator(self):
|
||||
for (
|
||||
time_namespace_id,
|
||||
boottime,
|
||||
) in self.get_time_namespaces_bootime(
|
||||
self.context,
|
||||
self.config["kernel"],
|
||||
):
|
||||
fields = [
|
||||
time_namespace_id or renderers.NotAvailableValue(),
|
||||
boottime,
|
||||
]
|
||||
yield 0, fields
|
||||
|
||||
def generate_timeline(self):
|
||||
for (
|
||||
time_namespace_id,
|
||||
boottime,
|
||||
) in self.get_time_namespaces_bootime(
|
||||
self.context,
|
||||
self.config["kernel"],
|
||||
):
|
||||
description = f"System boot time for time namespace {time_namespace_id}"
|
||||
|
||||
yield description, timeliner.TimeLinerType.BOOTTIME, boottime
|
||||
|
||||
def run(self):
|
||||
columns = [
|
||||
("TIME NS", int),
|
||||
("Boot Time", datetime.datetime),
|
||||
]
|
||||
return renderers.TreeGrid(columns, self._generator())
|
||||
@@ -23,6 +23,7 @@ class TimeLinerType(enum.IntEnum):
|
||||
MODIFIED = 2
|
||||
ACCESSED = 3
|
||||
CHANGED = 4
|
||||
BOOTTIME = 5
|
||||
|
||||
|
||||
class TimeLinerInterface(metaclass=abc.ABCMeta):
|
||||
@@ -171,6 +172,10 @@ class Timeliner(interfaces.plugins.PluginInterface):
|
||||
TimeLinerType.CHANGED,
|
||||
renderers.NotApplicableValue(),
|
||||
),
|
||||
times.get(
|
||||
TimeLinerType.BOOTTIME,
|
||||
renderers.NotApplicableValue(),
|
||||
),
|
||||
],
|
||||
)
|
||||
)
|
||||
@@ -178,11 +183,11 @@ class Timeliner(interfaces.plugins.PluginInterface):
|
||||
# Write each entry because the body file doesn't need to be sorted
|
||||
if fp:
|
||||
times = self.timeline[(plugin_name, item)]
|
||||
# Body format is: MD5|name|inode|mode_as_string|UID|GID|size|atime|mtime|ctime|crtime
|
||||
# Body format is: MD5|name|inode|mode_as_string|UID|GID|size|atime|mtime|ctime|crtime|boottime
|
||||
|
||||
if self._any_time_present(times):
|
||||
fp.write(
|
||||
"|{} - {}|0|0|0|0|0|{}|{}|{}|{}\n".format(
|
||||
"|{} - {}|0|0|0|0|0|{}|{}|{}|{}|{}\n".format(
|
||||
plugin_name,
|
||||
self._sanitize_body_format(item),
|
||||
self._text_format(
|
||||
@@ -197,6 +202,9 @@ class Timeliner(interfaces.plugins.PluginInterface):
|
||||
self._text_format(
|
||||
times.get(TimeLinerType.CREATED, "0")
|
||||
),
|
||||
self._text_format(
|
||||
times.get(TimeLinerType.BOOTTIME, "0")
|
||||
),
|
||||
)
|
||||
)
|
||||
except Exception as e:
|
||||
@@ -320,6 +328,7 @@ class Timeliner(interfaces.plugins.PluginInterface):
|
||||
("Modified Date", datetime.datetime),
|
||||
("Accessed Date", datetime.datetime),
|
||||
("Changed Date", datetime.datetime),
|
||||
("Boot Date", datetime.datetime),
|
||||
],
|
||||
generator=self._generator(plugins_to_run),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user