Files
volatility3/volatility/cli/__init__.py
T

137 lines
5.1 KiB
Python

"""A CommandLine User Interface for the volatility framework
User interfaces make use of the framework to:
* determine available plugins
* request necessary information for those plugins from the user
* determine what "automagic" modules will be used to populate information the user does not provide
* run the plugin
* display the results
"""
import argparse
import json
import logging
import os
import sys
import volatility.framework
import volatility.plugins
from volatility.framework import automagic, constants, contexts, interfaces
from volatility.framework.interfaces.configuration import HierarchicalDict
from volatility.framework.renderers.text import TextRenderer
__author__ = 'mike'
# Make sure we log everything
logging.basicConfig(filename = 'example.log',
format = '%(asctime)s %(name)-12s %(levelname)-8s %(message)s',
datefmt = '%m-%d %H:%M',
level = 0)
vollog = logging.getLogger("volatility")
console = logging.StreamHandler()
# Trim the console down by default
console.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(levelname)-8s %(name)-12s: %(message)s')
console.setFormatter(formatter)
logging.getLogger("").addHandler(console)
class CommandLine(object):
"""Constructs a command-line interface object for users to run plugins"""
def __init__(self):
pass
def run(self):
"""Executes the command line module, taking the system arguments, determining the plugin to run and then running it"""
sys.stdout.write("Volatility Framework {}\n".format(constants.PACKAGE_VERSION))
volatility.framework.require_interface_version(0, 0, 0)
# TODO: Get CLI config options
volatility.framework.import_files(volatility.plugins)
# TODO: Choose a plugin
parser = argparse.ArgumentParser(prog = 'volatility',
description = "An open-source memory forensics framework")
parser.add_argument("-p", "--plugin", help = "Run the following plugin", default = "windows.pslist.PsList")
parser.add_argument("file", help = "Temporary method for changing the file", default = None)
parser.add_argument("-c", "--config", help = "Load the configuration from a json file", default = None,
type = str)
parser.add_argument("-v", "--verbosity", help = "Increase output verbosity", default = 0, action = "count")
# argparse_adapter.adapt_config(context.config, parser)
# Run the argparser
args = parser.parse_args()
console.setLevel(10 - min(3, args.verbosity))
print("PLUGIN", args.plugin)
plug_class = args.plugin.split(".")[-1]
plug_mod = ".".join(args.plugin.split(".")[:-1])
plug_name = "volatility.plugins." + plug_mod
plugin = None
for module in sys.modules:
if plug_name == module:
plugin = getattr(sys.modules[module], plug_class)
break
else:
raise RuntimeError("Invalid plugin requested: {}".format(plug_name))
config_path = interfaces.configuration.path_join("plugins", plugin.__name__.lower())
###
# PASS TO UI
###
# Hand the plugin requirements over to the CLI (us) and let it construct the config tree
# UI fills in the config:
ctx = contexts.Context()
if args.config:
with open(args.config, "r") as f:
json_val = json.load(f)
ctx.config.splice("plugins.pslist", HierarchicalDict(json_val))
if not args.file or not os.path.exists(args.file):
raise RuntimeError("Please provide a valid filename")
else:
ctx.config["automagic.LayerStacker.single_location"] = "file://" + os.path.abspath(args.file)
pass
###
# BACK TO THE FRAMEWORK
###
# Clever magic figures out how to fulfill each requirement that might not be fulfilled
automagics = automagic.available(ctx)
automagic.run(automagics, ctx, plugin, "plugins", progress_callback = progress_callback)
# Check all the requirements and/or go back to the automagic step
if not plugin.validate(ctx, config_path):
raise RuntimeError("Unable to validate the plugin configuration")
print("\n\n")
constructed = plugin(ctx, config_path)
with open("config.json", "w") as f:
json.dump(dict(constructed.build_configuration()), f, sort_keys = True, indent = 2)
# Construct and run the plugin
TextRenderer().render(constructed.run())
def progress_callback(progress, description = None):
""" A sinmple function for providing text-based feedback
.. warning:: Only for development use.
:param progress: Percentage of progress of the current procedure
:type progress: int or float
"""
print("\rProgress: ", round(progress, 2), "\t\t", description or '', end = '\n')
def main():
"""A convenience function for constructing and running the :class:`CommandLine`'s run method"""
CommandLine().run()