Files
volatility3/volatility/plugins/timeliner.py
T

129 lines
5.9 KiB
Python

import abc
import datetime
import enum
import logging
import traceback
import typing
from volatility import framework
from volatility.framework import renderers, automagic
from volatility.framework.configuration import requirements
from volatility.framework.interfaces import plugins, configuration
vollog = logging.getLogger(__name__)
class TimeLinerType(enum.IntEnum):
CREATED = 1
MODIFIED = 2
ACCESSED = 3
CHANGED = 4
class TimeLinerInterface(object, metaclass = abc.ABCMeta):
"""Interface defining methods that timeliner will use to generate a body file"""
@abc.abstractmethod
def generate_timeline(self) -> typing.Generator[
typing.Tuple[str, TimeLinerType, datetime.datetime, TimeLinerType], None, None]:
"""Method generates Tuples of (description, timestamp_type, timestamp)
These need not be generated in any particular order, sorting will be done later
"""
class Timeliner(plugins.PluginInterface):
"""Runs all relevant plugins that provide time related information and orders the results by time"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.timeline = {}
@classmethod
def get_requirements(cls):
return [requirements.StringRequirement(name = 'plugins',
description = "Comma separated list of plugins to run",
optional = True,
default = None)]
def _generator(self) -> typing.Optional[typing.Iterable[typing.Tuple[int, typing.Tuple]]]:
"""Takes a timeline, sorts it and output the data from each relevant row from each plugin"""
# Generate the results for each plugin
for plugin in self.runable_plugins:
plugin_name = plugin.__class__.__name__
try:
vollog.log(logging.INFO, "Running {}".format(plugin_name))
for (item, timestamp_type, timestamp) in plugin.generate_timeline():
times = self.timeline.get((plugin_name, item), {})
if times.get(timestamp_type, None) is not None:
vollog.debug(
"Multiple timestamps for the same plugin/file combination found: {} {}".format(plugin_name,
item))
times[timestamp_type] = timestamp
self.timeline[(plugin_name, item)] = times
except Exception:
# FIXME: traceback shouldn't be printed directly, but logged instead
traceback.print_exc()
vollog.log(logging.INFO, "Exception occurred running plugin: {}".format(plugin_name))
for (plugin_name, item) in self.timeline:
times = self.timeline[(plugin_name, item)]
data = (0, [plugin_name, item,
times.get(TimeLinerType.CREATED, renderers.NotApplicableValue()),
times.get(TimeLinerType.MODIFIED, renderers.NotApplicableValue()),
times.get(TimeLinerType.ACCESSED, renderers.NotApplicableValue()),
times.get(TimeLinerType.CHANGED, renderers.NotApplicableValue())])
yield data
def run(self):
"""Isolate each plugin and run it"""
# Initialize for the run
sep = configuration.CONFIG_SEPARATOR
plugin_list = list(framework.class_subclasses(TimeLinerInterface))
automagics = automagic.available(self._context)
self.runable_plugins = []
# Get the filter from the configuration
selected_list = self.config.get('plugins', None)
if selected_list is not None:
selected_list = selected_list.split(",")
else:
# Use all the plugins if there's no filter
selected_list = [plugin.__name__ for plugin in plugin_list]
# Identify plugins that we can run which output datetimes
for plugin_class in plugin_list:
usable = False
plugin_name = plugin_class.__name__
for selected in selected_list:
if selected in plugin_name:
usable = True
if usable:
try:
automagics = automagic.choose_automagic(automagics, plugin_class)
automagic_config_path = configuration.path_join(self.config_path,
sep.join(plugin_name.split(sep)[:-1]))
errors = automagic.run(automagics,
self.context,
plugin_class,
automagic_config_path,
progress_callback = self._progress_callback)
for error in errors:
vollog.log(logging.DEBUG, "\n".join(error.format(chain = True)))
plugin = plugin_class(self.context,
configuration.path_join(self.config_path, plugin_name),
progress_callback = self._progress_callback)
self.runable_plugins.append(plugin)
except Exception:
# Remove the failed plugin from the list and continue
continue
return renderers.TreeGrid(columns = [("Plugin", str),
("Description", str),
("Created Date", datetime.datetime),
("Modified Date", datetime.datetime),
("Accessed Date", datetime.datetime),
("Changed Date", datetime.datetime)],
generator = self._generator())