diff --git a/development/dtbfinder.py b/development/dtbfinder.py index 30f84080d..00f96dc0c 100644 --- a/development/dtbfinder.py +++ b/development/dtbfinder.py @@ -13,31 +13,35 @@ if __name__ == '__main__': import argparse parser = argparse.ArgumentParser() - parser.add_argument("filenames", metavar = "FILE", nargs = "+", action = "store", help = "FILE to read for testing") + parser.add_argument( + "filenames", metavar = "FILE", nargs = "+", action = "store", help = "FILE to read for testing") parser.add_argument("--32bit", action = "store_false", dest = "bit32", help = "Disable 32-bit scanning") parser.add_argument("--64bit", action = "store_false", dest = "bit64", help = "Disable 64-bit scanning") parser.add_argument("--pae", action = "store_false", dest = "pae", help = "Disable pae scanning") parser.add_argument("-l", "--lime", action = "store_true", dest = "lime", help = "All files are LIME format") - parser.add_argument("-s", "--selfref", action = "store_true", dest = "selfref", - help = "Run more generic self-referential tests scanner") - parser.add_argument("-v", "--verbose", action = "count", default = 0, - help = "Increase the verbosity of the information returned") + parser.add_argument( + "-s", + "--selfref", + action = "store_true", + dest = "selfref", + help = "Run more generic self-referential tests scanner") + parser.add_argument( + "-v", "--verbose", action = "count", default = 0, help = "Increase the verbosity of the information returned") args = parser.parse_args() ctx = contexts.Context() for filename in args.filenames: - ctx.config[ - interfaces.configuration.path_join('config' + str(args.filenames.index(filename)), "filename")] = filename - data = layers.physical.FileLayer(ctx, - 'config' + str(args.filenames.index(filename)), + ctx.config[interfaces.configuration.path_join('config' + str(args.filenames.index(filename)), + "filename")] = filename + data = layers.physical.FileLayer(ctx, 'config' + str(args.filenames.index(filename)), 'data' + str(args.filenames.index(filename))) ctx.memory.add_layer(data) if args.lime: - ctx.config[interfaces.configuration.path_join('lime-config' + str(args.filenames.index(filename)), - "base_layer")] = 'data' + str(args.filenames.index(filename)) - data = layers.lime.LimeLayer(ctx, - 'lime-config' + str(args.filenames.index(filename)), + ctx.config[interfaces.configuration.path_join( + 'lime-config' + str(args.filenames.index(filename)), + "base_layer")] = 'data' + str(args.filenames.index(filename)) + data = layers.lime.LimeLayer(ctx, 'lime-config' + str(args.filenames.index(filename)), 'lime-data' + str(args.filenames.index(filename))) ctx.memory.add_layer(data) diff --git a/development/nlpdtbfinder.py b/development/nlpdtbfinder.py index 844aa5906..ade1de2de 100644 --- a/development/nlpdtbfinder.py +++ b/development/nlpdtbfinder.py @@ -22,7 +22,7 @@ import struct PAGE_SIZE = 0x1000 PHYS_MASK = 0xfffffffffff -PML4_ENTRY_SIZE = int((2 ** 64) / 512) +PML4_ENTRY_SIZE = int((2**64) / 512) class PML4EScanner(interfaces.layers.ScannerInterface): @@ -145,26 +145,26 @@ if __name__ == '__main__': import argparse parser = argparse.ArgumentParser() - parser.add_argument("filenames", metavar = "FILE", nargs = "+", action = "store", help = "FILE to read for testing") + parser.add_argument( + "filenames", metavar = "FILE", nargs = "+", action = "store", help = "FILE to read for testing") parser.add_argument("-l", "--lime", action = "store_true", dest = "lime", help = "All files are LIME format") - parser.add_argument("-v", "--verbose", action = "count", default = 0, - help = "Increase the verbosity of the information returned") + parser.add_argument( + "-v", "--verbose", action = "count", default = 0, help = "Increase the verbosity of the information returned") args = parser.parse_args() ctx = contexts.Context() for filename in args.filenames: - ctx.config[ - interfaces.configuration.path_join('config' + str(args.filenames.index(filename)), "filename")] = filename - data = layers.physical.FileLayer(ctx, - 'config' + str(args.filenames.index(filename)), + ctx.config[interfaces.configuration.path_join('config' + str(args.filenames.index(filename)), + "filename")] = filename + data = layers.physical.FileLayer(ctx, 'config' + str(args.filenames.index(filename)), 'data' + str(args.filenames.index(filename))) ctx.memory.add_layer(data) if args.lime: - ctx.config[interfaces.configuration.path_join('lime-config' + str(args.filenames.index(filename)), - "base_layer")] = 'data' + str(args.filenames.index(filename)) - data = layers.lime.LimeLayer(ctx, - 'lime-config' + str(args.filenames.index(filename)), + ctx.config[interfaces.configuration.path_join( + 'lime-config' + str(args.filenames.index(filename)), + "base_layer")] = 'data' + str(args.filenames.index(filename)) + data = layers.lime.LimeLayer(ctx, 'lime-config' + str(args.filenames.index(filename)), 'lime-data' + str(args.filenames.index(filename))) ctx.memory.add_layer(data) diff --git a/development/pdbscanner.py b/development/pdbscanner.py index 22ac5573c..939b4e249 100644 --- a/development/pdbscanner.py +++ b/development/pdbscanner.py @@ -13,8 +13,8 @@ if __name__ == '__main__': from volatility.framework import contexts parser = argparse.ArgumentParser() - parser.add_argument("filenames", metavar = "FILE", nargs = "+", - action = "store", help = "FILE to read for testing") + parser.add_argument( + "filenames", metavar = "FILE", nargs = "+", action = "store", help = "FILE to read for testing") args = parser.parse_args() @@ -26,21 +26,17 @@ if __name__ == '__main__': config_name = 'config' + str(index) base_name = 'data' + str(index) ctx.config[interfaces.configuration.path_join(config_name, "filename")] = filename - base = layers.physical.FileLayer(ctx, - config_name, - base_name) + base = layers.physical.FileLayer(ctx, config_name, base_name) ctx.memory.add_layer(base) # XXX What's the right way to check for LiME? - (magic,) = struct.unpack('=3.8.0"], - 'disasm': ["capstone;platform_system=='Linux'", - "capstone-windows;platform_system=='Windows'"], - 'doc': ["sphinx>=1.8.2", - "sphinx_autodoc_typehints>=1.4.0"] - } -) + 'disasm': ["capstone;platform_system=='Linux'", "capstone-windows;platform_system=='Windows'"], + 'doc': ["sphinx>=1.8.2", "sphinx_autodoc_typehints>=1.4.0"] + }) diff --git a/volatility/cli/__init__.py b/volatility/cli/__init__.py index 963104879..72d52b098 100644 --- a/volatility/cli/__init__.py +++ b/volatility/cli/__init__.py @@ -74,46 +74,68 @@ class CommandLine(interfaces.plugins.FileConsumerInterface): volatility.framework.require_interface_version(0, 0, 0) - parser = argparse.ArgumentParser(prog = 'volatility', - description = "An open-source memory forensics framework") - parser.add_argument("-c", "--config", help = "Load the configuration from a json file", default = None, - type = str) - parser.add_argument("-e", "--extend", help = "Extend the configuration with a new (or changed) setting", - default = None, - action = 'append') - parser.add_argument("-p", "--plugin-dirs", help = "Semi-colon separated list of paths to find plugins", - default = "", type = str) - parser.add_argument("-s", "--symbol-dirs", help = "Semi-colon separated list of paths to find symbols", - default = "", type = str) + parser = argparse.ArgumentParser( + prog = 'volatility', description = "An open-source memory forensics framework") + parser.add_argument( + "-c", "--config", help = "Load the configuration from a json file", default = None, type = str) + parser.add_argument( + "-e", + "--extend", + help = "Extend the configuration with a new (or changed) setting", + default = None, + action = 'append') + parser.add_argument( + "-p", + "--plugin-dirs", + help = "Semi-colon separated list of paths to find plugins", + default = "", + type = str) + parser.add_argument( + "-s", + "--symbol-dirs", + help = "Semi-colon separated list of paths to find symbols", + default = "", + type = str) parser.add_argument("-v", "--verbosity", help = "Increase output verbosity", default = 0, action = "count") - 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( + "-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("-l", "--log", help = "Log output to a file as well as the console", default = None, - type = str) - parser.add_argument("-f", "--file", metavar = 'FILE', default = None, type = str, - help = "Shorthand for --single-location=file:// if single-location is not defined") - parser.add_argument("--write-config", help = "Write configuration JSON file out to config.json", - default = False, - action = 'store_true') + parser.add_argument( + "-l", "--log", help = "Log output to a file as well as the console", default = None, type = str) + parser.add_argument( + "-f", + "--file", + metavar = 'FILE', + default = None, + type = str, + help = "Shorthand for --single-location=file:// if single-location is not defined") + parser.add_argument( + "--write-config", + help = "Write configuration JSON file out to config.json", + default = False, + action = 'store_true') # 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) if partial_args.plugin_dirs: - volatility.plugins.__path__ = [os.path.abspath(p) for p in - partial_args.plugin_dirs.split(";")] + constants.PLUGINS_PATH + volatility.plugins.__path__ = [os.path.abspath(p) + for p in partial_args.plugin_dirs.split(";")] + constants.PLUGINS_PATH if partial_args.symbol_dirs: - volatility.symbols.__path__ = [os.path.abspath(p) for p in - partial_args.symbol_dirs.split(";")] + constants.SYMBOL_BASEPATHS + volatility.symbols.__path__ = [os.path.abspath(p) + for p in partial_args.symbol_dirs.split(";")] + constants.SYMBOL_BASEPATHS 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_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") @@ -206,12 +228,7 @@ class CommandLine(interfaces.plugins.FileConsumerInterface): if args.quiet: progress_callback = MuteProgress() - constructed = plugins.run_plugin(ctx, - automagics, - plugin, - base_config_path, - progress_callback, - self) + constructed = plugins.run_plugin(ctx, automagics, plugin, base_config_path, progress_callback, self) if args.write_config: vollog.debug("Writing out configuration data to config.json") @@ -223,11 +240,9 @@ class CommandLine(interfaces.plugins.FileConsumerInterface): except exceptions.UnsatisfiedException as excp: parser.exit(1, "Unable to validate the plugin requirements: {}\n".format(excp.unsatisfied)) - def populate_config(self, - context: interfaces.context.ContextInterface, + def populate_config(self, context: interfaces.context.ContextInterface, configurables_list: Dict[str, interfaces.configuration.ConfigurableInterface], - args: argparse.Namespace, - plugin_config_path: str) -> None: + args: argparse.Namespace, plugin_config_path: str) -> None: """Populate the context config based on the returned args We have already determined these elements must be descended from ConfigurableInterface @@ -278,8 +293,7 @@ class CommandLine(interfaces.plugins.FileConsumerInterface): else: vollog.warning("Refusing to overwrite an existing file: {}".format(output_filename)) - def populate_requirements_argparse(self, - parser: Union[argparse.ArgumentParser, argparse._ArgumentGroup], + def populate_requirements_argparse(self, parser: Union[argparse.ArgumentParser, argparse._ArgumentGroup], configurable: Type[interfaces.configuration.ConfigurableInterface]): """Adds the plugin's simple requirements to the provided parser @@ -295,8 +309,8 @@ class CommandLine(interfaces.plugins.FileConsumerInterface): for requirement in configurable.get_requirements(): additional = {} # type: Dict[str, Any] if not isinstance(requirement, interfaces.configuration.RequirementInterface): - raise TypeError( - "Plugin contains requirements that are not RequirementInterfaces: {}".format(configurable.__name__)) + raise TypeError("Plugin contains requirements that are not RequirementInterfaces: {}".format( + configurable.__name__)) if isinstance(requirement, interfaces.configuration.SimpleTypeRequirement): additional["type"] = requirement.instance_type if isinstance(requirement, requirements.IntRequirement): @@ -313,9 +327,13 @@ class CommandLine(interfaces.plugins.FileConsumerInterface): additional["choices"] = requirement.choices else: continue - parser.add_argument("--" + requirement.name.replace('_', '-'), help = requirement.description, - default = requirement.default, dest = requirement.name, - required = not requirement.optional, **additional) + parser.add_argument( + "--" + requirement.name.replace('_', '-'), + help = requirement.description, + default = requirement.default, + dest = requirement.name, + required = not requirement.optional, + **additional) # We shouldn't really steal a private member from argparse, but otherwise we're just duplicating code diff --git a/volatility/cli/text_renderer.py b/volatility/cli/text_renderer.py index 2998d0fd3..73874f682 100644 --- a/volatility/cli/text_renderer.py +++ b/volatility/cli/text_renderer.py @@ -37,14 +37,15 @@ def hex_bytes_as_text(value: bytes) -> str: ascii.append(chr(byte) if 0x20 < byte <= 0x7E else ".") if (count % 8) == 7: output += "\n" - output += " ".join(hex[count - 7: count + 1]) + output += " ".join(hex[count - 7:count + 1]) output += "\t" - output += "".join(ascii[count - 7: count + 1]) + output += "".join(ascii[count - 7:count + 1]) count += 1 return output class Optional(object): + def __init__(self, func: Callable[[Any], str]) -> None: self._func = func @@ -69,10 +70,12 @@ def display_disassembly(disasm: interfaces.renderers.Disassembly) -> str: """ if CAPSTONE_PRESENT: - disasm_types = {'intel': capstone.Cs(capstone.CS_ARCH_X86, capstone.CS_MODE_32), - 'intel64': capstone.Cs(capstone.CS_ARCH_X86, capstone.CS_MODE_64), - 'arm': capstone.Cs(capstone.CS_ARCH_ARM, capstone.CS_MODE_ARM), - 'arm64': capstone.Cs(capstone.CS_ARCH_ARM64, capstone.CS_MODE_ARM)} + disasm_types = { + 'intel': capstone.Cs(capstone.CS_ARCH_X86, capstone.CS_MODE_32), + 'intel64': capstone.Cs(capstone.CS_ARCH_X86, capstone.CS_MODE_64), + 'arm': capstone.Cs(capstone.CS_ARCH_ARM, capstone.CS_MODE_ARM), + 'arm64': capstone.Cs(capstone.CS_ARCH_ARM64, capstone.CS_MODE_ARM) + } output = "" if disasm.architecture is not None: for i in disasm_types[disasm.architecture].disasm(disasm.data, disasm.offset): @@ -82,13 +85,15 @@ def display_disassembly(disasm: interfaces.renderers.Disassembly) -> str: class QuickTextRenderer(interfaces.renderers.Renderer): - type_renderers = {format_hints.Bin: Optional(lambda x: "0b{:b}".format(x)), - format_hints.Hex: Optional(lambda x: "0x{:x}".format(x)), - format_hints.HexBytes: Optional(hex_bytes_as_text), - interfaces.renderers.Disassembly: Optional(display_disassembly), - bytes: Optional(lambda x: " ".join(["{0:2x}".format(b) for b in x])), - datetime.datetime: Optional(lambda x: x.strftime("%Y-%m-%d %H:%M:%S.%f %Z")), - 'default': Optional(lambda x: "{}".format(x))} + type_renderers = { + format_hints.Bin: Optional(lambda x: "0b{:b}".format(x)), + format_hints.Hex: Optional(lambda x: "0x{:x}".format(x)), + format_hints.HexBytes: Optional(hex_bytes_as_text), + interfaces.renderers.Disassembly: Optional(display_disassembly), + bytes: Optional(lambda x: " ".join(["{0:2x}".format(b) for b in x])), + datetime.datetime: Optional(lambda x: x.strftime("%Y-%m-%d %H:%M:%S.%f %Z")), + 'default': Optional(lambda x: "{}".format(x)) + } def __init__(self, options = None) -> None: super().__init__(options) diff --git a/volatility/cli/volshell/__init__.py b/volatility/cli/volshell/__init__.py index 8e3db2b0f..801a0692a 100644 --- a/volatility/cli/volshell/__init__.py +++ b/volatility/cli/volshell/__init__.py @@ -39,28 +39,49 @@ class VolShell(cli.CommandLine): framework.require_interface_version(0, 0, 0) - parser = argparse.ArgumentParser(prog = 'volshell', - description = "A tool for interactivate forensic analysis of memory images") - parser.add_argument("-c", "--config", help = "Load the configuration from a json file", default = None, - type = str) - parser.add_argument("-e", "--extend", help = "Extend the configuration with a new (or changed) setting", - default = None, - action = 'append') - parser.add_argument("-p", "--plugin-dirs", help = "Semi-colon separated list of paths to find plugins", - default = "", type = str) - parser.add_argument("-s", "--symbol-dirs", help = "Semi-colon separated list of paths to find symbols", - default = "", type = str) + parser = argparse.ArgumentParser( + prog = 'volshell', description = "A tool for interactivate forensic analysis of memory images") + parser.add_argument( + "-c", "--config", help = "Load the configuration from a json file", default = None, type = str) + parser.add_argument( + "-e", + "--extend", + help = "Extend the configuration with a new (or changed) setting", + default = None, + action = 'append') + parser.add_argument( + "-p", + "--plugin-dirs", + help = "Semi-colon separated list of paths to find plugins", + default = "", + type = str) + parser.add_argument( + "-s", + "--symbol-dirs", + help = "Semi-colon separated list of paths to find symbols", + default = "", + type = str) parser.add_argument("-v", "--verbosity", help = "Increase output verbosity", default = 0, action = "count") - 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( + "-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', default = None, type = str, - help = "Shorthand for --single-location=file:// if single-location is not defined") - parser.add_argument("--write-config", help = "Write configuration JSON file out to config.json", - 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', + default = None, + type = str, + help = "Shorthand for --single-location=file:// if single-location is not defined") + parser.add_argument( + "--write-config", + help = "Write configuration JSON file out to config.json", + default = False, + action = 'store_true') # Volshell specific flags parser.add_argument("-w", "--windows", default = False, action = "store_true", help = "Run a Windows volshell") @@ -71,18 +92,18 @@ class VolShell(cli.CommandLine): known_args = [arg for arg in sys.argv if arg != '--help' and arg != '-h'] partial_args, _ = parser.parse_known_args(known_args) if partial_args.plugin_dirs: - volatility.plugins.__path__ = [os.path.abspath(p) for p in - partial_args.plugin_dirs.split(";")] + constants.PLUGINS_PATH + volatility.plugins.__path__ = [os.path.abspath(p) + for p in partial_args.plugin_dirs.split(";")] + constants.PLUGINS_PATH if partial_args.symbol_dirs: - volatility.symbols.__path__ = [os.path.abspath(p) for p in - partial_args.symbol_dirs.split(";")] + constants.SYMBOL_BASEPATHS + volatility.symbols.__path__ = [os.path.abspath(p) + for p in partial_args.symbol_dirs.split(";")] + constants.SYMBOL_BASEPATHS 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_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") @@ -114,12 +135,11 @@ 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': shellplugin.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( - plugin.capitalize())) + subparser = parser.add_argument_group( + title = plugin.capitalize(), + description = "Configuration options based on {} options".format(plugin.capitalize())) self.populate_requirements_argparse(subparser, volshell_plugin_list[plugin]) configurables_list[plugin] = volshell_plugin_list[plugin] @@ -180,12 +200,7 @@ class VolShell(cli.CommandLine): if args.quiet: progress_callback = cli.MuteProgress() - constructed = plugins.run_plugin(ctx, - automagics, - plugin, - base_config_path, - progress_callback, - self) + constructed = plugins.run_plugin(ctx, automagics, plugin, base_config_path, progress_callback, self) if args.write_config: vollog.debug("Writing out configuration data to config.json") diff --git a/volatility/cli/volshell/shellplugin.py b/volatility/cli/volshell/shellplugin.py index 25838f849..b3dfa9ef2 100644 --- a/volatility/cli/volshell/shellplugin.py +++ b/volatility/cli/volshell/shellplugin.py @@ -11,9 +11,10 @@ class Volshell(interfaces.plugins.PluginInterface): @classmethod def get_requirements(cls): - return [requirements.TranslationLayerRequirement(name = 'primary', - description = 'Kernel Address Space', - architectures = ["Intel32", "Intel64"])] + return [ + requirements.TranslationLayerRequirement( + name = 'primary', description = 'Kernel Address Space', architectures = ["Intel32", "Intel64"]) + ] def run(self, additional_locals: Dict[str, Any] = None) -> interfaces.renderers.TreeGrid: """Runs the interactive volshell plugin @@ -76,10 +77,5 @@ class Volshell(interfaces.plugins.PluginInterface): relative_offset, member_type = object.vol.members[member] len_offset = len(hex(relative_offset)) len_member = len(member) - print(" " * (longest_offset - len_offset), - hex(relative_offset), - "\t\t", - member, - " " * (longest_member - len_member), - "\t\t", - member_type.vol.type_name) + print(" " * (longest_offset - len_offset), hex(relative_offset), "\t\t", member, + " " * (longest_member - len_member), "\t\t", member_type.vol.type_name) diff --git a/volatility/cli/volshell/windows.py b/volatility/cli/volshell/windows.py index 6acaf91ee..904336a94 100644 --- a/volatility/cli/volshell/windows.py +++ b/volatility/cli/volshell/windows.py @@ -10,11 +10,10 @@ class Volshell(shellplugin.Volshell): @classmethod def get_requirements(cls): - return (super().get_requirements() + - [requirements.SymbolRequirement(name = "nt_symbols", description = "Windows OS"), - requirements.IntRequirement(name = 'pid', - description = "Process ID", - optional = True)]) + return (super().get_requirements() + [ + requirements.SymbolRequirement(name = "nt_symbols", description = "Windows OS"), + requirements.IntRequirement(name = 'pid', description = "Process ID", optional = True) + ]) def list_processes(self): """Lists all the processes in the primary layer""" @@ -46,9 +45,7 @@ class Volshell(shellplugin.Volshell): def load_functions(self) -> Dict[str, Callable]: result = super().load_functions() - result.update({ - 'ps': lambda: list(self.list_processes()) - }) + result.update({'ps': lambda: list(self.list_processes())}) return result def run(self, additional_locals = None): diff --git a/volatility/framework/__init__.py b/volatility/framework/__init__.py index 6c3beff73..56750c35b 100644 --- a/volatility/framework/__init__.py +++ b/volatility/framework/__init__.py @@ -39,18 +39,17 @@ def require_interface_version(*args) -> None: """Checks the required version of a plugin""" if len(args): if args[0] != interface_version()[0]: - raise RuntimeError( - "Framework interface version {} is incompatible with required version {}".format(interface_version()[0], - args[0])) + raise RuntimeError("Framework interface version {} is incompatible with required version {}".format( + interface_version()[0], args[0])) if len(args) > 1: if args[1] > interface_version()[1]: raise RuntimeError( "Framework interface version {} is an older revision than the required version {}".format( - ".".join([str(x) for x in interface_version()[0:1]]), - ".".join([str(x) for x in args[0:2]]))) + ".".join([str(x) for x in interface_version()[0:1]]), ".".join([str(x) for x in args[0:2]]))) class noninheritable(object): + def __init__(self, value: Any, cls: Type) -> None: self.default_value = value self.cls = cls @@ -128,6 +127,6 @@ def list_plugins() -> Dict[str, Type[interfaces.plugins.PluginInterface]]: # We currently require 3.5.3 since 3.5.1 has no typing.Type and 3.5.2 is broken for ''/delayed encapsulated types required_python_version = (3, 5, 3) if (sys.version_info.major != required_python_version[0] or sys.version_info.minor < required_python_version[1] or - (sys.version_info.minor == required_python_version[1] and sys.version_info.micro < required_python_version[2])): + (sys.version_info.minor == required_python_version[1] and sys.version_info.micro < required_python_version[2])): raise RuntimeError( "Volatility framework requires python version {}.{}.{} or greater".format(*required_python_version)) diff --git a/volatility/framework/automagic/__init__.py b/volatility/framework/automagic/__init__.py index 44d093c75..5919f4d57 100644 --- a/volatility/framework/automagic/__init__.py +++ b/volatility/framework/automagic/__init__.py @@ -18,21 +18,11 @@ from volatility.framework.configuration import requirements vollog = logging.getLogger(__name__) -windows_automagic = ['ConstructionMagic', - 'LayerStacker', - 'WintelHelper', - 'KernelPDBScanner', - 'WinSwapLayers'] +windows_automagic = ['ConstructionMagic', 'LayerStacker', 'WintelHelper', 'KernelPDBScanner', 'WinSwapLayers'] -linux_automagic = ['ConstructionMagic', - 'LayerStacker', - 'LinuxBannerCache', - 'LinuxSymbolFinder'] +linux_automagic = ['ConstructionMagic', 'LayerStacker', 'LinuxBannerCache', 'LinuxSymbolFinder'] -mac_automagic = ['ConstructionMagic', - 'LayerStacker', - 'MacBannerCache', - 'MacSymbolFinder'] +mac_automagic = ['ConstructionMagic', 'LayerStacker', 'MacBannerCache', 'MacSymbolFinder'] def available(context: interfaces.context.ContextInterface) -> List[interfaces.automagic.AutomagicInterface]: @@ -46,8 +36,10 @@ def available(context: interfaces.context.ContextInterface) -> List[interfaces.a """ import_files(sys.modules[__name__]) config_path = constants.AUTOMAGIC_CONFIG_PATH - return sorted([clazz(context, interfaces.configuration.path_join(config_path, clazz.__name__)) for clazz in - class_subclasses(interfaces.automagic.AutomagicInterface)], + return sorted([ + clazz(context, interfaces.configuration.path_join(config_path, clazz.__name__)) + for clazz in class_subclasses(interfaces.automagic.AutomagicInterface) + ], key = lambda x: x.priority) @@ -74,8 +66,8 @@ def choose_automagic(automagics, plugin): def run(automagics: List[interfaces.automagic.AutomagicInterface], context: interfaces.context.ContextInterface, - configurable: Union[interfaces.configuration.ConfigurableInterface, - Type[interfaces.configuration.ConfigurableInterface]], + configurable: Union[interfaces.configuration.ConfigurableInterface, Type[interfaces.configuration. + ConfigurableInterface]], config_path: str, progress_callback: validity.ProgressCallback = None) -> List[traceback.TracebackException]: """Runs through the list of `automagics` in order, allowing them to make changes to the context diff --git a/volatility/framework/automagic/construct_layers.py b/volatility/framework/automagic/construct_layers.py index 49d69fc25..f3f07b515 100644 --- a/volatility/framework/automagic/construct_layers.py +++ b/volatility/framework/automagic/construct_layers.py @@ -25,7 +25,8 @@ class ConstructionMagic(interfaces.automagic.AutomagicInterface): context: interfaces.context.ContextInterface, config_path: str, requirement: interfaces.configuration.RequirementInterface, - progress_callback = None, optional = False) -> List[str]: + progress_callback = None, + optional = False) -> List[str]: result = [] # type: List[str] if requirement.unsatisfied(context, config_path): # Having called validate at the top level tells us both that we need to dig deeper diff --git a/volatility/framework/automagic/linux.py b/volatility/framework/automagic/linux.py index d7a574ca9..c66bbc84a 100644 --- a/volatility/framework/automagic/linux.py +++ b/volatility/framework/automagic/linux.py @@ -55,11 +55,11 @@ class LintelStacker(interfaces.automagic.StackerLayerInterface): if symbol_files: isf_path = symbol_files[0] table_name = context.symbol_space.free_table_name('LintelStacker') - table = linux.LinuxKernelIntermedSymbols(context, 'temporary.' + table_name, name = table_name, - isf_url = isf_path) + table = linux.LinuxKernelIntermedSymbols( + context, 'temporary.' + table_name, name = table_name, isf_url = isf_path) context.symbol_space.append(table) - kaslr_shift, _ = LinuxUtilities.find_aslr(context, table_name, layer_name, - progress_callback = progress_callback) + kaslr_shift, _ = LinuxUtilities.find_aslr( + context, table_name, layer_name, progress_callback = progress_callback) layer_class = intel.Intel # type: Type if 'init_level4_pgt' in table.symbols: @@ -68,8 +68,8 @@ class LintelStacker(interfaces.automagic.StackerLayerInterface): else: dtb_symbol_name = 'swapper_pg_dir' - dtb = LinuxUtilities.virtual_to_physical_address(table.get_symbol(dtb_symbol_name).address + - kaslr_shift) + dtb = LinuxUtilities.virtual_to_physical_address( + table.get_symbol(dtb_symbol_name).address + kaslr_shift) # Build the new layer new_layer_name = context.memory.free_layer_name("IntelLayer") @@ -218,8 +218,7 @@ class LinuxUtilities(object): return ret @classmethod - def files_descriptors_for_process(cls, - config: interfaces.configuration.HierarchicalDict, + def files_descriptors_for_process(cls, config: interfaces.configuration.HierarchicalDict, context: interfaces.context.ContextInterface, task: interfaces.objects.ObjectInterface): @@ -274,8 +273,10 @@ class LinuxUtilities(object): swapper_signature = rb"swapper(\/0|\x00\x00)\x00\x00\x00\x00\x00\x00" module = context.module(symbol_table, layer_name, 0) - for offset in context.memory[layer_name].scan(scanner = scanners.RegExScanner(swapper_signature), - context = context, progress_callback = progress_callback): + for offset in context.memory[layer_name].scan( + scanner = scanners.RegExScanner(swapper_signature), + context = context, + progress_callback = progress_callback): task_symbol = module.get_type('task_struct') init_task_address = offset - task_symbol.relative_child_offset('comm') init_task = module.object(type_name = 'task_struct', offset = init_task_address) @@ -290,8 +291,8 @@ class LinuxUtilities(object): if aslr_shift & 0xfff != 0 or kaslr_shift & 0xfff != 0: continue - vollog.debug( - "Linux ASLR shift values determined: physical {:0x} virtual {:0x}".format(kaslr_shift, aslr_shift)) + vollog.debug("Linux ASLR shift values determined: physical {:0x} virtual {:0x}".format( + kaslr_shift, aslr_shift)) return kaslr_shift, aslr_shift # We don't throw an exception, because we may legitimately not have an ASLR shift, but we report it diff --git a/volatility/framework/automagic/mac.py b/volatility/framework/automagic/mac.py index 1cb1be34e..387b559b5 100644 --- a/volatility/framework/automagic/mac.py +++ b/volatility/framework/automagic/mac.py @@ -47,9 +47,10 @@ class MacintelStacker(interfaces.automagic.StackerLayerInterface): mac_banners = MacBannerCache.load_banners() - for banner_offset, banner in layer.scan(context = context, - scanner = scanners.MultiStringScanner([x for x in mac_banners if x]), - progress_callback = progress_callback): + for banner_offset, banner in layer.scan( + context = context, + scanner = scanners.MultiStringScanner([x for x in mac_banners if x]), + progress_callback = progress_callback): dtb = None vollog.debug("Identified banner: {}".format(repr(banner))) @@ -57,28 +58,30 @@ class MacintelStacker(interfaces.automagic.StackerLayerInterface): if symbol_files: isf_path = symbol_files[0] table_name = context.symbol_space.free_table_name('MacintelStacker') - table = mac.MacKernelIntermedSymbols(context = context, - config_path = join('temporary', table_name), - name = table_name, - isf_url = isf_path) + table = mac.MacKernelIntermedSymbols( + context = context, + config_path = join('temporary', table_name), + name = table_name, + isf_url = isf_path) context.symbol_space.append(table) - kaslr_shift = MacUtilities.find_aslr(context = context, - symbol_table = table_name, - layer_name = layer_name, - compare_banner = banner, - compare_banner_offset = banner_offset, - progress_callback = progress_callback) + kaslr_shift = MacUtilities.find_aslr( + context = context, + symbol_table = table_name, + layer_name = layer_name, + compare_banner = banner, + compare_banner_offset = banner_offset, + progress_callback = progress_callback) - bootpml4_addr = MacUtilities.virtual_to_physical_address(table.get_symbol("BootPML4").address + - kaslr_shift) + bootpml4_addr = MacUtilities.virtual_to_physical_address( + table.get_symbol("BootPML4").address + kaslr_shift) new_layer_name = context.memory.free_layer_name("MacDTBTempLayer") config_path = join("automagic", "MacIntelHelper", new_layer_name) context.config[join(config_path, "memory_layer")] = layer_name context.config[join(config_path, "page_map_offset")] = bootpml4_addr - layer = layers.intel.Intel32e(context, config_path = config_path, - name = new_layer_name, metadata = {'os': 'Mac'}) + layer = layers.intel.Intel32e( + context, config_path = config_path, name = new_layer_name, metadata = {'os': 'Mac'}) idlepml4_ptr = table.get_symbol("IdlePML4").address + kaslr_shift idlepml4_str = layer.read(idlepml4_ptr, 4) @@ -126,8 +129,10 @@ class MacUtilities(object): def _scan_generator(cls, context, layer_name, progress_callback): darwin_signature = rb"Darwin Kernel Version \d{1,3}\.\d{1,3}\.\d{1,3}: [^\x00]+\x00" - for offset in context.memory[layer_name].scan(scanner = scanners.RegExScanner(darwin_signature), - context = context, progress_callback = progress_callback): + for offset in context.memory[layer_name].scan( + scanner = scanners.RegExScanner(darwin_signature), + context = context, + progress_callback = progress_callback): banner = context.memory[layer_name].read(offset, 128) diff --git a/volatility/framework/automagic/pdbscan.py b/volatility/framework/automagic/pdbscan.py index bb00590ee..dec7baaa6 100644 --- a/volatility/framework/automagic/pdbscan.py +++ b/volatility/framework/automagic/pdbscan.py @@ -87,9 +87,9 @@ def scan(ctx: interfaces.context.ContextInterface, if end is None: end = ctx.memory[layer_name].maximum_address - for (GUID, age, pdb_name, signature_offset) in ctx.memory[layer_name].scan(ctx, PdbSignatureScanner(pdb_names), - progress_callback = progress_callback, - sections = [(start, end - start)]): + for (GUID, age, pdb_name, signature_offset) in ctx.memory[layer_name].scan( + ctx, PdbSignatureScanner(pdb_names), progress_callback = progress_callback, sections = [(start, + end - start)]): mz_offset = None sig_pfn = signature_offset // page_size @@ -103,11 +103,13 @@ def scan(ctx: interfaces.context.ContextInterface, break min_pfn = sig_pfn - yield {'GUID': GUID, - 'age': age, - 'pdb_name': str(pdb_name, "utf-8"), - 'signature_offset': signature_offset, - 'mz_offset': mz_offset} + yield { + 'GUID': GUID, + 'age': age, + 'pdb_name': str(pdb_name, "utf-8"), + 'signature_offset': signature_offset, + 'mz_offset': mz_offset + } class KernelPDBScanner(interfaces.automagic.AutomagicInterface): @@ -126,8 +128,7 @@ class KernelPDBScanner(interfaces.automagic.AutomagicInterface): priority = 30 # Make sure uncompressed/outside-framework takes precedence, so users can overload. - prefixes = [os.path.join("..", "..", "..", "symbols", "windows"), - os.path.join("..", "..", "symbols", "windows")] + prefixes = [os.path.join("..", "..", "..", "symbols", "windows"), os.path.join("..", "..", "symbols", "windows")] """Provides a list of prefixes that are searched when locating Intermediate Format data files""" suffixes = ['.json', '.json.xz'] """Provides a list of supported suffixes for Intermediate Format data files""" @@ -162,17 +163,16 @@ class KernelPDBScanner(interfaces.automagic.AutomagicInterface): memlayer = context.memory[virtual_layer_name] if isinstance(memlayer, intel.Intel): page_size = memlayer.page_size # type: int - results = {virtual_layer_name: scan(context, - layer_name, - page_size, - progress_callback = progress_callback)} + results = { + virtual_layer_name: + scan(context, layer_name, page_size, progress_callback = progress_callback) + } else: for subreq in requirement.requirements.values(): results.update(self.recurse_pdb_finder(context, sub_config_path, subreq)) return results - def recurse_symbol_fulfiller(self, - context: interfaces.context.ContextInterface, + def recurse_symbol_fulfiller(self, context: interfaces.context.ContextInterface, valid_kernels: ValidKernelsType) -> None: """Fulfills the SymbolRequirements in `self._symbol_requirements` found by the `recurse_symbol_requirements`. @@ -212,8 +212,7 @@ class KernelPDBScanner(interfaces.automagic.AutomagicInterface): else: vollog.debug("No suitable kernel pdb signature found") - def set_kernel_virtual_offset(self, - context: interfaces.context.ContextInterface, + def set_kernel_virtual_offset(self, context: interfaces.context.ContextInterface, valid_kernels: ValidKernelsType) -> None: """Traverses the requirement tree, looking for kernel_virtual_offset values that may need setting and sets it based on the previously identified `valid_kernels`. @@ -254,16 +253,16 @@ class KernelPDBScanner(interfaces.automagic.AutomagicInterface): kvo = kernel['mz_offset'] + (1 << (vlayer.bits_per_register - 1)) try: kvp = vlayer.mapping(kvo, 0) - if (any([(p == kernel['mz_offset'] and layer_name == physical_layer_name) for (_, p, _, layer_name) in - kvp])): + if (any([(p == kernel['mz_offset'] and layer_name == physical_layer_name) + for (_, p, _, layer_name) in kvp])): valid_kernels[virtual_layer_name] = (kvo, kernel) # Sit the virtual offset under the TranslationLayer it applies to context.config[kvo_path] = kvo vollog.debug("Setting kernel_virtual_offset to {}".format(hex(kvo))) break else: - vollog.debug( - "Potential kernel_virtual_offset did not map to expected location: {}".format(hex(kvo))) + vollog.debug("Potential kernel_virtual_offset did not map to expected location: {}".format( + hex(kvo))) except exceptions.InvalidAddressException: vollog.debug("Potential kernel_virtual_offset caused a page fault: {}".format(hex(kvo))) return valid_kernels @@ -281,15 +280,16 @@ class KernelPDBScanner(interfaces.automagic.AutomagicInterface): physical_layer_name = self.get_physical_layer_name(context, vlayer) physical_layer = context.memory[physical_layer_name] # TODO: On older windows, this might be \WINDOWS\system32\nt rather than \SystemRoot\system32\nt - results = physical_layer.scan(context, scanners.BytesScanner(b"\\SystemRoot\\system32\\nt"), - progress_callback = progress_callback) + results = physical_layer.scan( + context, scanners.BytesScanner(b"\\SystemRoot\\system32\\nt"), progress_callback = progress_callback) seen = set() # type: Set[int] # Because this will launch a scan of the virtual layer, we want to be careful for result in results: # TODO: Identify the specific structure we're finding and document this a bit better - pointer = context.object("pdbscan!unsigned long long", - offset = (result - 16 - int(vlayer.bits_per_register / 8)), - layer_name = physical_layer_name) + pointer = context.object( + "pdbscan!unsigned long long", + offset = (result - 16 - int(vlayer.bits_per_register / 8)), + layer_name = physical_layer_name) address = pointer & vlayer.address_mask if address in seen: continue @@ -319,9 +319,8 @@ class KernelPDBScanner(interfaces.automagic.AutomagicInterface): seen = set() # type: Set[int] for result in results: # TODO: Identify the specific structure we're finding and document this a bit better - pointer = context.object("pdbscan!unsigned long long", - offset = result + 8, - layer_name = physical_layer_name) + pointer = context.object( + "pdbscan!unsigned long long", offset = result + 8, layer_name = physical_layer_name) address = pointer & vlayer.address_mask if address in seen: continue @@ -338,9 +337,7 @@ class KernelPDBScanner(interfaces.automagic.AutomagicInterface): return valid_kernels # List of methods to be run, in order, to determine the valid kernels - methods = [method_fixed_mapping, - method_kdbg_offset, - method_module_offset] + methods = [method_fixed_mapping, method_kdbg_offset, method_module_offset] def determine_valid_kernels(self, context: interfaces.context.ContextInterface, @@ -383,9 +380,7 @@ class KernelPDBScanner(interfaces.automagic.AutomagicInterface): if "pdbscan" not in context.symbol_space: context.symbol_space.append(native.NativeTable("pdbscan", native.std_ctypes)) # TODO: check if this is a windows symbol requirement, otherwise ignore it - self._symbol_requirements = self.find_requirements(context, - config_path, - requirement, + self._symbol_requirements = self.find_requirements(context, config_path, requirement, requirements.SymbolRequirement) for sub_config_path, symbol_req in self._symbol_requirements: parent_path = interfaces.configuration.parent_path(sub_config_path) diff --git a/volatility/framework/automagic/stacker.py b/volatility/framework/automagic/stacker.py index 5ec5cbed1..798a821ea 100644 --- a/volatility/framework/automagic/stacker.py +++ b/volatility/framework/automagic/stacker.py @@ -63,9 +63,7 @@ class LayerStacker(interfaces.automagic.AutomagicInterface): return None - def stack(self, - context: interfaces.context.ContextInterface, - config_path: str, + def stack(self, context: interfaces.context.ContextInterface, config_path: str, requirement: interfaces.configuration.RequirementInterface, progress_callback: validity.ProgressCallback) -> None: """Stacks the various layers and attaches these to a specific requirement @@ -103,8 +101,8 @@ class LayerStacker(interfaces.automagic.AutomagicInterface): # Repeatedly apply "determine what this is" code and build as much up as possible stacked = True stacked_layers = [current_layer_name] - stack_set = sorted(framework.class_subclasses(interfaces.automagic.StackerLayerInterface), - key = lambda x: x.stack_order) + stack_set = sorted( + framework.class_subclasses(interfaces.automagic.StackerLayerInterface), key = lambda x: x.stack_order) while stacked: stacked = False new_layer = None @@ -138,10 +136,8 @@ class LayerStacker(interfaces.automagic.AutomagicInterface): context.config.merge(path, new_context.memory[layer].build_configuration()) # Call the construction magic now we may have new things to construct - constructor = construct_layers.ConstructionMagic(context, - interfaces.configuration.path_join( - self.config_path, - "ConstructionMagic")) + constructor = construct_layers.ConstructionMagic( + context, interfaces.configuration.path_join(self.config_path, "ConstructionMagic")) constructor(context, config_path, requirement) # Stash the changed config items @@ -149,9 +145,7 @@ class LayerStacker(interfaces.automagic.AutomagicInterface): vollog.debug("Stacked layers: {}".format(stacked_layers)) - def find_suitable_requirements(self, - context: interfaces.context.ContextInterface, - config_path: str, + def find_suitable_requirements(self, context: interfaces.context.ContextInterface, config_path: str, requirement: interfaces.configuration.RequirementInterface, stacked_layers: List[str]) -> Optional[Tuple[str, str]]: """Looks for translation layer requirements and attempts to apply the stacked layers to it. If it succeeds @@ -186,6 +180,7 @@ class LayerStacker(interfaces.automagic.AutomagicInterface): @classmethod def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: # This is not optional for the stacker to run, so optional must be marked as False - return [requirements.URIRequirement("single_location", - description = "Specifies a base location on which to stack", - optional = True)] + return [ + requirements.URIRequirement( + "single_location", description = "Specifies a base location on which to stack", optional = True) + ] diff --git a/volatility/framework/automagic/symbol_finder.py b/volatility/framework/automagic/symbol_finder.py index c72afbe8d..c16755c1c 100644 --- a/volatility/framework/automagic/symbol_finder.py +++ b/volatility/framework/automagic/symbol_finder.py @@ -17,9 +17,7 @@ class SymbolFinder(interfaces.automagic.AutomagicInterface): banner_cache = None symbol_class = None - def __init__(self, - context: interfaces.context.ContextInterface, - config_path: str) -> None: + def __init__(self, context: interfaces.context.ContextInterface, config_path: str) -> None: super().__init__(context, config_path) self._requirements = [] # type: List[Tuple[str, interfaces.configuration.ConstructableRequirementInterface]] self._banners = {} # type: symbol_cache.BannersType @@ -44,21 +42,22 @@ class SymbolFinder(interfaces.automagic.AutomagicInterface): if self.symbol_class is None: return - self._requirements = self.find_requirements(context, config_path, requirement, - (requirements.TranslationLayerRequirement, - requirements.SymbolRequirement), - shortcut = False) + self._requirements = self.find_requirements( + context, + config_path, + requirement, (requirements.TranslationLayerRequirement, requirements.SymbolRequirement), + shortcut = False) for (sub_path, requirement) in self._requirements: parent_path = interfaces.configuration.parent_path(sub_path) - if (isinstance(requirement, requirements.SymbolRequirement) and requirement.unsatisfied(context, - parent_path)): + if (isinstance(requirement, requirements.SymbolRequirement) + and requirement.unsatisfied(context, parent_path)): for (tl_sub_path, tl_requirement) in self._requirements: tl_parent_path = interfaces.configuration.parent_path(tl_sub_path) # Find the TranslationLayer sibling to the SymbolRequirement - if (isinstance(tl_requirement, requirements.TranslationLayerRequirement) and - tl_parent_path == parent_path): + if (isinstance(tl_requirement, requirements.TranslationLayerRequirement) + and tl_parent_path == parent_path): if context.config.get(tl_sub_path, None): self._banner_scan(context, parent_path, requirement, context.config[tl_sub_path], progress_callback) @@ -83,8 +82,7 @@ class SymbolFinder(interfaces.automagic.AutomagicInterface): # Check if the Stacker has already found what we're looking for if layer.config.get(self.banner_config_key, None): - banner_list = [ - (0, bytes(layer.config[self.banner_config_key], 'latin-1'))] # type: Iterable[Any] + banner_list = [(0, bytes(layer.config[self.banner_config_key], 'latin-1'))] # type: Iterable[Any] else: # Swap to the physical layer for scanning # TODO: Fix this so it works for layers other than just Intel diff --git a/volatility/framework/automagic/windows.py b/volatility/framework/automagic/windows.py index f490478d4..d9cf97d1f 100644 --- a/volatility/framework/automagic/windows.py +++ b/volatility/framework/automagic/windows.py @@ -40,11 +40,7 @@ class DtbTest(validity.ValidityRoutines): and determine whether it points back to that page's offset. """ - def __init__(self, - layer_type: Type[layers.intel.Intel], - ptr_struct: str, - ptr_reference: int, - mask: int) -> None: + def __init__(self, layer_type: Type[layers.intel.Intel], ptr_struct: str, ptr_reference: int, mask: int) -> None: self.layer_type = self._check_class(layer_type, layers.intel.Intel) self.ptr_struct = self._check_type(ptr_struct, str) self.ptr_size = struct.calcsize(ptr_struct) @@ -55,10 +51,7 @@ class DtbTest(validity.ValidityRoutines): def _unpack(self, value: bytes) -> int: return struct.unpack("<" + self.ptr_struct, value)[0] - def __call__(self, - data: bytes, - data_offset: int, - page_offset: int) -> Optional[Tuple[int, Any]]: + def __call__(self, data: bytes, data_offset: int, page_offset: int) -> Optional[Tuple[int, Any]]: """Tests a specific page in a chunk of data to see if it contains a self-referential pointer. Args: @@ -70,7 +63,7 @@ class DtbTest(validity.ValidityRoutines): A valid DTB within this page (and an additional parameter for data) """ value = data[page_offset + (self.ptr_reference * self.ptr_size):page_offset + ( - (self.ptr_reference + 1) * self.ptr_size)] + (self.ptr_reference + 1) * self.ptr_size)] try: ptr = self._unpack(value) except struct.error: @@ -112,27 +105,27 @@ class DtbTest(validity.ValidityRoutines): class DtbTest32bit(DtbTest): + def __init__(self): - super().__init__(layer_type = layers.intel.WindowsIntel, - ptr_struct = "I", - ptr_reference = 0x300, - mask = 0xFFFFF000) + super().__init__( + layer_type = layers.intel.WindowsIntel, ptr_struct = "I", ptr_reference = 0x300, mask = 0xFFFFF000) class DtbTest64bit(DtbTest): + def __init__(self): - super().__init__(layer_type = layers.intel.WindowsIntel32e, - ptr_struct = "Q", - ptr_reference = 0x1ED, - mask = 0x3FFFFFFFFFF000) + super().__init__( + layer_type = layers.intel.WindowsIntel32e, + ptr_struct = "Q", + ptr_reference = 0x1ED, + mask = 0x3FFFFFFFFFF000) class DtbTestPae(DtbTest): + def __init__(self): - super().__init__(layer_type = layers.intel.WindowsIntelPAE, - ptr_struct = "Q", - ptr_reference = 0x3, - mask = 0x3FFFFFFFFFF000) + super().__init__( + layer_type = layers.intel.WindowsIntelPAE, ptr_struct = "Q", ptr_reference = 0x3, mask = 0x3FFFFFFFFFF000) def second_pass(self, dtb: int, data: bytes, data_offset: int) -> Optional[Tuple[int, Any]]: """PAE top level directory tables contains four entries and the self-referential pointer occurs in the second @@ -152,7 +145,7 @@ class DtbTestPae(DtbTest): dtb -= 0x4000 # If we're not in something that the overlap would pick up if dtb - data_offset >= 0: - pointers = data[dtb - data_offset + (3 * self.ptr_size): dtb - data_offset + (4 * self.ptr_size)] + pointers = data[dtb - data_offset + (3 * self.ptr_size):dtb - data_offset + (4 * self.ptr_size)] val = self._unpack(pointers) if (val & self.mask == dtb + 0x4000) and (val & 0xFFF == 0x001): return dtb, None @@ -162,15 +155,8 @@ class DtbTestPae(DtbTest): class DtbSelfReferential(DtbTest): """A generic DTB test which looks for a self-referential pointer at *any* index within the page.""" - def __init__(self, - layer_type: Type[layers.intel.Intel], - ptr_struct: str, - ptr_reference: int, - mask: int) -> None: - super().__init__(layer_type = layer_type, - ptr_struct = ptr_struct, - ptr_reference = ptr_reference, - mask = mask) + def __init__(self, layer_type: Type[layers.intel.Intel], ptr_struct: str, ptr_reference: int, mask: int) -> None: + super().__init__(layer_type = layer_type, ptr_struct = ptr_struct, ptr_reference = ptr_reference, mask = mask) def __call__(self, data: bytes, data_offset: int, page_offset: int) -> Optional[Tuple[int, int]]: page = data[page_offset:page_offset + self.page_size] @@ -190,15 +176,20 @@ class DtbSelfReferential(DtbTest): class DtbSelfRef32bit(DtbSelfReferential): + def __init__(self): - super().__init__(layer_type = layers.intel.WindowsIntel, ptr_struct = "I", ptr_reference = 0x300, - mask = 0xFFFFF000) + super().__init__( + layer_type = layers.intel.WindowsIntel, ptr_struct = "I", ptr_reference = 0x300, mask = 0xFFFFF000) class DtbSelfRef64bit(DtbSelfReferential): + def __init__(self): - super().__init__(layer_type = layers.intel.WindowsIntel32e, ptr_struct = "Q", ptr_reference = 0x1ED, - mask = 0x3FFFFFFFFFF000) + super().__init__( + layer_type = layers.intel.WindowsIntel32e, + ptr_struct = "Q", + ptr_reference = 0x1ED, + mask = 0x3FFFFFFFFFF000) class PageMapScanner(interfaces.layers.ScannerInterface): @@ -241,24 +232,24 @@ class WintelHelper(interfaces.automagic.AutomagicInterface): progress_callback: validity.ProgressCallback = None) -> None: useful = [] sub_config_path = interfaces.configuration.path_join(config_path, requirement.name) - if (isinstance(requirement, requirements.TranslationLayerRequirement) and - requirement.requirements.get("class", False)): + if (isinstance(requirement, requirements.TranslationLayerRequirement) + and requirement.requirements.get("class", False)): class_req = requirement.requirements["class"] for test in self.tests: - if (test.layer_type.__module__ + "." + test.layer_type.__name__ == - class_req.config_value(context, sub_config_path)): + if (test.layer_type.__module__ + "." + test.layer_type.__name__ == class_req.config_value( + context, sub_config_path)): useful.append(test) # Determine if a class has been chosen # Once an appropriate class has been chosen, attempt to determine the page_map_offset value - if ("memory_layer" in requirement.requirements and - not requirement.requirements["memory_layer"].unsatisfied(context, sub_config_path)): + if ("memory_layer" in requirement.requirements + and not requirement.requirements["memory_layer"].unsatisfied(context, sub_config_path)): # Only bother getting the DTB if we don't already have one page_map_offset_path = interfaces.configuration.path_join(sub_config_path, "page_map_offset") if not context.config.get(page_map_offset_path, None): - physical_layer_name = requirement.requirements["memory_layer"].config_value(context, - sub_config_path) + physical_layer_name = requirement.requirements["memory_layer"].config_value( + context, sub_config_path) if not isinstance(physical_layer_name, str): raise TypeError("Physical layer name is not a string: {}".format(sub_config_path)) physical_layer = context.memory[physical_layer_name] @@ -280,6 +271,7 @@ class WintelHelper(interfaces.automagic.AutomagicInterface): class WintelStacker(interfaces.automagic.StackerLayerInterface): + @classmethod def stack(cls, context: interfaces.context.ContextInterface, @@ -301,8 +293,7 @@ class WintelStacker(interfaces.automagic.StackerLayerInterface): layer = config_path = None # Check the metadata - if (base_layer.metadata.get('os', None) == 'Windows' and - base_layer.metadata.get('page_map_offset')): + if (base_layer.metadata.get('os', None) == 'Windows' and base_layer.metadata.get('page_map_offset')): arch = base_layer.metadata.get('architecture', None) if arch not in ['Intel32', 'Intel64']: return None @@ -316,12 +307,9 @@ class WintelStacker(interfaces.automagic.StackerLayerInterface): new_layer_name = context.memory.free_layer_name("IntelLayer") config_path = interfaces.configuration.path_join("IntelHelper", new_layer_name) context.config[interfaces.configuration.path_join(config_path, "memory_layer")] = layer_name - context.config[interfaces.configuration.path_join(config_path, "page_map_offset")] = base_layer.metadata[ - 'page_map_offset'] - layer = layer_type(context, - config_path = config_path, - name = new_layer_name, - metadata = {'os': 'Windows'}) + context.config[interfaces.configuration.path_join( + config_path, "page_map_offset")] = base_layer.metadata['page_map_offset'] + layer = layer_type(context, config_path = config_path, name = new_layer_name, metadata = {'os': 'Windows'}) # Check for the self-referential pointer if layer is None: @@ -333,20 +321,19 @@ class WintelStacker(interfaces.automagic.StackerLayerInterface): config_path = interfaces.configuration.path_join("IntelHelper", new_layer_name) context.config[interfaces.configuration.path_join(config_path, "memory_layer")] = layer_name context.config[interfaces.configuration.path_join(config_path, "page_map_offset")] = dtb - layer = test.layer_type(context, - config_path = config_path, - name = new_layer_name, - metadata = {'os': 'Windows'}) + layer = test.layer_type( + context, config_path = config_path, name = new_layer_name, metadata = {'os': 'Windows'}) break # Fall back to a heuristic for finding the Windows DTB if layer is None: vollog.debug("Self-referential pointer not in well-known location, moving to recent windows heuristic") # There is a very high chance that the DTB will live in this narrow segment, assuming we couldn't find it previously - hits = context.memory[layer_name].scan(context, - PageMapScanner([DtbSelfRef64bit()]), - sections = [(0x1a0000, 0x50000)], - progress_callback = progress_callback) + hits = context.memory[layer_name].scan( + context, + PageMapScanner([DtbSelfRef64bit()]), + sections = [(0x1a0000, 0x50000)], + progress_callback = progress_callback) # Flatten the generator hits = list(hits) if hits: @@ -357,11 +344,11 @@ class WintelStacker(interfaces.automagic.StackerLayerInterface): context.config[interfaces.configuration.path_join(config_path, "memory_layer")] = layer_name context.config[interfaces.configuration.path_join(config_path, "page_map_offset")] = page_map_offset # TODO: Need to determine the layer type (chances are high it's x64, hence this default) - layer = layers.intel.WindowsIntel32e(context, config_path = config_path, - name = new_layer_name, metadata = {'os': 'Windows'}) + layer = layers.intel.WindowsIntel32e( + context, config_path = config_path, name = new_layer_name, metadata = {'os': 'Windows'}) if layer is not None and config_path: - vollog.debug("DTB was found at: 0x{:0x}".format( - context.config[interfaces.configuration.path_join(config_path, "page_map_offset")])) + vollog.debug("DTB was found at: 0x{:0x}".format(context.config[interfaces.configuration.path_join( + config_path, "page_map_offset")])) return layer @@ -376,9 +363,8 @@ class WinSwapLayers(interfaces.automagic.AutomagicInterface): progress_callback: validity.ProgressCallback = None) -> None: """Finds translation layers that can have swap layers added""" path_join = interfaces.configuration.path_join - self._translation_requirement = self.find_requirements(context, config_path, requirement, - requirements.TranslationLayerRequirement, - shortcut = False) + self._translation_requirement = self.find_requirements( + context, config_path, requirement, requirements.TranslationLayerRequirement, shortcut = False) for trans_sub_config, trans_req in self._translation_requirement: if not isinstance(trans_req, requirements.TranslationLayerRequirement): # We need this so the type-checker knows we're a TranslationLayerRequirement @@ -404,9 +390,8 @@ class WinSwapLayers(interfaces.automagic.AutomagicInterface): context.config[layer_class_path] = 'volatility.framework.layers.physical.FileLayer' # Add the requirement - new_req = requirements.TranslationLayerRequirement(name = current_layer_name, - description = "Swap Layer", - optional = False) + new_req = requirements.TranslationLayerRequirement( + name = current_layer_name, description = "Swap Layer", optional = False) swap_req.add_requirement(new_req) context.config[path_join(swap_sub_config, 'number_of_elements')] = counter @@ -432,9 +417,12 @@ class WinSwapLayers(interfaces.automagic.AutomagicInterface): @classmethod def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: """Returns the requirements of this plugin""" - return [requirements.ListRequirement(name = "single_swap_locations", - element_type = str, - min_elements = 0, - max_elements = 16, - description = "Specifies a list of swap layer URIs for use with single-location", - optional = True)] + return [ + requirements.ListRequirement( + name = "single_swap_locations", + element_type = str, + min_elements = 0, + max_elements = 16, + description = "Specifies a list of swap layer URIs for use with single-location", + optional = True) + ] diff --git a/volatility/framework/configuration/requirements.py b/volatility/framework/configuration/requirements.py index d1d059718..995fdf22a 100644 --- a/volatility/framework/configuration/requirements.py +++ b/volatility/framework/configuration/requirements.py @@ -20,9 +20,7 @@ class MultiRequirement(configuration.RequirementInterface): Technically the Interface could handle this, but it's an interface, so this is a concrete implementation. """ - def unsatisfied(self, - context: configuration.ContextInterface, - config_path: str) -> List[str]: + def unsatisfied(self, context: configuration.ContextInterface, config_path: str) -> List[str]: return self.unsatisfied_children(context, config_path) @@ -65,7 +63,9 @@ class ListRequirement(configuration.RequirementInterface): def __init__(self, element_type: Type[configuration.SimpleTypes] = str, max_elements: Optional[int] = 0, - min_elements: Optional[int] = None, *args, **kwargs) -> None: + min_elements: Optional[int] = None, + *args, + **kwargs) -> None: """Constructs the object Args: @@ -132,7 +132,8 @@ class ChoiceRequirement(configuration.RequirementInterface): return [] -class ComplexListRequirement(MultiRequirement, configuration.ConfigurableRequirementInterface, metaclass = abc.ABCMeta): +class ComplexListRequirement( + MultiRequirement, configuration.ConfigurableRequirementInterface, metaclass = abc.ABCMeta): """Allows a variable length list of requirements""" def unsatisfied(self, context: interfaces.context.ContextInterface, config_path: str) -> List[str]: @@ -141,17 +142,18 @@ class ComplexListRequirement(MultiRequirement, configuration.ConfigurableRequire ret_list = super().unsatisfied(context, config_path) if ret_list: return ret_list - if (self.config_value(context, config_path, None) is None or - self.config_value(context, configuration.path_join(config_path, 'number_of_elements'))): + if (self.config_value(context, config_path, None) is None + or self.config_value(context, configuration.path_join(config_path, 'number_of_elements'))): return [config_path] return [] @classmethod def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: # This is not optional for the stacker to run, so optional must be marked as False - return [IntRequirement("number_of_elements", - description = "Determines how many layers are in this list", - optional = False)] + return [ + IntRequirement( + "number_of_elements", description = "Determines how many layers are in this list", optional = False) + ] @abc.abstractmethod def construct(self, context: interfaces.context.ContextInterface, config_path: str) -> None: @@ -161,9 +163,7 @@ class ComplexListRequirement(MultiRequirement, configuration.ConfigurableRequire def new_requirement(self, index) -> interfaces.configuration.RequirementInterface: """Builds a new requirement based on the specified index""" - def build_configuration(self, - context: interfaces.context.ContextInterface, - config_path: str, + def build_configuration(self, context: interfaces.context.ContextInterface, config_path: str, _: Any) -> configuration.HierarchicalDict: result = configuration.HierarchicalDict() num_elem_config_path = configuration.path_join(config_path, self.name, 'number_of_elements') @@ -198,9 +198,7 @@ class LayerListRequirement(ComplexListRequirement): def new_requirement(self, index) -> interfaces.configuration.RequirementInterface: """Constructs a new requirement based on the specified index""" - return TranslationLayerRequirement(name = self.name + str(index), - description = "Swap Layer", - optional = False) + return TranslationLayerRequirement(name = self.name + str(index), description = "Swap Layer", optional = False) class TranslationLayerRequirement(configuration.ConstructableRequirementInterface, @@ -234,9 +232,7 @@ class TranslationLayerRequirement(configuration.ConstructableRequirementInterfac self.architectures = architectures super().__init__(name, description, default, optional) - def unsatisfied(self, - context: interfaces.context.ContextInterface, - config_path: str) -> List[str]: + def unsatisfied(self, context: interfaces.context.ContextInterface, config_path: str) -> List[str]: """Validate that the value is a valid layer name and that the layer adheres to the requirements""" config_path = configuration.path_join(config_path, self.name) value = self.config_value(context, config_path, None) @@ -247,8 +243,8 @@ class TranslationLayerRequirement(configuration.ConstructableRequirementInterfac if self.oses and context.memory[value].metadata.get('os', None) not in self.oses: vollog.log(9, "TypeError - Layer is not the required OS: {}".format(value)) return [config_path] - if (self.architectures and - context.memory[value].metadata.get('architecture', None) not in self.architectures): + if (self.architectures + and context.memory[value].metadata.get('architecture', None) not in self.architectures): vollog.log(9, "TypeError - Layer is not the required Architecture: {}".format(value)) return [config_path] return [] @@ -263,8 +259,7 @@ class TranslationLayerRequirement(configuration.ConstructableRequirementInterfac ### NOTE: This validate method has side effects (the dependencies can change)!!! self._validate_class(context, interfaces.configuration.parent_path(config_path)) - vollog.log(constants.LOGLEVEL_V, - "IndexError - No configuration provided: {}".format(config_path)) + vollog.log(constants.LOGLEVEL_V, "IndexError - No configuration provided: {}".format(config_path)) return [config_path] def construct(self, context: interfaces.context.ContextInterface, config_path: str) -> None: @@ -278,12 +273,12 @@ class TranslationLayerRequirement(configuration.ConstructableRequirementInterfac name = self.name + str(counter) counter += 1 - args = {"context": context, - "config_path": config_path, - "name": name} + args = {"context": context, "config_path": config_path, "name": name} - if any([subreq.unsatisfied(context, config_path) for subreq in self.requirements.values() if - not subreq.optional]): + if any( + [subreq.unsatisfied(context, config_path) + for subreq in self.requirements.values() + if not subreq.optional]): return None obj = self._construct_class(context, config_path, args) @@ -293,9 +288,7 @@ class TranslationLayerRequirement(configuration.ConstructableRequirementInterfac # context.config[config_path] = obj.name return None - def build_configuration(self, - context: interfaces.context.ContextInterface, - _: str, + def build_configuration(self, context: interfaces.context.ContextInterface, _: str, value: Any) -> configuration.HierarchicalDict: """Builds the appropriate configuration for the specified requirement""" return context.memory[value].build_configuration() @@ -315,8 +308,8 @@ class SymbolRequirement(configuration.ConstructableRequirementInterface, return [config_path] if value not in context.symbol_space: # This is an expected situation, so return False rather than raise - vollog.log(constants.LOGLEVEL_V, - "IndexError - Value not present in the symbol space: {}".format(value or "")) + vollog.log(constants.LOGLEVEL_V, "IndexError - Value not present in the symbol space: {}".format(value + or "")) return [config_path] return [] @@ -326,18 +319,18 @@ class SymbolRequirement(configuration.ConstructableRequirementInterface, # Determine the space name name = context.symbol_space.free_table_name(self.name) - args = {"context": context, - "config_path": config_path, - "name": name} + args = {"context": context, "config_path": config_path, "name": name} - if any([subreq.unsatisfied(context, config_path) for subreq in self.requirements.values() if - not subreq.optional]): + if any( + [subreq.unsatisfied(context, config_path) + for subreq in self.requirements.values() + if not subreq.optional]): return None # Fill out the parameter for class creation if not isinstance(self.requirements["class"], configuration.ClassRequirement): - raise ValueError( - "Class requirement is not of type ClassRequirement: {}".format(repr(self.requirements["class"]))) + raise ValueError("Class requirement is not of type ClassRequirement: {}".format( + repr(self.requirements["class"]))) cls = self.requirements["class"].cls node_config = context.config.branch(config_path) for req in cls.get_requirements(): @@ -349,9 +342,7 @@ class SymbolRequirement(configuration.ConstructableRequirementInterface, context.symbol_space.append(obj) return None - def build_configuration(self, - context: interfaces.context.ContextInterface, - _: str, + def build_configuration(self, context: interfaces.context.ContextInterface, _: str, value: Any) -> configuration.HierarchicalDict: """Builds the appropriate configuration for the specified requirement""" return context.symbol_space[value].build_configuration() diff --git a/volatility/framework/constants/__init__.py b/volatility/framework/constants/__init__.py index 6d95130a6..6f89271cc 100644 --- a/volatility/framework/constants/__init__.py +++ b/volatility/framework/constants/__init__.py @@ -8,10 +8,14 @@ import sys import volatility.framework.constants.linux import volatility.framework.constants.windows -PLUGINS_PATH = [os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "plugins")), - os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "plugins"))] -SYMBOL_BASEPATHS = [os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "symbols")), - os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "symbols"))] +PLUGINS_PATH = [ + os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "plugins")), + os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "plugins")) +] +SYMBOL_BASEPATHS = [ + os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "symbols")), + os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "symbols")) +] BANG = "!" PACKAGE_VERSION = "3.0.0_alpha1" DISABLE_MULTITHREADED_SCANNING = False @@ -30,4 +34,3 @@ os.makedirs(CACHE_PATH, exist_ok = True) LINUX_BANNERS_PATH = os.path.join(CACHE_PATH, "linux_banners.cache") MAC_BANNERS_PATH = os.path.join(CACHE_PATH, "mac_banners.cache") - diff --git a/volatility/framework/contexts/__init__.py b/volatility/framework/contexts/__init__.py index 11d1f62ee..6329d2387 100644 --- a/volatility/framework/contexts/__init__.py +++ b/volatility/framework/contexts/__init__.py @@ -98,31 +98,34 @@ class Context(interfaces.context.ContextInterface): arguments.update(object_template.vol) object_template = object_template.clone() object_template.update_vol(**arguments) - return object_template(context = self, - object_info = interfaces.objects.ObjectInformation(layer_name = layer_name, - offset = offset, - native_layer_name = native_layer_name)) + return object_template( + context = self, + object_info = interfaces.objects.ObjectInformation( + layer_name = layer_name, offset = offset, native_layer_name = native_layer_name)) @functools.lru_cache() - def module(self, # type: ignore # FIXME: mypy #5107 - module_name: str, - layer_name: str, - offset: int, - native_layer_name: Optional[str] = None, - size: Optional[int] = None) -> interfaces.context.ModuleInterface: + def module( + self, # type: ignore # FIXME: mypy #5107 + module_name: str, + layer_name: str, + offset: int, + native_layer_name: Optional[str] = None, + size: Optional[int] = None) -> interfaces.context.ModuleInterface: """Creates a module object""" if size: - return SizedModule(self, - module_name = module_name, - layer_name = layer_name, - offset = offset, - size = size, - native_layer_name = native_layer_name) - return Module(self, - module_name = module_name, - layer_name = layer_name, - offset = offset, - native_layer_name = native_layer_name) + return SizedModule( + self, + module_name = module_name, + layer_name = layer_name, + offset = offset, + size = size, + native_layer_name = native_layer_name) + return Module( + self, + module_name = module_name, + layer_name = layer_name, + offset = offset, + native_layer_name = native_layer_name) def get_module_wrapper(method: str) -> Callable: @@ -138,6 +141,7 @@ def get_module_wrapper(method: str) -> Callable: class Module(interfaces.context.ModuleInterface): + def object(self, symbol_name: Optional[str] = None, type_name: Optional[str] = None, @@ -193,12 +197,13 @@ class SizedModule(Module): size: int, symbol_table_name: Optional[str] = None, native_layer_name: Optional[str] = None) -> None: - super().__init__(context, - module_name = module_name, - layer_name = layer_name, - offset = offset, - native_layer_name = native_layer_name, - symbol_table_name = symbol_table_name) + super().__init__( + context, + module_name = module_name, + layer_name = layer_name, + offset = offset, + native_layer_name = native_layer_name, + symbol_table_name = symbol_table_name) self._size = self._check_type(size, int) @property @@ -216,8 +221,8 @@ class SizedModule(Module): layer = self._context.memory[self.layer_name] if not isinstance(layer, interfaces.layers.TranslationLayerInterface): raise TypeError("Hashing modules on non-TranslationLayers is not allowed") - return hashlib.md5( - bytes(str(list(layer.mapping(self.offset, self.size, ignore_errors = True))), 'utf-8')).hexdigest() + return hashlib.md5(bytes(str(list(layer.mapping(self.offset, self.size, ignore_errors = True))), + 'utf-8')).hexdigest() def get_symbols_by_absolute_location(self, offset: int, size: int = 0) -> List[str]: """Returns the symbols within this module that live at the specified absolute offset provided""" @@ -225,8 +230,9 @@ class SizedModule(Module): raise ValueError("Size must be strictly non-negative") if offset > self._offset + self.size: return [] - return list(self._context.symbol_space.get_symbols_by_location(offset = offset - self._offset, size = size, - table_name = self.symbol_table_name)) + return list( + self._context.symbol_space.get_symbols_by_location( + offset = offset - self._offset, size = size, table_name = self.symbol_table_name)) class ModuleCollection(validity.ValidityRoutines): diff --git a/volatility/framework/exceptions.py b/volatility/framework/exceptions.py index 5fbb2cc9c..7ec46996f 100644 --- a/volatility/framework/exceptions.py +++ b/volatility/framework/exceptions.py @@ -34,12 +34,7 @@ class PagedInvalidAddressException(InvalidAddressException): Includes the invalid address and the number of bits of the address that are invalid """ - def __init__(self, - layer_name: str, - invalid_address: int, - invalid_bits: int, - entry: int, - *args) -> None: + def __init__(self, layer_name: str, invalid_address: int, invalid_bits: int, entry: int, *args) -> None: super().__init__(layer_name, invalid_address, *args) self.invalid_bits = invalid_bits self.entry = entry @@ -51,12 +46,7 @@ class SwappedInvalidAddressException(PagedInvalidAddressException): Includes the swap lookup""" - def __init__(self, - layer_name: str, - invalid_address: int, - invalid_bits: int, - entry: int, - swap_offset: int, + def __init__(self, layer_name: str, invalid_address: int, invalid_bits: int, entry: int, swap_offset: int, *args) -> None: super().__init__(layer_name, invalid_address, invalid_bits, entry, *args) self.swap_offset = swap_offset @@ -87,6 +77,7 @@ class MissingStructureException(VolatilityException): class UnsatisfiedException(VolatilityException): + def __init__(self, unsatisfied: List[str]) -> None: super().__init__() self.unsatisfied = unsatisfied diff --git a/volatility/framework/interfaces/automagic.py b/volatility/framework/interfaces/automagic.py index d3902247f..a70533371 100644 --- a/volatility/framework/interfaces/automagic.py +++ b/volatility/framework/interfaces/automagic.py @@ -33,14 +33,11 @@ class AutomagicInterface(interfaces.configuration.ConfigurableInterface, metacla priority = 10 """An ordering to indicate how soon this automagic should be run""" - def __init__(self, - context: interfaces.context.ContextInterface, - config_path: str, *args, **kwargs) -> None: + def __init__(self, context: interfaces.context.ContextInterface, config_path: str, *args, **kwargs) -> None: super().__init__(context, config_path) for requirement in self.get_requirements(): if not isinstance(requirement, (interfaces.configuration.SimpleTypeRequirement, - requirements.ChoiceRequirement, - requirements.ListRequirement)): + requirements.ChoiceRequirement, requirements.ListRequirement)): raise ValueError( "Automagic requirements must be a SimpleTypeRequirement, ChoiceRequirement or ListRequirement") diff --git a/volatility/framework/interfaces/configuration.py b/volatility/framework/interfaces/configuration.py index 1f4289dbd..49e310681 100644 --- a/volatility/framework/interfaces/configuration.py +++ b/volatility/framework/interfaces/configuration.py @@ -57,9 +57,7 @@ class HierarchicalDict(collections.abc.Mapping): """ - def __init__(self, - initial_dict: Dict = None, - separator: str = CONFIG_SEPARATOR) -> None: + def __init__(self, initial_dict: Dict = None, separator: str = CONFIG_SEPARATOR) -> None: if not (isinstance(separator, str) and len(separator) == 1): raise TypeError("Separator must be a one character string: {}".format(separator)) self._separator = separator @@ -71,8 +69,8 @@ class HierarchicalDict(collections.abc.Mapping): for k, v in initial_dict.items(): self[k] = v elif initial_dict is not None: - raise TypeError("Initial_dict must be a dictionary or JSON string containing a dictionary: {}".format( - initial_dict)) + raise TypeError( + "Initial_dict must be a dictionary or JSON string containing a dictionary: {}".format(initial_dict)) @property def separator(self) -> str: @@ -306,9 +304,7 @@ class RequirementInterface(validity.ValidityRoutines, metaclass = ABCMeta): self._check_type(requirement, RequirementInterface) del self._requirements[requirement.name] - def unsatisfied_children(self, - context: interfaces.context.ContextInterface, - config_path: str) -> List[str]: + def unsatisfied_children(self, context: interfaces.context.ContextInterface, config_path: str) -> List[str]: """Method that will validate all child requirements""" result = [] for requirement in self.requirements.values(): @@ -320,9 +316,7 @@ class RequirementInterface(validity.ValidityRoutines, metaclass = ABCMeta): # Validation routines @abstractmethod - def unsatisfied(self, - context: interfaces.context.ContextInterface, - config_path: str) -> List[str]: + def unsatisfied(self, context: interfaces.context.ContextInterface, config_path: str) -> List[str]: """Method to validate the value stored at config_path for the configuration object against a context Returns a list containing its own name (or multiple unsatisfied requirement names) when invalid @@ -347,10 +341,10 @@ class SimpleTypeRequirement(RequirementInterface): value = self.config_value(context, config_path, None) if not isinstance(value, self.instance_type): - vollog.log(constants.LOGLEVEL_V, - "TypeError - {} requirements only accept {} type: {}".format(self.name, - self.instance_type.__name__, - value)) + vollog.log( + constants.LOGLEVEL_V, + "TypeError - {} requirements only accept {} type: {}".format(self.name, self.instance_type.__name__, + value)) return [config_path] return [] @@ -457,9 +451,7 @@ class ConstructableRequirementInterface(RequirementInterface): class ConfigurableRequirementInterface(RequirementInterface): """Simple Abstract class to provide build_required_config""" - def build_configuration(self, - context: interfaces.context.ContextInterface, - config_path: str, + def build_configuration(self, context: interfaces.context.ContextInterface, config_path: str, value: Any) -> HierarchicalDict: """Proxies to a ConfigurableInterface if necessary""" @@ -467,9 +459,7 @@ class ConfigurableRequirementInterface(RequirementInterface): class ConfigurableInterface(validity.ValidityRoutines, metaclass = ABCMeta): """Class to allow objects to have requirements and read configuration data from the context config tree""" - def __init__(self, - context: interfaces.context.ContextInterface, - config_path: str) -> None: + def __init__(self, context: interfaces.context.ContextInterface, config_path: str) -> None: """Basic initializer that allows configurables to access their own config settings""" super().__init__() self._context = self._check_type(context, ContextInterface) @@ -513,9 +503,7 @@ class ConfigurableInterface(validity.ValidityRoutines, metaclass = ABCMeta): result[req.name] = value if isinstance(req, ConfigurableRequirementInterface): if value is not None: - result.splice(req.name, req.build_configuration(self.context, - self.config_path, - value)) + result.splice(req.name, req.build_configuration(self.context, self.config_path, value)) return result @classmethod @@ -548,8 +536,8 @@ class ConfigurableInterface(validity.ValidityRoutines, metaclass = ABCMeta): if args: vollog.debug("Non-keyword arguments to make_subconfig are ignored - this is a bug in the calling code") - random_config_dict = ''.join( - random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(8)) + random_config_dict = ''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits) + for _ in range(8)) new_config_path = path_join(self.config_path, random_config_dict) # TODO: Check that the new_config_path is empty, although it's not critical if it's not since the values are merged in diff --git a/volatility/framework/interfaces/context.py b/volatility/framework/interfaces/context.py index 774c61c94..5df398732 100644 --- a/volatility/framework/interfaces/context.py +++ b/volatility/framework/interfaces/context.py @@ -75,11 +75,7 @@ class ContextInterface(object, metaclass = ABCMeta): Memory constraints may become an issue for this function depending on how much is actually stored in the context""" return copy.deepcopy(self) - def module(self, - module_name: str, - layer_name: str, - offset: int, - size: Optional[int] = None) -> 'ModuleInterface': + def module(self, module_name: str, layer_name: str, offset: int, size: Optional[int] = None) -> 'ModuleInterface': """Create a module object """ @@ -121,10 +117,7 @@ class ModuleInterface(validity.ValidityRoutines, metaclass = ABCMeta): return self._layer_name @abstractmethod - def object(self, - symbol_name: str = None, - type_name: str = None, - offset: int = None, + def object(self, symbol_name: str = None, type_name: str = None, offset: int = None, **kwargs) -> 'interfaces.objects.ObjectInterface': """Returns an object created using the symbol_table_name and layer_name of the Module""" diff --git a/volatility/framework/interfaces/layers.py b/volatility/framework/interfaces/layers.py index fe1382a67..6a9172982 100644 --- a/volatility/framework/interfaces/layers.py +++ b/volatility/framework/interfaces/layers.py @@ -87,13 +87,15 @@ class ScannerInterface(validity.ValidityRoutines, metaclass = ABCMeta): """ -class DataLayerInterface(interfaces.configuration.ConfigurableInterface, validity.ValidityRoutines, - metaclass = ABCMeta): +class DataLayerInterface( + interfaces.configuration.ConfigurableInterface, validity.ValidityRoutines, metaclass = ABCMeta): """A Layer that directly holds data (and does not translate it). This is effectively a leaf node in a layer tree. It directly accesses a data source and exposes it within volatility.""" - _direct_metadata = collections.ChainMap({}, {'architecture': 'Unknown', - 'os': 'Unknown'}) # type: collections.ChainMap[str, str] + _direct_metadata = collections.ChainMap({}, { + 'architecture': 'Unknown', + 'os': 'Unknown' + }) # type: collections.ChainMap[str, str] def __init__(self, context: 'interfaces.context.ContextInterface', @@ -200,8 +202,9 @@ class DataLayerInterface(interfaces.configuration.ConfigurableInterface, validit while not result.ready(): if progress_callback: # Run the progress_callback - progress_callback(scan_metric(progress.value), - "Scanning {} using {}".format(self.name, scanner.__class__.__name__)) + progress_callback( + scan_metric(progress.value), + "Scanning {} using {}".format(self.name, scanner.__class__.__name__)) # Ensures we don't burn CPU cycles going round in a ready waiting loop # without delaying the user too long between progress updates/results result.wait(0.1) @@ -212,8 +215,9 @@ class DataLayerInterface(interfaces.configuration.ConfigurableInterface, validit scan_chunk = functools.partial(self._scan_chunk, scanner, progress) for value in scan_iterator(): if progress_callback: - progress_callback(scan_metric(progress.value), - "Scanning {} using {}".format(self.name, scanner.__class__.__name__)) + progress_callback( + scan_metric(progress.value), + "Scanning {} using {}".format(self.name, scanner.__class__.__name__)) yield from scan_chunk(value) except Exception as e: # We don't care the kind of exception, so catch and report on everything, yielding nothing further @@ -221,8 +225,7 @@ class DataLayerInterface(interfaces.configuration.ConfigurableInterface, validit vollog.log(constants.LOGLEVEL_VVV, "\n".join(traceback.TracebackException.from_exception(e).format(chain = True))) - def _coalesce_sections(self, - sections: Iterable[Tuple[int, int]]) -> Iterable[Tuple[int, int]]: + def _coalesce_sections(self, sections: Iterable[Tuple[int, int]]) -> Iterable[Tuple[int, int]]: """Take a list of (start, length) sections and coalesce any adjacent sections""" result = [] # type: List[Tuple[int, int]] position = 0 @@ -248,8 +251,7 @@ class DataLayerInterface(interfaces.configuration.ConfigurableInterface, validit result[1] = (last_start, self.maximum_address - last_start) return result - def _scan_iterator(self, - scanner: 'ScannerInterface', + def _scan_iterator(self, scanner: 'ScannerInterface', sections: Iterable[Tuple[int, int]]) -> Iterable[IteratorValue]: """Iterator that indicates which blocks in the layer are to be read by for the scanning @@ -270,9 +272,7 @@ class DataLayerInterface(interfaces.configuration.ConfigurableInterface, validit offset += chunk_size # We ignore the type due to the iterator_value, actually it only needs to match the output from _scan_iterator - def _scan_chunk(self, - scanner: 'ScannerInterface', - progress: 'ProgressValue', + def _scan_chunk(self, scanner: 'ScannerInterface', progress: 'ProgressValue', iterator_value: IteratorValue) -> List[Any]: data_to_scan, chunk_end = iterator_value data = b'' @@ -280,16 +280,13 @@ class DataLayerInterface(interfaces.configuration.ConfigurableInterface, validit try: data += self.context.memory[layer_name].read(address, chunk_size) except exceptions.InvalidAddressException: - vollog.debug( - "Invalid address in layer {} found scanning {} at address {:x}".format(layer_name, self.name, - address)) + vollog.debug("Invalid address in layer {} found scanning {} at address {:x}".format( + layer_name, self.name, address)) progress.value = chunk_end return list(scanner(data, chunk_end - len(data))) - def _scan_metric(self, - _scanner: 'ScannerInterface', - sections: List[Tuple[int, int]]) -> Callable[[int], float]: + def _scan_metric(self, _scanner: 'ScannerInterface', sections: List[Tuple[int, int]]) -> Callable[[int], float]: if not sections: raise ValueError("Sections have no size, nothing to scan") @@ -324,10 +321,7 @@ class TranslationLayerInterface(DataLayerInterface, metaclass = ABCMeta): """ @abstractmethod - def mapping(self, - offset: int, - length: int, - ignore_errors: bool = False) -> Iterable[Tuple[int, int, int, str]]: + def mapping(self, offset: int, length: int, ignore_errors: bool = False) -> Iterable[Tuple[int, int, int, str]]: """Returns a sorted iterable of (offset, mapped_offset, length, layer) mappings ignore_errors will provide all available maps with gaps, but their total length may not add up to the requested length @@ -363,9 +357,8 @@ class TranslationLayerInterface(DataLayerInterface, metaclass = ABCMeta): output = [] # type: List[bytes] for (offset, mapped_offset, mapped_length, layer) in self.mapping(offset, length, ignore_errors = pad): if not pad and offset > current_offset: - raise exceptions.InvalidAddressException(self.name, current_offset, - "Layer {} cannot map offset: {}".format(self.name, - current_offset)) + raise exceptions.InvalidAddressException( + self.name, current_offset, "Layer {} cannot map offset: {}".format(self.name, current_offset)) elif offset > current_offset: output += [b"\x00" * (offset - current_offset)] current_offset = offset @@ -382,9 +375,8 @@ class TranslationLayerInterface(DataLayerInterface, metaclass = ABCMeta): length = len(value) for (offset, mapped_offset, length, layer) in self.mapping(offset, length): if offset > current_offset: - raise exceptions.InvalidAddressException(self.name, current_offset, - "Layer {} cannot map offset: {}".format(self.name, - current_offset)) + raise exceptions.InvalidAddressException( + self.name, current_offset, "Layer {} cannot map offset: {}".format(self.name, current_offset)) elif offset < current_offset: raise exceptions.LayerException("Mapping returned an overlapping element") self._context.memory.write(layer, mapped_offset, value) @@ -392,8 +384,7 @@ class TranslationLayerInterface(DataLayerInterface, metaclass = ABCMeta): # ## Scan implementation with knowledge of pages - def _scan_iterator(self, - scanner: 'ScannerInterface', + def _scan_iterator(self, scanner: 'ScannerInterface', sections: Iterable[Tuple[int, int]]) -> Iterable[IteratorValue]: for (section_start, section_length) in sections: for mapped in self.mapping(section_start, section_length, ignore_errors = True): @@ -415,21 +406,14 @@ class Memory(validity.ValidityRoutines, collections.abc.Mapping): def __init__(self) -> None: self._layers = {} # type: Dict[str, DataLayerInterface] - def read(self, - layer: str, - offset: int, - length: int, - pad: bool = False): + def read(self, layer: str, offset: int, length: int, pad: bool = False): """Reads from a particular layer at offset for length bytes Returns 'bytes' not 'str' """ return self[layer].read(offset, length, pad) - def write(self, - layer: str, - offset: int, - data: bytes) -> None: + def write(self, layer: str, offset: int, data: bytes) -> None: """Writes to a particular layer at offset for length bytes""" self[layer].write(offset, data) @@ -444,8 +428,8 @@ class Memory(validity.ValidityRoutines, collections.abc.Mapping): if isinstance(layer, TranslationLayerInterface): missing_list = [sublayer for sublayer in layer.dependencies if sublayer not in self._layers] if missing_list: - raise exceptions.LayerException( - "Layer {} has unmet dependencies: {}".format(layer.name, ", ".join(missing_list))) + raise exceptions.LayerException("Layer {} has unmet dependencies: {}".format( + layer.name, ", ".join(missing_list))) self._layers[layer.name] = layer def del_layer(self, name: str) -> None: @@ -456,8 +440,8 @@ class Memory(validity.ValidityRoutines, collections.abc.Mapping): for layer in self._layers: depend_list = [superlayer for superlayer in self._layers if name in self._layers[layer].dependencies] if depend_list: - raise exceptions.LayerException( - "Layer {} is depended upon: {}".format(self._layers[layer].name, ", ".join(depend_list))) + raise exceptions.LayerException("Layer {} is depended upon: {}".format( + self._layers[layer].name, ", ".join(depend_list))) self._layers[name].destroy() del self._layers[name] @@ -486,5 +470,6 @@ class Memory(validity.ValidityRoutines, collections.abc.Mapping): class DummyProgress(object): + def __init__(self): self.value = 0 diff --git a/volatility/framework/interfaces/objects.py b/volatility/framework/interfaces/objects.py index 8a5aa1ed3..f196759c1 100644 --- a/volatility/framework/interfaces/objects.py +++ b/volatility/framework/interfaces/objects.py @@ -57,21 +57,20 @@ class ObjectInformation(ReadOnlyMapping): self._check_type(offset, int) if parent: self._check_type(parent, ObjectInterface) - super().__init__({'layer_name': layer_name, - 'offset': offset, - 'member_name': member_name, - 'parent': parent, - 'native_layer_name': native_layer_name or layer_name}) + super().__init__({ + 'layer_name': layer_name, + 'offset': offset, + 'member_name': member_name, + 'parent': parent, + 'native_layer_name': native_layer_name or layer_name + }) class ObjectInterface(validity.ValidityRoutines, metaclass = ABCMeta): """A base object required to be the ancestor of every object used in volatility""" - def __init__(self, - context: 'interfaces_context.ContextInterface', - type_name: str, - object_info: 'ObjectInformation', - **kwargs) -> None: + def __init__(self, context: 'interfaces_context.ContextInterface', type_name: str, + object_info: 'ObjectInformation', **kwargs) -> None: # Since objects are likely to be instantiated often, # we're only checking that context, offset and parent # Everything else may be wrong, but that will get caught later on @@ -89,8 +88,10 @@ class ObjectInterface(validity.ValidityRoutines, metaclass = ABCMeta): mask = context.memory[object_info.layer_name].address_mask normalized_offset = object_info.offset & mask - self._vol = collections.ChainMap({}, object_info, {'type_name': type_name, 'offset': normalized_offset}, - kwargs) + self._vol = collections.ChainMap({}, object_info, { + 'type_name': type_name, + 'offset': normalized_offset + }, kwargs) self._context = context @property @@ -118,12 +119,11 @@ class ObjectInterface(validity.ValidityRoutines, metaclass = ABCMeta): raise ValueError("Unable to determine table for symbol: {}".format(self.vol.type_name)) table_name = self.vol.type_name[:self.vol.type_name.index(constants.BANG)] if table_name not in self._context.symbol_space: - raise KeyError("Symbol table not found in context's symbol_space for symbol: {}".format(self.vol.type_name)) + raise KeyError("Symbol table not found in context's symbol_space for symbol: {}".format( + self.vol.type_name)) return self._context.symbol_space[table_name] - def cast(self, - new_type_name: str, - **additional) -> 'ObjectInterface': + def cast(self, new_type_name: str, **additional) -> 'ObjectInterface': """Returns a new object at the offset and from the layer that the current object inhabits .. note:: If new type name does not include a symbol table, the symbol table for the current object is used @@ -135,13 +135,13 @@ class ObjectInterface(validity.ValidityRoutines, metaclass = ABCMeta): object_template = self._context.symbol_space.get_type(new_type_name) object_template = object_template.clone() object_template.update_vol(**additional) - object_info = ObjectInformation(layer_name = self.vol.layer_name, - offset = self.vol.offset, - member_name = self.vol.member_name, - parent = self.vol.parent, - native_layer_name = self.vol.native_layer_name) - return object_template(context = self._context, - object_info = object_info) + object_info = ObjectInformation( + layer_name = self.vol.layer_name, + offset = self.vol.offset, + member_name = self.vol.member_name, + parent = self.vol.parent, + native_layer_name = self.vol.native_layer_name) + return object_template(context = self._context, object_info = object_info) def has_member(self, member_name: str) -> bool: """Returns whether the object would contain a member called member_name""" @@ -166,24 +166,17 @@ class ObjectInterface(validity.ValidityRoutines, metaclass = ABCMeta): return [] @classmethod - def replace_child(cls, - template: 'Template', - old_child: 'Template', - new_child: 'Template') -> None: + def replace_child(cls, template: 'Template', old_child: 'Template', new_child: 'Template') -> None: """Substitutes the old_child for the new_child""" raise KeyError("Template does not contain any children to replace: {}".format(template.vol.type_name)) @classmethod - def relative_child_offset(cls, - template: 'Template', - child: str) -> int: + def relative_child_offset(cls, template: 'Template', child: str) -> int: """Returns the relative offset from the head of the parent data to the child member""" raise KeyError("Template does not contain any children: {}".format(template.vol.type_name)) @classmethod - def has_member(cls, - template: 'Template', - member_name: str) -> bool: + def has_member(cls, template: 'Template', member_name: str) -> bool: """Returns whether the object would contain a member called member_name""" return False @@ -263,7 +256,6 @@ class Template(validity.ValidityRoutines): return self._vol[attr] raise AttributeError("{} object has no attribute {}".format(self.__class__.__name__, attr)) - def __call__(self, - context: 'interfaces_context.ContextInterface', + def __call__(self, context: 'interfaces_context.ContextInterface', object_info: ObjectInformation) -> ObjectInterface: """Constructs the object""" diff --git a/volatility/framework/interfaces/plugins.py b/volatility/framework/interfaces/plugins.py index 9b93626e8..c4fafe535 100644 --- a/volatility/framework/interfaces/plugins.py +++ b/volatility/framework/interfaces/plugins.py @@ -53,6 +53,7 @@ class FileConsumerInterface(object): # The plugin accepts the context and modifies as necessary # The plugin runs and produces a TreeGrid output + class PluginInterface(interfaces_configuration.ConfigurableInterface, validity.ValidityRoutines, metaclass = ABCMeta): """Class that defines the basic interface that all Plugins must maintain. The constructor must only take a `context` and `config_path`, so that plugins can be launched automatically. As diff --git a/volatility/framework/interfaces/renderers.py b/volatility/framework/interfaces/renderers.py index 3b8e2f1e3..6895244f7 100644 --- a/volatility/framework/interfaces/renderers.py +++ b/volatility/framework/interfaces/renderers.py @@ -39,6 +39,7 @@ class ColumnSortKey(metaclass = ABCMeta): class TreeNode(collections.Sequence, metaclass = ABCMeta): + def __init__(self, path, treegrid, parent, values): """Initializes the TreeNode""" @@ -97,12 +98,7 @@ class Disassembly(object): _Type = TypeVar("_Type", bound = Type) ColumnsType = List[Tuple[str, Type]] -BaseTypes = Union[Type[int], - Type[str], - Type[float], - Type[bytes], - Type[datetime.datetime], - Type[BaseAbsentValue], +BaseTypes = Union[Type[int], Type[str], Type[float], Type[bytes], Type[datetime.datetime], Type[BaseAbsentValue], Type[Disassembly]] VisitorSignature = Callable[[TreeNode, _Type], _Type] @@ -140,9 +136,7 @@ class TreeGrid(object, metaclass = ABCMeta): """Method used to sanitize column names for TreeNodes""" @abstractmethod - def populate(self, - func: VisitorSignature = None, - initial_accumulator: Any = None) -> None: + def populate(self, func: VisitorSignature = None, initial_accumulator: Any = None) -> None: """Populates the tree by consuming the TreeGrid's construction generator Func is called on every node, so can be used to create output on demand diff --git a/volatility/framework/interfaces/symbols.py b/volatility/framework/interfaces/symbols.py index 555cc7f42..ad28a41d1 100644 --- a/volatility/framework/interfaces/symbols.py +++ b/volatility/framework/interfaces/symbols.py @@ -70,9 +70,7 @@ class BaseSymbolTableInterface(validity.ValidityRoutines): Note: table_mapping is a rarely used feature (since symbol tables are typically self-contained) """ - def __init__(self, - name: str, - native_types: 'NativeTableInterface', + def __init__(self, name: str, native_types: 'NativeTableInterface', table_mapping: Optional[Dict[str, str]] = None) -> None: self.name = self._check_type(name, str) if table_mapping is None: @@ -164,8 +162,8 @@ class BaseSymbolTableInterface(validity.ValidityRoutines): # This allows for searching with and without the table name (in case multiple tables contain # the same symbol name and we've not specifically been told which one) symbol = self.get_symbol(symbol_name) - if symbol.type_name is not None and ( - symbol.type_name == type_name or (symbol.type_name.endswith(constants.BANG + type_name))): + if symbol.type_name is not None and (symbol.type_name == type_name or + (symbol.type_name.endswith(constants.BANG + type_name))): yield symbol.name def get_symbols_by_location(self, offset: int, size: int = 0) -> Iterable[str]: @@ -193,10 +191,7 @@ class SymbolSpaceInterface(collections.abc.Mapping): """Returns all symbols based on the type of the symbol""" @abstractmethod - def get_symbols_by_location(self, - offset: int, - size: int = 0, - table_name: Optional[str] = None) -> Iterable[str]: + def get_symbols_by_location(self, offset: int, size: int = 0, table_name: Optional[str] = None) -> Iterable[str]: """Returns all symbols that exist at a specific relative address""" @abstractmethod diff --git a/volatility/framework/layers/__init__.py b/volatility/framework/layers/__init__.py index 6de289a47..01ac71d74 100644 --- a/volatility/framework/layers/__init__.py +++ b/volatility/framework/layers/__init__.py @@ -29,10 +29,10 @@ from volatility.framework.layers import intel, lime, physical, segmented, vmware vollog = logging.getLogger(__name__) - # TODO: Type-annotating the ResourceAccessor.open method is difficult because HTTPResponse is not actually an IO[Any] type # fix this + class ResourceAccessor(object): """Object for openning URLs as files (downloading locally first if necessary)""" diff --git a/volatility/framework/layers/crash.py b/volatility/framework/layers/crash.py index bf06c520b..5addde2ba 100644 --- a/volatility/framework/layers/crash.py +++ b/volatility/framework/layers/crash.py @@ -31,10 +31,7 @@ class WindowsCrashDump32Layer(segmented.SegmentedLayer): _magic_struct = struct.Struct(' None: + def __init__(self, context: interfaces.context.ContextInterface, config_path: str, name: str) -> None: # Construct these so we can use self.config self._context = context @@ -43,9 +40,7 @@ class WindowsCrashDump32Layer(segmented.SegmentedLayer): self._base_layer = self.config["base_layer"] # Create a custom SymbolSpace - self._crash_table_name = intermed.IntermediateSymbolTable.create(context, - self._config_path, - 'windows', + self._crash_table_name = intermed.IntermediateSymbolTable.create(context, self._config_path, 'windows', 'crash') # Check Header hdr_layer = self._context.memory[self._base_layer] @@ -53,9 +48,10 @@ class WindowsCrashDump32Layer(segmented.SegmentedLayer): self._check_header(hdr_layer, hdr_offset) # Need to create a header object - self.header = self.context.object(self._crash_table_name + constants.BANG + - "_DMP_HEADER", offset = hdr_offset, - layer_name = self._base_layer) + self.header = self.context.object( + self._crash_table_name + constants.BANG + "_DMP_HEADER", + offset = hdr_offset, + layer_name = self._base_layer) # Extract the DTB self.dtb = self.header.DirectoryTableBase @@ -73,9 +69,7 @@ class WindowsCrashDump32Layer(segmented.SegmentedLayer): offset = self.headerpages for x in self.header.PhysicalMemoryBlockBuffer.Run: - segments.append((x.BasePage * 0x1000, - offset * 0x1000, - x.PageCount * 0x1000)) + segments.append((x.BasePage * 0x1000, offset * 0x1000, x.PageCount * 0x1000)) # print("Segments {:x} {:x} {:x}".format(x.BasePage * 0x1000, # offset * 0x1000, # x.PageCount * 0x1000)) @@ -87,9 +81,7 @@ class WindowsCrashDump32Layer(segmented.SegmentedLayer): self._segments = segments @classmethod - def _check_header(cls, - base_layer: interfaces.layers.DataLayerInterface, - offset: int = 0) -> Tuple[int, int]: + def _check_header(cls, base_layer: interfaces.layers.DataLayerInterface, offset: int = 0) -> Tuple[int, int]: # Verify the Window's crash dump file magic try: @@ -99,11 +91,11 @@ class WindowsCrashDump32Layer(segmented.SegmentedLayer): (signature, validdump) = cls._magic_struct.unpack(header_data) if signature != cls.SIGNATURE: - raise WindowsCrashDump32FormatException( - "bad signature 0x{:x} at file offset 0x{:x}".format(signature, offset)) + raise WindowsCrashDump32FormatException("bad signature 0x{:x} at file offset 0x{:x}".format( + signature, offset)) if validdump != cls.VALIDDUMP: - raise WindowsCrashDump32FormatException( - "invalid dump 0x{:x} at file offset 0x{:x}".format(validdump, offset)) + raise WindowsCrashDump32FormatException("invalid dump 0x{:x} at file offset 0x{:x}".format( + validdump, offset)) return (signature, validdump) diff --git a/volatility/framework/layers/intel.py b/volatility/framework/layers/intel.py index da4651e16..ec3efcf37 100644 --- a/volatility/framework/layers/intel.py +++ b/volatility/framework/layers/intel.py @@ -35,10 +35,10 @@ class Intel(interfaces.layers.TranslationLayerInterface): # NOTE: _maxphyaddr is MAXPHYADDR as defined in the Intel specs *NOT* the maximum physical address _maxphyaddr = 32 _maxvirtaddr = _maxphyaddr - _structure = [('page directory', 10, False), - ('page table', 10, True)] - _direct_metadata = collections.ChainMap({'architecture': 'Intel32'}, - interfaces.layers.TranslationLayerInterface._direct_metadata) + _structure = [('page directory', 10, False), ('page table', 10, True)] + _direct_metadata = collections.ChainMap({ + 'architecture': 'Intel32' + }, interfaces.layers.TranslationLayerInterface._direct_metadata) def __init__(self, context: interfaces.context.ContextInterface, @@ -81,8 +81,8 @@ class Intel(interfaces.layers.TranslationLayerInterface): @staticmethod def _mask(value: int, high_bit: int, low_bit: int) -> int: """Returns the bits of a value between highbit and lowbit inclusive""" - high_mask = (2 ** (high_bit + 1)) - 1 - low_mask = (2 ** low_bit) - 1 + high_mask = (2**(high_bit + 1)) - 1 + low_mask = (2**low_bit) - 1 mask = (high_mask ^ low_mask) # print(high_bit, low_bit, bin(mask), bin(value)) return value & mask @@ -122,8 +122,8 @@ class Intel(interfaces.layers.TranslationLayerInterface): for (name, size, large_page) in self._structure: # Check we're valid if not self._page_is_valid(entry): - raise exceptions.PagedInvalidAddressException(self.name, offset, position + 1, entry, - "Page Fault at entry " + hex(entry) + " in table " + name) + raise exceptions.PagedInvalidAddressException( + self.name, offset, position + 1, entry, "Page Fault at entry " + hex(entry) + " in table " + name) # Check if we're a large page if large_page and (entry & (1 << 7)): # We're a large page, the rest is finished below @@ -141,12 +141,12 @@ class Intel(interfaces.layers.TranslationLayerInterface): # If the table is entirely duplicates, then mark the whole table as bad if (table == table[:struct.calcsize(self._entry_format)] * - (self.page_size // struct.calcsize(self._entry_format))): - raise exceptions.PagedInvalidAddressException(self.name, offset, position + 1, entry, - "Page Fault at entry " + hex(entry) + " in table " + name) + (self.page_size // struct.calcsize(self._entry_format))): + raise exceptions.PagedInvalidAddressException( + self.name, offset, position + 1, entry, "Page Fault at entry " + hex(entry) + " in table " + name) # Read the data for the next entry - entry_data = table[(index << self._index_shift): - (index << self._index_shift) + struct.calcsize(self._entry_format)] + entry_data = table[( + index << self._index_shift):(index << self._index_shift) + struct.calcsize(self._entry_format)] # Read out the new entry from memory entry, = struct.unpack(self._entry_format, entry_data) @@ -157,15 +157,14 @@ class Intel(interfaces.layers.TranslationLayerInterface): """Returns whether the address offset can be translated to a valid address""" try: # TODO: Consider reimplementing this, since calls to mapping can call is_valid - return all([self._context.memory[layer].is_valid(mapped_offset) for _, mapped_offset, _, layer in - self.mapping(offset, length)]) + return all([ + self._context.memory[layer].is_valid(mapped_offset) + for _, mapped_offset, _, layer in self.mapping(offset, length) + ]) except exceptions.InvalidAddressException: return False - def mapping(self, - offset: int, - length: int, - ignore_errors: bool = False) -> Iterable[Tuple[int, int, int, str]]: + def mapping(self, offset: int, length: int, ignore_errors: bool = False) -> Iterable[Tuple[int, int, int, str]]: """Returns a sorted iterable of (offset, mapped_offset, length, layer) mappings This allows translation layers to provide maps of contiguous regions in one layer @@ -174,8 +173,7 @@ class Intel(interfaces.layers.TranslationLayerInterface): try: mapped_offset, _, layer_name = self._translate(offset) if not self._context.memory[layer_name].is_valid(mapped_offset): - raise exceptions.InvalidAddressException(layer_name = layer_name, - invalid_address = mapped_offset) + raise exceptions.InvalidAddressException(layer_name = layer_name, invalid_address = mapped_offset) except exceptions.InvalidAddressException: if not ignore_errors: raise @@ -211,16 +209,13 @@ class Intel(interfaces.layers.TranslationLayerInterface): @classmethod def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: - return [requirements.TranslationLayerRequirement(name = 'memory_layer', - optional = False), - requirements.LayerListRequirement(name = 'swap_layers', - optional = True), - requirements.IntRequirement(name = 'page_map_offset', - optional = False), - requirements.IntRequirement(name = 'kernel_virtual_offset', - optional = True), - requirements.StringRequirement(name = 'kernel_banner', - optional = True)] + return [ + requirements.TranslationLayerRequirement(name = 'memory_layer', optional = False), + requirements.LayerListRequirement(name = 'swap_layers', optional = True), + requirements.IntRequirement(name = 'page_map_offset', optional = False), + requirements.IntRequirement(name = 'kernel_virtual_offset', optional = True), + requirements.StringRequirement(name = 'kernel_banner', optional = True) + ] class IntelPAE(Intel): @@ -231,9 +226,7 @@ class IntelPAE(Intel): _bits_per_register = 32 _maxphyaddr = 40 _maxvirtaddr = 32 - _structure = [('page directory pointer', 2, False), - ('page directory', 9, True), - ('page table', 9, True)] + _structure = [('page directory pointer', 2, False), ('page directory', 9, True), ('page table', 9, True)] class Intel32e(Intel): @@ -245,9 +238,7 @@ class Intel32e(Intel): _bits_per_register = 64 _maxphyaddr = 52 _maxvirtaddr = 48 - _structure = [('page map layer 4', 9, False), - ('page directory pointer', 9, True), - ('page directory', 9, True), + _structure = [('page map layer 4', 9, False), ('page directory pointer', 9, True), ('page directory', 9, True), ('page table', 9, True)] @@ -276,26 +267,26 @@ class WindowsMixin(Intel): unknown_bit = bool(entry & (1 << 7)) n = (entry >> 1) & 0xF vbit = bool(entry & 1) - if (not tbit and not pbit and not vbit and unknown_bit) and ( - (entry >> bit_offset) != 0): + if (not tbit and not pbit and not vbit and unknown_bit) and ((entry >> bit_offset) != 0): swap_offset = entry >> bit_offset << excp.invalid_bits if layer.config.get('swap_layers', False): - swap_layer_name = layer.config.get(interfaces.configuration.path_join('swap_layers', - 'swap_layers' + str(n)), - None) + swap_layer_name = layer.config.get( + interfaces.configuration.path_join('swap_layers', 'swap_layers' + str(n)), None) if swap_layer_name: return swap_offset, 1 << excp.invalid_bits, swap_layer_name - raise exceptions.SwappedInvalidAddressException(layer_name = excp.layer_name, - invalid_address = excp.invalid_address, - invalid_bits = excp.invalid_bits, - entry = excp.entry, - swap_offset = swap_offset) + raise exceptions.SwappedInvalidAddressException( + layer_name = excp.layer_name, + invalid_address = excp.invalid_address, + invalid_bits = excp.invalid_bits, + entry = excp.entry, + swap_offset = swap_offset) raise ### These must be full separate classes so that JSON configs re-create them properly + class WindowsIntel(WindowsMixin, Intel): def _translate(self, offset): diff --git a/volatility/framework/layers/lime.py b/volatility/framework/layers/lime.py index 9be7ade0b..0884fea2d 100644 --- a/volatility/framework/layers/lime.py +++ b/volatility/framework/layers/lime.py @@ -29,10 +29,7 @@ class LimeLayer(segmented.SegmentedLayer): # XXX move this to a custom SymbolSpace? _header_struct = struct.Struct(' None: + def __init__(self, context: interfaces.context.ContextInterface, config_path: str, name: str) -> None: super().__init__(context, config_path, name) # We must run this on creation in order to get the right min/maxaddr in case scanning is our first action @@ -50,8 +47,8 @@ class LimeLayer(segmented.SegmentedLayer): start, end = self._check_header(base_layer, offset) if start < maxaddr or end < start: - raise LimeFormatException( - "bad start/end 0x{:x}/0x{:x} at file offset 0x{:x}".format(start, end, offset)) + raise LimeFormatException("bad start/end 0x{:x}/0x{:x} at file offset 0x{:x}".format( + start, end, offset)) segment_length = end - start + 1 segments.append((start, offset + header_size, segment_length)) @@ -64,9 +61,7 @@ class LimeLayer(segmented.SegmentedLayer): self._segments = segments @classmethod - def _check_header(cls, - base_layer: interfaces.layers.DataLayerInterface, - offset: int = 0) -> Tuple[int, int]: + def _check_header(cls, base_layer: interfaces.layers.DataLayerInterface, offset: int = 0) -> Tuple[int, int]: try: header_data = base_layer.read(offset, cls._header_struct.size) except exceptions.InvalidAddressException: diff --git a/volatility/framework/layers/physical.py b/volatility/framework/layers/physical.py index 6b2fc9a03..75a569f60 100644 --- a/volatility/framework/layers/physical.py +++ b/volatility/framework/layers/physical.py @@ -30,8 +30,8 @@ class BufferDataLayer(interfaces.layers.DataLayerInterface): def is_valid(self, offset: int, length: int = 1) -> bool: """Returns whether the offset is valid or not""" - return bool(self.minimum_address <= offset <= self.maximum_address and - self.minimum_address <= offset + length - 1 <= self.maximum_address) + return bool(self.minimum_address <= offset <= self.maximum_address + and self.minimum_address <= offset + length - 1 <= self.maximum_address) def read(self, address: int, length: int, pad: bool = False) -> bytes: """Reads the data from the buffer""" @@ -51,8 +51,10 @@ class BufferDataLayer(interfaces.layers.DataLayerInterface): @classmethod def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: # No real requirements (only the buffer). Need to figure out if there's a better way of representing this - return [requirements.BytesRequirement(name = 'buffer', description = "The direct bytes to interact with", - optional = False)] + return [ + requirements.BytesRequirement( + name = 'buffer', description = "The direct bytes to interact with", optional = False) + ] class FileLayer(interfaces.layers.DataLayerInterface): @@ -108,8 +110,8 @@ class FileLayer(interfaces.layers.DataLayerInterface): """Returns whether the offset is valid or not""" if length <= 0: raise TypeError("Length must be positive") - return bool(self.minimum_address <= offset <= self.maximum_address and - self.minimum_address <= offset + length - 1 <= self.maximum_address) + return bool(self.minimum_address <= offset <= self.maximum_address + and self.minimum_address <= offset + length - 1 <= self.maximum_address) def read(self, offset: int, length: int, pad: bool = False) -> bytes: """Reads from the file at offset for length""" @@ -125,9 +127,8 @@ class FileLayer(interfaces.layers.DataLayerInterface): if pad: data += (b"\x00" * (length - len(data))) else: - raise exceptions.InvalidAddressException(self.name, offset + len(data), - "Could not read sufficient bytes from the " + - self.name + " file") + raise exceptions.InvalidAddressException( + self.name, offset + len(data), "Could not read sufficient bytes from the " + self.name + " file") return data def write(self, offset: int, data: bytes) -> None: diff --git a/volatility/framework/layers/registry.py b/volatility/framework/layers/registry.py index bb85ebbbd..d064ec82c 100644 --- a/volatility/framework/layers/registry.py +++ b/volatility/framework/layers/registry.py @@ -20,6 +20,7 @@ class RegistryInvalidIndex(exceptions.LayerException): class RegistryHive(interfaces.layers.TranslationLayerInterface): + def __init__(self, context: interfaces.context.ContextInterface, config_path: str, @@ -31,9 +32,7 @@ class RegistryHive(interfaces.layers.TranslationLayerInterface): self._hive_offset = self.config["hive_offset"] self._table_name = self.config["nt_symbols"] - self._reg_table_name = intermed.IntermediateSymbolTable.create(context, - self._config_path, - 'windows', + self._reg_table_name = intermed.IntermediateSymbolTable.create(context, self._config_path, 'windows', 'registry') self.hive = self.context.object(self._table_name + constants.BANG + "_CMHIVE", self._base_layer, @@ -41,16 +40,14 @@ class RegistryHive(interfaces.layers.TranslationLayerInterface): # TODO: Check the checksum if self.hive.Signature != 0xbee0bee0: - raise RegistryFormatException( - "Registry hive at {} does not have a valid signature".format(self._hive_offset)) + raise RegistryFormatException("Registry hive at {} does not have a valid signature".format( + self._hive_offset)) # Win10 17063 introduced the Registry process to map most hives. Check # if it exists and update RegistryHive._base_layer - for proc in pslist.PsList.list_processes(self.context, - self.config['base_layer'], - self.config['nt_symbols']): - proc_name = proc.ImageFileName.cast("string", max_length = proc.ImageFileName.vol.count, - errors = 'replace') + for proc in pslist.PsList.list_processes(self.context, self.config['base_layer'], self.config['nt_symbols']): + proc_name = proc.ImageFileName.cast( + "string", max_length = proc.ImageFileName.vol.count, errors = 'replace') if proc_name == "Registry" and proc.InheritedFromUniqueProcessId == 4: proc_layer_name = proc.add_process_layer() self._base_layer = proc_layer_name @@ -85,8 +82,10 @@ class RegistryHive(interfaces.layers.TranslationLayerInterface): def get_cell(self, cell_offset: int) -> 'objects.Struct': """Returns the appropriate Cell value for a cell offset""" # This would be an _HCELL containing CELL_DATA, but to save time we skip the size of the HCELL - cell = self._context.object(symbol = self._table_name + constants.BANG + "_CELL_DATA", offset = cell_offset + 4, - layer_name = self.name) + cell = self._context.object( + symbol = self._table_name + constants.BANG + "_CELL_DATA", + offset = cell_offset + 4, + layer_name = self.name) return cell def get_node(self, cell_offset: int) -> 'objects.Struct': @@ -107,8 +106,8 @@ class RegistryHive(interfaces.layers.TranslationLayerInterface): return cell.u.KeyIndex else: # It doesn't matter that we use KeyNode, we're just after the first two bytes - vollog.debug( - "Unknown Signature {} (0x{:x}) at offset {}".format(signature, cell.u.KeyNode.Signature, cell_offset)) + vollog.debug("Unknown Signature {} (0x{:x}) at offset {}".format(signature, cell.u.KeyNode.Signature, + cell_offset)) return cell def get_key(self, key: str, return_list: bool = False) -> Union[List[objects.Struct], objects.Struct]: @@ -139,9 +138,7 @@ class RegistryHive(interfaces.layers.TranslationLayerInterface): return node_key return node_key[-1] - def visit_nodes(self, - visitor: Callable[[objects.Struct], None], - node: Optional[objects.Struct] = None) -> None: + def visit_nodes(self, visitor: Callable[[objects.Struct], None], node: Optional[objects.Struct] = None) -> None: """Applies a callable (visitor) to all nodes within the registry tree from a given node""" if not node: node = self.get_node(self.root_cell_offset) @@ -152,17 +149,19 @@ class RegistryHive(interfaces.layers.TranslationLayerInterface): @staticmethod def _mask(value: int, high_bit: int, low_bit: int) -> int: """Returns the bits of a value between highbit and lowbit inclusive""" - high_mask = (2 ** (high_bit + 1)) - 1 - low_mask = (2 ** low_bit) - 1 + high_mask = (2**(high_bit + 1)) - 1 + low_mask = (2**low_bit) - 1 mask = (high_mask ^ low_mask) # print(high_bit, low_bit, bin(mask), bin(value)) return value & mask @classmethod def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: - return [IntRequirement(name = 'hive_offset', description = '', default = 0, optional = False), - requirements.SymbolRequirement(name = "nt_symbols", description = "Windows OS"), - TranslationLayerRequirement(name = 'base_layer', optional = False)] + return [ + IntRequirement(name = 'hive_offset', description = '', default = 0, optional = False), + requirements.SymbolRequirement(name = "nt_symbols", description = "Windows OS"), + TranslationLayerRequirement(name = 'base_layer', optional = False) + ] def _translate(self, offset: int) -> int: """Translates a single cell index to a cell memory offset and the suboffset within it""" @@ -181,10 +180,7 @@ class RegistryHive(interfaces.layers.TranslationLayerInterface): entry = table.Table[table_index] return entry.get_block_offset() + suboffset - def mapping(self, - offset: int, - length: int, - ignore_errors: bool = False) -> Iterable[Tuple[int, int, int, str]]: + def mapping(self, offset: int, length: int, ignore_errors: bool = False) -> Iterable[Tuple[int, int, int, str]]: # TODO: Check the offset and offset + length are not outside the norms if length < 0: @@ -194,8 +190,8 @@ class RegistryHive(interfaces.layers.TranslationLayerInterface): while length > 0: # Try using the symbol first hbin_offset = self._translate(self._mask(offset, 31, 12)) - hbin = self.context.object(self._reg_table_name + constants.BANG + "_HBIN", - offset = hbin_offset, layer_name = self._base_layer) + hbin = self.context.object( + self._reg_table_name + constants.BANG + "_HBIN", offset = hbin_offset, layer_name = self._base_layer) # Now get the cell's offset and figure out if it goes outside the bin # We could use some invariants such as whether cells always fit within a bin? @@ -205,8 +201,10 @@ class RegistryHive(interfaces.layers.TranslationLayerInterface): # In which case, hunt backwards for the right hbin header and check the size again while hbin.Signature.cast("string", max_length = 4, encoding = "latin-1") != 'hbin': hbin_offset = hbin_offset - 0x1000 - hbin = self.context.object(self._reg_table_name + constants.BANG + "_HBIN", - offset = hbin_offset, layer_name = self._base_layer) + hbin = self.context.object( + self._reg_table_name + constants.BANG + "_HBIN", + offset = hbin_offset, + layer_name = self._base_layer) if translated_offset + length > hbin_offset + hbin.Size and hbin.Size > 0: raise RegistryFormatException("Cell address {} outside expected HBIN limit: {}".format( hex(translated_offset + length), hex(hbin_offset + hbin.Size))) diff --git a/volatility/framework/layers/scanners/multistring_testrig.py b/volatility/framework/layers/scanners/multistring_testrig.py index 600ccfae6..3bf3df9ec 100644 --- a/volatility/framework/layers/scanners/multistring_testrig.py +++ b/volatility/framework/layers/scanners/multistring_testrig.py @@ -2,8 +2,8 @@ def tester(searcher): import argparse parser = argparse.ArgumentParser(usage = "Searches through a haystack for a set of needles") - parser.add_argument("-n", "--needles", help = "The filename of the file containing newline separated needles", - required = True) + parser.add_argument( + "-n", "--needles", help = "The filename of the file containing newline separated needles", required = True) parser.add_argument("haystack", help = "The filename of the binary haystack file to search") args = parser.parse_args() diff --git a/volatility/framework/layers/segmented.py b/volatility/framework/layers/segmented.py index eb5202a63..e237ccbd1 100644 --- a/volatility/framework/layers/segmented.py +++ b/volatility/framework/layers/segmented.py @@ -36,8 +36,10 @@ class SegmentedLayer(interfaces.layers.TranslationLayerInterface, metaclass = AB def is_valid(self, offset: int, length: int = 1) -> bool: """Returns whether the address offset can be translated to a valid address""" try: - return all([self._context.memory[self._base_layer].is_valid(mapped_offset) for _i, mapped_offset, _i, _s in - self.mapping(offset, length)]) + return all([ + self._context.memory[self._base_layer].is_valid(mapped_offset) + for _i, mapped_offset, _i, _s in self.mapping(offset, length) + ]) except exceptions.InvalidAddressException: return False @@ -123,5 +125,4 @@ class SegmentedLayer(interfaces.layers.TranslationLayerInterface, metaclass = AB @classmethod def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: - return [requirements.TranslationLayerRequirement(name = 'base_layer', - optional = False)] + return [requirements.TranslationLayerRequirement(name = 'base_layer', optional = False)] diff --git a/volatility/framework/layers/vmware.py b/volatility/framework/layers/vmware.py index 74c5eb03d..be36c7264 100644 --- a/volatility/framework/layers/vmware.py +++ b/volatility/framework/layers/vmware.py @@ -50,9 +50,8 @@ class VmwareLayer(segmented.SegmentedLayer): groups = {} for group in range(groupCount): - name, tag_location, _unknown = struct.unpack(self.group_structure, - meta_layer.read(header_size + (group * group_size), - group_size)) + name, tag_location, _unknown = struct.unpack( + self.group_structure, meta_layer.read(header_size + (group * group_size), group_size)) name = name.rstrip(b"\x00") groups[name] = tag_location memory = groups[b"memory"] @@ -66,27 +65,30 @@ class VmwareLayer(segmented.SegmentedLayer): name_len = ord(meta_layer.read(offset + 1, 1)) tags_read = (flags == 0) and (name_len == 0) if not tags_read: - name = self._context.object("vmware!string", layer_name = self._meta_layer, offset = offset + 2, - max_length = name_len) + name = self._context.object( + "vmware!string", layer_name = self._meta_layer, offset = offset + 2, max_length = name_len) indicies_len = (flags >> 6) & 3 indicies = [] for index in range(indicies_len): indicies.append( - self._context.object("vmware!unsigned int", - offset = offset + name_len + 2 + (index * index_len), - layer_name = self._meta_layer)) - data = self._context.object("vmware!unsigned int", layer_name = self._meta_layer, - offset = offset + 2 + name_len + (indicies_len * index_len)) + self._context.object( + "vmware!unsigned int", + offset = offset + name_len + 2 + (index * index_len), + layer_name = self._meta_layer)) + data = self._context.object( + "vmware!unsigned int", + layer_name = self._meta_layer, + offset = offset + 2 + name_len + (indicies_len * index_len)) tags[(name, tuple(indicies))] = (flags, data) - offset += 2 + name_len + (indicies_len * index_len) + self._context.symbol_space.get_type( - "vmware!unsigned int").size + offset += 2 + name_len + ( + indicies_len * index_len) + self._context.symbol_space.get_type("vmware!unsigned int").size if tags[("regionsCount", ())][1] == 0: raise ValueError("VMware VMEM is not split into regions") for region in range(tags[("regionsCount", ())][1]): - offset = tags[("regionPPN", (region,))][1] * self._page_size - mapped_offset = tags[("regionPageNum", (region,))][1] * self._page_size - length = tags[("regionSize", (region,))][1] * self._page_size + offset = tags[("regionPPN", (region, ))][1] * self._page_size + mapped_offset = tags[("regionPageNum", (region, ))][1] * self._page_size + length = tags[("regionSize", (region, ))][1] * self._page_size self._segments.append((offset, mapped_offset, length)) @property @@ -96,14 +98,14 @@ class VmwareLayer(segmented.SegmentedLayer): @classmethod def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: """This vmware translation layer always requires a separate metadata layer""" - return [requirements.TranslationLayerRequirement(name = 'base_layer', - optional = False), - requirements.TranslationLayerRequirement(name = 'meta_layer', - optional = False) - ] + return [ + requirements.TranslationLayerRequirement(name = 'base_layer', optional = False), + requirements.TranslationLayerRequirement(name = 'meta_layer', optional = False) + ] class VmwareStacker(interfaces.automagic.StackerLayerInterface): + @classmethod def stack(cls, context: interfaces.context.ContextInterface, @@ -131,8 +133,7 @@ class VmwareStacker(interfaces.automagic.StackerLayerInterface): return None new_layer_name = context.memory.free_layer_name("VmwareLayer") context.config[interfaces.configuration.path_join(current_config_path, "base_layer")] = layer_name - context.config[ - interfaces.configuration.path_join(current_config_path, "meta_layer")] = current_layer_name + context.config[interfaces.configuration.path_join(current_config_path, "meta_layer")] = current_layer_name new_layer = VmwareLayer(context, current_config_path, new_layer_name) return new_layer return None diff --git a/volatility/framework/objects/__init__.py b/volatility/framework/objects/__init__.py index 32fad3b6f..9237dc61f 100644 --- a/volatility/framework/objects/__init__.py +++ b/volatility/framework/objects/__init__.py @@ -13,14 +13,11 @@ vollog = logging.getLogger(__name__) DataFormatInfo = collections.namedtuple('DataFormatInfo', ['length', 'byteorder', 'signed']) -def convert_data_to_value(data: bytes, - struct_type: Type[Union[int, float, bytes, str, bool]], +def convert_data_to_value(data: bytes, struct_type: Type[Union[int, float, bytes, str, bool]], data_format: DataFormatInfo) -> Union[int, float, bytes, str, bool]: """Converts a series of bytes to a particular type of value""" if struct_type == int: - return int.from_bytes(data, - byteorder = data_format.byteorder, - signed = data_format.signed) + return int.from_bytes(data, byteorder = data_format.byteorder, signed = data_format.signed) if struct_type == bool: struct_format = "?" elif struct_type == float: @@ -44,10 +41,8 @@ def convert_value_to_data(value: Union[int, float, bytes, str, bool], raise TypeError("Written value is not of the correct type for {}".format(struct_type.__class__.__name__)) if struct_type == int: - return int.to_bytes(value, - length = data_format.length, - byteorder = data_format.byteorder, - signed = data_format.signed) + return int.to_bytes( + value, length = data_format.length, byteorder = data_format.byteorder, signed = data_format.signed) if struct_type == bool: struct_format = "?" elif struct_type == float: @@ -67,6 +62,7 @@ class Void(interfaces.objects.ObjectInterface): """Returns an object to represent void/unknown types""" class VolTemplateProxy(interfaces.objects.ObjectInterface.VolTemplateProxy): + @classmethod def size(cls, template: interfaces.objects.Template) -> int: """Dummy size for Void objects""" @@ -85,15 +81,10 @@ class PrimitiveObject(interfaces.objects.ObjectInterface): """PrimitiveObject is an interface for any objects that should simulate a Python primitive""" _struct_type = int # type: ClassVar[Type] - def __init__(self, - context: interfaces.context.ContextInterface, - type_name: str, - object_info: interfaces.objects.ObjectInformation, - data_format: DataFormatInfo) -> None: - super().__init__(context = context, - type_name = type_name, - object_info = object_info, - data_format = data_format) + def __init__(self, context: interfaces.context.ContextInterface, type_name: str, + object_info: interfaces.objects.ObjectInformation, data_format: DataFormatInfo) -> None: + super().__init__( + context = context, type_name = type_name, object_info = object_info, data_format = data_format) self._data_format = data_format def __new__(cls: 'PrimitiveObject', @@ -111,9 +102,7 @@ class PrimitiveObject(interfaces.objects.ObjectInterface): We also sneak in new_value, so that we don't have to do expensive (read: impossible) context reads when unpickling.""" if new_value is None: - value = cls._unmarshall(context, - data_format, - object_info) + value = cls._unmarshall(context, data_format, object_info) else: value = new_value result = cls._struct_type.__new__(cls, value) @@ -129,20 +118,16 @@ class PrimitiveObject(interfaces.objects.ObjectInterface): if k not in ["context", "data_format", "object_info", "type_name"]: kwargs[k] = v kwargs['new_value'] = self.__new_value - return (self._context, - self._vol.maps[-2]['type_name'], - self._vol.maps[-3], - self._data_format), kwargs + return (self._context, self._vol.maps[-2]['type_name'], self._vol.maps[-3], self._data_format), kwargs @classmethod - def _unmarshall(cls, - context: interfaces.context.ContextInterface, - data_format: DataFormatInfo, + def _unmarshall(cls, context: interfaces.context.ContextInterface, data_format: DataFormatInfo, object_info: ObjectInformation) -> Union[int, float, bool, bytes, str]: data = context.memory.read(object_info.layer_name, object_info.offset, data_format.length) return convert_data_to_value(data, cls._struct_type, data_format) class VolTemplateProxy(interfaces.objects.ObjectInterface.VolTemplateProxy): + @classmethod def size(cls, template: interfaces.objects.Template) -> int: """Returns the size of the templated object""" @@ -182,10 +167,11 @@ class Bytes(PrimitiveObject, bytes): type_name: str, object_info: interfaces.objects.ObjectInformation, length: int = 1) -> None: - super().__init__(context = context, - type_name = type_name, - object_info = object_info, - data_format = DataFormatInfo(length, "big", False)) + super().__init__( + context = context, + type_name = type_name, + object_info = object_info, + data_format = DataFormatInfo(length, "big", False)) self._vol['length'] = length def __new__(cls: 'Bytes', @@ -198,10 +184,9 @@ class Bytes(PrimitiveObject, bytes): The only reason the **kwargs is added, is so that the inherriting types can override __init__ without needing to override __new__""" - return cls._struct_type.__new__(cls, - cls._unmarshall(context, - data_format = DataFormatInfo(length, "big", False), - object_info = object_info)) + return cls._struct_type.__new__( + cls, + cls._unmarshall(context, data_format = DataFormatInfo(length, "big", False), object_info = object_info)) class String(PrimitiveObject, str): @@ -221,10 +206,11 @@ class String(PrimitiveObject, str): max_length: int = 1, encoding: str = "utf-8", errors: str = "strict") -> None: - super().__init__(context = context, - type_name = type_name, - object_info = object_info, - data_format = DataFormatInfo(max_length, "big", False)) + super().__init__( + context = context, + type_name = type_name, + object_info = object_info, + data_format = DataFormatInfo(max_length, "big", False)) self._vol["max_length"] = max_length self._vol['encoding'] = encoding self._vol['errors'] = errors @@ -247,13 +233,11 @@ class String(PrimitiveObject, str): if errors: params['errors'] = errors # Pass the encoding and error parameters to the string constructor to appropriately encode the string - value = cls._struct_type.__new__(cls, # type: ignore - cls._unmarshall(context, - data_format = DataFormatInfo(max_length, - "big", - False), - object_info = object_info), - **params) + value = cls._struct_type.__new__( + cls, # type: ignore + cls._unmarshall( + context, data_format = DataFormatInfo(max_length, "big", False), object_info = object_info), + **params) if value.find('\x00') >= 0: value = value[:value.find('\x00')] return value @@ -269,16 +253,12 @@ class Pointer(Integer): data_format: DataFormatInfo, subtype: Optional[templates.ObjectTemplate] = None) -> None: self._check_type(subtype, templates.ObjectTemplate) - super().__init__(context = context, - object_info = object_info, - type_name = type_name, - data_format = data_format) + super().__init__( + context = context, object_info = object_info, type_name = type_name, data_format = data_format) self._vol['subtype'] = subtype @classmethod - def _unmarshall(cls, - context: interfaces.context.ContextInterface, - data_format: DataFormatInfo, + def _unmarshall(cls, context: interfaces.context.ContextInterface, data_format: DataFormatInfo, object_info: ObjectInformation) -> Any: """Ensure that pointer values always fall within the address space of the layer they're constructed on @@ -302,11 +282,10 @@ class Pointer(Integer): layer_name = layer_name or self.vol.native_layer_name mask = self._context.memory[layer_name].address_mask offset = self & mask - return self.vol.subtype(context = self._context, - object_info = interfaces.objects.ObjectInformation( - layer_name = layer_name, - offset = offset, - parent = self)) + return self.vol.subtype( + context = self._context, + object_info = interfaces.objects.ObjectInformation( + layer_name = layer_name, offset = offset, parent = self)) def is_readable(self, layer_name: Optional[str] = None) -> bool: """Determines whether the address of this pointer can be read from memory""" @@ -322,6 +301,7 @@ class Pointer(Integer): return self._vol['subtype'].has_member(member_name) class VolTemplateProxy(interfaces.objects.ObjectInterface.VolTemplateProxy): + @classmethod def size(cls, template: interfaces.objects.Template) -> int: return Integer.VolTemplateProxy.size(template) @@ -334,9 +314,7 @@ class Pointer(Integer): return [] @classmethod - def replace_child(cls, - template: interfaces.objects.Template, - old_child: interfaces.objects.Template, + def replace_child(cls, template: interfaces.objects.Template, old_child: interfaces.objects.Template, new_child: interfaces.objects.Template) -> None: """Substitutes the old_child for the new_child""" if 'subtype' in template.vol: @@ -344,9 +322,7 @@ class Pointer(Integer): template.update_vol(subtype = new_child) @classmethod - def has_member(cls, - template: interfaces.objects.Template, - member_name: str) -> bool: + def has_member(cls, template: interfaces.objects.Template, member_name: str) -> bool: return template.vol['subtype'].has_member(member_name) @@ -373,14 +349,14 @@ class BitField(interfaces.objects.ObjectInterface, int): start_bit: int = 0, end_bit: int = 0, **kwargs) -> 'BitField': - value = base_type(context = context, - object_info = object_info) + value = base_type(context = context, object_info = object_info) return int.__new__(cls, (value >> start_bit) & ((1 << end_bit) - 1)) # type: ignore def write(self, value): raise NotImplementedError("Writing to BitFields is not yet implemented") class VolTemplateProxy(interfaces.objects.ObjectInterface.VolTemplateProxy): + @classmethod def size(cls, template: interfaces.objects.Template) -> int: return Integer.VolTemplateProxy.size(template) @@ -393,9 +369,7 @@ class BitField(interfaces.objects.ObjectInterface, int): return [] @classmethod - def replace_child(cls, - template: interfaces.objects.Template, - old_child: interfaces.objects.Template, + def replace_child(cls, template: interfaces.objects.Template, old_child: interfaces.objects.Template, new_child: interfaces.objects.Template) -> None: """Substitutes the old_child for the new_child""" if 'base_type' in template.vol: @@ -406,23 +380,15 @@ class BitField(interfaces.objects.ObjectInterface, int): class Enumeration(interfaces.objects.ObjectInterface, int): """Returns an object made up of choices""" - def __new__(cls, - context: interfaces.context.ContextInterface, - type_name: str, - object_info: interfaces.objects.ObjectInformation, - base_type: interfaces.objects.Template, - choices: Dict[str, int], - **kwargs) -> 'Enumeration': + def __new__(cls, context: interfaces.context.ContextInterface, type_name: str, + object_info: interfaces.objects.ObjectInformation, base_type: interfaces.objects.Template, + choices: Dict[str, int], **kwargs) -> 'Enumeration': cls._check_class(base_type.vol.object_class, Integer) - value = base_type(context = context, - object_info = object_info) + value = base_type(context = context, object_info = object_info) return int.__new__(cls, value) # type: ignore - def __init__(self, - context: interfaces.context.ContextInterface, - type_name: str, - object_info: interfaces.objects.ObjectInformation, - base_type: Integer, + def __init__(self, context: interfaces.context.ContextInterface, type_name: str, + object_info: interfaces.objects.ObjectInformation, base_type: Integer, choices: Dict[str, int]) -> None: super().__init__(context, type_name, object_info) @@ -465,6 +431,7 @@ class Enumeration(interfaces.objects.ObjectInterface, int): raise NotImplementedError("Writing to Enumerations is not yet implemented") class VolTemplateProxy(interfaces.objects.ObjectInterface.VolTemplateProxy): + @classmethod def size(cls, template: interfaces.objects.Template) -> int: return template.vol['base_type'].size @@ -477,9 +444,7 @@ class Enumeration(interfaces.objects.ObjectInterface, int): return [] @classmethod - def replace_child(cls, - template: interfaces.objects.Template, - old_child: interfaces.objects.Template, + def replace_child(cls, template: interfaces.objects.Template, old_child: interfaces.objects.Template, new_child: interfaces.objects.Template) -> None: """Substitutes the old_child for the new_child""" if 'base_type' in template.vol: @@ -497,9 +462,7 @@ class Array(interfaces.objects.ObjectInterface, abc.Sequence): count: int = 0, subtype: templates.ObjectTemplate = None) -> None: self._check_type(subtype, templates.ObjectTemplate) - super().__init__(context = context, - type_name = type_name, - object_info = object_info) + super().__init__(context = context, type_name = type_name, object_info = object_info) self._vol['count'] = self._check_type(count, int) self._vol['subtype'] = subtype @@ -516,6 +479,7 @@ class Array(interfaces.objects.ObjectInterface, abc.Sequence): self._vol['count'] = self._check_type(value, int) class VolTemplateProxy(interfaces.objects.ObjectInterface.VolTemplateProxy): + @classmethod def size(cls, template: interfaces.objects.Template) -> int: """Returns the size of the array, based on the count and the subtype""" @@ -531,9 +495,7 @@ class Array(interfaces.objects.ObjectInterface, abc.Sequence): return [] @classmethod - def replace_child(cls, - template: interfaces.objects.Template, - old_child: interfaces.objects.Template, + def replace_child(cls, template: interfaces.objects.Template, old_child: interfaces.objects.Template, new_child: interfaces.objects.Template) -> None: """Substitutes the old_child for the new_child""" if 'subtype' in template.vol: @@ -541,9 +503,7 @@ class Array(interfaces.objects.ObjectInterface, abc.Sequence): template.update_vol(subtype = new_child) @classmethod - def relative_child_offset(cls, - template: interfaces.objects.Template, - child: str) -> int: + def relative_child_offset(cls, template: interfaces.objects.Template, child: str) -> int: """Returns the relative offset from the head of the parent data to the child member""" if 'subtype' in template.vol and child == 'subtype': return 0 @@ -568,10 +528,11 @@ class Array(interfaces.objects.ObjectInterface, abc.Sequence): return_list = False series = [series] for index in series: - object_info = ObjectInformation(layer_name = self.vol.layer_name, - offset = mask & (self.vol.offset + (self.vol.subtype.size * index)), - parent = self, - native_layer_name = self.vol.native_layer_name) + object_info = ObjectInformation( + layer_name = self.vol.layer_name, + offset = mask & (self.vol.offset + (self.vol.subtype.size * index)), + parent = self, + native_layer_name = self.vol.native_layer_name) result += [self.vol.subtype(context = self._context, object_info = object_info)] if not return_list: return result[0] @@ -591,17 +552,11 @@ class Struct(interfaces.objects.ObjectInterface): Keep the number of methods in this class low or very specific, since each one could overload a valid member. """ - def __init__(self, - context: interfaces.context.ContextInterface, - type_name: str, - object_info: interfaces.objects.ObjectInformation, - size: int, + def __init__(self, context: interfaces.context.ContextInterface, type_name: str, + object_info: interfaces.objects.ObjectInformation, size: int, members: Dict[str, Tuple[int, interfaces.objects.Template]]) -> None: - super().__init__(context = context, - type_name = type_name, - object_info = object_info, - size = size, - members = members) + super().__init__( + context = context, type_name = type_name, object_info = object_info, size = size, members = members) self._check_members(members) self._concrete_members = {} # type: Dict[str, Dict] @@ -610,6 +565,7 @@ class Struct(interfaces.objects.ObjectInterface): return member_name in self.vol.members class VolTemplateProxy(interfaces.objects.ObjectInterface.VolTemplateProxy): + @classmethod def size(cls, template: interfaces.objects.Template) -> int: """Method to return the size of this type""" @@ -623,9 +579,7 @@ class Struct(interfaces.objects.ObjectInterface): return [member for _, member in template.vol.members.values()] @classmethod - def replace_child(cls, - template: interfaces.objects.Template, - old_child: interfaces.objects.Template, + def replace_child(cls, template: interfaces.objects.Template, old_child: interfaces.objects.Template, new_child: interfaces.objects.Template) -> None: """Replace a child elements within the arguments handed to the template""" for member in template.vol.members.get('members', {}): @@ -641,9 +595,7 @@ class Struct(interfaces.objects.ObjectInterface): template.update_vol(members = tmp_list) @classmethod - def relative_child_offset(cls, - template: interfaces.objects.Template, - child: str) -> int: + def relative_child_offset(cls, template: interfaces.objects.Template, child: str) -> int: """Returns the relative offset of a child to its parent""" retlist = template.vol.members.get(child, None) if retlist is None: @@ -651,15 +603,12 @@ class Struct(interfaces.objects.ObjectInterface): return retlist[0] @classmethod - def has_member(cls, - template: interfaces.objects.Template, - member_name: str) -> bool: + def has_member(cls, template: interfaces.objects.Template, member_name: str) -> bool: """Returns whether the object would contain a member called member_name""" return member_name in template.vol.members @classmethod - def _check_members(cls, - members: Dict[str, Tuple[int, interfaces.objects.Template]]) -> None: + def _check_members(cls, members: Dict[str, Tuple[int, interfaces.objects.Template]]) -> None: # Members should be an iterable mapping of symbol names to tuples of (relative_offset, ObjectTemplate) # An object template is a callable that when called with a context, offset, layer_name and type_name if not isinstance(members, abc.Mapping): @@ -678,13 +627,14 @@ class Struct(interfaces.objects.ObjectInterface): elif attr in self.vol.members: mask = self._context.memory[self.vol.layer_name].address_mask relative_offset, member = self.vol.members[attr] - member = member(context = self._context, - object_info = interfaces.objects.ObjectInformation(layer_name = self.vol.layer_name, - offset = mask & ( - self.vol.offset + relative_offset), - member_name = attr, - parent = self, - native_layer_name = self.vol.native_layer_name)) + member = member( + context = self._context, + object_info = interfaces.objects.ObjectInformation( + layer_name = self.vol.layer_name, + offset = mask & (self.vol.offset + relative_offset), + member_name = attr, + parent = self, + native_layer_name = self.vol.native_layer_name)) self._concrete_members[attr] = member return member raise AttributeError("Struct has no attribute: {}.{}".format(self.vol.type_name, attr)) @@ -701,6 +651,7 @@ class Struct(interfaces.objects.ObjectInterface): class Union(Struct): pass + # Really nasty way of duplicating the class # WILL cause problems with any mutable class/static variables # Union = type('Union', Struct.__bases__, dict(Struct.__dict__)) diff --git a/volatility/framework/objects/templates.py b/volatility/framework/objects/templates.py index 53510a1c2..d017c1dcf 100644 --- a/volatility/framework/objects/templates.py +++ b/volatility/framework/objects/templates.py @@ -17,10 +17,7 @@ class ObjectTemplate(interfaces.objects.Template, validity.ValidityRoutines): * etc """ - def __init__(self, - object_class: Type[interfaces.objects.ObjectInterface], - type_name: str, - **arguments) -> None: + def __init__(self, object_class: Type[interfaces.objects.ObjectInterface], type_name: str, **arguments) -> None: super().__init__(type_name = type_name, **arguments) self._check_class(object_class, interfaces.objects.ObjectInterface) self._arguments['object_class'] = object_class @@ -41,9 +38,7 @@ class ObjectTemplate(interfaces.objects.Template, validity.ValidityRoutines): """ return self.vol.object_class.VolTemplateProxy.relative_child_offset(self, child) - def replace_child(self, - old_child: interfaces.objects.Template, - new_child: interfaces.objects.Template) -> None: + def replace_child(self, old_child: interfaces.objects.Template, new_child: interfaces.objects.Template) -> None: """Replaces `old_child` for `new_child` in the templated object's child list (see :class:`~volatility.framework.interfaces.objects.ObjectInterface.VolTemplateProxy`) """ return self.vol.object_class.VolTemplateProxy.replace_child(self, old_child, new_child) @@ -53,8 +48,7 @@ class ObjectTemplate(interfaces.objects.Template, validity.ValidityRoutines): """ return self.vol.object_class.VolTemplateProxy.has_member(self, member_name) - def __call__(self, - context: interfaces.context.ContextInterface, + def __call__(self, context: interfaces.context.ContextInterface, object_info: interfaces.objects.ObjectInformation) -> interfaces.objects.ObjectInterface: """Constructs the object @@ -64,9 +58,7 @@ class ObjectTemplate(interfaces.objects.Template, validity.ValidityRoutines): for arg in self.vol: if arg != 'object_class': arguments[arg] = self.vol[arg] - return self.vol.object_class(context = context, - object_info = object_info, - **arguments) + return self.vol.object_class(context = context, object_info = object_info, **arguments) class ReferenceTemplate(interfaces.objects.Template): @@ -84,16 +76,15 @@ class ReferenceTemplate(interfaces.objects.Template): """Referenced symbols must be appropriately resolved before they can provide information such as size This is because the size request has no context within which to determine the actual symbol structure. """ - raise exceptions.SymbolError( - "Template contains no information about its structure: {}".format(self.vol.type_name)) + raise exceptions.SymbolError("Template contains no information about its structure: {}".format( + self.vol.type_name)) size = property(_unresolved) # type: ClassVar[Any] replace_child = _unresolved # type: ClassVar[Any] relative_child_offset = _unresolved # type: ClassVar[Any] has_member = _unresolved # type: ClassVar[Any] - def __call__(self, - context: interfaces.context.ContextInterface, + def __call__(self, context: interfaces.context.ContextInterface, object_info: interfaces.objects.ObjectInformation): template = context.symbol_space.get_type(self.vol.type_name) return template(context = context, object_info = object_info) diff --git a/volatility/framework/objects/utility.py b/volatility/framework/objects/utility.py index d9f4c10a0..99f2fc4d2 100644 --- a/volatility/framework/objects/utility.py +++ b/volatility/framework/objects/utility.py @@ -3,8 +3,7 @@ from typing import Optional, Union from volatility.framework import interfaces, objects, constants -def array_to_string(array: objects.Array, - count: Optional[int] = None, +def array_to_string(array: objects.Array, count: Optional[int] = None, errors: str = 'replace') -> interfaces.objects.ObjectInterface: """Takes a volatility Array of characters and returns a string""" # TODO: Consider checking the Array's target is a native char @@ -16,9 +15,7 @@ def array_to_string(array: objects.Array, return array.cast("string", max_length = count, errors = errors) -def pointer_to_string(pointer: objects.Pointer, - count: int, - errors: str = 'replace'): +def pointer_to_string(pointer: objects.Pointer, count: int, errors: str = 'replace'): """Takes a volatility Pointer to characters and returns a string""" if not isinstance(pointer, objects.Pointer): raise TypeError("pointer_to_string takes a Pointer") @@ -28,8 +25,7 @@ def pointer_to_string(pointer: objects.Pointer, return char.cast("string", max_length = count, errors = errors) -def array_of_pointers(array: interfaces.objects.ObjectInterface, - count: int, +def array_of_pointers(array: interfaces.objects.ObjectInterface, count: int, subtype: Union[str, interfaces.objects.Template], context: interfaces.context.ContextInterface) -> interfaces.objects.ObjectInterface: """Takes an object, and recasts it as an array of pointers to subtype""" @@ -41,5 +37,3 @@ def array_of_pointers(array: interfaces.objects.ObjectInterface, subtype_pointer = context.symbol_space.get_type(symbol_table + constants.BANG + "pointer") subtype_pointer.update_vol(subtype = subtype) return array.cast("array", count = count, subtype = subtype_pointer) - - diff --git a/volatility/framework/plugins/__init__.py b/volatility/framework/plugins/__init__.py index ea89a016e..7ef9d4e61 100644 --- a/volatility/framework/plugins/__init__.py +++ b/volatility/framework/plugins/__init__.py @@ -11,10 +11,8 @@ from volatility.framework import interfaces, automagic, exceptions, constants, v vollog = logging.getLogger(__name__) -def run_plugin(context: interfaces.context.ContextInterface, - automagics: List[interfaces.automagic.AutomagicInterface], - plugin: Type[interfaces.plugins.PluginInterface], - base_config_path: str, +def run_plugin(context: interfaces.context.ContextInterface, automagics: List[interfaces.automagic.AutomagicInterface], + plugin: Type[interfaces.plugins.PluginInterface], base_config_path: str, progress_callback: validity.ProgressCallback, file_consumer: interfaces.plugins.FileConsumerInterface) -> interfaces.plugins.PluginInterface: """Constructs a plugin object based on the parameters diff --git a/volatility/framework/plugins/configwriter.py b/volatility/framework/plugins/configwriter.py index eb5152dce..1dd7caeab 100644 --- a/volatility/framework/plugins/configwriter.py +++ b/volatility/framework/plugins/configwriter.py @@ -14,14 +14,12 @@ class ConfigWriter(plugins.PluginInterface): @classmethod def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: - return [requirements.TranslationLayerRequirement(name = 'primary', - description = 'Kernel Address Space', - architectures = ["Intel32", "Intel64"]), - requirements.BooleanRequirement(name = 'extra', - description = 'Outputs whole configuration tree', - default = False, - optional = True) - ] + return [ + requirements.TranslationLayerRequirement( + name = 'primary', description = 'Kernel Address Space', architectures = ["Intel32", "Intel64"]), + requirements.BooleanRequirement( + name = 'extra', description = 'Outputs whole configuration tree', default = False, optional = True) + ] def _generator(self): filename = "config.json" @@ -41,6 +39,4 @@ class ConfigWriter(plugins.PluginInterface): yield (0, (k, json.dumps(v))) def run(self): - return renderers.TreeGrid([("Key", str), - ("Value", str)], - self._generator()) + return renderers.TreeGrid([("Key", str), ("Value", str)], self._generator()) diff --git a/volatility/framework/plugins/linux/bash.py b/volatility/framework/plugins/linux/bash.py index f02306acc..421d8da5e 100644 --- a/volatility/framework/plugins/linux/bash.py +++ b/volatility/framework/plugins/linux/bash.py @@ -21,11 +21,11 @@ class Bash(plugins.PluginInterface, timeliner.TimeLinerInterface): @classmethod def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: - return [requirements.TranslationLayerRequirement(name = 'primary', - description = 'Kernel Address Space', - architectures = ["Intel32", "Intel64"]), - requirements.SymbolRequirement(name = "vmlinux", - description = "Linux Kernel")] + return [ + requirements.TranslationLayerRequirement( + name = 'primary', description = 'Kernel Address Space', architectures = ["Intel32", "Intel64"]), + requirements.SymbolRequirement(name = "vmlinux", description = "Linux Kernel") + ] def _generator(self, tasks): is_32bit = not symbols.symbol_table_is_64bit(self.context, self.config["vmlinux"]) @@ -36,13 +36,10 @@ class Bash(plugins.PluginInterface, timeliner.TimeLinerInterface): pack_format = "Q" bash_json_file = "bash64" - bash_table_name = BashIntermedSymbols.create(self.context, - self.config_path, - "linux", - bash_json_file) + bash_table_name = BashIntermedSymbols.create(self.context, self.config_path, "linux", bash_json_file) - ts_offset = self.context.symbol_space.get_type( - bash_table_name + constants.BANG + "hist_entry").relative_child_offset("timestamp") + ts_offset = self.context.symbol_space.get_type(bash_table_name + constants.BANG + + "hist_entry").relative_child_offset("timestamp") for task in tasks: task_name = utility.array_to_string(task.comm) @@ -58,19 +55,22 @@ class Bash(plugins.PluginInterface, timeliner.TimeLinerInterface): bang_addrs = [] # find '#' values on the heap - for address in proc_layer.scan(self.context, - scanners.BytesScanner(b"#"), - sections = task.get_process_memory_sections(heap_only = True)): + for address in proc_layer.scan( + self.context, + scanners.BytesScanner(b"#"), + sections = task.get_process_memory_sections(heap_only = True)): bang_addrs.append(struct.pack(pack_format, address)) history_entries = [] - for address, _ in proc_layer.scan(self.context, - scanners.MultiStringScanner(bang_addrs), - sections = task.get_process_memory_sections(heap_only = True)): - hist = self.context.object(bash_table_name + constants.BANG + "hist_entry", - offset = address - ts_offset, - layer_name = proc_layer_name) + for address, _ in proc_layer.scan( + self.context, + scanners.MultiStringScanner(bang_addrs), + sections = task.get_process_memory_sections(heap_only = True)): + hist = self.context.object( + bash_table_name + constants.BANG + "hist_entry", + offset = address - ts_offset, + layer_name = proc_layer_name) if hist.is_valid(): history_entries.append(hist) @@ -84,24 +84,16 @@ class Bash(plugins.PluginInterface, timeliner.TimeLinerInterface): plugin = pslist.PsList.list_tasks return renderers.TreeGrid( - [("PID", int), - ("Process", str), - ("CommandTime", datetime.datetime), - ("Command", str)], - self._generator(plugin(self.context, - self.config['primary'], - self.config['vmlinux'], - filter = filt))) + [("PID", int), ("Process", str), ("CommandTime", datetime.datetime), ("Command", str)], + self._generator(plugin(self.context, self.config['primary'], self.config['vmlinux'], filter = filt))) def generate_timeline(self): filt = pslist.PsList.create_filter([self.config.get('pid', None)]) plugin = pslist.PsList.list_tasks - for row in self._generator(plugin(self.context, - self.config['primary'], - self.config['vmlinux'], - filter = filt)): + for row in self._generator( + plugin(self.context, self.config['primary'], self.config['vmlinux'], filter = filt)): _depth, row_data = row description = "{} ({}): \"{}\"".format(row_data[0], row_data[1], row_data[3]) yield (description, timeliner.TimeLinerType.CREATED, row_data[2]) diff --git a/volatility/framework/plugins/linux/check_afinfo.py b/volatility/framework/plugins/linux/check_afinfo.py index 6cf774f1b..fa81cde98 100644 --- a/volatility/framework/plugins/linux/check_afinfo.py +++ b/volatility/framework/plugins/linux/check_afinfo.py @@ -19,11 +19,11 @@ class Check_afinfo(plugins.PluginInterface): @classmethod def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: - return [requirements.TranslationLayerRequirement(name = 'primary', - description = 'Kernel Address Space', - architectures = ["Intel32", "Intel64"]), - requirements.SymbolRequirement(name = "vmlinux", - description = "Linux Kernel")] + return [ + requirements.TranslationLayerRequirement( + name = 'primary', description = 'Kernel Address Space', architectures = ["Intel32", "Intel64"]), + requirements.SymbolRequirement(name = "vmlinux", description = "Linux Kernel") + ] # returns whether the symbol is found within the kernel (system.map) or not def _is_known_address(self, handler_addr): @@ -62,9 +62,7 @@ class Check_afinfo(plugins.PluginInterface): _, aslr_shift = linux.LinuxUtilities.find_aslr(self.context, self.config['vmlinux'], self.config['primary']) vmlinux = self.context.module(self.config['vmlinux'], self.config['primary'], aslr_shift) - linux.LinuxUtilities.aslr_mask_symbol_table(self.context, - self.config['primary'], - self.config['vmlinux'], + linux.LinuxUtilities.aslr_mask_symbol_table(self.context, self.config['primary'], self.config['vmlinux'], aslr_shift) op_members = vmlinux.get_type('file_operations').members @@ -89,8 +87,5 @@ class Check_afinfo(plugins.PluginInterface): def run(self): - return renderers.TreeGrid( - [("Symbol Name", str), - ("Member", str), - ("Handler Address", format_hints.Hex)], - self._generator()) + return renderers.TreeGrid([("Symbol Name", str), ("Member", str), ("Handler Address", format_hints.Hex)], + self._generator()) diff --git a/volatility/framework/plugins/linux/check_syscall.py b/volatility/framework/plugins/linux/check_syscall.py index 04391d6fd..91cb30423 100644 --- a/volatility/framework/plugins/linux/check_syscall.py +++ b/volatility/framework/plugins/linux/check_syscall.py @@ -26,11 +26,11 @@ class Check_syscall(plugins.PluginInterface): @classmethod def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: - return [requirements.TranslationLayerRequirement(name = 'primary', - description = 'Kernel Address Space', - architectures = ["Intel32", "Intel64"]), - requirements.SymbolRequirement(name = "vmlinux", - description = "Linux Kernel")] + return [ + requirements.TranslationLayerRequirement( + name = 'primary', description = 'Kernel Address Space', architectures = ["Intel32", "Intel64"]), + requirements.SymbolRequirement(name = "vmlinux", description = "Linux Kernel") + ] def _get_table_size_next_symbol(self, table_addr, ptr_sz, vmlinux): """ @@ -94,7 +94,8 @@ class Check_syscall(plugins.PluginInterface): md = capstone.Cs(capstone.CS_ARCH_X86, mode) try: - func_addr = self.context.symbol_space.get_symbol(vmlinux.name + constants.BANG + syscall_entry_func).address + func_addr = self.context.symbol_space.get_symbol(vmlinux.name + constants.BANG + + syscall_entry_func).address except exceptions.SymbolError as e: # if we can't find the disassemble function then bail and rely on a different method return 0 @@ -127,9 +128,7 @@ class Check_syscall(plugins.PluginInterface): _, aslr_shift = linux.LinuxUtilities.find_aslr(self.context, self.config['vmlinux'], self.config['primary']) vmlinux = self.context.module(self.config['vmlinux'], self.config['primary'], aslr_shift) - linux.LinuxUtilities.aslr_mask_symbol_table(self.context, - self.config['vmlinux'], - self.config['primary'], + linux.LinuxUtilities.aslr_mask_symbol_table(self.context, self.config['vmlinux'], self.config['primary'], aslr_shift) ptr_sz = vmlinux.get_type("pointer").size @@ -159,8 +158,8 @@ class Check_syscall(plugins.PluginInterface): tables.append(("32bit", ia32_info)) for (table_name, (tableaddr, tblsz)) in tables: - table = vmlinux.object(type_name = "array", subtype = vmlinux.get_type("pointer"), - offset = tableaddr, count = tblsz) + table = vmlinux.object( + type_name = "array", subtype = vmlinux.get_type("pointer"), offset = tableaddr, count = tblsz) for (i, call_addr) in enumerate(table): if not call_addr: @@ -178,10 +177,5 @@ class Check_syscall(plugins.PluginInterface): def run(self): - return renderers.TreeGrid( - [("Table Address", format_hints.Hex), - ("Table Name", str), - ("Index", int), - ("Handler Address", format_hints.Hex), - ("Handler Symbol", str)], - self._generator()) + return renderers.TreeGrid([("Table Address", format_hints.Hex), ("Table Name", str), ("Index", int), + ("Handler Address", format_hints.Hex), ("Handler Symbol", str)], self._generator()) diff --git a/volatility/framework/plugins/linux/elfs.py b/volatility/framework/plugins/linux/elfs.py index 4168d84b2..d113f8b7a 100644 --- a/volatility/framework/plugins/linux/elfs.py +++ b/volatility/framework/plugins/linux/elfs.py @@ -17,11 +17,11 @@ class Elfs(plugins.PluginInterface): @classmethod def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: - return [requirements.TranslationLayerRequirement(name = 'primary', - description = 'Kernel Address Space', - architectures = ["Intel32", "Intel64"]), - requirements.SymbolRequirement(name = "vmlinux", - description = "Linux Kernel")] + return [ + requirements.TranslationLayerRequirement( + name = 'primary', description = 'Kernel Address Space', architectures = ["Intel32", "Intel64"]), + requirements.SymbolRequirement(name = "vmlinux", description = "Linux Kernel") + ] def _generator(self, tasks): for task in tasks: @@ -40,14 +40,7 @@ class Elfs(plugins.PluginInterface): path = vma.get_name(task) - yield ( - 0, - (task.pid, - name, - format_hints.Hex(vma.vm_start), - format_hints.Hex(vma.vm_end), - path - )) + yield (0, (task.pid, name, format_hints.Hex(vma.vm_start), format_hints.Hex(vma.vm_end), path)) def run(self): filt = pslist.PsList.create_filter([self.config.get('pid', None)]) @@ -55,12 +48,6 @@ class Elfs(plugins.PluginInterface): plugin = pslist.PsList.list_tasks return renderers.TreeGrid( - [("PID", int), - ("Process", str), - ("Start", format_hints.Hex), - ("End", format_hints.Hex), + [("PID", int), ("Process", str), ("Start", format_hints.Hex), ("End", format_hints.Hex), ("File Path", str)], - self._generator(plugin(self.context, - self.config['primary'], - self.config['vmlinux'], - filter = filt))) + self._generator(plugin(self.context, self.config['primary'], self.config['vmlinux'], filter = filt))) diff --git a/volatility/framework/plugins/linux/lsmod.py b/volatility/framework/plugins/linux/lsmod.py index 1f66f8f6d..e04692982 100644 --- a/volatility/framework/plugins/linux/lsmod.py +++ b/volatility/framework/plugins/linux/lsmod.py @@ -17,17 +17,14 @@ class Lsmod(plugins.PluginInterface): @classmethod def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: - return [requirements.TranslationLayerRequirement(name = 'primary', - description = 'Kernel Address Space', - architectures = ["Intel32", "Intel64"]), - requirements.SymbolRequirement(name = "vmlinux", - description = "Linux Kernel")] + return [ + requirements.TranslationLayerRequirement( + name = 'primary', description = 'Kernel Address Space', architectures = ["Intel32", "Intel64"]), + requirements.SymbolRequirement(name = "vmlinux", description = "Linux Kernel") + ] @classmethod - def list_modules(cls, - context: interfaces.context.ContextInterface, - layer_name: str, - vmlinux_symbols: str): + def list_modules(cls, context: interfaces.context.ContextInterface, layer_name: str, vmlinux_symbols: str): """Lists all the modules in the primary layer""" _, aslr_shift = linux.LinuxUtilities.find_aslr(context, vmlinux_symbols, layer_name) @@ -43,9 +40,7 @@ class Lsmod(plugins.PluginInterface): yield module def _generator(self): - for module in self.list_modules(self.context, - self.config['primary'], - self.config['vmlinux']): + for module in self.list_modules(self.context, self.config['primary'], self.config['vmlinux']): mod_size = module.get_init_size() + module.get_core_size() @@ -54,8 +49,4 @@ class Lsmod(plugins.PluginInterface): yield 0, (format_hints.Hex(module.vol.offset), mod_name, mod_size) def run(self): - return renderers.TreeGrid( - [("Offset", format_hints.Hex), - ("Name", str), - ("Size", int)], - self._generator()) + return renderers.TreeGrid([("Offset", format_hints.Hex), ("Name", str), ("Size", int)], self._generator()) diff --git a/volatility/framework/plugins/linux/lsof.py b/volatility/framework/plugins/linux/lsof.py index c7166082e..b07978abd 100644 --- a/volatility/framework/plugins/linux/lsof.py +++ b/volatility/framework/plugins/linux/lsof.py @@ -19,19 +19,19 @@ class Lsof(plugins.PluginInterface): @classmethod def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: - return [requirements.TranslationLayerRequirement(name = 'primary', - description = 'Kernel Address Space', - architectures = ["Intel32", "Intel64"]), - requirements.SymbolRequirement(name = "vmlinux", - description = "Linux Kernel")] + return [ + requirements.TranslationLayerRequirement( + name = 'primary', description = 'Kernel Address Space', architectures = ["Intel32", "Intel64"]), + requirements.SymbolRequirement(name = "vmlinux", description = "Linux Kernel") + ] def _generator(self, tasks): for task in tasks: name = utility.array_to_string(task.comm) pid = int(task.pid) - for fd_num, _, full_path in linux.LinuxUtilities.files_descriptors_for_process(self.config, self.context, - task): + for fd_num, _, full_path in linux.LinuxUtilities.files_descriptors_for_process( + self.config, self.context, task): yield (0, (pid, name, fd_num, full_path)) def run(self): @@ -42,11 +42,5 @@ class Lsof(plugins.PluginInterface): plugin = pslist.PsList.list_tasks return renderers.TreeGrid( - [("PID", int), - ("Process", str), - ("FD", int), - ("Path", str)], - self._generator(plugin(self.context, - self.config['primary'], - self.config['vmlinux'], - filter = filter))) + [("PID", int), ("Process", str), ("FD", int), ("Path", str)], + self._generator(plugin(self.context, self.config['primary'], self.config['vmlinux'], filter = filter))) diff --git a/volatility/framework/plugins/linux/malfind.py b/volatility/framework/plugins/linux/malfind.py index e8383a044..21826c197 100644 --- a/volatility/framework/plugins/linux/malfind.py +++ b/volatility/framework/plugins/linux/malfind.py @@ -15,11 +15,11 @@ class Malfind(interfaces_plugins.PluginInterface): @classmethod def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: - return [requirements.TranslationLayerRequirement(name = 'primary', - description = 'Kernel Address Space', - architectures = ["Intel32", "Intel64"]), - requirements.SymbolRequirement(name = "vmlinux", - description = "Linux Kernel")] + return [ + requirements.TranslationLayerRequirement( + name = 'primary', description = 'Kernel Address Space', architectures = ["Intel32", "Intel64"]), + requirements.SymbolRequirement(name = "vmlinux", description = "Linux Kernel") + ] def list_injections(self, task): """Generate memory regions for a process that may contain @@ -55,27 +55,15 @@ class Malfind(interfaces_plugins.PluginInterface): disasm = interfaces_renderers.Disassembly(data, vma.vm_start, architecture) - yield (0, (task.pid, - process_name, - format_hints.Hex(vma.vm_start), - format_hints.Hex(vma.vm_end), - vma.get_protection(), - format_hints.HexBytes(data), - disasm)) + yield (0, (task.pid, process_name, format_hints.Hex(vma.vm_start), format_hints.Hex(vma.vm_end), + vma.get_protection(), format_hints.HexBytes(data), disasm)) def run(self): filt = pslist.PsList.create_filter([self.config.get('pid', None)]) plugin = pslist.PsList.list_tasks - return renderers.TreeGrid([("PID", int), - ("Process", str), - ("Start", format_hints.Hex), - ("End", format_hints.Hex), - ("Protection", str), - ("Hexdump", format_hints.HexBytes), - ("Disasm", interfaces_renderers.Disassembly)], - self._generator(plugin(self.context, - self.config['primary'], - self.config['vmlinux'], - filter = filt))) + return renderers.TreeGrid( + [("PID", int), ("Process", str), ("Start", format_hints.Hex), ("End", format_hints.Hex), + ("Protection", str), ("Hexdump", format_hints.HexBytes), ("Disasm", interfaces_renderers.Disassembly)], + self._generator(plugin(self.context, self.config['primary'], self.config['vmlinux'], filter = filt))) diff --git a/volatility/framework/plugins/linux/proc.py b/volatility/framework/plugins/linux/proc.py index 155c3a105..8ddd2ade2 100644 --- a/volatility/framework/plugins/linux/proc.py +++ b/volatility/framework/plugins/linux/proc.py @@ -16,11 +16,11 @@ class Maps(plugins.PluginInterface): @classmethod def get_requirements(cls): # Since we're calling the plugin, make sure we have the plugin's requirements - return [requirements.TranslationLayerRequirement(name = 'primary', - description = 'Kernel Address Space', - architectures = ["Intel32", "Intel64"]), - requirements.SymbolRequirement(name = "vmlinux", - description = "Linux Kernel")] + return [ + requirements.TranslationLayerRequirement( + name = 'primary', description = 'Kernel Address Space', architectures = ["Intel32", "Intel64"]), + requirements.SymbolRequirement(name = "vmlinux", description = "Linux Kernel") + ] def _generator(self, tasks): for task in tasks: @@ -46,19 +46,8 @@ class Maps(plugins.PluginInterface): path = vma.get_name(task) - yield ( - 0, - (task.pid, - name, - format_hints.Hex(vma.vm_start), - format_hints.Hex(vma.vm_end), - flags, - format_hints.Hex(page_offset), - major, - minor, - inode, - path - )) + yield (0, (task.pid, name, format_hints.Hex(vma.vm_start), format_hints.Hex(vma.vm_end), flags, + format_hints.Hex(page_offset), major, minor, inode, path)) def run(self): filter = pslist.PsList.create_filter([self.config.get('pid', None)]) @@ -66,17 +55,6 @@ class Maps(plugins.PluginInterface): plugin = pslist.PsList.list_tasks return renderers.TreeGrid( - [("PID", int), - ("Process", str), - ("Start", format_hints.Hex), - ("End", format_hints.Hex), - ("Flags", str), - ("PgOff", format_hints.Hex), - ("Major", int), - ("Minor", int), - ("Inode", int), - ("File Path", str)], - self._generator(plugin(self.context, - self.config['primary'], - self.config['vmlinux'], - filter = filter))) + [("PID", int), ("Process", str), ("Start", format_hints.Hex), ("End", format_hints.Hex), ("Flags", str), + ("PgOff", format_hints.Hex), ("Major", int), ("Minor", int), ("Inode", int), ("File Path", str)], + self._generator(plugin(self.context, self.config['primary'], self.config['vmlinux'], filter = filter))) diff --git a/volatility/framework/plugins/linux/pslist.py b/volatility/framework/plugins/linux/pslist.py index 1b1ab65b1..bf0883f56 100644 --- a/volatility/framework/plugins/linux/pslist.py +++ b/volatility/framework/plugins/linux/pslist.py @@ -12,11 +12,11 @@ class PsList(interfaces_plugins.PluginInterface): @classmethod def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: - return [requirements.TranslationLayerRequirement(name = 'primary', - description = 'Kernel Address Space', - architectures = ["Intel32", "Intel64"]), - requirements.SymbolRequirement(name = "vmlinux", - description = "Linux Kernel")] + return [ + requirements.TranslationLayerRequirement( + name = 'primary', description = 'Kernel Address Space', architectures = ["Intel32", "Intel64"]), + requirements.SymbolRequirement(name = "vmlinux", description = "Linux Kernel") + ] @classmethod def create_filter(cls, pid_list: List[int] = None) -> Callable[[int], bool]: @@ -24,6 +24,7 @@ class PsList(interfaces_plugins.PluginInterface): pid_list = pid_list or [] filter_list = [x for x in pid_list if x is not None] if filter_list: + def filter_func(x): return x not in filter_list @@ -32,10 +33,11 @@ class PsList(interfaces_plugins.PluginInterface): return lambda _: False def _generator(self): - for task in self.list_tasks(self.context, - self.config['primary'], - self.config['vmlinux'], - filter = self.create_filter([self.config.get('pid', None)])): + for task in self.list_tasks( + self.context, + self.config['primary'], + self.config['vmlinux'], + filter = self.create_filter([self.config.get('pid', None)])): pid = task.pid ppid = 0 if task.parent: @@ -49,7 +51,6 @@ class PsList(interfaces_plugins.PluginInterface): layer_name: str, vmlinux_symbols: str, filter: Callable[[int], bool] = lambda _: False) -> Iterable[interfaces.objects.ObjectInterface]: - """Lists all the tasks in the primary layer""" _, aslr_shift = linux.LinuxUtilities.find_aslr(context, vmlinux_symbols, layer_name) @@ -61,7 +62,4 @@ class PsList(interfaces_plugins.PluginInterface): yield task def run(self): - return renderers.TreeGrid([("PID", int), - ("PPID", int), - ("COMM", str)], - self._generator()) + return renderers.TreeGrid([("PID", int), ("PPID", int), ("COMM", str)], self._generator()) diff --git a/volatility/framework/plugins/linux/pstree.py b/volatility/framework/plugins/linux/pstree.py index 8d96ec26e..678fcdea7 100644 --- a/volatility/framework/plugins/linux/pstree.py +++ b/volatility/framework/plugins/linux/pstree.py @@ -38,9 +38,7 @@ class PsTree(pslist.PsList): def yield_processes(pid): proc = self._processes[pid] - row = (proc.pid, - proc.parent.pid, - utility.array_to_string(proc.comm)) + row = (proc.pid, proc.parent.pid, utility.array_to_string(proc.comm)) yield (self._levels[pid] - 1, row) for child_pid in self._children.get(pid, []): diff --git a/volatility/framework/plugins/mac/psaux.py b/volatility/framework/plugins/mac/psaux.py index 5ad7398c7..16705d237 100644 --- a/volatility/framework/plugins/mac/psaux.py +++ b/volatility/framework/plugins/mac/psaux.py @@ -13,11 +13,11 @@ class Psaux(plugins.PluginInterface): @classmethod def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: - return [requirements.TranslationLayerRequirement(name = 'primary', - description = 'Kernel Address Space', - architectures = ["Intel32", "Intel64"]), - requirements.SymbolRequirement(name = "darwin", - description = "Mac Kernel")] + return [ + requirements.TranslationLayerRequirement( + name = 'primary', description = 'Kernel Address Space', architectures = ["Intel32", "Intel64"]), + requirements.SymbolRequirement(name = "darwin", description = "Mac Kernel") + ] def _generator(self, tasks: Iterator[Any]) -> Generator[Tuple[int, Tuple[int, str, int, str]], None, None]: for task in tasks: @@ -29,8 +29,7 @@ class Psaux(plugins.PluginInterface): argsstart = task.user_stack - task.p_argslen - if (not proc_layer.is_valid(argsstart) or - not task.p_argslen or not task.p_argc): + if (not proc_layer.is_valid(argsstart) or not task.p_argslen or not task.p_argc): continue # Add one because the first two are usually duplicates @@ -87,11 +86,5 @@ class Psaux(plugins.PluginInterface): plugin = pslist.PsList.list_tasks return renderers.TreeGrid( - [("PID", int), - ("Process", str), - ("Argc", int), - ("Arguments", str)], - self._generator(plugin(self.context, - self.config['primary'], - self.config['darwin'], - filter = filter))) + [("PID", int), ("Process", str), ("Argc", int), ("Arguments", str)], + self._generator(plugin(self.context, self.config['primary'], self.config['darwin'], filter = filter))) diff --git a/volatility/framework/plugins/mac/pslist.py b/volatility/framework/plugins/mac/pslist.py index bce628034..7427e379c 100644 --- a/volatility/framework/plugins/mac/pslist.py +++ b/volatility/framework/plugins/mac/pslist.py @@ -15,11 +15,11 @@ class PsList(interfaces_plugins.PluginInterface): @classmethod def get_requirements(cls): - return [requirements.TranslationLayerRequirement(name = 'primary', - description = 'Kernel Address Space', - architectures = ["Intel32", "Intel64"]), - requirements.SymbolRequirement(name = "darwin", - description = "Mac Kernel")] + return [ + requirements.TranslationLayerRequirement( + name = 'primary', description = 'Kernel Address Space', architectures = ["Intel32", "Intel64"]), + requirements.SymbolRequirement(name = "darwin", description = "Mac Kernel") + ] @classmethod def create_filter(cls, pid_list: List[int] = None) -> Callable[[int], bool]: @@ -32,10 +32,11 @@ class PsList(interfaces_plugins.PluginInterface): return filter def _generator(self): - for task in self.list_tasks(self.context, - self.config['primary'], - self.config['darwin'], - filter = self.create_filter([self.config.get('pid', None)])): + for task in self.list_tasks( + self.context, + self.config['primary'], + self.config['darwin'], + filter = self.create_filter([self.config.get('pid', None)])): pid = task.p_pid ppid = task.p_ppid name = utility.array_to_string(task.p_comm) @@ -48,7 +49,6 @@ class PsList(interfaces_plugins.PluginInterface): mac_symbols: str, filter: Callable[[int], bool] = lambda _: False) \ -> Generator[interfaces.objects.ObjectInterface, None, None]: - """Lists all the tasks in the primary layer""" aslr_shift = mac.MacUtilities.find_aslr(context, mac_symbols, layer_name) @@ -68,7 +68,4 @@ class PsList(interfaces_plugins.PluginInterface): proc = proc.p_list.le_next.dereference() def run(self): - return renderers.TreeGrid([("PID", int), - ("PPID", int), - ("COMM", str)], - self._generator()) + return renderers.TreeGrid([("PID", int), ("PPID", int), ("COMM", str)], self._generator()) diff --git a/volatility/framework/plugins/timeliner.py b/volatility/framework/plugins/timeliner.py index 1c7a4d91b..4a92b0114 100644 --- a/volatility/framework/plugins/timeliner.py +++ b/volatility/framework/plugins/timeliner.py @@ -52,6 +52,7 @@ class Timeliner(interfaces.plugins.PluginInterface): filter_func = passthrough if selected_list: + def filter_plugins(name, selected): return any([s in name for s in selected]) @@ -61,14 +62,18 @@ class Timeliner(interfaces.plugins.PluginInterface): @classmethod def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: - return [requirements.StringRequirement(name = 'plugins', - description = "Comma separated list of plugins to run", - optional = True, - default = None), - requirements.BooleanRequirement(name = 'record-config', - description = "Whether to record the state of all the plugins once complete", - optional = True, - default = False)] + return [ + requirements.StringRequirement( + name = 'plugins', + description = "Comma separated list of plugins to run", + optional = True, + default = None), + requirements.BooleanRequirement( + name = 'record-config', + description = "Whether to record the state of all the plugins once complete", + optional = True, + default = False) + ] def _generator(self, runable_plugins: List[TimeLinerInterface]) -> Optional[Iterable[Tuple[int, Tuple]]]: """Takes a timeline, sorts it and output the data from each relevant row from each plugin""" @@ -80,9 +85,8 @@ class Timeliner(interfaces.plugins.PluginInterface): 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)) + 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: @@ -92,11 +96,13 @@ class Timeliner(interfaces.plugins.PluginInterface): 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())]) + 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): @@ -112,12 +118,8 @@ class Timeliner(interfaces.plugins.PluginInterface): try: automagics = automagic.choose_automagic(self.automagics, plugin_class) - plugin = plugins.run_plugin(self.context, - automagics, - plugin_class, - self.config_path, - self._progress_callback, - self._file_consumer) + plugin = plugins.run_plugin(self.context, automagics, plugin_class, self.config_path, + self._progress_callback, self._file_consumer) if isinstance(plugin, TimeLinerInterface): runable_plugins.append(plugin) @@ -131,20 +133,19 @@ class Timeliner(interfaces.plugins.PluginInterface): for plugin in runable_plugins: old_dict = dict(plugin.build_configuration()) for entry in old_dict: - total_config[interfaces.configuration.path_join(plugin.__class__.__name__, entry)] = old_dict[entry] + total_config[interfaces.configuration.path_join(plugin.__class__.__name__, + entry)] = old_dict[entry] filedata = interfaces.plugins.FileInterface("config.json") with io.TextIOWrapper(filedata.data, write_through = True) as fp: json.dump(total_config, fp, sort_keys = True, indent = 2) self.produce_file(filedata) - 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(runable_plugins)) + 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(runable_plugins)) def build_configuration(self): """Builds the configuration to save for the plugin such that it can be reconstructed""" diff --git a/volatility/framework/plugins/windows/cmdline.py b/volatility/framework/plugins/windows/cmdline.py index d61c1ee28..3e535e14c 100644 --- a/volatility/framework/plugins/windows/cmdline.py +++ b/volatility/framework/plugins/windows/cmdline.py @@ -14,10 +14,11 @@ class CmdLine(interfaces_plugins.PluginInterface): @classmethod def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: # Since we're calling the plugin, make sure we have the plugin's requirements - return [requirements.TranslationLayerRequirement(name = 'primary', - description = 'Kernel Address Space', - architectures = ["Intel32", "Intel64"]), - requirements.SymbolRequirement(name = "nt_symbols", description = "Windows OS")] + return [ + requirements.TranslationLayerRequirement( + name = 'primary', description = 'Kernel Address Space', architectures = ["Intel32", "Intel64"]), + requirements.SymbolRequirement(name = "nt_symbols", description = "Windows OS") + ] def _generator(self, procs): @@ -27,9 +28,10 @@ class CmdLine(interfaces_plugins.PluginInterface): proc_layer_name = proc.add_process_layer() try: - peb = self._context.object(self.config["nt_symbols"] + constants.BANG + "_PEB", - layer_name = proc_layer_name, - offset = proc.Peb) + peb = self._context.object( + self.config["nt_symbols"] + constants.BANG + "_PEB", + layer_name = proc_layer_name, + offset = proc.Peb) result_text = peb.ProcessParameters.CommandLine.get_string() @@ -39,18 +41,16 @@ class CmdLine(interfaces_plugins.PluginInterface): except exceptions.PagedInvalidAddressException as exp: result_text = "Required memory at {0:#x} is not valid (process exited?)".format(exp.invalid_address) - yield (0, (proc.UniqueProcessId, - process_name, - result_text)) + yield (0, (proc.UniqueProcessId, process_name, result_text)) def run(self): filter_func = pslist.PsList.create_filter([self.config.get('pid', None)]) - return renderers.TreeGrid([("PID", int), - ("Process", str), - ("Args", str)], - self._generator(pslist.PsList.list_processes(context = self.context, - layer_name = self.config['primary'], - symbol_table = self.config['nt_symbols'], - filter_func = filter_func))) + return renderers.TreeGrid([("PID", int), ("Process", str), ("Args", str)], + self._generator( + pslist.PsList.list_processes( + context = self.context, + layer_name = self.config['primary'], + symbol_table = self.config['nt_symbols'], + filter_func = filter_func))) diff --git a/volatility/framework/plugins/windows/dlldump.py b/volatility/framework/plugins/windows/dlldump.py index 221b024f9..20d5e9165 100644 --- a/volatility/framework/plugins/windows/dlldump.py +++ b/volatility/framework/plugins/windows/dlldump.py @@ -33,10 +33,7 @@ class DllDump(interfaces_plugins.PluginInterface): optional = True)] def _generator(self, procs): - pe_table_name = PEIntermedSymbols.create(self.context, - self.config_path, - "windows", - "pe") + pe_table_name = PEIntermedSymbols.create(self.context, self.config_path, "windows", "pe") filter_func = lambda _: False if self.config.get('address', None) is not None: @@ -56,10 +53,9 @@ class DllDump(interfaces_plugins.PluginInterface): # rather than relying on the PEB for DLLs, which can be swapped, # it requires special handling on wow64 processes, and its # unreliable from an integrity standpoint, let's use the VADs instead - protection_string = vad.get_protection(vadinfo.VadInfo.protect_values(self.context, - self.config['primary'], - self.config['nt_symbols']), - vadinfo.winnt_protections) + protection_string = vad.get_protection( + vadinfo.VadInfo.protect_values(self.context, self.config['primary'], + self.config['nt_symbols']), vadinfo.winnt_protections) # DLLs are write copy... if protection_string != "PAGE_EXECUTE_WRITECOPY": @@ -70,14 +66,13 @@ class DllDump(interfaces_plugins.PluginInterface): continue try: - filedata = interfaces_plugins.FileInterface( - "pid.{0}.{1}.{2:#x}.dmp".format(proc.UniqueProcessId, - ntpath.basename(vad.get_file_name()), - vad.get_start())) + filedata = interfaces_plugins.FileInterface("pid.{0}.{1}.{2:#x}.dmp".format( + proc.UniqueProcessId, ntpath.basename(vad.get_file_name()), vad.get_start())) - dos_header = self.context.object(pe_table_name + constants.BANG + - "_IMAGE_DOS_HEADER", offset = vad.get_start(), - layer_name = proc_layer_name) + dos_header = self.context.object( + pe_table_name + constants.BANG + "_IMAGE_DOS_HEADER", + offset = vad.get_start(), + layer_name = proc_layer_name) for offset, data in dos_header.reconstruct(): filedata.data.seek(offset) @@ -88,17 +83,15 @@ class DllDump(interfaces_plugins.PluginInterface): except Exception: result_text = "Unable to dump PE at {0:#x}".format(vad.get_start()) - yield (0, (proc.UniqueProcessId, - process_name, - result_text)) + yield (0, (proc.UniqueProcessId, process_name, result_text)) def run(self): filter_func = pslist.PsList.create_filter([self.config.get('pid', None)]) - return renderers.TreeGrid([("PID", int), - ("Process", str), - ("Result", str)], - self._generator(pslist.PsList.list_processes(context = self.context, - layer_name = self.config['primary'], - symbol_table = self.config['nt_symbols'], - filter_func = filter_func))) + return renderers.TreeGrid([("PID", int), ("Process", str), ("Result", str)], + self._generator( + pslist.PsList.list_processes( + context = self.context, + layer_name = self.config['primary'], + symbol_table = self.config['nt_symbols'], + filter_func = filter_func))) diff --git a/volatility/framework/plugins/windows/dlllist.py b/volatility/framework/plugins/windows/dlllist.py index 122c7c82d..00f99ca4f 100644 --- a/volatility/framework/plugins/windows/dlllist.py +++ b/volatility/framework/plugins/windows/dlllist.py @@ -13,10 +13,11 @@ class DllList(interfaces_plugins.PluginInterface): @classmethod def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: # Since we're calling the plugin, make sure we have the plugin's requirements - return [requirements.TranslationLayerRequirement(name = 'primary', - description = 'Kernel Address Space', - architectures = ["Intel32", "Intel64"]), - requirements.SymbolRequirement(name = "nt_symbols", description = "Windows OS")] + return [ + requirements.TranslationLayerRequirement( + name = 'primary', description = 'Kernel Address Space', architectures = ["Intel32", "Intel64"]), + requirements.SymbolRequirement(name = "nt_symbols", description = "Windows OS") + ] def _generator(self, procs): @@ -33,22 +34,20 @@ class DllList(interfaces_plugins.PluginInterface): pass yield (0, (proc.UniqueProcessId, - proc.ImageFileName.cast("string", max_length = proc.ImageFileName.vol.count, - errors = 'replace'), - format_hints.Hex(entry.DllBase), format_hints.Hex(entry.SizeOfImage), - BaseDllName, FullDllName)) + proc.ImageFileName.cast( + "string", max_length = proc.ImageFileName.vol.count, errors = 'replace'), + format_hints.Hex(entry.DllBase), format_hints.Hex(entry.SizeOfImage), BaseDllName, + FullDllName)) def run(self): filter_func = pslist.PsList.create_filter([self.config.get('pid', None)]) - return renderers.TreeGrid([("PID", int), - ("Process", str), - ("Base", format_hints.Hex), - ("Size", format_hints.Hex), - ("Name", str), - ("Path", str)], - self._generator(pslist.PsList.list_processes(context = self.context, - layer_name = self.config['primary'], - symbol_table = self.config['nt_symbols'], - filter_func = filter_func))) + return renderers.TreeGrid([("PID", int), ("Process", str), ("Base", format_hints.Hex), + ("Size", format_hints.Hex), ("Name", str), ("Path", str)], + self._generator( + pslist.PsList.list_processes( + context = self.context, + layer_name = self.config['primary'], + symbol_table = self.config['nt_symbols'], + filter_func = filter_func))) diff --git a/volatility/framework/plugins/windows/handles.py b/volatility/framework/plugins/windows/handles.py index f66cba4e7..d7f715077 100644 --- a/volatility/framework/plugins/windows/handles.py +++ b/volatility/framework/plugins/windows/handles.py @@ -32,10 +32,11 @@ class Handles(interfaces_plugins.PluginInterface): @classmethod def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: # Since we're calling the plugin, make sure we have the plugin's requirements - return [requirements.TranslationLayerRequirement(name = 'primary', - description = 'Kernel Address Space', - architectures = ["Intel32", "Intel64"]), - requirements.SymbolRequirement(name = "nt_symbols", description = "Windows OS")] + return [ + requirements.TranslationLayerRequirement( + name = 'primary', description = 'Kernel Address Space', architectures = ["Intel32", "Intel64"]), + requirements.SymbolRequirement(name = "nt_symbols", description = "Windows OS") + ] def _decode_pointer(self, value, magic): """Windows encodes pointers to objects and decodes them on the fly @@ -76,8 +77,8 @@ class Handles(interfaces_plugins.PluginInterface): offset = self._decode_pointer(handle_table_entry.LowValue, magic) # print("LowValue: {0:#x} Magic: {1:#x} Offset: {2:#x}".format(handle_table_entry.InfoTable, magic, offset)) - object_header = self.context.object(self.config["nt_symbols"] + constants.BANG + "_OBJECT_HEADER", virtual, - offset = offset) + object_header = self.context.object( + self.config["nt_symbols"] + constants.BANG + "_OBJECT_HEADER", virtual, offset = offset) object_header.GrantedAccess = handle_table_entry.GrantedAccessBits object_header.HandleValue = handle_value @@ -121,10 +122,7 @@ class Handles(interfaces_plugins.PluginInterface): return self._sar_value @classmethod - def list_objects(cls, - context: interfaces.context.ContextInterface, - layer_name: str, - symbol_table: str) -> dict: + def list_objects(cls, context: interfaces.context.ContextInterface, layer_name: str, symbol_table: str) -> dict: """List the executive object types (_OBJECT_TYPE) using the ObTypeIndexTable or ObpObjectTypes symbol (differs per OS). This method will be necessary for determining what type of @@ -143,9 +141,8 @@ class Handles(interfaces_plugins.PluginInterface): except exceptions.SymbolError: table_addr = ntkrnlmp.get_symbol("ObpObjectTypes").address - ptrs = ntkrnlmp.object(type_name = "array", offset = kvo + table_addr, - subtype = ntkrnlmp.get_type("pointer"), - count = 100) + ptrs = ntkrnlmp.object( + type_name = "array", offset = kvo + table_addr, subtype = ntkrnlmp.get_type("pointer"), count = 100) for i, ptr in enumerate(ptrs): # the first entry in the table is always null. break the @@ -166,21 +163,17 @@ class Handles(interfaces_plugins.PluginInterface): return type_map @classmethod - def find_cookie(cls, - context: interfaces.context.ContextInterface, - layer_name: str, + def find_cookie(cls, context: interfaces.context.ContextInterface, layer_name: str, symbol_table: str) -> Optional[interfaces.objects.ObjectInterface]: """Find the ObHeaderCookie value (if it exists)""" try: - offset = context.symbol_space.get_symbol( - symbol_table + constants.BANG + "ObHeaderCookie").address + offset = context.symbol_space.get_symbol(symbol_table + constants.BANG + "ObHeaderCookie").address except exceptions.SymbolError: return None kvo = context.memory[layer_name].config['kernel_virtual_offset'] - return context.object(symbol_table + constants.BANG + "unsigned int", - layer_name, offset = kvo + offset) + return context.object(symbol_table + constants.BANG + "unsigned int", layer_name, offset = kvo + offset) def _make_handle_array(self, offset, level, depth = 0): """Parse a process' handle table and yield valid handle table @@ -201,8 +194,7 @@ class Handles(interfaces_plugins.PluginInterface): if not self.context.memory[virtual].is_valid(offset): return - table = ntkrnlmp.object(type_name = "array", offset = offset, - subtype = subtype, count = int(count)) + table = ntkrnlmp.object(type_name = "array", offset = offset, subtype = subtype, count = int(count)) layer_object = self.context.memory[virtual] masked_offset = (offset & layer_object.maximum_address) @@ -217,8 +209,8 @@ class Handles(interfaces_plugins.PluginInterface): handle_multiplier = 4 handle_level_base = depth * count * handle_multiplier - handle_value = ((entry.vol.offset - masked_offset) / - (subtype.size / handle_multiplier)) + handle_level_base + handle_value = ( + (entry.vol.offset - masked_offset) / (subtype.size / handle_multiplier)) + handle_level_base item = self._get_item(entry, handle_value) @@ -248,12 +240,10 @@ class Handles(interfaces_plugins.PluginInterface): def _generator(self, procs): - type_map = self.list_objects(context = self.context, - layer_name = self.config["primary"], - symbol_table = self.config["nt_symbols"]) - cookie = self.find_cookie(context = self.context, - layer_name = self.config["primary"], - symbol_table = self.config["nt_symbols"]) + type_map = self.list_objects( + context = self.context, layer_name = self.config["primary"], symbol_table = self.config["nt_symbols"]) + cookie = self.find_cookie( + context = self.context, layer_name = self.config["primary"], symbol_table = self.config["nt_symbols"]) for proc in procs: @@ -278,8 +268,8 @@ class Handles(interfaces_plugins.PluginInterface): obj_name = item.file_name_with_device() elif obj_type == "Process": item = entry.Body.cast(self.config["nt_symbols"] + constants.BANG + "_EPROCESS") - obj_name = "{} Pid {}".format(utility.array_to_string(proc.ImageFileName), - item.UniqueProcessId) + obj_name = "{} Pid {}".format( + utility.array_to_string(proc.ImageFileName), item.UniqueProcessId) elif obj_type == "Thread": item = entry.Body.cast(self.config["nt_symbols"] + constants.BANG + "_ETHREAD") obj_name = "Tid {} Pid {}".format(item.Cid.UniqueThread, item.Cid.UniqueProcess) @@ -297,24 +287,18 @@ class Handles(interfaces_plugins.PluginInterface): "Cannot access _OBJECT_HEADER at {0:#x}".format(entry.vol.offset)) continue - yield (0, (proc.UniqueProcessId, - process_name, - format_hints.Hex(entry.HandleValue), - obj_type, - format_hints.Hex(entry.GrantedAccess), - obj_name)) + yield (0, (proc.UniqueProcessId, process_name, format_hints.Hex(entry.HandleValue), obj_type, + format_hints.Hex(entry.GrantedAccess), obj_name)) def run(self): filter_func = pslist.PsList.create_filter([self.config.get('pid', None)]) - return renderers.TreeGrid([("PID", int), - ("Process", str), - ("HandleValue", format_hints.Hex), - ("Type", str), - ("GrantedAccess", format_hints.Hex), - ("Name", str)], - self._generator(pslist.PsList.list_processes(self.context, - self.config['primary'], - self.config['nt_symbols'], - filter_func = filter_func))) + return renderers.TreeGrid([("PID", int), ("Process", str), ("HandleValue", format_hints.Hex), ("Type", str), + ("GrantedAccess", format_hints.Hex), ("Name", str)], + self._generator( + pslist.PsList.list_processes( + self.context, + self.config['primary'], + self.config['nt_symbols'], + filter_func = filter_func))) diff --git a/volatility/framework/plugins/windows/info.py b/volatility/framework/plugins/windows/info.py index 0347a12b9..7d6bc6c2e 100644 --- a/volatility/framework/plugins/windows/info.py +++ b/volatility/framework/plugins/windows/info.py @@ -14,10 +14,11 @@ class Info(plugins.PluginInterface): @classmethod def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: - return [requirements.TranslationLayerRequirement(name = 'primary', - description = 'Kernel Address Space', - architectures = ["Intel32", "Intel64"]), - requirements.SymbolRequirement(name = "nt_symbols", description = "Windows OS")] + return [ + requirements.TranslationLayerRequirement( + name = 'primary', description = 'Kernel Address Space', architectures = ["Intel32", "Intel64"]), + requirements.SymbolRequirement(name = "nt_symbols", description = "Windows OS") + ] def get_depends(self, layer_name: str, index: int = 0): """List the dependencies of a given layer. @@ -45,27 +46,21 @@ class Info(plugins.PluginInterface): native_types = self.context.symbol_space[self.config["nt_symbols"]].natives - kdbg_table_name = KdbgIntermedSymbols.create(self.context, - self.config_path, - "windows", - "kdbg", - native_types = native_types) + kdbg_table_name = KdbgIntermedSymbols.create( + self.context, self.config_path, "windows", "kdbg", native_types = native_types) - pe_table_name = PEIntermedSymbols.create(self.context, - self.config_path, - "windows", - "pe") + pe_table_name = PEIntermedSymbols.create(self.context, self.config_path, "windows", "pe") kvo = virtual_layer.config["kernel_virtual_offset"] - ntkrnlmp = self.context.module(self.config["nt_symbols"], - layer_name = virtual_layer_name, offset = kvo) + ntkrnlmp = self.context.module(self.config["nt_symbols"], layer_name = virtual_layer_name, offset = kvo) kdbg_offset = ntkrnlmp.get_symbol("KdDebuggerDataBlock").address - kdbg = self.context.object(kdbg_table_name + constants.BANG + - "_KDDEBUGGER_DATA64", offset = kvo + kdbg_offset, - layer_name = virtual_layer_name) + kdbg = self.context.object( + kdbg_table_name + constants.BANG + "_KDDEBUGGER_DATA64", + offset = kvo + kdbg_offset, + layer_name = virtual_layer_name) yield (0, ("Memory Location", self.config["primary.memory_layer.location"])) yield (0, ("Kernel Base", hex(self.config["primary.kernel_virtual_offset"]))) @@ -83,9 +78,8 @@ class Info(plugins.PluginInterface): vers_offset = ntkrnlmp.get_symbol("KdVersionBlock").address - vers = ntkrnlmp.object(type_name = "_DBGKD_GET_VERSION64", - layer_name = virtual_layer_name, - offset = kvo + vers_offset) + vers = ntkrnlmp.object( + type_name = "_DBGKD_GET_VERSION64", layer_name = virtual_layer_name, offset = kvo + vers_offset) yield (0, ("KdVersionBlock", hex(vers.vol.offset))) yield (0, ("Major/Minor", "{0}.{1}".format(vers.MajorVersion, vers.MinorVersion))) @@ -93,9 +87,8 @@ class Info(plugins.PluginInterface): cpu_count_offset = ntkrnlmp.get_symbol("KeNumberProcessors").address - cpu_count = ntkrnlmp.object(type_name = "unsigned int", - layer_name = virtual_layer_name, - offset = kvo + cpu_count_offset) + cpu_count = ntkrnlmp.object( + type_name = "unsigned int", layer_name = virtual_layer_name, offset = kvo + cpu_count_offset) yield (0, ("KeNumberProcessors", str(cpu_count))) @@ -105,24 +98,19 @@ class Info(plugins.PluginInterface): else: kuser_addr = 0xFFFFF78000000000 - kuser = ntkrnlmp.object(type_name = "_KUSER_SHARED_DATA", - layer_name = virtual_layer_name, - offset = kuser_addr) + kuser = ntkrnlmp.object(type_name = "_KUSER_SHARED_DATA", layer_name = virtual_layer_name, offset = kuser_addr) yield (0, ("SystemTime", str(kuser.SystemTime.get_time()))) - yield (0, ("NtSystemRoot", str(kuser.NtSystemRoot.cast("string", - encoding = "utf-16", - errors = "replace", - max_length = 260)))) + yield (0, ("NtSystemRoot", + str(kuser.NtSystemRoot.cast("string", encoding = "utf-16", errors = "replace", max_length = 260)))) yield (0, ("NtProductType", str(kuser.NtProductType.description))) yield (0, ("NtMajorVersion", str(kuser.NtMajorVersion))) yield (0, ("NtMinorVersion", str(kuser.NtMinorVersion))) # yield (0, ("KdDebuggerEnabled", "True" if ord(kuser.KdDebuggerEnabled) else "False")) # yield (0, ("SafeBootMode", "True" if ord(kuser.SafeBootMode) else "False")) - dos_header = self.context.object(pe_table_name + constants.BANG + - "_IMAGE_DOS_HEADER", offset = kvo, - layer_name = virtual_layer_name) + dos_header = self.context.object( + pe_table_name + constants.BANG + "_IMAGE_DOS_HEADER", offset = kvo, layer_name = virtual_layer_name) nt_header = dos_header.get_nt_header() @@ -134,6 +122,4 @@ class Info(plugins.PluginInterface): def run(self): - return TreeGrid([("Variable", str), - ("Value", str)], - self._generator()) + return TreeGrid([("Variable", str), ("Value", str)], self._generator()) diff --git a/volatility/framework/plugins/windows/malfind.py b/volatility/framework/plugins/windows/malfind.py index 8e66e0581..ca4285686 100644 --- a/volatility/framework/plugins/windows/malfind.py +++ b/volatility/framework/plugins/windows/malfind.py @@ -13,10 +13,11 @@ class Malfind(interfaces.plugins.PluginInterface): @classmethod def get_requirements(cls): # Since we're calling the plugin, make sure we have the plugin's requirements - return [requirements.TranslationLayerRequirement(name = 'primary', - description = 'Kernel Address Space', - architectures = ["Intel32", "Intel64"]), - requirements.SymbolRequirement(name = "nt_symbols", description = "Windows OS")] + return [ + requirements.TranslationLayerRequirement( + name = 'primary', description = 'Kernel Address Space', architectures = ["Intel32", "Intel64"]), + requirements.SymbolRequirement(name = "nt_symbols", description = "Windows OS") + ] @classmethod def is_vad_empty(self, proc_layer, vad): @@ -46,9 +47,7 @@ class Malfind(interfaces.plugins.PluginInterface): return True @classmethod - def list_injections(cls, - context: interfaces.context.ContextInterface, - symbol_table: str, + def list_injections(cls, context: interfaces.context.ContextInterface, symbol_table: str, proc: interfaces.objects.ObjectInterface): """Generate memory regions for a process that may contain injected code. @@ -61,18 +60,17 @@ class Malfind(interfaces.plugins.PluginInterface): proc_layer = context.memory[proc_layer_name] for vad in proc.get_vad_root().traverse(): - protection_string = vad.get_protection(vadinfo.VadInfo.protect_values(context, - proc_layer_name, - symbol_table), - vadinfo.winnt_protections) + protection_string = vad.get_protection( + vadinfo.VadInfo.protect_values(context, proc_layer_name, symbol_table), vadinfo.winnt_protections) write_exec = "EXECUTE" in protection_string and "WRITE" in protection_string # the write/exec check applies to everything if not write_exec: continue - if (vad.get_private_memory() == 1 and vad.get_tag() == "VadS") or ( - vad.get_private_memory() == 0 and protection_string != "PAGE_EXECUTE_WRITECOPY"): + if (vad.get_private_memory() == 1 + and vad.get_tag() == "VadS") or (vad.get_private_memory() == 0 + and protection_string != "PAGE_EXECUTE_WRITECOPY"): if cls.is_vad_empty(proc_layer, vad): continue @@ -96,34 +94,23 @@ class Malfind(interfaces.plugins.PluginInterface): disasm = interfaces.renderers.Disassembly(data, vad.get_start(), architecture) - yield (0, (proc.UniqueProcessId, - process_name, - format_hints.Hex(vad.get_start()), - format_hints.Hex(vad.get_end()), - vad.get_tag(), - vad.get_protection(vadinfo.VadInfo.protect_values(self.context, - proc.vol.layer_name, - self.config["nt_symbols"]), - vadinfo.winnt_protections), - vad.get_commit_charge(), - vad.get_private_memory(), - format_hints.HexBytes(data), - disasm)) + yield (0, (proc.UniqueProcessId, process_name, format_hints.Hex(vad.get_start()), + format_hints.Hex(vad.get_end()), vad.get_tag(), + vad.get_protection( + vadinfo.VadInfo.protect_values(self.context, proc.vol.layer_name, + self.config["nt_symbols"]), vadinfo.winnt_protections), + vad.get_commit_charge(), vad.get_private_memory(), format_hints.HexBytes(data), disasm)) def run(self): filter_func = pslist.PsList.create_filter([self.config.get('pid', None)]) - return renderers.TreeGrid([("PID", int), - ("Process", str), - ("Start VPN", format_hints.Hex), - ("End VPN", format_hints.Hex), - ("Tag", str), - ("Protection", str), - ("CommitCharge", int), - ("PrivateMemory", int), - ("Hexdump", format_hints.HexBytes), + return renderers.TreeGrid([("PID", int), ("Process", str), ("Start VPN", format_hints.Hex), + ("End VPN", format_hints.Hex), ("Tag", str), ("Protection", str), + ("CommitCharge", int), ("PrivateMemory", int), ("Hexdump", format_hints.HexBytes), ("Disasm", interfaces.renderers.Disassembly)], - self._generator(pslist.PsList.list_processes(context = self.context, - layer_name = self.config['primary'], - symbol_table = self.config['nt_symbols'], - filter_func = filter_func))) + self._generator( + pslist.PsList.list_processes( + context = self.context, + layer_name = self.config['primary'], + symbol_table = self.config['nt_symbols'], + filter_func = filter_func))) diff --git a/volatility/framework/plugins/windows/moddump.py b/volatility/framework/plugins/windows/moddump.py index a8484949c..c878b49de 100644 --- a/volatility/framework/plugins/windows/moddump.py +++ b/volatility/framework/plugins/windows/moddump.py @@ -21,10 +21,11 @@ class ModDump(interfaces_plugins.PluginInterface): @classmethod def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: # Reuse the requirements from the plugins we use - return [requirements.TranslationLayerRequirement(name = 'primary', - description = 'Kernel Address Space', - architectures = ["Intel32", "Intel64"]), - requirements.SymbolRequirement(name = "nt_symbols", description = "Windows OS")] + return [ + requirements.TranslationLayerRequirement( + name = 'primary', description = 'Kernel Address Space', architectures = ["Intel32", "Intel64"]), + requirements.SymbolRequirement(name = "nt_symbols", description = "Windows OS") + ] @classmethod def get_session_layers(cls, @@ -42,18 +43,17 @@ class ModDump(interfaces_plugins.PluginInterface): seen_ids = [] # type: List[interfaces.objects.ObjectInterface] filter_func = pslist.PsList.create_filter(pids or []) - for proc in pslist.PsList.list_processes(context = context, - layer_name = layer_name, - symbol_table = symbol_table, - filter_func = filter_func): + for proc in pslist.PsList.list_processes( + context = context, layer_name = layer_name, symbol_table = symbol_table, filter_func = filter_func): proc_layer_name = proc.add_process_layer() try: # create the session space object in the process' own layer. # not all processes have a valid session pointer. - session_space = context.object(symbol_table + constants.BANG + "_MM_SESSION_SPACE", - layer_name = layer_name, - offset = proc.Session) + session_space = context.object( + symbol_table + constants.BANG + "_MM_SESSION_SPACE", + layer_name = layer_name, + offset = proc.Session) if session_space.SessionId in seen_ids: continue @@ -68,9 +68,7 @@ class ModDump(interfaces_plugins.PluginInterface): yield proc_layer_name @classmethod - def find_session_layer(cls, - context: interfaces.context.ContextInterface, - session_layers: Iterable[str], + def find_session_layer(cls, context: interfaces.context.ContextInterface, session_layers: Iterable[str], base_address: int): """Given a base address and a list of layer names, find a layer that can access the specified address. @@ -91,13 +89,8 @@ class ModDump(interfaces_plugins.PluginInterface): def _generator(self, mods): - session_layers = list(self.get_session_layers(self.context, - self.config['primary'], - self.config['nt_symbols'])) - pe_table_name = PEIntermedSymbols.create(self.context, - self.config_path, - "windows", - "pe") + session_layers = list(self.get_session_layers(self.context, self.config['primary'], self.config['nt_symbols'])) + pe_table_name = PEIntermedSymbols.create(self.context, self.config_path, "windows", "pe") for mod in mods: try: @@ -110,12 +103,12 @@ class ModDump(interfaces_plugins.PluginInterface): result_text = "Cannot find a viable session layer for {0:#x}".format(mod.DllBase) else: try: - dos_header = self.context.object(pe_table_name + constants.BANG + - "_IMAGE_DOS_HEADER", offset = mod.DllBase, - layer_name = session_layer_name) + dos_header = self.context.object( + pe_table_name + constants.BANG + "_IMAGE_DOS_HEADER", + offset = mod.DllBase, + layer_name = session_layer_name) - filedata = interfaces_plugins.FileInterface( - "module.{0:#x}.dmp".format(mod.DllBase)) + filedata = interfaces_plugins.FileInterface("module.{0:#x}.dmp".format(mod.DllBase)) for offset, data in dos_header.reconstruct(): filedata.data.seek(offset) @@ -133,16 +126,13 @@ class ModDump(interfaces_plugins.PluginInterface): except exceptions.InvalidAddressException as exp: result_text = "Required memory at {0:#x} is not valid".format(exp.invalid_address) - yield (0, (format_hints.Hex(mod.DllBase), - BaseDllName, - result_text)) + yield (0, (format_hints.Hex(mod.DllBase), BaseDllName, result_text)) def run(self): - return renderers.TreeGrid([("Base", format_hints.Hex), - ("Name", str), - ("Result", str)], + return renderers.TreeGrid([("Base", format_hints.Hex), ("Name", str), ("Result", str)], self._generator( - modules.Modules.list_modules(context = self.context, - layer_name = self.config['primary'], - symbol_table = self.config['nt_symbols']))) + modules.Modules.list_modules( + context = self.context, + layer_name = self.config['primary'], + symbol_table = self.config['nt_symbols']))) diff --git a/volatility/framework/plugins/windows/modules.py b/volatility/framework/plugins/windows/modules.py index 682067a71..8dd91b41d 100644 --- a/volatility/framework/plugins/windows/modules.py +++ b/volatility/framework/plugins/windows/modules.py @@ -12,10 +12,11 @@ class Modules(interfaces.plugins.PluginInterface): @classmethod def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: - return [requirements.TranslationLayerRequirement(name = 'primary', - description = 'Kernel Address Space', - architectures = ["Intel32", "Intel64"]), - requirements.SymbolRequirement(name = "nt_symbols", description = "Windows OS")] + return [ + requirements.TranslationLayerRequirement( + name = 'primary', description = 'Kernel Address Space', architectures = ["Intel32", "Intel64"]), + requirements.SymbolRequirement(name = "nt_symbols", description = "Windows OS") + ] def _generator(self): for mod in self.list_modules(self.context, self.config['primary'], self.config['nt_symbols']): @@ -30,18 +31,16 @@ class Modules(interfaces.plugins.PluginInterface): except exceptions.InvalidAddressException: FullDllName = "" - yield (0, (format_hints.Hex(mod.vol.offset), - format_hints.Hex(mod.DllBase), - format_hints.Hex(mod.SizeOfImage), - BaseDllName, - FullDllName, - )) + yield (0, ( + format_hints.Hex(mod.vol.offset), + format_hints.Hex(mod.DllBase), + format_hints.Hex(mod.SizeOfImage), + BaseDllName, + FullDllName, + )) @classmethod - def list_modules(cls, - context: interfaces.context.ContextInterface, - layer_name: str, - symbol_table: str): + def list_modules(cls, context: interfaces.context.ContextInterface, layer_name: str, symbol_table: str): """Lists all the modules in the primary layer""" kvo = context.memory[layer_name].config['kernel_virtual_offset'] @@ -64,9 +63,5 @@ class Modules(interfaces.plugins.PluginInterface): yield mod def run(self): - return renderers.TreeGrid([("Offset", format_hints.Hex), - ("Base", format_hints.Hex), - ("Size", format_hints.Hex), - ("Name", str), - ("Path", str)], - self._generator()) + return renderers.TreeGrid([("Offset", format_hints.Hex), ("Base", format_hints.Hex), + ("Size", format_hints.Hex), ("Name", str), ("Path", str)], self._generator()) diff --git a/volatility/framework/plugins/windows/poolscanner.py b/volatility/framework/plugins/windows/poolscanner.py index bab947411..a83936e07 100644 --- a/volatility/framework/plugins/windows/poolscanner.py +++ b/volatility/framework/plugins/windows/poolscanner.py @@ -25,6 +25,7 @@ class PoolType(enum.IntEnum): class PoolHeaderSymbolTable(intermed.IntermediateSymbolTable): + def __init__(self, *args, **kwargs) -> None: super().__init__(*args, **kwargs) self.set_type_class('_POOL_HEADER', extensions._POOL_HEADER) @@ -55,52 +56,56 @@ class PoolScanner(plugins.PluginInterface): @classmethod def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: - return [requirements.TranslationLayerRequirement(name = 'primary', - description = 'Kernel Address Space', - architectures = ["Intel32", "Intel64"]), - requirements.SymbolRequirement(name = "nt_symbols", description = "Windows OS")] + return [ + requirements.TranslationLayerRequirement( + name = 'primary', description = 'Kernel Address Space', architectures = ["Intel32", "Intel64"]), + requirements.SymbolRequirement(name = "nt_symbols", description = "Windows OS") + ] def _generator(self): constraints = [ # atom tables - PoolConstraint(b'AtmT', - type_name = self.config["nt_symbols"] + constants.BANG + "_RTL_ATOM_TABLE", - size = (200, None), - page_type = PoolType.PAGED | PoolType.NONPAGED | PoolType.FREE), + PoolConstraint( + b'AtmT', + type_name = self.config["nt_symbols"] + constants.BANG + "_RTL_ATOM_TABLE", + size = (200, None), + page_type = PoolType.PAGED | PoolType.NONPAGED | PoolType.FREE), # processes on windows before windows 8 - PoolConstraint(b'Pro\xe3', - type_name = self.config["nt_symbols"] + constants.BANG + "_EPROCESS", - object_type = "Process", - size = (600, None), - page_type = PoolType.PAGED | PoolType.NONPAGED | PoolType.FREE), + PoolConstraint( + b'Pro\xe3', + type_name = self.config["nt_symbols"] + constants.BANG + "_EPROCESS", + object_type = "Process", + size = (600, None), + page_type = PoolType.PAGED | PoolType.NONPAGED | PoolType.FREE), # processes on windows starting with windows 8 - PoolConstraint(b'Proc', - type_name = self.config["nt_symbols"] + constants.BANG + "_EPROCESS", - object_type = "Process", - size = (600, None), - page_type = PoolType.PAGED | PoolType.NONPAGED | PoolType.FREE), + PoolConstraint( + b'Proc', + type_name = self.config["nt_symbols"] + constants.BANG + "_EPROCESS", + object_type = "Process", + size = (600, None), + page_type = PoolType.PAGED | PoolType.NONPAGED | PoolType.FREE), # files on windows before windows 8 - PoolConstraint(b'Fil\xe5', - type_name = self.config["nt_symbols"] + constants.BANG + "_FILE_OBJECT", - object_type = "File", - size = (150, None), - page_type = PoolType.PAGED | PoolType.NONPAGED | PoolType.FREE), + PoolConstraint( + b'Fil\xe5', + type_name = self.config["nt_symbols"] + constants.BANG + "_FILE_OBJECT", + object_type = "File", + size = (150, None), + page_type = PoolType.PAGED | PoolType.NONPAGED | PoolType.FREE), # files on windows starting with windows 8 - PoolConstraint(b'File', - type_name = self.config["nt_symbols"] + constants.BANG + "_FILE_OBJECT", - object_type = "File", - size = (150, None), - page_type = PoolType.PAGED | PoolType.NONPAGED | PoolType.FREE), + PoolConstraint( + b'File', + type_name = self.config["nt_symbols"] + constants.BANG + "_FILE_OBJECT", + object_type = "File", + size = (150, None), + page_type = PoolType.PAGED | PoolType.NONPAGED | PoolType.FREE), ] # get the object type map - type_map = handles.Handles.list_objects(context = self.context, - layer_name = self.config["primary"], - symbol_table = self.config["nt_symbols"]) + type_map = handles.Handles.list_objects( + context = self.context, layer_name = self.config["primary"], symbol_table = self.config["nt_symbols"]) - cookie = handles.Handles.find_cookie(context = self.context, - layer_name = self.config["primary"], - symbol_table = self.config["nt_symbols"]) + cookie = handles.Handles.find_cookie( + context = self.context, layer_name = self.config["primary"], symbol_table = self.config["nt_symbols"]) # FIXME: replace these lambdas with real functions is_windows_10 = lambda: False @@ -114,18 +119,16 @@ class PoolScanner(plugins.PluginInterface): if not is_windows_10(): scan_layer = self.context.memory[scan_layer].config['memory_layer'] - for constraint, header in self.pool_scan(self._context, - scan_layer, - self.config['nt_symbols'], - constraints, - alignment = 8): + for constraint, header in self.pool_scan( + self._context, scan_layer, self.config['nt_symbols'], constraints, alignment = 8): - mem_object = header.get_object(type_name = constraint.type_name, - type_map = type_map, - use_top_down = is_windows_8_or_later(), - object_type = constraint.object_type, - native_layer_name = 'primary', - cookie = cookie) + mem_object = header.get_object( + type_name = constraint.type_name, + type_map = type_map, + use_top_down = is_windows_8_or_later(), + object_type = constraint.object_type, + native_layer_name = 'primary', + cookie = cookie) if mem_object is None: vollog.log(constants.LOGLEVEL_VVV, "Cannot create an instance of {}".format(constraint.type_name)) @@ -133,9 +136,8 @@ class PoolScanner(plugins.PluginInterface): # generate some type-specific info for sanity checking if constraint.object_type == "Process": - name = mem_object.ImageFileName.cast("string", - max_length = mem_object.ImageFileName.vol.count, - errors = "replace") + name = mem_object.ImageFileName.cast( + "string", max_length = mem_object.ImageFileName.vol.count, errors = "replace") elif constraint.object_type == "File": try: name = mem_object.FileName.String @@ -145,10 +147,7 @@ class PoolScanner(plugins.PluginInterface): else: name = renderers.NotApplicableValue() - yield (0, (constraint.type_name, - format_hints.Hex(header.vol.offset), - header.vol.layer_name, - name)) + yield (0, (constraint.type_name, format_hints.Hex(header.vol.offset), header.vol.layer_name, name)) @classmethod def pool_scan(cls, @@ -184,14 +183,12 @@ class PoolScanner(plugins.PluginInterface): else: pool_header_json_filename = "poolheader-x86" - new_table_name = PoolHeaderSymbolTable.create(context = context, - config_path = configuration.path_join( - context.symbol_space[symbol_table].config_path, - "poolheader" - ), - sub_path = "windows", - filename = pool_header_json_filename, - table_mapping = {'nt_symbols': symbol_table}) + new_table_name = PoolHeaderSymbolTable.create( + context = context, + config_path = configuration.path_join(context.symbol_space[symbol_table].config_path, "poolheader"), + sub_path = "windows", + filename = pool_header_json_filename, + table_mapping = {'nt_symbols': symbol_table}) module = context.module(new_table_name, layer_name, offset = 0) header_type = module.get_type('_POOL_HEADER') @@ -220,8 +217,8 @@ class PoolScanner(plugins.PluginInterface): if (constraint.page_type & PoolType.FREE) and header.PoolType == 0: checks_pass = True - elif ( - constraint.page_type & PoolType.PAGED) and header.PoolType % 2 == 0 and header.PoolType > 0: + elif (constraint.page_type & + PoolType.PAGED) and header.PoolType % 2 == 0 and header.PoolType > 0: checks_pass = True elif (constraint.page_type & PoolType.NONPAGED) and header.PoolType % 2 == 1: checks_pass = True @@ -244,8 +241,5 @@ class PoolScanner(plugins.PluginInterface): yield (constraint, header) def run(self) -> renderers.TreeGrid: - return renderers.TreeGrid([("Tag", str), - ("Offset", format_hints.Hex), - ("Layer", str), - ("Name", str)], + return renderers.TreeGrid([("Tag", str), ("Offset", format_hints.Hex), ("Layer", str), ("Name", str)], self._generator()) diff --git a/volatility/framework/plugins/windows/procdump.py b/volatility/framework/plugins/windows/procdump.py index 027fa3dc3..f54ff9a7f 100644 --- a/volatility/framework/plugins/windows/procdump.py +++ b/volatility/framework/plugins/windows/procdump.py @@ -20,17 +20,15 @@ class ProcDump(interfaces_plugins.PluginInterface): @classmethod def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: # Since we're calling the plugin, make sure we have the plugin's requirements - return [requirements.TranslationLayerRequirement(name = 'primary', - description = 'Kernel Address Space', - architectures = ["Intel32", "Intel64"]), - requirements.SymbolRequirement(name = "nt_symbols", description = "Windows OS")] + return [ + requirements.TranslationLayerRequirement( + name = 'primary', description = 'Kernel Address Space', architectures = ["Intel32", "Intel64"]), + requirements.SymbolRequirement(name = "nt_symbols", description = "Windows OS") + ] def _generator(self, procs): - pe_table_name = PEIntermedSymbols.create(self.context, - self.config_path, - "windows", - "pe") + pe_table_name = PEIntermedSymbols.create(self.context, self.config_path, "windows", "pe") for proc in procs: process_name = utility.array_to_string(proc.ImageFileName) @@ -38,16 +36,18 @@ class ProcDump(interfaces_plugins.PluginInterface): proc_layer_name = proc.add_process_layer() try: - peb = self._context.object(self.config["nt_symbols"] + constants.BANG + "_PEB", - layer_name = proc_layer_name, - offset = proc.Peb) + peb = self._context.object( + self.config["nt_symbols"] + constants.BANG + "_PEB", + layer_name = proc_layer_name, + offset = proc.Peb) - dos_header = self.context.object(pe_table_name + constants.BANG + - "_IMAGE_DOS_HEADER", offset = peb.ImageBaseAddress, - layer_name = proc_layer_name) + dos_header = self.context.object( + pe_table_name + constants.BANG + "_IMAGE_DOS_HEADER", + offset = peb.ImageBaseAddress, + layer_name = proc_layer_name) - filedata = interfaces_plugins.FileInterface( - "pid.{0}.{1:#x}.dmp".format(proc.UniqueProcessId, peb.ImageBaseAddress)) + filedata = interfaces_plugins.FileInterface("pid.{0}.{1:#x}.dmp".format( + proc.UniqueProcessId, peb.ImageBaseAddress)) for offset, data in dos_header.reconstruct(): filedata.data.seek(offset) @@ -65,17 +65,15 @@ class ProcDump(interfaces_plugins.PluginInterface): except exceptions.PagedInvalidAddressException as exp: result_text = "Required memory at {0:#x} is not valid (process exited?)".format(exp.invalid_address) - yield (0, (proc.UniqueProcessId, - process_name, - result_text)) + yield (0, (proc.UniqueProcessId, process_name, result_text)) def run(self): filter_func = pslist.PsList.create_filter([self.config.get('pid', None)]) - return renderers.TreeGrid([("PID", int), - ("Process", str), - ("Result", str)], - self._generator(pslist.PsList.list_processes(context = self.context, - layer_name = self.config['primary'], - symbol_table = self.config['nt_symbols'], - filter_func = filter_func))) + return renderers.TreeGrid([("PID", int), ("Process", str), ("Result", str)], + self._generator( + pslist.PsList.list_processes( + context = self.context, + layer_name = self.config['primary'], + symbol_table = self.config['nt_symbols'], + filter_func = filter_func))) diff --git a/volatility/framework/plugins/windows/pslist.py b/volatility/framework/plugins/windows/pslist.py index e08387dc5..a2e3ec89e 100644 --- a/volatility/framework/plugins/windows/pslist.py +++ b/volatility/framework/plugins/windows/pslist.py @@ -15,18 +15,21 @@ class PsList(plugins.PluginInterface, timeliner.TimeLinerInterface): @classmethod def get_requirements(cls): - return [requirements.TranslationLayerRequirement(name = 'primary', - description = 'Kernel Address Space', - architectures = ["Intel32", "Intel64"]), - requirements.SymbolRequirement(name = "nt_symbols", description = "Windows OS"), - # TODO: Convert this to a ListRequirement so that people can filter on sets of pids - requirements.IntRequirement(name = 'pid', - description = "Process ID to include (all other processes are excluded)", - optional = True), - requirements.BooleanRequirement(name = 'physical', - description = 'Display physical offsets instead of virtual', - default = cls.PHYSICAL_DEFAULT, - optional = True)] + return [ + requirements.TranslationLayerRequirement( + name = 'primary', description = 'Kernel Address Space', architectures = ["Intel32", "Intel64"]), + requirements.SymbolRequirement(name = "nt_symbols", description = "Windows OS"), + # TODO: Convert this to a ListRequirement so that people can filter on sets of pids + requirements.IntRequirement( + name = 'pid', + description = "Process ID to include (all other processes are excluded)", + optional = True), + requirements.BooleanRequirement( + name = 'physical', + description = 'Display physical offsets instead of virtual', + default = cls.PHYSICAL_DEFAULT, + optional = True) + ] @classmethod def create_filter(cls, pid_list: List[int] = None) -> Callable[[int], bool]: @@ -74,10 +77,11 @@ class PsList(plugins.PluginInterface, timeliner.TimeLinerInterface): def _generator(self): - for proc in self.list_processes(self.context, - self.config['primary'], - self.config['nt_symbols'], - filter_func = self.create_filter([self.config.get('pid', None)])): + for proc in self.list_processes( + self.context, + self.config['primary'], + self.config['nt_symbols'], + filter_func = self.create_filter([self.config.get('pid', None)])): if not self.config.get('physical', self.PHYSICAL_DEFAULT): offset = proc.vol.offset @@ -88,18 +92,11 @@ class PsList(plugins.PluginInterface, timeliner.TimeLinerInterface): raise TypeError("Primary layer is not an intel layer") (_, offset, _, _) = list(memory.mapping(offset = proc.vol.offset, length = 0))[0] - yield (0, (proc.UniqueProcessId, - proc.InheritedFromUniqueProcessId, - proc.ImageFileName.cast("string", - max_length = proc.ImageFileName.vol.count, - errors = 'replace'), - format_hints.Hex(offset), - proc.ActiveThreads, - proc.get_handle_count(), - proc.get_session_id(), - proc.get_is_wow64(), - proc.get_create_time(), - proc.get_exit_time())) + yield (0, + (proc.UniqueProcessId, proc.InheritedFromUniqueProcessId, + proc.ImageFileName.cast("string", max_length = proc.ImageFileName.vol.count, errors = 'replace'), + format_hints.Hex(offset), proc.ActiveThreads, proc.get_handle_count(), proc.get_session_id(), + proc.get_is_wow64(), proc.get_create_time(), proc.get_exit_time())) def generate_timeline(self): for row in self._generator(): @@ -111,14 +108,8 @@ class PsList(plugins.PluginInterface, timeliner.TimeLinerInterface): def run(self): offsettype = "(V)" if not self.config.get('physical', self.PHYSICAL_DEFAULT) else "(P)" - return renderers.TreeGrid([("PID", int), - ("PPID", int), - ("ImageFileName", str), - ("Offset{0}".format(offsettype), format_hints.Hex), - ("Threads", int), - ("Handles", int), - ("SessionId", int), - ("Wow64", bool), - ("CreateTime", datetime.datetime), - ("ExitTime", datetime.datetime)], + return renderers.TreeGrid([("PID", int), ("PPID", int), ("ImageFileName", str), + ("Offset{0}".format(offsettype), format_hints.Hex), ("Threads", int), + ("Handles", int), ("SessionId", int), ("Wow64", bool), + ("CreateTime", datetime.datetime), ("ExitTime", datetime.datetime)], self._generator()) diff --git a/volatility/framework/plugins/windows/pstree.py b/volatility/framework/plugins/windows/pstree.py index 84197ebed..2074587dd 100644 --- a/volatility/framework/plugins/windows/pstree.py +++ b/volatility/framework/plugins/windows/pstree.py @@ -45,18 +45,10 @@ class PsTree(pslist.PsList): def yield_processes(pid): proc = self._processes[pid] - row = (proc.UniqueProcessId, - proc.InheritedFromUniqueProcessId, - proc.ImageFileName.cast("string", - max_length = proc.ImageFileName.vol.count, - errors = 'replace'), - format_hints.Hex(offset), - proc.ActiveThreads, - proc.get_handle_count(), - proc.get_session_id(), - proc.get_is_wow64(), - proc.get_create_time(), - proc.get_exit_time()) + row = (proc.UniqueProcessId, proc.InheritedFromUniqueProcessId, + proc.ImageFileName.cast("string", max_length = proc.ImageFileName.vol.count, errors = 'replace'), + format_hints.Hex(offset), proc.ActiveThreads, proc.get_handle_count(), proc.get_session_id(), + proc.get_is_wow64(), proc.get_create_time(), proc.get_exit_time()) yield (self._levels[pid] - 1, row) for child_pid in self._children.get(pid, []): diff --git a/volatility/framework/plugins/windows/registry/hivelist.py b/volatility/framework/plugins/windows/registry/hivelist.py index 463356cad..4f589d5a7 100644 --- a/volatility/framework/plugins/windows/registry/hivelist.py +++ b/volatility/framework/plugins/windows/registry/hivelist.py @@ -11,23 +11,22 @@ class HiveList(plugins.PluginInterface): @classmethod def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: - return [requirements.TranslationLayerRequirement(name = 'primary', - description = 'Kernel Address Space', - architectures = ["Intel32", "Intel64"]), - requirements.SymbolRequirement(name = "nt_symbols", description = "Windows OS"), - requirements.StringRequirement(name = 'filter', - description = "String to filter hive names returned", - optional = True, - default = None)] + return [ + requirements.TranslationLayerRequirement( + name = 'primary', description = 'Kernel Address Space', architectures = ["Intel32", "Intel64"]), + requirements.SymbolRequirement(name = "nt_symbols", description = "Windows OS"), + requirements.StringRequirement( + name = 'filter', description = "String to filter hive names returned", optional = True, default = None) + ] def _generator(self) -> Iterator[Tuple[int, Tuple[int, str]]]: - for hive in self.list_hives(context = self.context, - layer_name = self.config["primary"], - symbol_table = self.config["nt_symbols"], - filter_string = self.config.get('filter', None)): + for hive in self.list_hives( + context = self.context, + layer_name = self.config["primary"], + symbol_table = self.config["nt_symbols"], + filter_string = self.config.get('filter', None)): - yield (0, (format_hints.Hex(hive.vol.offset), - hive.get_name() or "")) + yield (0, (format_hints.Hex(hive.vol.offset), hive.get_name() or "")) @classmethod def list_hives(cls, @@ -51,6 +50,4 @@ class HiveList(plugins.PluginInterface): yield hive def run(self) -> renderers.TreeGrid: - return renderers.TreeGrid([("Offset", format_hints.Hex), - ("FileFullPath", str)], - self._generator()) + return renderers.TreeGrid([("Offset", format_hints.Hex), ("FileFullPath", str)], self._generator()) diff --git a/volatility/framework/plugins/windows/registry/printkey.py b/volatility/framework/plugins/windows/registry/printkey.py index b499906f4..6211c49e7 100644 --- a/volatility/framework/plugins/windows/registry/printkey.py +++ b/volatility/framework/plugins/windows/registry/printkey.py @@ -16,27 +16,18 @@ class PrintKey(interfaces.plugins.PluginInterface): @classmethod def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: - return [requirements.TranslationLayerRequirement(name = 'primary', - description = 'Kernel Address Space', - architectures = ["Intel32", "Intel64"]), - requirements.SymbolRequirement(name = "nt_symbols", - description = "Windows OS"), - requirements.IntRequirement(name = 'offset', - description = "Hive Offset", - default = None, - optional = True), - requirements.StringRequirement(name = 'key', - description = "Key to start from", - default = None, - optional = True), - requirements.BooleanRequirement(name = 'recurse', - description = 'Recurses through keys', - default = False, - optional = True)] + return [ + requirements.TranslationLayerRequirement( + name = 'primary', description = 'Kernel Address Space', architectures = ["Intel32", "Intel64"]), + requirements.SymbolRequirement(name = "nt_symbols", description = "Windows OS"), + requirements.IntRequirement(name = 'offset', description = "Hive Offset", default = None, optional = True), + requirements.StringRequirement( + name = 'key', description = "Key to start from", default = None, optional = True), + requirements.BooleanRequirement( + name = 'recurse', description = 'Recurses through keys', default = False, optional = True) + ] - def hive_walker(self, - hive: RegistryHive, - node_path: Sequence[objects.Struct] = None, + def hive_walker(self, hive: RegistryHive, node_path: Sequence[objects.Struct] = None, key_path: str = None) -> Generator: """Walks through a set of nodes from a given node (last one in node_path). Avoids loops by not traversing into nodes already present in the node_path @@ -51,25 +42,14 @@ class PrintKey(interfaces.plugins.PluginInterface): last_write_time = conversion.wintime_to_datetime(node.LastWriteTime.QuadPart) for key_node in node.get_subkeys(): - result = (key_path.count("\\"), - (last_write_time, - renderers.format_hints.Hex(hive.hive_offset), - "Key", - key_path, - key_node.get_name(), - "", - key_node.get_volatile())) + result = (key_path.count("\\"), (last_write_time, renderers.format_hints.Hex(hive.hive_offset), "Key", + key_path, key_node.get_name(), "", key_node.get_volatile())) yield result for value_node in node.get_values(): - result = (key_path.count("\\"), - (last_write_time, - renderers.format_hints.Hex(hive.hive_offset), - RegValueTypes.get(value_node.Type).name, - key_path, - value_node.get_name(), - str(value_node.decode_data()), - node.get_volatile())) + result = (key_path.count("\\"), (last_write_time, renderers.format_hints.Hex(hive.hive_offset), + RegValueTypes.get(value_node.Type).name, key_path, value_node.get_name(), + str(value_node.decode_data()), node.get_volatile())) yield result if self.config.get('recurse', None): @@ -82,9 +62,10 @@ class PrintKey(interfaces.plugins.PluginInterface): if self.config.get('offset', None) is None: try: import volatility.plugins.windows.registry.hivelist as hivelist - hive_offsets = [hive.vol.offset for hive in hivelist.HiveList.list_hives(self.context, - self.config['primary'], - self.config['nt_symbols'])] + hive_offsets = [ + hive.vol.offset for hive in hivelist.HiveList.list_hives(self.context, self.config['primary'], + self.config['nt_symbols']) + ] except ImportError: vollog.warning("Unable to import windows.hivelist plugin, please provide a hive offset") raise ValueError("Unable to import windows.hivelist plugin, please provide a hive offset") @@ -93,9 +74,8 @@ class PrintKey(interfaces.plugins.PluginInterface): for hive_offset in hive_offsets: # Construct the hive - reg_config_path = self.make_subconfig(hive_offset = hive_offset, - base_layer = self.config['primary'], - nt_symbols = self.config['nt_symbols']) + reg_config_path = self.make_subconfig( + hive_offset = hive_offset, base_layer = self.config['primary'], nt_symbols = self.config['nt_symbols']) hive = RegistryHive(self.context, reg_config_path, name = 'hive' + hex(hive_offset)) try: self.context.memory.add_layer(hive) @@ -109,27 +89,18 @@ class PrintKey(interfaces.plugins.PluginInterface): except (exceptions.PagedInvalidAddressException, KeyError) as excp: if type(excp) == KeyError: - vollog.debug( - "Key '{}' not found in Hive at offset {}.".format(self.config['key'], hex(hive_offset))) + vollog.debug("Key '{}' not found in Hive at offset {}.".format(self.config['key'], + hex(hive_offset))) else: vollog.debug("Invalid address identified in Hive: {}".format(hex(excp.invalid_address))) - result = (0, - (renderers.UnreadableValue(), - format_hints.Hex(hive.hive_offset), - "Key", - self.config.get('key', "ROOT"), - renderers.UnreadableValue(), - renderers.UnreadableValue(), - renderers.UnreadableValue())) + result = (0, (renderers.UnreadableValue(), format_hints.Hex(hive.hive_offset), "Key", + self.config.get('key', "ROOT"), renderers.UnreadableValue(), renderers.UnreadableValue(), + renderers.UnreadableValue())) yield result def run(self): - return TreeGrid(columns = [('Last Write Time', datetime.datetime), - ('Hive Offset', format_hints.Hex), - ('Type', str), - ('Key', str), - ('Name', str), - ('Data', str), - ('Volatile', bool)], - generator = self.registry_walker()) + return TreeGrid( + columns = [('Last Write Time', datetime.datetime), ('Hive Offset', format_hints.Hex), ('Type', str), + ('Key', str), ('Name', str), ('Data', str), ('Volatile', bool)], + generator = self.registry_walker()) diff --git a/volatility/framework/plugins/windows/registry/userassist.py b/volatility/framework/plugins/windows/registry/userassist.py index 28cefaaa5..52ced92d9 100644 --- a/volatility/framework/plugins/windows/registry/userassist.py +++ b/volatility/framework/plugins/windows/registry/userassist.py @@ -29,15 +29,12 @@ class UserAssist(interfaces.plugins.PluginInterface): @classmethod def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: - return [requirements.TranslationLayerRequirement(name = 'primary', - description = 'Kernel Address Space', - architectures = ["Intel32", "Intel64"]), - requirements.SymbolRequirement(name = "nt_symbols", - description = "Windows OS"), - requirements.IntRequirement(name = 'offset', - description = "Hive Offset", - default = None, - optional = True)] + return [ + requirements.TranslationLayerRequirement( + name = 'primary', description = 'Kernel Address Space', architectures = ["Intel32", "Intel64"]), + requirements.SymbolRequirement(name = "nt_symbols", description = "Windows OS"), + requirements.IntRequirement(name = 'offset', description = "Hive Offset", default = None, optional = True) + ] def parse_userassist_data(self, reg_val): """Reads the raw data of a _CM_KEY_VALUE and returns a dict of userassist fields""" @@ -85,8 +82,7 @@ class UserAssist(interfaces.plugins.PluginInterface): else: item["id"] = int(userassist_obj.ID) item["count"] = int(userassist_obj.CountStartingAtFive - if userassist_obj.CountStartingAtFive < 5 - else userassist_obj.CountStartingAtFive - 5) + if userassist_obj.CountStartingAtFive < 5 else userassist_obj.CountStartingAtFive - 5) item["focus"] = renderers.NotApplicableValue() item["time"] = renderers.NotApplicableValue() @@ -102,14 +98,14 @@ class UserAssist(interfaces.plugins.PluginInterface): elif self._win7 is False: self._userassist_type_name = "_VOL_USERASSIST_TYPES_XP" - self._userassist_size = self.context.symbol_space.get_type( - self._reg_table_name + constants.BANG + self._userassist_type_name).size + self._userassist_size = self.context.symbol_space.get_type(self._reg_table_name + constants.BANG + + self._userassist_type_name).size def _win7_or_later(self) -> bool: # TODO: change this if there is a better way of determining the OS version # _KUSER_SHARED_DATA.CookiePad is in Windows 6.1 (Win7) and later - return self.context.symbol_space.get_type( - self.config['nt_symbols'] + constants.BANG + "_KUSER_SHARED_DATA").has_member('CookiePad') + return self.context.symbol_space.get_type(self.config['nt_symbols'] + constants.BANG + + "_KUSER_SHARED_DATA").has_member('CookiePad') def list_userassist(self, hive: RegistryHive): """Generate userassist data for a registry hive.""" @@ -125,8 +121,8 @@ class UserAssist(interfaces.plugins.PluginInterface): self._determine_userassist_type() - userassist_node_path = hive.get_key("software\\microsoft\\windows\\currentversion\\explorer\\userassist", - return_list = True) + userassist_node_path = hive.get_key( + "software\\microsoft\\windows\\currentversion\\explorer\\userassist", return_list = True) if not userassist_node_path: vollog.warning("list_userassist did not find a valid node_path (or None)") @@ -141,37 +137,32 @@ class UserAssist(interfaces.plugins.PluginInterface): countkey_last_write_time = conversion.wintime_to_datetime(countkey.LastWriteTime.QuadPart) # output the parent Count key - result = (0, - (renderers.format_hints.Hex(hive.hive_offset), - hive_name, - countkey_path, - countkey_last_write_time, - "Key", - renderers.NotApplicableValue(), - renderers.NotApplicableValue(), - renderers.NotApplicableValue(), - renderers.NotApplicableValue(), - renderers.NotApplicableValue(), - renderers.NotApplicableValue(), - renderers.NotApplicableValue())) # type: Tuple[int, Tuple[format_hints.Hex, Any, Any, Any, Any, Any, Any, Any, Any, Any, Any, Any]] + result = ( + 0, (renderers.format_hints.Hex(hive.hive_offset), hive_name, + countkey_path, countkey_last_write_time, "Key", renderers.NotApplicableValue(), + renderers.NotApplicableValue(), renderers.NotApplicableValue(), renderers.NotApplicableValue(), + renderers.NotApplicableValue(), renderers.NotApplicableValue(), renderers.NotApplicableValue()) + ) # type: Tuple[int, Tuple[format_hints.Hex, Any, Any, Any, Any, Any, Any, Any, Any, Any, Any, Any]] yield result # output any subkeys under Count for subkey in countkey.get_subkeys(): subkey_name = subkey.get_name() - result = (1, (renderers.format_hints.Hex(hive.hive_offset), - hive_name, - countkey_path, - countkey_last_write_time, - "Subkey", - subkey_name, - renderers.NotApplicableValue(), - renderers.NotApplicableValue(), - renderers.NotApplicableValue(), - renderers.NotApplicableValue(), - renderers.NotApplicableValue(), - renderers.NotApplicableValue(),)) + result = (1, ( + renderers.format_hints.Hex(hive.hive_offset), + hive_name, + countkey_path, + countkey_last_write_time, + "Subkey", + subkey_name, + renderers.NotApplicableValue(), + renderers.NotApplicableValue(), + renderers.NotApplicableValue(), + renderers.NotApplicableValue(), + renderers.NotApplicableValue(), + renderers.NotApplicableValue(), + )) yield result # output any values under Count @@ -189,18 +180,20 @@ class UserAssist(interfaces.plugins.PluginInterface): value_name = value_name.replace(guid, self._folder_guids[guid]) userassist_data_dict = self.parse_userassist_data(value) - result = (1, (renderers.format_hints.Hex(hive.hive_offset), - hive_name, - countkey_path, - countkey_last_write_time, - "Value", - value_name, - userassist_data_dict["id"], - userassist_data_dict["count"], - userassist_data_dict["focus"], - userassist_data_dict["time"], - userassist_data_dict["lastupdated"], - format_hints.HexBytes(userassist_data_dict["rawdata"]),)) + result = (1, ( + renderers.format_hints.Hex(hive.hive_offset), + hive_name, + countkey_path, + countkey_last_write_time, + "Value", + value_name, + userassist_data_dict["id"], + userassist_data_dict["count"], + userassist_data_dict["focus"], + userassist_data_dict["time"], + userassist_data_dict["lastupdated"], + format_hints.HexBytes(userassist_data_dict["rawdata"]), + )) yield result def _generator(self): @@ -209,27 +202,26 @@ class UserAssist(interfaces.plugins.PluginInterface): if self.config.get('offset', None) is None: try: import volatility.plugins.windows.registry.hivelist as hivelist - hive_offsets = [hive.vol.offset for hive in - hivelist.HiveList.list_hives(context = self.context, - layer_name = self.config['primary'], - symbol_table = self.config['nt_symbols'], - filter_string = "ntuser.dat")] + hive_offsets = [ + hive.vol.offset for hive in hivelist.HiveList.list_hives( + context = self.context, + layer_name = self.config['primary'], + symbol_table = self.config['nt_symbols'], + filter_string = "ntuser.dat") + ] except ImportError: vollog.warning("Unable to import windows.hivelist plugin, please provide a hive offset") raise ValueError("Unable to import windows.hivelist plugin, please provide a hive offset") else: hive_offsets = [self.config['offset']] - self._reg_table_name = intermed.IntermediateSymbolTable.create(self.context, - self._config_path, - 'windows', + self._reg_table_name = intermed.IntermediateSymbolTable.create(self.context, self._config_path, 'windows', 'registry') for hive_offset in hive_offsets: # Construct the hive - reg_config_path = self.make_subconfig(hive_offset = hive_offset, - base_layer = self.config['primary'], - nt_symbols = self.config['nt_symbols']) + reg_config_path = self.make_subconfig( + hive_offset = hive_offset, base_layer = self.config['primary'], nt_symbols = self.config['nt_symbols']) hive_name = None try: @@ -245,33 +237,17 @@ class UserAssist(interfaces.plugins.PluginInterface): "software\\microsoft\\windows\\currentversion\\explorer\\userassist", hex(hive_offset))) # yield UnreadableValues when an exception occurs for a given hive_offset - result = (0, - (renderers.format_hints.Hex(hive_offset), - hive_name if hive_name else renderers.UnreadableValue(), - renderers.UnreadableValue(), - renderers.UnreadableValue(), - renderers.UnreadableValue(), - renderers.UnreadableValue(), - renderers.UnreadableValue(), - renderers.UnreadableValue(), - renderers.UnreadableValue(), - renderers.UnreadableValue(), - renderers.UnreadableValue(), - renderers.UnreadableValue())) + result = (0, (renderers.format_hints.Hex(hive_offset), + hive_name if hive_name else renderers.UnreadableValue(), renderers.UnreadableValue(), + renderers.UnreadableValue(), renderers.UnreadableValue(), renderers.UnreadableValue(), + renderers.UnreadableValue(), renderers.UnreadableValue(), renderers.UnreadableValue(), + renderers.UnreadableValue(), renderers.UnreadableValue(), renderers.UnreadableValue())) yield result def run(self): - return renderers.TreeGrid([("Hive Offset", renderers.format_hints.Hex), - ("Hive Name", str), - ("Path", str), - ("Last Write Time", datetime.datetime), - ("Type", str), - ("Name", str), - ("ID", int), - ("Count", int), - ("Focus Count", int), - ("Time Focused", str), - ("Last Updated", datetime.datetime), - ("Raw Data", format_hints.HexBytes)], + return renderers.TreeGrid([("Hive Offset", renderers.format_hints.Hex), ("Hive Name", str), ("Path", str), + ("Last Write Time", datetime.datetime), ("Type", str), ("Name", str), ("ID", int), + ("Count", int), ("Focus Count", int), ("Time Focused", str), + ("Last Updated", datetime.datetime), ("Raw Data", format_hints.HexBytes)], self._generator()) diff --git a/volatility/framework/plugins/windows/ssdt.py b/volatility/framework/plugins/windows/ssdt.py index 198b6f9f2..53b1717b5 100644 --- a/volatility/framework/plugins/windows/ssdt.py +++ b/volatility/framework/plugins/windows/ssdt.py @@ -17,10 +17,11 @@ class SSDT(plugins.PluginInterface): @classmethod def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: - return [requirements.TranslationLayerRequirement(name = 'primary', - description = 'Kernel Address Space', - architectures = ["Intel32", "Intel64"]), - requirements.SymbolRequirement(name = "nt_symbols", description = "Windows OS")] + return [ + requirements.TranslationLayerRequirement( + name = 'primary', description = 'Kernel Address Space', architectures = ["Intel32", "Intel64"]), + requirements.SymbolRequirement(name = "nt_symbols", description = "Windows OS") + ] def _generator(self, mods: Iterator[Any]) -> Iterator[Tuple[int, Tuple[int, int, str, str]]]: @@ -42,11 +43,7 @@ class SSDT(plugins.PluginInterface): else: symbol_table_name = None - context_module = contexts.SizedModule(self._context, - module_name, - layer_name, - mod.DllBase, - mod.SizeOfImage, + context_module = contexts.SizedModule(self._context, module_name, layer_name, mod.DllBase, mod.SizeOfImage, symbol_table_name) context_modules.append(context_module) @@ -82,9 +79,11 @@ class SSDT(plugins.PluginInterface): find_address = passthrough - functions = ntkrnlmp.object(type_name = "array", offset = kvo + service_table_address, - subtype = ntkrnlmp.get_type(array_subtype), - count = service_limit) + functions = ntkrnlmp.object( + type_name = "array", + offset = kvo + service_table_address, + subtype = ntkrnlmp.get_type(array_subtype), + count = service_limit) for idx, function in enumerate(functions): @@ -96,22 +95,13 @@ class SSDT(plugins.PluginInterface): for symbol in symbol_generator: symbols_found = True - yield (0, (idx, - format_hints.Hex(function), - module_name, - symbol.split(constants.BANG)[1])) + yield (0, (idx, format_hints.Hex(function), module_name, symbol.split(constants.BANG)[1])) if not symbols_found: - yield (0, (idx, - format_hints.Hex(function), - module_name, - renderers.NotAvailableValue())) + yield (0, (idx, format_hints.Hex(function), module_name, renderers.NotAvailableValue())) def run(self) -> renderers.TreeGrid: - return renderers.TreeGrid([("Index", int), - ("Address", format_hints.Hex), - ("Module", str), - ("Symbol", str)], - self._generator(modules.Modules.list_modules(self.context, - self.config['primary'], - self.config['nt_symbols']))) + return renderers.TreeGrid([("Index", int), ("Address", format_hints.Hex), ("Module", str), ("Symbol", str)], + self._generator( + modules.Modules.list_modules(self.context, self.config['primary'], + self.config['nt_symbols']))) diff --git a/volatility/framework/plugins/windows/strings.py b/volatility/framework/plugins/windows/strings.py index 8425efae4..234932b19 100644 --- a/volatility/framework/plugins/windows/strings.py +++ b/volatility/framework/plugins/windows/strings.py @@ -15,18 +15,17 @@ class Strings(interfaces.plugins.PluginInterface): @classmethod def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: - return [requirements.TranslationLayerRequirement(name = 'primary', - description = 'Kernel Address Space', - architectures = ["Intel32", "Intel64"]), - requirements.SymbolRequirement(name = "nt_symbols", description = "Windows OS"), - requirements.URIRequirement(name = "strings_file", description = "Strings file")] + return [ + requirements.TranslationLayerRequirement( + name = 'primary', description = 'Kernel Address Space', architectures = ["Intel32", "Intel64"]), + requirements.SymbolRequirement(name = "nt_symbols", description = "Windows OS"), + requirements.URIRequirement(name = "strings_file", description = "Strings file") + ] # TODO: Make URLRequirement that can accept a file address which the framework can open def run(self): - return renderers.TreeGrid([("String", str), - ("Physical Address", format_hints.Hex), - ("Result", str)], + return renderers.TreeGrid([("String", str), ("Physical Address", format_hints.Hex), ("Result", str)], self._generator()) def _generator(self) -> Generator[Tuple, None, None]: @@ -73,8 +72,7 @@ class Strings(interfaces.plugins.PluginInterface): # TODO: Include kernel modules - for process in pslist.PsList.list_processes(self.context, - self.config['primary'], + for process in pslist.PsList.list_processes(self.context, self.config['primary'], self.config['nt_symbols']): proc_layer_name = process.add_process_layer() proc_layer = self.context.memory[proc_layer_name] diff --git a/volatility/framework/plugins/windows/vaddump.py b/volatility/framework/plugins/windows/vaddump.py index 585fd4b0d..0480c709a 100644 --- a/volatility/framework/plugins/windows/vaddump.py +++ b/volatility/framework/plugins/windows/vaddump.py @@ -45,10 +45,8 @@ class VadDump(interfaces_plugins.PluginInterface): for vad in vadinfo.VadInfo.list_vads(proc, filter_func = filter_func): try: - filedata = interfaces_plugins.FileInterface( - "pid.{0}.vad.{1:#x}-{2:#x}.dmp".format(proc.UniqueProcessId, - vad.get_start(), - vad.get_end())) + filedata = interfaces_plugins.FileInterface("pid.{0}.vad.{1:#x}-{2:#x}.dmp".format( + proc.UniqueProcessId, vad.get_start(), vad.get_end())) offset = vad.get_start() out_of_range = vad.get_start() + vad.get_end() @@ -65,17 +63,15 @@ class VadDump(interfaces_plugins.PluginInterface): except exceptions.InvalidAddressException: result_text = "Unable to dump {0:#x} - {1:#x}".format(vad.get_start(), vad.get_end()) - yield (0, (proc.UniqueProcessId, - process_name, - result_text)) + yield (0, (proc.UniqueProcessId, process_name, result_text)) def run(self): filter_func = pslist.PsList.create_filter([self.config.get('pid', None)]) - return renderers.TreeGrid([("PID", int), - ("Process", str), - ("Result", str)], - self._generator(pslist.PsList.list_processes(context = self.context, - layer_name = self.config['primary'], - symbol_table = self.config['nt_symbols'], - filter_func = filter_func))) + return renderers.TreeGrid([("PID", int), ("Process", str), ("Result", str)], + self._generator( + pslist.PsList.list_processes( + context = self.context, + layer_name = self.config['primary'], + symbol_table = self.config['nt_symbols'], + filter_func = filter_func))) diff --git a/volatility/framework/plugins/windows/vadinfo.py b/volatility/framework/plugins/windows/vadinfo.py index 087c615cf..a8a3d6fc3 100644 --- a/volatility/framework/plugins/windows/vadinfo.py +++ b/volatility/framework/plugins/windows/vadinfo.py @@ -49,9 +49,7 @@ class VadInfo(interfaces.plugins.PluginInterface): optional = True)] @classmethod - def protect_values(cls, - context: interfaces.context.ContextInterface, - virtual_layer: str, + def protect_values(cls, context: interfaces.context.ContextInterface, virtual_layer: str, nt_symbols: str) -> Iterable[int]: """Look up the array of memory protection constants from the memory sample. These don't change often, but if they do in the future, then finding them @@ -60,9 +58,8 @@ class VadInfo(interfaces.plugins.PluginInterface): kvo = context.memory[virtual_layer].config["kernel_virtual_offset"] ntkrnlmp = context.module(nt_symbols, layer_name = virtual_layer, offset = kvo) addr = ntkrnlmp.get_symbol("MmProtectToValue").address - values = ntkrnlmp.object(type_name = "array", offset = kvo + addr, - subtype = ntkrnlmp.get_type("int"), - count = 32) + values = ntkrnlmp.object( + type_name = "array", offset = kvo + addr, subtype = ntkrnlmp.get_type("int"), count = 32) return values # type: ignore @classmethod @@ -81,6 +78,7 @@ class VadInfo(interfaces.plugins.PluginInterface): filter_func = passthrough if self.config.get('address', None) is not None: + def filter_function(x): return x.get_start() not in [self.config['address']] @@ -90,36 +88,24 @@ class VadInfo(interfaces.plugins.PluginInterface): process_name = utility.array_to_string(proc.ImageFileName) for vad in self.list_vads(proc, filter_func = filter_func): - yield (0, (proc.UniqueProcessId, - process_name, - format_hints.Hex(vad.vol.offset), - format_hints.Hex(vad.get_start()), - format_hints.Hex(vad.get_end()), - vad.get_tag(), - vad.get_protection(self.protect_values(self.context, - self.config['primary'], - self.config['nt_symbols']), winnt_protections), - vad.get_commit_charge(), - vad.get_private_memory(), - format_hints.Hex(vad.get_parent()), - vad.get_file_name())) + yield (0, (proc.UniqueProcessId, process_name, format_hints.Hex(vad.vol.offset), + format_hints.Hex(vad.get_start()), format_hints.Hex(vad.get_end()), vad.get_tag(), + vad.get_protection( + self.protect_values(self.context, self.config['primary'], self.config['nt_symbols']), + winnt_protections), vad.get_commit_charge(), vad.get_private_memory(), + format_hints.Hex(vad.get_parent()), vad.get_file_name())) def run(self): filter_func = pslist.PsList.create_filter([self.config.get('pid', None)]) - return renderers.TreeGrid([("PID", int), - ("Process", str), - ("Offset", format_hints.Hex), - ("Start VPN", format_hints.Hex), - ("End VPN", format_hints.Hex), - ("Tag", str), - ("Protection", str), - ("CommitCharge", int), - ("PrivateMemory", int), - ("Parent", format_hints.Hex), - ("File", str)], - self._generator(pslist.PsList.list_processes(context = self.context, - layer_name = self.config['primary'], - symbol_table = self.config['nt_symbols'], - filter_func = filter_func))) + return renderers.TreeGrid([("PID", int), ("Process", str), ("Offset", format_hints.Hex), + ("Start VPN", format_hints.Hex), ("End VPN", format_hints.Hex), ("Tag", str), + ("Protection", str), ("CommitCharge", int), ("PrivateMemory", int), + ("Parent", format_hints.Hex), ("File", str)], + self._generator( + pslist.PsList.list_processes( + context = self.context, + layer_name = self.config['primary'], + symbol_table = self.config['nt_symbols'], + filter_func = filter_func))) diff --git a/volatility/framework/plugins/windows/vadyarascan.py b/volatility/framework/plugins/windows/vadyarascan.py index 89faf9ad1..5d3180983 100644 --- a/volatility/framework/plugins/windows/vadyarascan.py +++ b/volatility/framework/plugins/windows/vadyarascan.py @@ -20,25 +20,22 @@ class VadYaraScan(interfaces.plugins.PluginInterface): @classmethod def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: - return [requirements.TranslationLayerRequirement(name = 'primary', - description = "Primary kernel address space", - architectures = ["Intel32", "Intel64"]), - requirements.SymbolRequirement(name = "nt_symbols", description = "Windows OS"), - requirements.BooleanRequirement(name = "wide", - description = "Match wide (unicode) strings", - default = False, - optional = True), - requirements.StringRequirement(name = "yara_rules", - description = "Yara rules (as a string)", - optional = True), - requirements.URIRequirement(name = "yara_file", - description = "Yara rules (as a file)", - optional = True), - requirements.IntRequirement(name = "max_size", - default = 0x40000000, - description = "Set the maximum size (default is 1GB)", - optional = True) - ] + return [ + requirements.TranslationLayerRequirement( + name = 'primary', description = "Primary kernel address space", architectures = ["Intel32", + "Intel64"]), + requirements.SymbolRequirement(name = "nt_symbols", description = "Windows OS"), + requirements.BooleanRequirement( + name = "wide", description = "Match wide (unicode) strings", default = False, optional = True), + requirements.StringRequirement( + name = "yara_rules", description = "Yara rules (as a string)", optional = True), + requirements.URIRequirement(name = "yara_file", description = "Yara rules (as a file)", optional = True), + requirements.IntRequirement( + name = "max_size", + default = 0x40000000, + description = "Set the maximum size (default is 1GB)", + optional = True) + ] def _generator(self): @@ -60,13 +57,15 @@ class VadYaraScan(interfaces.plugins.PluginInterface): filter_func = pslist.PsList.create_filter([self.config.get('pid', None)]) - for task in pslist.PsList.list_processes(context = self.context, - layer_name = self.config['primary'], - symbol_table = self.config['nt_symbols'], - filter_func = filter_func): - for offset, name in layer.scan(context = self.context, - scanner = yarascan.YaraScanner(rules = rules), - sections = self.get_vad_maps(task)): + for task in pslist.PsList.list_processes( + context = self.context, + layer_name = self.config['primary'], + symbol_table = self.config['nt_symbols'], + filter_func = filter_func): + for offset, name in layer.scan( + context = self.context, + scanner = yarascan.YaraScanner(rules = rules), + sections = self.get_vad_maps(task)): yield format_hints.Hex(offset), name def get_vad_maps(self, task: Any) -> Iterable[Tuple[int, int]]: @@ -80,5 +79,4 @@ class VadYaraScan(interfaces.plugins.PluginInterface): yield (start, end - start) def run(self): - return renderers.TreeGrid([('Offset', format_hints.Hex), - ('Rule', str)], self._generator()) + return renderers.TreeGrid([('Offset', format_hints.Hex), ('Rule', str)], self._generator()) diff --git a/volatility/framework/plugins/windows/verinfo.py b/volatility/framework/plugins/windows/verinfo.py index eda602539..6aeb9d277 100644 --- a/volatility/framework/plugins/windows/verinfo.py +++ b/volatility/framework/plugins/windows/verinfo.py @@ -27,16 +27,14 @@ class VerInfo(interfaces_plugins.PluginInterface): def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: ## TODO: we might add a regex option on the name later, but otherwise we're good ## TODO: and we don't want any CLI options from pslist, modules, or moddump - return [requirements.TranslationLayerRequirement(name = 'primary', - description = 'Kernel Address Space', - architectures = ["Intel32", "Intel64"]), - requirements.SymbolRequirement(name = "nt_symbols", description = "Windows OS"), ] + return [ + requirements.TranslationLayerRequirement( + name = 'primary', description = 'Kernel Address Space', architectures = ["Intel32", "Intel64"]), + requirements.SymbolRequirement(name = "nt_symbols", description = "Windows OS"), + ] @classmethod - def get_version_information(cls, - context: interfaces.context.ContextInterface, - pe_table_name: str, - layer_name: str, + def get_version_information(cls, context: interfaces.context.ContextInterface, pe_table_name: str, layer_name: str, base_address: int) -> Tuple[int, int, int, int]: """Get File and Product version information from PE files @@ -52,9 +50,8 @@ class VerInfo(interfaces_plugins.PluginInterface): pe_data = io.BytesIO() - dos_header = context.object(pe_table_name + constants.BANG + - "_IMAGE_DOS_HEADER", offset = base_address, - layer_name = layer_name) + dos_header = context.object( + pe_table_name + constants.BANG + "_IMAGE_DOS_HEADER", offset = base_address, layer_name = layer_name) for offset, data in dos_header.reconstruct(): pe_data.seek(offset) @@ -72,8 +69,7 @@ class VerInfo(interfaces_plugins.PluginInterface): return major, minor, product, build - def _generator(self, - procs: Generator[interfaces.objects.ObjectInterface, None, None], + def _generator(self, procs: Generator[interfaces.objects.ObjectInterface, None, None], mods: Generator[interfaces.objects.ObjectInterface, None, None], session_layers: Generator[str, None, None]): """Generates a list of PE file version info for processes, dlls, and modules. @@ -84,10 +80,7 @@ class VerInfo(interfaces_plugins.PluginInterface): session_layers: of layers in the session to be checked """ - pe_table_name = PEIntermedSymbols.create(self.context, - self.config_path, - "windows", - "pe") + pe_table_name = PEIntermedSymbols.create(self.context, self.config_path, "windows", "pe") for mod in mods: try: @@ -97,24 +90,17 @@ class VerInfo(interfaces_plugins.PluginInterface): session_layer_name = moddump.ModDump.find_session_layer(self.context, session_layers, mod.DllBase) (major, minor, product, build) = [ - renderers.NotAvailableValue()] * 4 # type: Tuple[Union[int, interfaces.renderers.BaseAbsentValue],Union[int, interfaces.renderers.BaseAbsentValue],Union[int, interfaces.renderers.BaseAbsentValue],Union[int, interfaces.renderers.BaseAbsentValue]] + renderers.NotAvailableValue() + ] * 4 # type: Tuple[Union[int, interfaces.renderers.BaseAbsentValue],Union[int, interfaces.renderers.BaseAbsentValue],Union[int, interfaces.renderers.BaseAbsentValue],Union[int, interfaces.renderers.BaseAbsentValue]] try: - (major, minor, product, build) = self.get_version_information(self._context, - pe_table_name, - session_layer_name, - mod.DllBase) + (major, minor, product, build) = self.get_version_information(self._context, pe_table_name, + session_layer_name, mod.DllBase) except (exceptions.InvalidAddressException, ValueError, AttributeError): (major, minor, product, build) = [renderers.UnreadableValue()] * 4 # the pid and process are not applicable for kernel modules - yield (0, (renderers.NotApplicableValue(), - renderers.NotApplicableValue(), - format_hints.Hex(mod.DllBase), - BaseDllName, - major, - minor, - product, - build)) + yield (0, (renderers.NotApplicableValue(), renderers.NotApplicableValue(), format_hints.Hex(mod.DllBase), + BaseDllName, major, minor, product, build)) # now go through the process and dll lists for proc in procs: @@ -129,44 +115,25 @@ class VerInfo(interfaces_plugins.PluginInterface): session_layer_name = moddump.ModDump.find_session_layer(self.context, session_layers, mod.DllBase) (major, minor, product, build) = [renderers.NotAvailableValue()] * 4 try: - (major, minor, product, build) = self.get_version_information(self._context, - pe_table_name, - proc_layer_name, - entry.DllBase) + (major, minor, product, build) = self.get_version_information(self._context, pe_table_name, + proc_layer_name, entry.DllBase) except (exceptions.InvalidAddressException, ValueError, AttributeError): (major, minor, product, build) = [renderers.UnreadableValue()] * 4 yield (0, (proc.UniqueProcessId, - proc.ImageFileName.cast("string", - max_length = proc.ImageFileName.vol.count, - errors = "replace"), - format_hints.Hex(entry.DllBase), - BaseDllName, - major, - minor, - product, - build)) + proc.ImageFileName.cast( + "string", max_length = proc.ImageFileName.vol.count, errors = "replace"), + format_hints.Hex(entry.DllBase), BaseDllName, major, minor, product, build)) def run(self): - procs = pslist.PsList.list_processes(self.context, - self.config["primary"], - self.config["nt_symbols"]) + procs = pslist.PsList.list_processes(self.context, self.config["primary"], self.config["nt_symbols"]) - mods = modules.Modules.list_modules(self.context, - self.config["primary"], - self.config["nt_symbols"]) + mods = modules.Modules.list_modules(self.context, self.config["primary"], self.config["nt_symbols"]) # populate the session layers for kernel modules - session_layers = moddump.ModDump.get_session_layers(self.context, - self.config['primary'], + session_layers = moddump.ModDump.get_session_layers(self.context, self.config['primary'], self.config['nt_symbols']) - return renderers.TreeGrid([("PID", int), - ("Process", str), - ("Base", format_hints.Hex), - ("Name", str), - ("Major", int), - ("Minor", int), - ("Product", int), - ("Build", int)], + return renderers.TreeGrid([("PID", int), ("Process", str), ("Base", format_hints.Hex), ("Name", str), + ("Major", int), ("Minor", int), ("Product", int), ("Build", int)], self._generator(procs, mods, session_layers)) diff --git a/volatility/framework/plugins/yarascan.py b/volatility/framework/plugins/yarascan.py index 4d300fe06..d6db39c20 100644 --- a/volatility/framework/plugins/yarascan.py +++ b/volatility/framework/plugins/yarascan.py @@ -33,36 +33,30 @@ class YaraScan(plugins.PluginInterface): @classmethod def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: - return [requirements.TranslationLayerRequirement(name = 'primary', - description = "Primary kernel address space", - architectures = ["Intel32", "Intel64"]), - requirements.BooleanRequirement(name = "all", - description = "Scan both process and kernel memory", - default = False, - optional = True), - requirements.BooleanRequirement(name = "insensitive", - description = "Makes the search case insensitive", - default = False, - optional = True), - requirements.BooleanRequirement(name = "kernel", - description = "Scan kernel modules", - default = False, - optional = True), - requirements.BooleanRequirement(name = "wide", - description = "Match wide (unicode) strings", - default = False, - optional = True), - requirements.StringRequirement(name = "yara_rules", - description = "Yara rules (as a string)", - optional = True), - requirements.URIRequirement(name = "yara_file", - description = "Yara rules (as a file)", - optional = True), - requirements.IntRequirement(name = "max_size", - default = 0x40000000, - description = "Set the maximum size (default is 1GB)", - optional = True) - ] + return [ + requirements.TranslationLayerRequirement( + name = 'primary', description = "Primary kernel address space", architectures = ["Intel32", + "Intel64"]), + requirements.BooleanRequirement( + name = "all", description = "Scan both process and kernel memory", default = False, optional = True), + requirements.BooleanRequirement( + name = "insensitive", + description = "Makes the search case insensitive", + default = False, + optional = True), + requirements.BooleanRequirement( + name = "kernel", description = "Scan kernel modules", default = False, optional = True), + requirements.BooleanRequirement( + name = "wide", description = "Match wide (unicode) strings", default = False, optional = True), + requirements.StringRequirement( + name = "yara_rules", description = "Yara rules (as a string)", optional = True), + requirements.URIRequirement(name = "yara_file", description = "Yara rules (as a file)", optional = True), + requirements.IntRequirement( + name = "max_size", + default = 0x40000000, + description = "Set the maximum size (default is 1GB)", + optional = True) + ] def _generator(self): @@ -82,10 +76,8 @@ class YaraScan(plugins.PluginInterface): else: vollog.error("No yara rules, nor yara rules file were specified") - for offset, name in layer.scan(context = self.context, - scanner = YaraScanner(rules = rules)): + for offset, name in layer.scan(context = self.context, scanner = YaraScanner(rules = rules)): yield (0, (format_hints.Hex(offset), name)) def run(self): - return renderers.TreeGrid([('Offset', format_hints.Hex), - ('Rule', str)], self._generator()) + return renderers.TreeGrid([('Offset', format_hints.Hex), ('Rule', str)], self._generator()) diff --git a/volatility/framework/renderers/__init__.py b/volatility/framework/renderers/__init__.py index 2a9457dca..7402f86f4 100644 --- a/volatility/framework/renderers/__init__.py +++ b/volatility/framework/renderers/__init__.py @@ -33,10 +33,7 @@ class NotAvailableValue(interfaces.renderers.BaseAbsentValue): class TreeNode(interfaces.renderers.TreeNode): """Class representing a particular node in a tree grid""" - def __init__(self, - path: str, - treegrid: 'TreeGrid', - parent: Optional['TreeNode'], + def __init__(self, path: str, treegrid: 'TreeGrid', parent: Optional['TreeNode'], values: List[interfaces.renderers.BaseTypes]) -> None: if not isinstance(treegrid, TreeGrid): raise TypeError("Treegrid must be an instance of TreeGrid") @@ -66,10 +63,7 @@ class TreeNode(interfaces.renderers.TreeNode): if not isinstance(val, (column.type, interfaces.renderers.BaseAbsentValue)): raise TypeError( "Values item with index {} is the wrong type for column {} (got {} but expected {})".format( - index, - column.name, - type(val), - column.type)) + index, column.name, type(val), column.type)) # TODO: Consider how to deal with timezone naive/aware datetimes (and alert plugin uses to be precise) # if isinstance(val, datetime.datetime): # tznaive = val.tzinfo is None or val.tzinfo.utcoffset(val) is None @@ -126,8 +120,7 @@ class TreeGrid(interfaces.renderers.TreeGrid): path_sep = "|" - def __init__(self, - columns: List[Tuple[str, interfaces.renderers.BaseTypes]], + def __init__(self, columns: List[Tuple[str, interfaces.renderers.BaseTypes]], generator: Optional[Iterable[Tuple[int, Tuple]]]) -> None: """Constructs a TreeGrid object using a specific set of columns @@ -148,8 +141,8 @@ class TreeGrid(interfaces.renderers.TreeGrid): for (name, column_type) in columns: is_simple_type = issubclass(column_type, self.base_types) if not is_simple_type: - raise TypeError( - "Column {}'s type is not a simple type: {}".format(name, column_type.__class__.__name__)) + raise TypeError("Column {}'s type is not a simple type: {}".format(name, + column_type.__class__.__name__)) converted_columns.append(interfaces.renderers.Column(len(converted_columns), name, column_type)) self.RowStructure = collections.namedtuple("RowStructure", [self.sanitize_name(column.name) for column in converted_columns]) @@ -168,9 +161,7 @@ class TreeGrid(interfaces.renderers.TreeGrid): output += (letter if letter in 'abcdefghiljklmnopqrstuvwxyz_0123456789' else '_') return output - def populate(self, - func: interfaces.renderers.VisitorSignature = None, - initial_accumulator: Any = None) -> None: + def populate(self, func: interfaces.renderers.VisitorSignature = None, initial_accumulator: Any = None) -> None: """Populates the tree by consuming the TreeGrid's construction generator Func is called on every node, so can be used to create output on demand @@ -178,6 +169,7 @@ class TreeGrid(interfaces.renderers.TreeGrid): """ accumulator = initial_accumulator if func is None: + def func(_x: interfaces.renderers.TreeNode, _y: Any) -> Any: return None @@ -187,7 +179,7 @@ class TreeGrid(interfaces.renderers.TreeGrid): parent_index = min(len(prev_nodes), level) parent = prev_nodes[parent_index - 1] if parent_index > 0 else None treenode = self._append(parent, item) - prev_nodes = prev_nodes[0: parent_index] + [treenode] + prev_nodes = prev_nodes[0:parent_index] + [treenode] if func is not None: accumulator = func(treenode, accumulator) self._row_count += 1 @@ -316,6 +308,7 @@ class TreeGrid(interfaces.renderers.TreeGrid): class ColumnSortKey(interfaces.renderers.ColumnSortKey): + def __init__(self, treegrid: TreeGrid, column_name: str, ascending: bool = True) -> None: _index = None self._type = None diff --git a/volatility/framework/symbols/__init__.py b/volatility/framework/symbols/__init__.py index e1fcef00a..c59c2f191 100644 --- a/volatility/framework/symbols/__init__.py +++ b/volatility/framework/symbols/__init__.py @@ -15,10 +15,8 @@ class SymbolType(enum.Enum): ENUM = 3 -SymbolSpaceReturnType = TypeVar("SymbolSpaceReturnType", - interfaces.objects.Template, - interfaces.symbols.SymbolInterface, - Dict[str, Any]) +SymbolSpaceReturnType = TypeVar("SymbolSpaceReturnType", interfaces.objects.Template, + interfaces.symbols.SymbolInterface, Dict[str, Any]) class SymbolSpace(interfaces.symbols.SymbolSpaceInterface, validity.ValidityRoutines): @@ -146,8 +144,8 @@ class SymbolSpace(interfaces.symbols.SymbolSpaceInterface, validity.ValidityRout if child.vol.type_name not in self._resolved: traverse_list.append(child.vol.type_name) try: - self._resolved[child.vol.type_name] = self._weak_resolve(SymbolType.TYPE, - child.vol.type_name) + self._resolved[child.vol.type_name] = self._weak_resolve( + SymbolType.TYPE, child.vol.type_name) except exceptions.SymbolError: self._resolved[child.vol.type_name] = self._UnresolvedTemplate(child.vol.type_name) # Stash the replacement @@ -239,10 +237,11 @@ def mask_symbol_table(symbol_table: interfaces.symbols.SymbolTableInterface, # This is speedy, but may not be very efficient from a memory perspective if symbol in cached_symbols: return cached_symbols[symbol] - new_symbol = interfaces.symbols.SymbolInterface(name = symbol.name, - address = address_mask & (symbol.address + table_aslr_shift), - type = symbol.type, - constant_data = symbol.constant_data) + new_symbol = interfaces.symbols.SymbolInterface( + name = symbol.name, + address = address_mask & (symbol.address + table_aslr_shift), + type = symbol.type, + constant_data = symbol.constant_data) cached_symbols[symbol] = new_symbol return new_symbol @@ -251,7 +250,6 @@ def mask_symbol_table(symbol_table: interfaces.symbols.SymbolTableInterface, return symbol_table -def symbol_table_is_64bit(context: interfaces.context.ContextInterface, - symbol_table_name: str) -> bool: +def symbol_table_is_64bit(context: interfaces.context.ContextInterface, symbol_table_name: str) -> bool: """Returns a boolean as to whether a particular symbol table within a context is 64-bit or not""" return context.symbol_space.get_type(symbol_table_name + constants.BANG + "pointer").size == 8 diff --git a/volatility/framework/symbols/generic/__init__.py b/volatility/framework/symbols/generic/__init__.py index a608918a3..b54716597 100644 --- a/volatility/framework/symbols/generic/__init__.py +++ b/volatility/framework/symbols/generic/__init__.py @@ -6,6 +6,7 @@ from volatility.framework import objects, interfaces class GenericIntelProcess(objects.Struct): + def _add_process_layer(self, context: interfaces.context.ContextInterface, dtb: Union[int, interfaces.objects.ObjectInterface], @@ -15,14 +16,13 @@ class GenericIntelProcess(objects.Struct): if config_prefix is None: # TODO: Ensure collisions can't happen by verifying the config_prefix is empty - random_prefix = ''.join( - random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(8)) + random_prefix = ''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits) + for _ in range(8)) config_prefix = interfaces.configuration.path_join("temporary", "_" + random_prefix) # Figure out a suitable name we can use for the new layer if preferred_name is None: - preferred_name = context.memory.free_layer_name( - prefix = self.vol.layer_name + "_Process_") + preferred_name = context.memory.free_layer_name(prefix = self.vol.layer_name + "_Process_") else: if preferred_name in context.memory: preferred_name = context.memory.free_layer_name(prefix = preferred_name) diff --git a/volatility/framework/symbols/intermed.py b/volatility/framework/symbols/intermed.py index 856f1681b..42a21d00f 100644 --- a/volatility/framework/symbols/intermed.py +++ b/volatility/framework/symbols/intermed.py @@ -17,7 +17,6 @@ from volatility.framework.symbols import native, metadata vollog = logging.getLogger(__name__) - # ## TODO # # All symbol tables should take a label to an object template @@ -42,7 +41,9 @@ vollog = logging.getLogger(__name__) # for container types # + def _construct_delegate_function(name: str, is_property: bool = False) -> Any: + def _delegate_function(self, *args, **kwargs): if is_property: return getattr(self._delegate, name) @@ -54,6 +55,7 @@ def _construct_delegate_function(name: str, is_property: bool = False) -> Any: class IntermediateSymbolTable(interfaces.symbols.SymbolTableInterface): + def __init__(self, context: interfaces.context.ContextInterface, config_path: str, @@ -89,16 +91,13 @@ class IntermediateSymbolTable(interfaces.symbols.SymbolTableInterface): metadata = json_object.get('metadata', None) # Determine the delegate or throw an exception - self._delegate = self._closest_version(metadata.get('format', "0.0.0"), self._versions)(context, - config_path, - name, - json_object, - native_types, - table_mapping) + self._delegate = self._closest_version(metadata.get('format', "0.0.0"), + self._versions)(context, config_path, name, json_object, native_types, + table_mapping) # Inherit - super().__init__(context, config_path, name, native_types or self._delegate.natives, - table_mapping = table_mapping) + super().__init__( + context, config_path, name, native_types or self._delegate.natives, table_mapping = table_mapping) @staticmethod def _closest_version(version: str, versions: Dict[Tuple[int, int, int], Type['ISFormatTable']]) \ @@ -128,9 +127,7 @@ class IntermediateSymbolTable(interfaces.symbols.SymbolTableInterface): del_type_class = _construct_delegate_function('del_type_class') @classmethod - def file_symbol_url(cls, - sub_path: str, - filename: Optional[str] = None) -> Generator[str, None, None]: + def file_symbol_url(cls, sub_path: str, filename: Optional[str] = None) -> Generator[str, None, None]: """Returns an iterator of appropriate file-scheme symbol URLs that can be opened by a ResourceAccessor class Filter reduces the number of results returned to only those URLs containing that string @@ -195,19 +192,22 @@ class IntermediateSymbolTable(interfaces.symbols.SymbolTableInterface): if not urls: raise ValueError("No symbol files found at provided filename: {}", filename) table_name = context.symbol_space.free_table_name(filename) - table = cls(context = context, - config_path = config_path, - name = table_name, - isf_url = urls[0], - native_types = native_types, - table_mapping = table_mapping) + table = cls( + context = context, + config_path = config_path, + name = table_name, + isf_url = urls[0], + native_types = native_types, + table_mapping = table_mapping) context.symbol_space.append(table) return table_name @classmethod def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: - return [requirements.StringRequirement("isf_url", - description = "JSON file containing the symbols encoded in the Intermediate Symbol Format")] + return [ + requirements.StringRequirement( + "isf_url", description = "JSON file containing the symbols encoded in the Intermediate Symbol Format") + ] class ISFormatTable(interfaces.symbols.SymbolTableInterface, metaclass = ABCMeta): @@ -253,11 +253,9 @@ class ISFormatTable(interfaces.symbols.SymbolTableInterface, metaclass = ABCMeta # TODO: Check the format and make use of the other metadata def _validate_json(self) -> None: - if ('user_types' not in self._json_object or - 'base_types' not in self._json_object or - 'metadata' not in self._json_object or - 'symbols' not in self._json_object or - 'enums' not in self._json_object): + if ('user_types' not in self._json_object or 'base_types' not in self._json_object + or 'metadata' not in self._json_object or 'symbols' not in self._json_object + or 'enums' not in self._json_object): raise exceptions.SymbolSpaceError("Malformed JSON file provided") def metadata(self) -> Optional[interfaces.symbols.MetadataInterface]: @@ -334,8 +332,7 @@ class Version1Format(ISFormatTable): elif type_name == 'enum': update = self._lookup_enum(dictionary['name']) elif type_name == 'bitfield': - update = {'start_bit': dictionary['bit_position'], - 'end_bit': dictionary['bit_length']} + update = {'start_bit': dictionary['bit_position'], 'end_bit': dictionary['bit_length']} update['base_type'] = self._interdict_to_template(dictionary['type']) # We do *not* call native_template.clone(), since it slows everything down a lot # We require that the native.get_type method always returns a newly constructed python object @@ -351,8 +348,8 @@ class Version1Format(ISFormatTable): reference_name = self.name + constants.BANG + reference_name else: reference_parts = reference_name.split(constants.BANG) - reference_name = (self.table_mapping.get(reference_parts[0], reference_parts[0]) + - constants.BANG + constants.BANG.join(reference_parts[1:])) + reference_name = (self.table_mapping.get(reference_parts[0], reference_parts[0]) + constants.BANG + + constants.BANG.join(reference_parts[1:])) return objects.templates.ReferenceTemplate(type_name = reference_name) @@ -361,8 +358,7 @@ class Version1Format(ISFormatTable): lookup = self._json_object['enums'].get(name, None) if not lookup: raise exceptions.SymbolSpaceError("Unknown enumeration: {}".format(name)) - result = {"choices": copy.deepcopy(lookup['constants']), - "base_type": self.natives.get_type(lookup['base'])} + result = {"choices": copy.deepcopy(lookup['constants']), "base_type": self.natives.get_type(lookup['base'])} return result def get_enumeration(self, enum_name: str) -> interfaces.objects.Template: @@ -374,11 +370,12 @@ class Version1Format(ISFormatTable): raise exceptions.SymbolError("Enumeration not found in {} table: {}".format(self.name, enum_name)) curdict = self._json_object['enums'][enum_name] base_type = self.natives.get_type(curdict['base']) - return objects.templates.ObjectTemplate(type_name = 'Enumeration', - object_class = objects.Enumeration, - base_type = base_type, - size = curdict['size'], - choices = curdict['constants']) + return objects.templates.ObjectTemplate( + type_name = 'Enumeration', + object_class = objects.Enumeration, + base_type = base_type, + size = curdict['size'], + choices = curdict['constants']) def get_type(self, type_name: str) -> interfaces.objects.Template: """Resolves an individual symbol""" @@ -394,10 +391,11 @@ class Version1Format(ISFormatTable): member = (interdict['offset'], self._interdict_to_template(interdict['type'])) members[member_name] = member object_class = self.get_type_class(type_name) - return objects.templates.ObjectTemplate(type_name = self.name + constants.BANG + type_name, - object_class = object_class, - size = curdict['length'], - members = members) + return objects.templates.ObjectTemplate( + type_name = self.name + constants.BANG + type_name, + object_class = object_class, + size = curdict['length'], + members = members) class Version2Format(Version1Format): @@ -441,10 +439,11 @@ class Version2Format(Version1Format): member = (interdict['offset'], self._interdict_to_template(interdict['type'])) members[member_name] = member object_class = self.get_type_class(type_name) - return objects.templates.ObjectTemplate(type_name = self.name + constants.BANG + type_name, - object_class = object_class, - size = curdict['size'], - members = members) + return objects.templates.ObjectTemplate( + type_name = self.name + constants.BANG + type_name, + object_class = object_class, + size = curdict['size'], + members = members) class Version3Format(Version2Format): @@ -464,8 +463,8 @@ class Version3Format(Version2Format): symbol_type = None if 'type' in symbol: symbol_type = self._interdict_to_template(symbol['type']) - self._symbol_cache[name] = interfaces.symbols.SymbolInterface(name = name, address = symbol['address'], - type = symbol_type) + self._symbol_cache[name] = interfaces.symbols.SymbolInterface( + name = name, address = symbol['address'], type = symbol_type) return self._symbol_cache[name] @@ -476,11 +475,13 @@ class Version4Format(Version3Format): age = 0 version = (current - age, age, revision) - format_mapping = {'int': objects.Integer, - 'float': objects.Float, - 'void': objects.Integer, - 'bool': objects.Boolean, - 'char': objects.Char} + format_mapping = { + 'int': objects.Integer, + 'float': objects.Float, + 'void': objects.Integer, + 'bool': objects.Boolean, + 'char': objects.Char + } def _get_natives(self) -> Optional[interfaces.symbols.NativeTableInterface]: """Determines the appropriate native_types to use from the JSON data""" @@ -521,9 +522,8 @@ class Version5Format(Version4Format): symbol_constant_data = None if 'constant_data' in symbol: symbol_constant_data = base64.b64decode(symbol.get('constant_data')) - self._symbol_cache[name] = interfaces.symbols.SymbolInterface(name = name, address = symbol['address'], - type = symbol_type, - constant_data = symbol_constant_data) + self._symbol_cache[name] = interfaces.symbols.SymbolInterface( + name = name, address = symbol['address'], type = symbol_type, constant_data = symbol_constant_data) return self._symbol_cache[name] diff --git a/volatility/framework/symbols/linux/__init__.py b/volatility/framework/symbols/linux/__init__.py index 8c8b3bd69..9842a1fc7 100644 --- a/volatility/framework/symbols/linux/__init__.py +++ b/volatility/framework/symbols/linux/__init__.py @@ -6,10 +6,7 @@ from volatility.framework.symbols.linux import extensions class LinuxKernelIntermedSymbols(intermed.IntermediateSymbolTable): provides = {"type": "interface"} - def __init__(self, - context: interfaces.context.ContextInterface, - config_path: str, - name: str, + def __init__(self, context: interfaces.context.ContextInterface, config_path: str, name: str, isf_url: str) -> None: super().__init__(context = context, config_path = config_path, name = name, isf_url = isf_url) diff --git a/volatility/framework/symbols/linux/bash.py b/volatility/framework/symbols/linux/bash.py index 3face3c39..0337925fc 100644 --- a/volatility/framework/symbols/linux/bash.py +++ b/volatility/framework/symbols/linux/bash.py @@ -1,10 +1,10 @@ from volatility.framework.symbols import intermed from volatility.framework.symbols.linux.extensions import bash + class BashIntermedSymbols(intermed.IntermediateSymbolTable): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.set_type_class('hist_entry', bash.hist_entry) - diff --git a/volatility/framework/symbols/linux/extensions/__init__.py b/volatility/framework/symbols/linux/extensions/__init__.py index caafc5006..1e6550455 100644 --- a/volatility/framework/symbols/linux/extensions/__init__.py +++ b/volatility/framework/symbols/linux/extensions/__init__.py @@ -10,10 +10,11 @@ from volatility.framework.symbols import generic vollog = logging.getLogger(__name__) - # Keep these in a basic module, to prevent import cycles when symbol providers require them + class module(generic.GenericIntelProcess): + def get_init_size(self): if self.has_member("init_layout"): return self.init_layout.size @@ -34,9 +35,8 @@ class module(generic.GenericIntelProcess): class task_struct(generic.GenericIntelProcess): - def add_process_layer(self, - config_prefix: str = None, - preferred_name: str = None) -> Optional[str]: + + def add_process_layer(self, config_prefix: str = None, preferred_name: str = None) -> Optional[str]: """Constructs a new layer based on the process's DTB. Returns the name of the Layer or None. """ @@ -73,6 +73,7 @@ class task_struct(generic.GenericIntelProcess): class fs_struct(objects.Struct): + def get_root_dentry(self): # < 2.6.26 if self.has_member("rootmnt"): @@ -93,6 +94,7 @@ class fs_struct(objects.Struct): class mm_struct(objects.Struct): + @property def mmap_iter(self) -> Iterable[interfaces.objects.ObjectInterface]: """Returns an iterator for the mmap list member of an mm_struct.""" @@ -223,6 +225,7 @@ class vm_area_struct(objects.Struct): class qstr(objects.Struct): + def name_as_str(self) -> str: if self.has_member("len"): str_length = self.len @@ -238,11 +241,13 @@ class qstr(objects.Struct): class dentry(objects.Struct): + def path(self) -> str: return self.d_name.name_as_str() class struct_file(objects.Struct): + def get_dentry(self) -> interfaces.objects.ObjectInterface: if self.has_member("f_dentry"): return self.f_dentry @@ -261,6 +266,7 @@ class struct_file(objects.Struct): class list_head(objects.Struct, collections.abc.Iterable): + def to_list(self, symbol_type: str, member: str, @@ -294,6 +300,7 @@ class list_head(objects.Struct, collections.abc.Iterable): class files_struct(objects.Struct): + def get_fds(self) -> interfaces.objects.ObjectInterface: if self.has_member("fdt"): return self.fdt.fd.dereference() @@ -345,6 +352,7 @@ class mount(objects.Struct): class vfsmount(objects.Struct): + def is_valid(self): return self.get_mnt_sb() != 0 and \ self.get_mnt_root() != 0 and \ diff --git a/volatility/framework/symbols/linux/extensions/bash.py b/volatility/framework/symbols/linux/extensions/bash.py index 89f8ba84d..82624fd02 100644 --- a/volatility/framework/symbols/linux/extensions/bash.py +++ b/volatility/framework/symbols/linux/extensions/bash.py @@ -5,6 +5,7 @@ from volatility.framework.renderers import conversion class hist_entry(objects.Struct): + def is_valid(self): try: cmd = self.get_command() diff --git a/volatility/framework/symbols/mac/__init__.py b/volatility/framework/symbols/mac/__init__.py index e137bd937..1f000cb67 100644 --- a/volatility/framework/symbols/mac/__init__.py +++ b/volatility/framework/symbols/mac/__init__.py @@ -6,10 +6,7 @@ from volatility.framework.symbols.mac import extensions class MacKernelIntermedSymbols(intermed.IntermediateSymbolTable): provides = {"type": "interface"} - def __init__(self, - context: interfaces.context.ContextInterface, - config_path: str, - name: str, + def __init__(self, context: interfaces.context.ContextInterface, config_path: str, name: str, isf_url: str) -> None: super().__init__(context = context, config_path = config_path, name = name, isf_url = isf_url) diff --git a/volatility/framework/symbols/mac/extensions/__init__.py b/volatility/framework/symbols/mac/extensions/__init__.py index 615ea12e5..1168f92ab 100644 --- a/volatility/framework/symbols/mac/extensions/__init__.py +++ b/volatility/framework/symbols/mac/extensions/__init__.py @@ -5,12 +5,11 @@ from volatility.framework.symbols import generic class proc(generic.GenericIntelProcess): + def get_task(self): return self.task.dereference().cast("task") - def add_process_layer(self, - config_prefix: str = None, - preferred_name: str = None) -> Optional[str]: + def add_process_layer(self, config_prefix: str = None, preferred_name: str = None) -> Optional[str]: """Constructs a new layer based on the process's DTB. Returns the name of the Layer or None. """ diff --git a/volatility/framework/symbols/native.py b/volatility/framework/symbols/native.py index 156f4c132..d1adf21ab 100644 --- a/volatility/framework/symbols/native.py +++ b/volatility/framework/symbols/native.py @@ -8,9 +8,7 @@ class NativeTable(interfaces.symbols.NativeTableInterface): """Symbol List that handles Native types""" # FIXME: typing the native_dictionary as Tuple[interfaces.objects.ObjectInterface, str] throws many errors - def __init__(self, - name: str, - native_dictionary: Dict[str, Any]) -> None: + def __init__(self, name: str, native_dictionary: Dict[str, Any]) -> None: super().__init__(name, self) self._native_dictionary = copy.deepcopy(native_dictionary) self._overrides = {} # type: Dict[str, interfaces.objects.ObjectInterface] @@ -70,28 +68,31 @@ class NativeTable(interfaces.symbols.NativeTableInterface): _native_type, native_format = self._native_dictionary[type_name] if type_name == 'pointer': additional = {'subtype': self.get_type('void')} - return objects.templates.ObjectTemplate(self.get_type_class(type_name), # pylint: disable=W0142 - type_name = prefix + type_name, - data_format = objects.DataFormatInfo(*native_format), - **additional) + return objects.templates.ObjectTemplate( + self.get_type_class(type_name), # pylint: disable=W0142 + type_name = prefix + type_name, + data_format = objects.DataFormatInfo(*native_format), + **additional) -std_ctypes = {'int': (objects.Integer, (4, "little", True)), - 'long': (objects.Integer, (4, "little", True)), - 'unsigned long': (objects.Integer, (4, "little", False)), - 'unsigned int': (objects.Integer, (4, "little", False)), - 'char': (objects.Integer, (1, "little", True)), - 'byte': (objects.Bytes, (1, "little", True)), - 'unsigned char': (objects.Integer, (1, "little", False)), - 'unsigned short int': (objects.Integer, (2, "little", False)), - 'unsigned short': (objects.Integer, (2, "little", False)), - 'unsigned be short': (objects.Integer, (2, "big", False)), - 'short': (objects.Integer, (2, "little", True)), - 'long long': (objects.Integer, (8, "little", True)), - 'unsigned long long': (objects.Integer, (8, "little", True)), - 'float': (objects.Float, (4, "little", True)), - 'double': (objects.Float, (8, "little", True)), - 'wchar': (objects.Integer, (2, "little", False))} +std_ctypes = { + 'int': (objects.Integer, (4, "little", True)), + 'long': (objects.Integer, (4, "little", True)), + 'unsigned long': (objects.Integer, (4, "little", False)), + 'unsigned int': (objects.Integer, (4, "little", False)), + 'char': (objects.Integer, (1, "little", True)), + 'byte': (objects.Bytes, (1, "little", True)), + 'unsigned char': (objects.Integer, (1, "little", False)), + 'unsigned short int': (objects.Integer, (2, "little", False)), + 'unsigned short': (objects.Integer, (2, "little", False)), + 'unsigned be short': (objects.Integer, (2, "big", False)), + 'short': (objects.Integer, (2, "little", True)), + 'long long': (objects.Integer, (8, "little", True)), + 'unsigned long long': (objects.Integer, (8, "little", True)), + 'float': (objects.Float, (4, "little", True)), + 'double': (objects.Float, (8, "little", True)), + 'wchar': (objects.Integer, (2, "little", False)) +} native_types = std_ctypes.copy() native_types['pointer'] = (objects.Pointer, (4, "little", False)) x86NativeTable = NativeTable("native", native_types) diff --git a/volatility/framework/symbols/windows/__init__.py b/volatility/framework/symbols/windows/__init__.py index 75c9298b4..8b774a290 100644 --- a/volatility/framework/symbols/windows/__init__.py +++ b/volatility/framework/symbols/windows/__init__.py @@ -6,10 +6,7 @@ from volatility.framework.symbols.windows.extensions import registry class WindowsKernelIntermedSymbols(intermed.IntermediateSymbolTable): - def __init__(self, - context: interfaces.context.ContextInterface, - config_path: str, - name: str, + def __init__(self, context: interfaces.context.ContextInterface, config_path: str, name: str, isf_url: str) -> None: super().__init__(context = context, config_path = config_path, name = name, isf_url = isf_url) diff --git a/volatility/framework/symbols/windows/extensions/__init__.py b/volatility/framework/symbols/windows/extensions/__init__.py index c985a0020..beb5e2254 100644 --- a/volatility/framework/symbols/windows/extensions/__init__.py +++ b/volatility/framework/symbols/windows/extensions/__init__.py @@ -11,9 +11,9 @@ from volatility.framework.symbols import generic vollog = logging.getLogger(__name__) - # Keep these in a basic module, to prevent import cycles when symbol providers require them + class _POOL_HEADER(objects.Struct): """A kernel pool allocation header. Exists at the base of the allocation and provides a tag that we can scan for.""" @@ -41,10 +41,11 @@ class _POOL_HEADER(objects.Struct): # if there is no object type, then just instantiate a structure if object_type is None: - mem_object = self._context.object(symbol_table_name + constants.BANG + type_name, - layer_name = self.vol.layer_name, - offset = self.vol.offset + pool_header_size, - native_layer_name = native_layer_name) + mem_object = self._context.object( + symbol_table_name + constants.BANG + type_name, + layer_name = self.vol.layer_name, + offset = self.vol.offset + pool_header_size, + native_layer_name = native_layer_name) return mem_object # otherwise we have an executive object in the pool @@ -61,10 +62,11 @@ class _POOL_HEADER(objects.Struct): end_offset = start_offset + min(max_optional_headers_length, self.BlockSize * alignment) for addr in range(start_offset, end_offset, alignment): - object_header = self._context.object(symbol_table_name + constants.BANG + "_OBJECT_HEADER", - layer_name = self.vol.layer_name, - offset = addr, - native_layer_name = native_layer_name) + object_header = self._context.object( + symbol_table_name + constants.BANG + "_OBJECT_HEADER", + layer_name = self.vol.layer_name, + offset = addr, + native_layer_name = native_layer_name) if not object_header.is_valid(): continue @@ -85,10 +87,11 @@ class _POOL_HEADER(objects.Struct): type_size = self._context.symbol_space.get_type(symbol_table_name + constants.BANG + type_name).size rounded_size = conversion.round(type_size, alignment, up = True) - mem_object = self._context.object(symbol_table_name + constants.BANG + type_name, - layer_name = self.vol.layer_name, - offset = self.vol.offset + self.BlockSize * alignment - rounded_size, - native_layer_name = native_layer_name) + mem_object = self._context.object( + symbol_table_name + constants.BANG + type_name, + layer_name = self.vol.layer_name, + offset = self.vol.offset + self.BlockSize * alignment - rounded_size, + native_layer_name = native_layer_name) object_header = mem_object.object_header() @@ -127,11 +130,12 @@ class _MMVAD_SHORT(objects.Struct): try: # TODO: instantiate a _POOL_HEADER and return PoolTag - bytesobj = self._context.object(symbol_table_name + constants.BANG + "bytes", - layer_name = self.vol.layer_name, - offset = vad_address, - native_layer_name = self.vol.native_layer_name, - length = 4) + bytesobj = self._context.object( + symbol_table_name + constants.BANG + "bytes", + layer_name = self.vol.layer_name, + offset = vad_address, + native_layer_name = self.vol.native_layer_name, + length = 4) return bytesobj.decode() except exceptions.InvalidAddressException: @@ -300,12 +304,12 @@ class _MMVAD_SHORT(objects.Struct): return self.u.VadFlags.PrivateMemory elif self.has_member("Core"): - if (self.Core.has_member("u1") and self.Core.u1.has_member( - "VadFlags1") and self.Core.u1.VadFlags1.has_member("PrivateMemory")): + if (self.Core.has_member("u1") and self.Core.u1.has_member("VadFlags1") + and self.Core.u1.VadFlags1.has_member("PrivateMemory")): return self.Core.u1.VadFlags1.PrivateMemory - elif (self.Core.has_member("u") and self.Core.u.has_member("VadFlags") and self.Core.u.VadFlags.has_member( - "PrivateMemory")): + elif (self.Core.has_member("u") and self.Core.u.has_member("VadFlags") + and self.Core.u.VadFlags.has_member("PrivateMemory")): return self.Core.u.VadFlags.PrivateMemory raise AttributeError("Unable to find the private memory member") @@ -381,10 +385,11 @@ class _EX_FAST_REF(objects.Struct): else: max_fast_ref = 15 - return self._context.object(symbol_table_name + constants.BANG + "pointer", - layer_name = self.vol.layer_name, - offset = self.Object & ~max_fast_ref, - native_layer_name = self.vol.native_layer_name) + return self._context.object( + symbol_table_name + constants.BANG + "pointer", + layer_name = self.vol.layer_name, + offset = self.Object & ~max_fast_ref, + native_layer_name = self.vol.native_layer_name) class ExecutiveObject(interfaces.objects.ObjectInterface): @@ -395,12 +400,13 @@ class ExecutiveObject(interfaces.objects.ObjectInterface): if constants.BANG not in self.vol.type_name: raise ValueError("Invalid symbol table name syntax (no {} found)".format(constants.BANG)) symbol_table_name = self.vol.type_name.split(constants.BANG)[0] - body_offset = self._context.symbol_space.get_type( - symbol_table_name + constants.BANG + "_OBJECT_HEADER").relative_child_offset("Body") - return self._context.object(symbol_table_name + constants.BANG + "_OBJECT_HEADER", - layer_name = self.vol.layer_name, - offset = self.vol.offset - body_offset, - native_layer_name = self.vol.native_layer_name) + body_offset = self._context.symbol_space.get_type(symbol_table_name + constants.BANG + + "_OBJECT_HEADER").relative_child_offset("Body") + return self._context.object( + symbol_table_name + constants.BANG + "_OBJECT_HEADER", + layer_name = self.vol.layer_name, + offset = self.vol.offset - body_offset, + native_layer_name = self.vol.native_layer_name) class _DEVICE_OBJECT(objects.Struct, ExecutiveObject): @@ -491,14 +497,16 @@ class _OBJECT_HEADER(objects.Struct): address = ntkrnlmp.get_symbol("ObpInfoMaskToOffset").address calculated_index = ord(self.InfoMask) & (name_info_bit | (name_info_bit - 1)) - header_offset = self._context.object(symbol_table_name + constants.BANG + "unsigned char", - layer_name = self.vol.native_layer_name, - offset = address + calculated_index) + header_offset = self._context.object( + symbol_table_name + constants.BANG + "unsigned char", + layer_name = self.vol.native_layer_name, + offset = address + calculated_index) - header = self._context.object(symbol_table_name + constants.BANG + "_OBJECT_HEADER_NAME_INFO", - layer_name = self.vol.layer_name, - offset = self.vol.offset - header_offset, - native_layer_name = self.vol.native_layer_name) + header = self._context.object( + symbol_table_name + constants.BANG + "_OBJECT_HEADER_NAME_INFO", + layer_name = self.vol.layer_name, + offset = self.vol.offset - header_offset, + native_layer_name = self.vol.native_layer_name) return header @@ -517,8 +525,8 @@ class _UNICODE_STRING(objects.Struct): # We explicitly do *not* catch errors here, we allow an exception to be thrown # (otherwise there's no way to determine anything went wrong) # It's up to the user of this method to catch exceptions - return self.Buffer.dereference().cast("string", max_length = self.Length, errors = "replace", - encoding = "utf16") + return self.Buffer.dereference().cast( + "string", max_length = self.Length, errors = "replace", encoding = "utf16") String = property(get_string) @@ -564,9 +572,7 @@ class _EPROCESS(generic.GenericIntelProcess, ExecutiveObject): return True - def add_process_layer(self, - config_prefix: str = None, - preferred_name: str = None): + def add_process_layer(self, config_prefix: str = None, preferred_name: str = None): """Constructs a new layer based on the process's DirectoryTableBase""" parent_layer = self._context.memory[self.vol.layer_name] @@ -599,9 +605,8 @@ class _EPROCESS(generic.GenericIntelProcess, ExecutiveObject): return sym_table = self.vol.type_name.split(constants.BANG)[0] - peb = self._context.object("{}{}_PEB".format(sym_table, constants.BANG), - layer_name = proc_layer_name, - offset = self.Peb) + peb = self._context.object( + "{}{}_PEB".format(sym_table, constants.BANG), layer_name = proc_layer_name, offset = self.Peb) for entry in peb.Ldr.InLoadOrderModuleList.to_list( "{}{}_LDR_DATA_TABLE_ENTRY".format(sym_table, constants.BANG), "InLoadOrderLinks"): @@ -628,10 +633,11 @@ class _EPROCESS(generic.GenericIntelProcess, ExecutiveObject): layer_name = self.vol.layer_name symbol_table_name = self.get_symbol_table().name kvo = self._context.memory[layer_name].config['kernel_virtual_offset'] - ntkrnlmp = self._context.module(symbol_table_name, - layer_name = layer_name, - offset = kvo, - native_layer_name = self.vol.native_layer_name) + ntkrnlmp = self._context.module( + symbol_table_name, + layer_name = layer_name, + offset = kvo, + native_layer_name = self.vol.native_layer_name) session = ntkrnlmp.object(type_name = "_MM_SESSION_SPACE", offset = self.Session) if session.has_member("SessionId"): @@ -702,18 +708,20 @@ class _LIST_ENTRY(objects.Struct, collections.abc.Iterable): link = getattr(self, direction).dereference() if not sentinel: - yield self._context.object(symbol_type, - layer, - offset = self.vol.offset - relative_offset, - native_layer_name = layer or self.vol.native_layer_name) + yield self._context.object( + symbol_type, + layer, + offset = self.vol.offset - relative_offset, + native_layer_name = layer or self.vol.native_layer_name) seen = {self.vol.offset} while link.vol.offset not in seen: - obj = self._context.object(symbol_type, - layer, - offset = link.vol.offset - relative_offset, - native_layer_name = layer or self.vol.native_layer_name) + obj = self._context.object( + symbol_type, + layer, + offset = link.vol.offset - relative_offset, + native_layer_name = layer or self.vol.native_layer_name) yield obj seen.add(link.vol.offset) diff --git a/volatility/framework/symbols/windows/extensions/kdbg.py b/volatility/framework/symbols/windows/extensions/kdbg.py index 5dc41fdbe..9333fc641 100644 --- a/volatility/framework/symbols/windows/extensions/kdbg.py +++ b/volatility/framework/symbols/windows/extensions/kdbg.py @@ -1,6 +1,7 @@ from volatility.framework import objects from volatility.framework import constants + class _KDDEBUGGER_DATA64(objects.Struct): def get_build_lab(self): @@ -9,11 +10,12 @@ class _KDDEBUGGER_DATA64(objects.Struct): layer_name = self.vol.layer_name symbol_table_name = self.get_symbol_table().name - return self._context.object(symbol_table_name + constants.BANG + "string", - layer_name=layer_name, - offset=self.NtBuildLab, - max_length=32, - errors="replace") + return self._context.object( + symbol_table_name + constants.BANG + "string", + layer_name = layer_name, + offset = self.NtBuildLab, + max_length = 32, + errors = "replace") def get_csdversion(self): """Returns the CSDVersion as an integer (i.e. Service Pack number)""" @@ -21,8 +23,9 @@ class _KDDEBUGGER_DATA64(objects.Struct): layer_name = self.vol.layer_name symbol_table_name = self.get_symbol_table().name - csdresult = self._context.object(symbol_table_name + constants.BANG + "unsigned long", - layer_name=layer_name, - offset=self.CmNtCSDVersion) + csdresult = self._context.object( + symbol_table_name + constants.BANG + "unsigned long", + layer_name = layer_name, + offset = self.CmNtCSDVersion) - return (csdresult >> 8) & 0xffffffff \ No newline at end of file + return (csdresult >> 8) & 0xffffffff diff --git a/volatility/framework/symbols/windows/extensions/pe.py b/volatility/framework/symbols/windows/extensions/pe.py index 76ccd9917..65aa661d2 100644 --- a/volatility/framework/symbols/windows/extensions/pe.py +++ b/volatility/framework/symbols/windows/extensions/pe.py @@ -21,9 +21,10 @@ class _IMAGE_DOS_HEADER(objects.Struct): layer_name = self.vol.layer_name symbol_table_name = self.get_symbol_table().name - nt_header = self._context.object(symbol_table_name + constants.BANG + "_IMAGE_NT_HEADERS", - layer_name = layer_name, - offset = self.vol.offset + self.e_lfanew) + nt_header = self._context.object( + symbol_table_name + constants.BANG + "_IMAGE_NT_HEADERS", + layer_name = layer_name, + offset = self.vol.offset + self.e_lfanew) if nt_header.Signature != 0x4550: raise ValueError("NT header signature {0:04X} is not a valid".format(nt_header.Signature)) @@ -34,11 +35,8 @@ class _IMAGE_DOS_HEADER(objects.Struct): return nt_header - def replace_header_field(self, - sect: interfaces.objects.ObjectInterface, - header: bytes, - item: interfaces.objects.ObjectInterface, - value: int) -> bytes: + def replace_header_field(self, sect: interfaces.objects.ObjectInterface, header: bytes, + item: interfaces.objects.ObjectInterface, value: int) -> bytes: """Replaces a member in an _IMAGE_SECTION_HEADER structure. Args: @@ -93,8 +91,8 @@ class _IMAGE_DOS_HEADER(objects.Struct): section_alignment = nt_header.OptionalHeader.SectionAlignment - sect_header_size = self._context.symbol_space.get_type( - symbol_table_name + constants.BANG + "_IMAGE_SECTION_HEADER").size + sect_header_size = self._context.symbol_space.get_type(symbol_table_name + constants.BANG + + "_IMAGE_SECTION_HEADER").size size_of_image = nt_header.OptionalHeader.SizeOfImage @@ -102,9 +100,8 @@ class _IMAGE_DOS_HEADER(objects.Struct): if size_of_image > (1024 * 1024 * 100): raise ValueError("The claimed SizeOfImage is too large: {}".format(size_of_image)) - raw_data = self._context.memory[layer_name].read(self.vol.offset, - nt_header.OptionalHeader.SizeOfImage, - pad = True) + raw_data = self._context.memory[layer_name].read( + self.vol.offset, nt_header.OptionalHeader.SizeOfImage, pad = True) # fix the PE image base before yielding the initial view of the data fixed_data = self.fix_image_base(raw_data, nt_header) @@ -156,12 +153,13 @@ class _IMAGE_NT_HEADERS(objects.Struct): layer_name = self.vol.layer_name symbol_table_name = self.get_symbol_table().name - sect_header_size = self._context.symbol_space.get_type( - symbol_table_name + constants.BANG + "_IMAGE_SECTION_HEADER").size + sect_header_size = self._context.symbol_space.get_type(symbol_table_name + constants.BANG + + "_IMAGE_SECTION_HEADER").size start_addr = self.FileHeader.SizeOfOptionalHeader + self.OptionalHeader.vol.offset for i in range(self.FileHeader.NumberOfSections): sect_addr = start_addr + (i * sect_header_size) - yield self._context.object(symbol_table_name + constants.BANG + "_IMAGE_SECTION_HEADER", - offset = sect_addr, - layer_name = layer_name) + yield self._context.object( + symbol_table_name + constants.BANG + "_IMAGE_SECTION_HEADER", + offset = sect_addr, + layer_name = layer_name) diff --git a/volatility/framework/symbols/windows/extensions/registry.py b/volatility/framework/symbols/windows/extensions/registry.py index 3b29f9c4a..086238b44 100644 --- a/volatility/framework/symbols/windows/extensions/registry.py +++ b/volatility/framework/symbols/windows/extensions/registry.py @@ -56,6 +56,7 @@ class RegKeyFlags(enum.IntEnum): class _HMAP_ENTRY(objects.Struct): + def get_block_offset(self) -> int: try: return self.PermanentBinAddress ^ (self.PermanentBinAddress & 0xf) @@ -64,6 +65,7 @@ class _HMAP_ENTRY(objects.Struct): class _CMHIVE(objects.Struct): + def get_name(self) -> Optional[interfaces.objects.ObjectInterface]: """Determine a name for the hive. Note that some attributes are unpredictably blank across different OS versions while others are populated, @@ -106,10 +108,9 @@ class _CM_KEY_BODY(objects.Struct): if not kcb: break - output.append(kcb.NameBlock.Name.cast("string", - encoding = "utf8", - max_length = kcb.NameBlock.NameLength, - errors = "replace")) + output.append( + kcb.NameBlock.Name.cast( + "string", encoding = "utf8", max_length = kcb.NameBlock.NameLength, errors = "replace")) kcb = kcb.ParentKcb return "\\".join(reversed(output)) @@ -155,8 +156,8 @@ class _CM_KEY_NODE(objects.Struct): elif node.vol.type_name.endswith(constants.BANG + "_CM_KEY_NODE"): yield node else: - vollog.debug( - "Unexpected node type encountered when traversing subkeys: {}".format(node.vol.type_name)) + vollog.debug("Unexpected node type encountered when traversing subkeys: {}".format( + node.vol.type_name)) else: vollog.log(constants.LOGLEVEL_VVV, "Node found with address outside the valid Hive size: {}".format(key_offset)) diff --git a/volatility/framework/validity.py b/volatility/framework/validity.py index 381c96f86..d1c6001a9 100644 --- a/volatility/framework/validity.py +++ b/volatility/framework/validity.py @@ -25,9 +25,8 @@ class ValidityRoutines(object): value: The value of which to validate the type valid_type: The type against which to validate """ - assert isinstance(value, - valid_type), cls.__name__ + " expected " + valid_type.__name__ + ", not " + type( - value).__name__ + assert isinstance( + value, valid_type), cls.__name__ + " expected " + valid_type.__name__ + ", not " + type(value).__name__ return value @classmethod diff --git a/volatility/plugins/windows/statistics.py b/volatility/plugins/windows/statistics.py index a93350f63..716f00ba2 100644 --- a/volatility/plugins/windows/statistics.py +++ b/volatility/plugins/windows/statistics.py @@ -10,9 +10,10 @@ class Statistics(plugins.PluginInterface): @classmethod def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: - return [requirements.TranslationLayerRequirement(name = 'primary', - description = 'Kernel Address Space', - architectures = ["Intel32", "Intel64"])] + return [ + requirements.TranslationLayerRequirement( + name = 'primary', description = 'Kernel Address Space', architectures = ["Intel32", "Intel64"]) + ] def _generator(self): # Do mass mapping and determine the number of different layers and how many pages go to each one @@ -44,13 +45,10 @@ class Statistics(plugins.PluginInterface): page_addr += page_size self._progress_callback((page_addr * 100) / layer.maximum_address, "Reading memory") - yield (0, (page_count, large_page_count, swap_count, large_swap_count, invalid_page_count, large_invalid_count)) + yield (0, (page_count, large_page_count, swap_count, large_swap_count, invalid_page_count, + large_invalid_count)) def run(self): - return renderers.TreeGrid([("Valid pages (all)", int), - ("Valid pages (large)", int), - ("Swapped Pages (all)", int), - ("Swapped Pages (large)", int), - ("Invalid Pages (all)", int), - ("Invalid Pages (large)", int)], - self._generator()) + return renderers.TreeGrid([("Valid pages (all)", int), ("Valid pages (large)", int), + ("Swapped Pages (all)", int), ("Swapped Pages (large)", int), + ("Invalid Pages (all)", int), ("Invalid Pages (large)", int)], self._generator()) diff --git a/volshell.py b/volshell.py index be553efd1..1fbc7c3a3 100644 --- a/volshell.py +++ b/volshell.py @@ -4,4 +4,3 @@ from volatility.cli import volshell if __name__ == '__main__': volshell.main() -