diff --git a/volatility/cli/volshell/__init__.py b/volatility/cli/volshell/__init__.py index 739bd1c65..146908dc1 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, linux, mac +from volatility.cli.volshell import generic, windows, linux, mac from volatility.framework import automagic, constants, contexts, exceptions, interfaces, plugins # Make sure we log everything @@ -145,7 +145,7 @@ class VolShell(cli.CommandLine): configurables_list[amagic.__class__.__name__] = amagic # We don't list plugin arguments, because they can be provided within python - volshell_plugin_list = {'generic': shellplugin.Volshell, 'windows': windows.Volshell} + volshell_plugin_list = {'generic': generic.Volshell, 'windows': windows.Volshell} for plugin in volshell_plugin_list: subparser = parser.add_argument_group(title = plugin.capitalize(), description = "Configuration options based on {} options".format( @@ -163,7 +163,7 @@ class VolShell(cli.CommandLine): vollog.log(constants.LOGLEVEL_VVV, "Cache directory used: {}".format(constants.CACHE_PATH)) - plugin = shellplugin.Volshell + plugin = generic.Volshell if args.windows: plugin = windows.Volshell if args.linux: diff --git a/volatility/cli/volshell/shellplugin.py b/volatility/cli/volshell/generic.py similarity index 84% rename from volatility/cli/volshell/shellplugin.py rename to volatility/cli/volshell/generic.py index ebe259ce8..e56876c25 100644 --- a/volatility/cli/volshell/shellplugin.py +++ b/volatility/cli/volshell/generic.py @@ -5,7 +5,7 @@ import binascii import code import struct import sys -from typing import Any, Dict, List, Optional +from typing import Any, Dict, List, Optional, Tuple from volatility.framework import renderers, interfaces from volatility.framework.configuration import requirements @@ -50,15 +50,25 @@ class Volshell(interfaces.plugins.PluginInterface): pass else: import rlcompleter - completer = rlcompleter.Completer(namespace = self.construct_locals()) + completer = rlcompleter.Completer(namespace = self._construct_locals_dict()) readline.set_completer(completer.complete) readline.parse_and_bind("tab: complete") print("Readline imported successfully") # TODO: provide help, consider generic functions (pslist?) and/or providing windows/linux functions + mode = self.__module__.split('.')[-1] + mode = mode[0].upper() + mode[1:] + + banner = """ + Call help() to see available functions + + Volshell mode: {} + Current Layer: {} + """.format(mode, self.current_layer) + sys.ps1 = "({}) >>> ".format(self.current_layer) - code.interact(banner = "\nCall help() to see available functions\n", local = self.construct_locals()) + code.interact(banner = banner, local = self._construct_locals_dict()) return renderers.TreeGrid([("Terminating", str)], None) @@ -66,7 +76,8 @@ class Volshell(interfaces.plugins.PluginInterface): """Describes the available commands""" variables = [] print("\nMethods:") - for name, item in self.construct_locals().items(): + for aliases, item in self.construct_locals(): + name = ", ".join(aliases) if item.__doc__ and callable(item): print("* {}".format(name)) print(" {}".format(item.__doc__)) @@ -77,29 +88,23 @@ class Volshell(interfaces.plugins.PluginInterface): for var in variables: print(" {}".format(var)) - def construct_locals(self) -> Dict[str, Any]: + def construct_locals(self) -> List[Tuple[List[str], Any]]: """Returns a dictionary listing the functions to be added to the environment.""" - return { - 'dt': self.display_type, - 'display_type': self.display_type, - 'db': self.display_bytes, - 'display_bytes': self.display_bytes, - 'dw': self.display_words, - 'display_words': self.display_words, - 'dd': self.display_doublewords, - 'display_doublewords': self.display_doublewords, - 'dq': self.display_quadwords, - 'display_quadwords': self.display_quadwords, - 'dis': self.disassemble, - 'disassemble': self.disassemble, - 'cl': self.change_layer, - 'change_layer': self.change_layer, - 'context': self.context, - 'self': self, - 'hh': self.help, - 'help': self.help, - } + return [(['dt', 'display_type'], self.display_type), (['db', 'display_bytes'], self.display_bytes), + (['dw', 'display_words'], self.display_words), (['dd', + 'display_doublewords'], self.display_doublewords), + (['dq', 'display_quadwords'], self.display_quadwords), (['dis', 'disassemble'], self.disassemble), + (['cl', 'change_layer'], self.change_layer), (['context'], self.context), (['self'], self), + (['hh', 'help'], self.help)] + + def _construct_locals_dict(self) -> Dict[str, Any]: + """Returns a dictionary of the locals """ + result = {} + for aliases, value in self.construct_locals(): + for alias in aliases: + result[alias] = value + return result def _read_data(self, offset, count = 128, layer_name = None): """Reads the bytes necessary for the display_* methods""" diff --git a/volatility/cli/volshell/linux.py b/volatility/cli/volshell/linux.py index 92d90e92c..700e4eb2e 100644 --- a/volatility/cli/volshell/linux.py +++ b/volatility/cli/volshell/linux.py @@ -2,14 +2,14 @@ # which is available at https://www.volatilityfoundation.org/license/vsl_v1.0 # -from typing import Dict, Any +from typing import Any, List, Tuple -from volatility.cli.volshell import shellplugin +from volatility.cli.volshell import generic from volatility.framework.configuration import requirements from volatility.plugins.linux import pslist -class Volshell(shellplugin.Volshell): +class Volshell(generic.Volshell): """Shell environment to directly interact with a linux memory image.""" @classmethod @@ -38,18 +38,13 @@ class Volshell(shellplugin.Volshell): # 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]: + def construct_locals(self) -> List[Tuple[List[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, - }) + result += [ + (['ct', 'change_task', 'cp'], self.change_task), + (['lt', 'list_tasks', 'ps'], self.list_tasks), + (['symbols'], self.context.symbol_space[self.config['vmlinux']]), + ] 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 index 48dc39b40..4da291ee5 100644 --- a/volatility/cli/volshell/mac.py +++ b/volatility/cli/volshell/mac.py @@ -2,14 +2,14 @@ # which is available at https://www.volatilityfoundation.org/license/vsl_v1.0 # -from typing import Dict, Any +from typing import Any, List, Tuple -from volatility.cli.volshell import shellplugin +from volatility.cli.volshell import generic from volatility.framework.configuration import requirements from volatility.plugins.mac import pslist -class Volshell(shellplugin.Volshell): +class Volshell(generic.Volshell): """Shell environment to directly interact with a mac memory image.""" @classmethod @@ -38,18 +38,13 @@ class Volshell(shellplugin.Volshell): # 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]: + def construct_locals(self) -> List[Tuple[List[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, - }) + result += [ + (['ct', 'change_task', 'cp'], self.change_task), + (['lt', 'list_tasks', 'ps'], self.list_tasks), + (['symbols'], self.context.symbol_space[self.config['darwin']]), + ] 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 d29b94a9f..17d036eed 100644 --- a/volatility/cli/volshell/windows.py +++ b/volatility/cli/volshell/windows.py @@ -2,14 +2,14 @@ # which is available at https://www.volatilityfoundation.org/license/vsl_v1.0 # -from typing import Dict, Any +from typing import Dict, Any, List, Tuple -from volatility.cli.volshell import shellplugin +from volatility.cli.volshell import generic from volatility.framework.configuration import requirements from volatility.plugins.windows import pslist -class Volshell(shellplugin.Volshell): +class Volshell(generic.Volshell): """Shell environment to directly interact with a windows memory image.""" @classmethod @@ -35,17 +35,13 @@ class Volshell(shellplugin.Volshell): # 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]: + def construct_locals(self) -> List[Tuple[List[str], Any]]: result = super().construct_locals() - result.update({ - 'cp': self.change_process, - 'change_process': self.change_process, - 'lp': self.list_processes, - 'list_processes': self.list_processes, - 'symbols': self.context.symbol_space[self.config['nt_symbols']], - # windbg compatibility aliases - 'ps': self.list_processes, - }) + result += [ + (['cp', 'change_process'], self.change_process), + (['lp', 'list_processes', 'ps'], self.list_processes), + (['symbols'], self.context.symbol_space[self.config['nt_symbols']]), + ] if self.config.get('pid', None) is not None: self.change_process(self.config['pid']) return result