mirror of
https://github.com/volatilityfoundation/volatility3.git
synced 2026-09-06 17:57:38 +02:00
CLI: Add support for a configuration options file
This commit is contained in:
+46
-12
@@ -19,7 +19,7 @@ import os
|
||||
import sys
|
||||
import tempfile
|
||||
import traceback
|
||||
from typing import Any, Dict, Type, Union
|
||||
from typing import Any, Dict, List, Tuple, Type, Union
|
||||
from urllib import parse, request
|
||||
|
||||
import volatility3.plugins
|
||||
@@ -92,6 +92,9 @@ class CommandLine:
|
||||
|
||||
renderers = dict([(x.name.lower(), x) for x in framework.class_subclasses(text_renderer.CLIRenderer)])
|
||||
|
||||
# Load up system defaults
|
||||
delayed_logs, default_config = self.load_system_defaults('vol.json')
|
||||
|
||||
parser = volargparse.HelpfulArgParser(add_help = False,
|
||||
prog = self.CLI_NAME,
|
||||
description = "An open-source memory forensics framework")
|
||||
@@ -174,6 +177,8 @@ class CommandLine:
|
||||
default = False,
|
||||
action = 'store_true')
|
||||
|
||||
parser.set_defaults(**default_config)
|
||||
|
||||
# We have to filter out help, otherwise parse_known_args will trigger the help message before having
|
||||
# processed the plugin choice or had the plugin subparser added.
|
||||
known_args = [arg for arg in sys.argv if arg != '--help' and arg != '-h']
|
||||
@@ -184,17 +189,7 @@ class CommandLine:
|
||||
banner_output = sys.stderr
|
||||
banner_output.write(f"Volatility 3 Framework {constants.PACKAGE_VERSION}\n")
|
||||
|
||||
if partial_args.plugin_dirs:
|
||||
volatility3.plugins.__path__ = [os.path.abspath(p)
|
||||
for p in partial_args.plugin_dirs.split(";")] + constants.PLUGINS_PATH
|
||||
|
||||
if partial_args.symbol_dirs:
|
||||
volatility3.symbols.__path__ = [os.path.abspath(p)
|
||||
for p in partial_args.symbol_dirs.split(";")] + constants.SYMBOL_BASEPATHS
|
||||
|
||||
if partial_args.cache_path:
|
||||
constants.CACHE_PATH = partial_args.cache_path
|
||||
|
||||
### Start up logging
|
||||
if partial_args.log:
|
||||
file_logger = logging.FileHandler(partial_args.log)
|
||||
file_logger.setLevel(1)
|
||||
@@ -210,6 +205,21 @@ class CommandLine:
|
||||
else:
|
||||
console.setLevel(10 - (partial_args.verbosity - 2))
|
||||
|
||||
for level, msg in delayed_logs:
|
||||
vollog.log(level, msg)
|
||||
|
||||
### Alter constants if necessary
|
||||
if partial_args.plugin_dirs:
|
||||
volatility3.plugins.__path__ = [os.path.abspath(p)
|
||||
for p in partial_args.plugin_dirs.split(";")] + constants.PLUGINS_PATH
|
||||
|
||||
if partial_args.symbol_dirs:
|
||||
volatility3.symbols.__path__ = [os.path.abspath(p)
|
||||
for p in partial_args.symbol_dirs.split(";")] + constants.SYMBOL_BASEPATHS
|
||||
|
||||
if partial_args.cache_path:
|
||||
constants.CACHE_PATH = partial_args.cache_path
|
||||
|
||||
vollog.info(f"Volatility plugins path: {volatility3.plugins.__path__}")
|
||||
vollog.info(f"Volatility symbols path: {volatility3.symbols.__path__}")
|
||||
|
||||
@@ -366,6 +376,30 @@ class CommandLine:
|
||||
raise ValueError(f"File does not exist: {filename}")
|
||||
return parse.urlunparse(single_location)
|
||||
|
||||
def load_system_defaults(self, filename: str) -> Tuple[List[Tuple[int, str]], Dict[str, Any]]:
|
||||
"""Modify the main configuration based on the default configuration override"""
|
||||
# Build the config path
|
||||
default_config_path = os.path.join(os.path.expanduser("~"), ".config", "volatility3", filename)
|
||||
if sys.platform == 'win32':
|
||||
default_config_path = os.path.join(os.environ.get("APPDATA", os.path.expanduser("~")), "volatility3",
|
||||
filename)
|
||||
|
||||
delayed_logs = []
|
||||
|
||||
# Process it if the files exist
|
||||
if os.path.exists(default_config_path):
|
||||
result = json.load(open(default_config_path, 'rb'))
|
||||
if not isinstance(result, dict):
|
||||
delayed_logs.append((logging.INFO,
|
||||
f'Default configuration file {default_config_path} does not contain a dictionary'))
|
||||
else:
|
||||
delayed_logs.append(
|
||||
(logging.INFO, f"Loading default configuration options from {default_config_path}"))
|
||||
delayed_logs.append((logging.DEBUG,
|
||||
f"Loaded configuration: {json.dumps(result, indent = 2, sort_keys = True)}"))
|
||||
return delayed_logs, result
|
||||
return delayed_logs, {}
|
||||
|
||||
def process_exceptions(self, excp):
|
||||
"""Provide useful feedback if an exception occurs during a run of a plugin."""
|
||||
# Ensure there's nothing in the cache
|
||||
|
||||
@@ -45,6 +45,9 @@ class VolShell(cli.CommandLine):
|
||||
|
||||
framework.require_interface_version(2, 0, 0)
|
||||
|
||||
# Load up system defaults
|
||||
delayed_logs, default_config = self.load_system_defaults('volshell.json')
|
||||
|
||||
parser = argparse.ArgumentParser(prog = self.CLI_NAME,
|
||||
description = "A tool for interactivate forensic analysis of memory images")
|
||||
parser.add_argument("-c",
|
||||
@@ -68,13 +71,16 @@ class VolShell(cli.CommandLine):
|
||||
default = "",
|
||||
type = str)
|
||||
parser.add_argument("-v", "--verbosity", help = "Increase output verbosity", default = 0, action = "count")
|
||||
parser.add_argument("--log",
|
||||
help = "Log output to a file as well as the console",
|
||||
default = None,
|
||||
type = str)
|
||||
parser.add_argument("-o",
|
||||
"--output-dir",
|
||||
help = "Directory in which to output any generated files",
|
||||
default = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..')),
|
||||
type = str)
|
||||
parser.add_argument("-q", "--quiet", help = "Remove progress feedback", default = False, action = 'store_true')
|
||||
parser.add_argument("--log", help = "Log output to a file as well as the console", default = None, type = str)
|
||||
parser.add_argument("-f",
|
||||
"--file",
|
||||
metavar = 'FILE',
|
||||
@@ -97,6 +103,10 @@ class VolShell(cli.CommandLine):
|
||||
help = f"Change the default path ({constants.CACHE_PATH}) used to store the cache",
|
||||
default = constants.CACHE_PATH,
|
||||
type = str)
|
||||
parser.add_argument("--offline",
|
||||
help = "Do not search online for additional JSON files",
|
||||
default = False,
|
||||
action = 'store_true')
|
||||
|
||||
# Volshell specific flags
|
||||
os_specific = parser.add_mutually_exclusive_group(required = False)
|
||||
@@ -108,10 +118,33 @@ class VolShell(cli.CommandLine):
|
||||
os_specific.add_argument("-l", "--linux", default = False, action = "store_true", help = "Run a Linux volshell")
|
||||
os_specific.add_argument("-m", "--mac", default = False, action = "store_true", help = "Run a Mac volshell")
|
||||
|
||||
parser.set_defaults(**default_config)
|
||||
|
||||
# We have to filter out help, otherwise parse_known_args will trigger the help message before having
|
||||
# processed the plugin choice or had the plugin subparser added.
|
||||
known_args = [arg for arg in sys.argv if arg != '--help' and arg != '-h']
|
||||
partial_args, _ = parser.parse_known_args(known_args)
|
||||
|
||||
### Start up logging
|
||||
if partial_args.log:
|
||||
file_logger = logging.FileHandler(partial_args.log)
|
||||
file_logger.setLevel(1)
|
||||
file_formatter = logging.Formatter(datefmt = '%y-%m-%d %H:%M:%S',
|
||||
fmt = '%(asctime)s %(name)-12s %(levelname)-8s %(message)s')
|
||||
file_logger.setFormatter(file_formatter)
|
||||
rootlog.addHandler(file_logger)
|
||||
vollog.info("Logging started")
|
||||
if partial_args.verbosity < 3:
|
||||
if partial_args.verbosity < 1:
|
||||
sys.tracebacklimit = None
|
||||
console.setLevel(30 - (partial_args.verbosity * 10))
|
||||
else:
|
||||
console.setLevel(10 - (partial_args.verbosity - 2))
|
||||
|
||||
for level, msg in delayed_logs:
|
||||
vollog.log(level, msg)
|
||||
|
||||
### Alter constants if necessary
|
||||
if partial_args.plugin_dirs:
|
||||
volatility3.plugins.__path__ = [os.path.abspath(p)
|
||||
for p in partial_args.plugin_dirs.split(";")] + constants.PLUGINS_PATH
|
||||
@@ -126,23 +159,13 @@ class VolShell(cli.CommandLine):
|
||||
vollog.info(f"Volatility plugins path: {volatility3.plugins.__path__}")
|
||||
vollog.info(f"Volatility symbols path: {volatility3.symbols.__path__}")
|
||||
|
||||
if partial_args.log:
|
||||
file_logger = logging.FileHandler(partial_args.log)
|
||||
file_logger.setLevel(0)
|
||||
file_formatter = logging.Formatter(datefmt = '%y-%m-%d %H:%M:%S',
|
||||
fmt = '%(asctime)s %(name)-12s %(levelname)-8s %(message)s')
|
||||
file_logger.setFormatter(file_formatter)
|
||||
vollog.addHandler(file_logger)
|
||||
vollog.info("Logging started")
|
||||
|
||||
if partial_args.verbosity < 3:
|
||||
console.setLevel(30 - (partial_args.verbosity * 10))
|
||||
else:
|
||||
console.setLevel(10 - (partial_args.verbosity - 2))
|
||||
|
||||
if partial_args.clear_cache:
|
||||
framework.clear_cache()
|
||||
|
||||
if partial_args.offline:
|
||||
constants.OFFLINE = partial_args.offline
|
||||
|
||||
# Do the initialization
|
||||
ctx = contexts.Context() # Construct a blank context
|
||||
failures = framework.import_files(volatility3.plugins,
|
||||
|
||||
Reference in New Issue
Block a user