From 16194ef114b3e1622889c1f8d8b45ede12d472f8 Mon Sep 17 00:00:00 2001 From: Mike Auty Date: Mon, 16 Sep 2019 11:35:46 +0100 Subject: [PATCH] Add in linux and mac volshell support. --- volatility/cli/volshell/__init__.py | 13 +++++-- volatility/cli/volshell/linux.py | 55 +++++++++++++++++++++++++++++ volatility/cli/volshell/mac.py | 55 +++++++++++++++++++++++++++++ volatility/cli/volshell/windows.py | 11 +++--- 4 files changed, 125 insertions(+), 9 deletions(-) create mode 100644 volatility/cli/volshell/linux.py create mode 100644 volatility/cli/volshell/mac.py diff --git a/volatility/cli/volshell/__init__.py b/volatility/cli/volshell/__init__.py index 0508067f5..dd1f8cbf1 100644 --- a/volatility/cli/volshell/__init__.py +++ b/volatility/cli/volshell/__init__.py @@ -13,7 +13,7 @@ import volatility.plugins import volatility.symbols from volatility import cli, framework from volatility.cli import text_renderer -from volatility.cli.volshell import shellplugin, windows +from volatility.cli.volshell import shellplugin, windows, linux, mac from volatility.framework import automagic, constants, contexts, exceptions, interfaces, plugins # Make sure we log everything @@ -90,8 +90,11 @@ class VolShell(cli.CommandLine): action = 'store_true') # Volshell specific flags - parser.add_argument("-w", "--windows", default = False, action = "store_true", help = "Run a Windows volshell") - parser.add_argument("-l", "--linux", default = False, action = "store_true", help = "Run a Linux volshell") + os_specific = parser.add_mutually_exclusive_group(required = False) + os_specific.add_argument( + "-w", "--windows", default = False, action = "store_true", help = "Run a Windows volshell") + 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") # 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. @@ -163,6 +166,10 @@ class VolShell(cli.CommandLine): plugin = shellplugin.Volshell if args.windows: plugin = windows.Volshell + if args.linux: + plugin = linux.Volshell + if args.mac: + plugin = mac.Volshell base_config_path = "plugins" plugin_config_path = interfaces.configuration.path_join(base_config_path, plugin.__name__) diff --git a/volatility/cli/volshell/linux.py b/volatility/cli/volshell/linux.py new file mode 100644 index 000000000..92d90e92c --- /dev/null +++ b/volatility/cli/volshell/linux.py @@ -0,0 +1,55 @@ +# This file is Copyright 2019 Volatility Foundation and licensed under the Volatility Software License 1.0 +# which is available at https://www.volatilityfoundation.org/license/vsl_v1.0 +# + +from typing import Dict, Any + +from volatility.cli.volshell import shellplugin +from volatility.framework.configuration import requirements +from volatility.plugins.linux import pslist + + +class Volshell(shellplugin.Volshell): + """Shell environment to directly interact with a linux memory image.""" + + @classmethod + def get_requirements(cls): + return (super().get_requirements() + [ + requirements.SymbolTableRequirement(name = "vmlinux", description = "Linux kernel symbols"), + requirements.PluginRequirement(name = 'pslist', plugin = pslist.PsList, version = (1, 0, 0)), + requirements.IntRequirement(name = 'pid', description = "Process ID", optional = True) + ]) + + def change_task(self, pid = None): + """Change the current process and layer, based on a process ID""" + tasks = self.list_tasks() + for task in tasks: + if task.pid == pid: + process_layer = task.add_process_layer() + if process_layer is not None: + self.change_layer(process_layer) + return + print("Layer for task ID {} could not be constructed".format(pid)) + return + print("No task with task ID {} found".format(pid)) + + def list_tasks(self): + """Returns a list of task objects from the primary layer""" + # We always use the main kernel memory and associated symbols + return list(pslist.PsList.list_tasks(self.context, self.config['primary'], self.config['vmlinux'])) + + def construct_locals(self) -> Dict[str, Any]: + result = super().construct_locals() + result.update({ + 'ct': self.change_task, + 'change_task': self.change_task, + 'lt': self.list_tasks, + 'list_tasks': self.list_tasks, + 'symbols': self.context.symbol_space[self.config['vmlinux']], + # windows/windbg compatibility aliases + 'cp': self.change_task, + 'ps': self.list_tasks, + }) + if self.config.get('pid', None) is not None: + self.change_task(self.config['pid']) + return result diff --git a/volatility/cli/volshell/mac.py b/volatility/cli/volshell/mac.py new file mode 100644 index 000000000..6fd38abb1 --- /dev/null +++ b/volatility/cli/volshell/mac.py @@ -0,0 +1,55 @@ +# This file is Copyright 2019 Volatility Foundation and licensed under the Volatility Software License 1.0 +# which is available at https://www.volatilityfoundation.org/license/vsl_v1.0 +# + +from typing import Dict, Any + +from volatility.cli.volshell import shellplugin +from volatility.framework.configuration import requirements +from volatility.plugins.mac import pslist + + +class Volshell(shellplugin.Volshell): + """Shell environment to directly interact with a mac memory image.""" + + @classmethod + def get_requirements(cls): + return (super().get_requirements() + [ + requirements.SymbolTableRequirement(name = "darwin", description = "Darwin kernel symbols"), + requirements.PluginRequirement(name = 'pslist', plugin = pslist.PsList, version = (1, 0, 0)), + requirements.IntRequirement(name = 'pid', description = "Process ID", optional = True) + ]) + + def change_task(self, pid = None): + """Change the current process and layer, based on a process ID""" + tasks = self.list_tasks() + for task in tasks: + if task.pid == pid: + process_layer = task.add_process_layer() + if process_layer is not None: + self.change_layer(process_layer) + return + print("Layer for task ID {} could not be constructed".format(pid)) + return + print("No task with task ID {} found".format(pid)) + + def list_tasks(self): + """Returns a list of task objects from the primary layer""" + # We always use the main kernel memory and associated symbols + return list(pslist.PsList.list_tasks(self.context, self.config['primary'], self.config['darwin'])) + + def construct_locals(self) -> Dict[str, Any]: + result = super().construct_locals() + result.update({ + 'ct': self.change_task, + 'change_task': self.change_task, + 'lt': self.list_tasks, + 'list_tasks': self.list_tasks, + 'symbols': self.context.symbol_space[self.config['darwin']], + # windows/windbg compatibility aliases + 'cp': self.change_task, + 'ps': self.list_tasks, + }) + if self.config.get('pid', None) is not None: + self.change_task(self.config['pid']) + return result diff --git a/volatility/cli/volshell/windows.py b/volatility/cli/volshell/windows.py index 54114f571..d29b94a9f 100644 --- a/volatility/cli/volshell/windows.py +++ b/volatility/cli/volshell/windows.py @@ -12,9 +12,6 @@ from volatility.plugins.windows import pslist class Volshell(shellplugin.Volshell): """Shell environment to directly interact with a windows memory image.""" - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - @classmethod def get_requirements(cls): return (super().get_requirements() + [ @@ -35,7 +32,7 @@ class Volshell(shellplugin.Volshell): def list_processes(self): """Returns a list of EPROCESS objects from the primary layer""" - # We always use the main kernel memory and the symbols + # We always use the main kernel memory and associated symbols return list(pslist.PsList.list_processes(self.context, self.config['primary'], self.config['nt_symbols'])) def construct_locals(self) -> Dict[str, Any]: @@ -43,9 +40,11 @@ class Volshell(shellplugin.Volshell): result.update({ 'cp': self.change_process, 'change_process': self.change_process, - 'ps': self.list_processes, + 'lp': self.list_processes, 'list_processes': self.list_processes, - 'symbols': self.context.symbol_space[self.config['nt_symbols']] + 'symbols': self.context.symbol_space[self.config['nt_symbols']], + # windbg compatibility aliases + 'ps': self.list_processes, }) if self.config.get('pid', None) is not None: self.change_process(self.config['pid'])