diff --git a/doc/source/conf.py b/doc/source/conf.py index b92aa160e..85583590c 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -12,8 +12,8 @@ # All configuration values have a default; values that are commented out # serve to show the default. -import sys import os +import sys # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the @@ -31,10 +31,11 @@ sys.path.insert(0, os.path.abspath('../..')) extensions = [ 'sphinx.ext.autodoc', 'sphinx.ext.doctest', + 'sphinx.ext.napoleon', 'sphinx.ext.intersphinx', 'sphinx.ext.todo', 'sphinx.ext.coverage', - 'sphinx.ext.viewcode', + 'sphinx.ext.viewcode' ] # Add any paths that contain templates here, relative to this directory. @@ -44,14 +45,14 @@ templates_path = ['tools/templates'] source_suffix = '.rst' # The encoding of source files. -#source_encoding = 'utf-8-sig' +# source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = 'Volatility' -copyright = '2014, Volatility Foundation' +copyright = '2012-2018, Volatility Foundation' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -64,13 +65,13 @@ release = '3.0.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. -#language = None +# language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: -#today = '' +# today = '' # Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' +# today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. @@ -78,27 +79,27 @@ exclude_patterns = [] # The reST default role (used for this markup: `text`) to use for all # documents. -#default_role = None +# default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True +# add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). -#add_module_names = True +# add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. -#show_authors = False +# show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] +# modindex_common_prefix = [] # If true, keep warnings as "system message" paragraphs in the built documents. -#keep_warnings = False +# keep_warnings = False # -- Options for HTML output ---------------------------------------------- @@ -113,17 +114,17 @@ html_theme_options = {'collapsiblesidebar': True} # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. -#html_theme_options = {} +# html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] +# html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". -#html_title = None +# html_title = None # A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None +# html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. @@ -142,64 +143,63 @@ html_static_path = ['_static', 'tools/static'] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied # directly to the root of the documentation. -#html_extra_path = [] +# html_extra_path = [] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' +# html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. -#html_use_smartypants = True +# html_use_smartypants = True # Custom sidebar templates, maps document names to template names. -#html_sidebars = {} +# html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. -#html_additional_pages = {} +# html_additional_pages = {} # If false, no module index is generated. -#html_domain_indices = True +# html_domain_indices = True # If false, no index is generated. -#html_use_index = True +# html_use_index = True # If true, the index is split into individual pages for each letter. -#html_split_index = False +# html_split_index = False # If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True +# html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True +# html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True +# html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. -#html_use_opensearch = '' +# html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None +# html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'Volatilitydoc' - # -- Options for LaTeX output --------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). - #'papersize': 'letterpaper', + # 'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). - #'pointsize': '10pt', + # 'pointsize': '10pt', # Additional stuff for the LaTeX preamble. - #'preamble': '', + # 'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples @@ -212,23 +212,23 @@ latex_documents = [ # The name of an image file (relative to this directory) to place at the top of # the title page. -#latex_logo = None +# latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. -#latex_use_parts = False +# latex_use_parts = False # If true, show page references after internal links. -#latex_show_pagerefs = False +# latex_show_pagerefs = False # If true, show URL addresses after external links. -#latex_show_urls = False +# latex_show_urls = False # Documents to append as an appendix to all manuals. -#latex_appendices = [] +# latex_appendices = [] # If false, no module index is generated. -#latex_domain_indices = True +# latex_domain_indices = True # -- Options for manual page output --------------------------------------- @@ -241,7 +241,7 @@ man_pages = [ ] # If true, show URL addresses after external links. -#man_show_urls = False +# man_show_urls = False # -- Options for Texinfo output ------------------------------------------- @@ -251,21 +251,21 @@ man_pages = [ # dir menu entry, description, category) texinfo_documents = [ ('index', 'Volatility', 'Volatility Documentation', - 'Volatility Foundation', 'Volatility', 'One line description of project.', + 'Volatility Foundation', 'Volatility', 'Memory forensics framework.', 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. -#texinfo_appendices = [] +# texinfo_appendices = [] # If false, no module index is generated. -#texinfo_domain_indices = True +# texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. -#texinfo_show_urls = 'footnote' +# texinfo_show_urls = 'footnote' # If true, do not generate a @detailmenu in the "Top" node's menu. -#texinfo_no_detailmenu = False +# texinfo_no_detailmenu = False # Example configuration for intersphinx: refer to the Python standard library. diff --git a/volatility/cli/__init__.py b/volatility/cli/__init__.py index 640fdba5c..c800038b6 100644 --- a/volatility/cli/__init__.py +++ b/volatility/cli/__init__.py @@ -38,16 +38,18 @@ vollog.addHandler(console) class PrintedProgress(object): + """A progress handler that prints the progress value and the description onto the command line""" + def __init__(self): self._max_message_len = 0 - def __call__(self, progress, description = None): - """ A sinmple function for providing text-based feedback + def __call__(self, progress: typing.Union[int, float], description: str = None): + """ A simple function for providing text-based feedback .. warning:: Only for development use. - :param progress: Percentage of progress of the current procedure - :type progress: int or float + Args: + progress: Percentage of progress of the current procedure """ message = "\rProgress: {0: 7.2f}\t\t{1:}".format(round(progress, 2), description or '') message_len = len(message) @@ -56,7 +58,9 @@ class PrintedProgress(object): class MuteProgress(PrintedProgress): - def __call__(self, progress, description = None): + """A dummy progress handler that produces no output when called""" + + def __call__(self, progress: typing.Union[int, float], description: str = None): pass @@ -207,10 +211,21 @@ class CommandLine(interfaces.plugins.FileConsumerInterface): plugin: typing.Type[interfaces.plugins.PluginInterface], plugin_config_path: str, write_config: bool = False, - quiet: bool = False): - """Run the actual plugin based on the parameters + quiet: bool = False) -> interfaces.plugins.PluginInterface: + """Constructs a plugin object based on the parameters Clever magic figures out how to fulfill each requirement that might not be fulfilled + + Args: + context: The volatility context to operate on + automagics: A list of automagic modules to run to augment the context + plugin: The plugin to run + plugin_config_path: The path within the context's config containing the plugin's configuration + write_config: Whether to record the configuration options after processing the automagic but before running + quiet: Whether or not to output progress information + + Returns: + The constructed plugin object """ progress_callback = PrintedProgress() if quiet: @@ -240,9 +255,17 @@ class CommandLine(interfaces.plugins.FileConsumerInterface): context: interfaces.context.ContextInterface, configurables_list: typing.Dict[str, interfaces.configuration.ConfigurableInterface], args: argparse.Namespace, - plugin_config_path: str): + 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""" + + We have already determined these elements must be descended from ConfigurableInterface + + Args: + context: The volatility context to operate on + configurables_list: A dictionary of configurable items that can be configured on the plugin + args: An object containing the arguments necessary + plugin_config_path: The path within the context's config containing the plugin's configuration + """ vargs = vars(args) for configurable in configurables_list: for requirement in configurables_list[configurable].get_requirements(): @@ -288,10 +311,9 @@ class CommandLine(interfaces.plugins.FileConsumerInterface): configurable: typing.Type[interfaces.configuration.ConfigurableInterface]): """Adds the plugin's simple requirements to the provided parser - :param parser: The parser to add the plugin's (simple) requirements to - :type parser: argparse.ArgumentParser - :param configurable: The plugin object to pull the requirements from - :type configurable: volatility.framework.interfaces.plugins.PluginInterface + Args: + parser: The parser to add the plugin's (simple) requirements to + configurable: The plugin object to pull the requirements from """ if not issubclass(configurable, interfaces.configuration.ConfigurableInterface): raise TypeError("Expected ConfigurableInterface type, not: {}".format(type(configurable))) @@ -326,7 +348,7 @@ class CommandLine(interfaces.plugins.FileConsumerInterface): # We shouldn't really steal a private member from argparse, but otherwise we're just duplicating code class HelpfulSubparserAction(argparse._SubParsersAction): - """Class to either select a unique plugin based on a substring, or identity the alternatives""" + """Class to either select a unique plugin based on a substring, or identify the alternatives""" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -369,7 +391,7 @@ class HelpfulSubparserAction(argparse._SubParsersAction): class UnsatisfiedException(exceptions.VolatilityException): - def __init__(self, unsatisfied): + def __init__(self, unsatisfied: typing.List[str]) -> None: super().__init__() self.unsatisfied = unsatisfied diff --git a/volatility/cli/text_renderer.py b/volatility/cli/text_renderer.py index 458291b23..7597f3341 100644 --- a/volatility/cli/text_renderer.py +++ b/volatility/cli/text_renderer.py @@ -18,7 +18,14 @@ from volatility.framework import interfaces, renderers def hex_bytes_as_text(value: bytes) -> str: - """Renders HexBytes as text""" + """Renders HexBytes as text + + Args: + value: A series of bytes to convert to text + + Returns: + A text representation of the hexadecimal bytes plus their ascii equivalents, separated by newline characters + """ if not isinstance(value, bytes): raise TypeError("hex_bytes_as_text takes bytes not: {}".format(type(value))) ascii = [] @@ -51,6 +58,16 @@ class Optional(object): def display_disassembly(disasm: interfaces.renderers.Disassembly) -> str: + """Renders a disassembly renderer type into string format + + Args: + disasm: Input disassembly objects + + Returns: + A string as rendererd by capstone where available, otherwise output as if it were just bytes + + """ + 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), @@ -80,6 +97,15 @@ class QuickTextRenderer(interfaces.renderers.Renderer): pass def render(self, grid: interfaces.renderers.TreeGrid) -> None: + """ + Renders each column immediately to stdout. + + This does not format each line's width appropriately, it merely tab separates each field + + Args: + grid: The TreeGrid object to render + + """ # TODO: Docstrings # TODO: Improve text output outfd = sys.stdout diff --git a/volatility/cli/volshell/__init__.py b/volatility/cli/volshell/__init__.py index 2f99ecae5..1d5122994 100644 --- a/volatility/cli/volshell/__init__.py +++ b/volatility/cli/volshell/__init__.py @@ -24,7 +24,10 @@ vollog.addHandler(console) class VolShell(cli.CommandLine): - """Program to allow interactive """ + """Program to allow interactive interaction with a memory image + + This allows a memory image to be examined through an interactive python terminal with all the volatility support + calls available.""" def run(self): sys.stdout.write("Volshell (Volatility Framework) {}\n".format(constants.PACKAGE_VERSION)) diff --git a/volatility/cli/volshell/shellplugin.py b/volatility/cli/volshell/shellplugin.py index 829b729a5..6b1d55df7 100644 --- a/volatility/cli/volshell/shellplugin.py +++ b/volatility/cli/volshell/shellplugin.py @@ -15,7 +15,13 @@ class Volshell(interfaces.plugins.PluginInterface): description = 'Kernel Address Space', architectures = ["Intel32", "Intel64"])] - def run(self, additional_locals = None): + def run(self, additional_locals: typing.Dict[str, typing.Any] = None) -> interfaces.renderers.TreeGrid: + """Runs the interactive volshell plugin + + Returns: + Return a TreeGrid but this is always empty since the point of this plugin is to run interactively + + """ # Provide some OS-agnostic convenience elements for ease context = self.context @@ -26,8 +32,10 @@ class Volshell(interfaces.plugins.PluginInterface): # Determine locals curframe = inspect.currentframe() - vars = curframe.f_globals.copy() - vars.update(curframe.f_locals) + vars = {} # type: typing.Dict[str, typing.Any] + if curframe: + vars = curframe.f_globals.copy() + vars.update(curframe.f_locals) if additional_locals is not None: vars.update(additional_locals) @@ -49,7 +57,7 @@ class Volshell(interfaces.plugins.PluginInterface): code.interact(local = vars) - return renderers.TreeGrid([], lambda: []) + return renderers.TreeGrid([], None) def load_functions(self) -> typing.Dict[str, typing.Callable]: """Returns a dictionary listing the functions to be added to the environment""" diff --git a/volatility/framework/automagic/__init__.py b/volatility/framework/automagic/__init__.py index 528cfd969..65cfb61bc 100644 --- a/volatility/framework/automagic/__init__.py +++ b/volatility/framework/automagic/__init__.py @@ -38,8 +38,8 @@ def available(context: interfaces.context.ContextInterface) \ The order is based on the priority attributes of the subclasses, in order to ensure the automagics are listed in an appropriate order. - :param context: The context that will contain any automagic configuration values. - :type context: volatility.framework.interfaces.context.ContextInterface + Args: + context: The context that will contain any automagic configuration values. """ import_files(sys.modules[__name__]) config_path = constants.AUTOMAGIC_CONFIG_PATH @@ -74,11 +74,12 @@ def run(automagics: typing.List[interfaces.automagic.AutomagicInterface], progress_callback: validity.ProgressCallback = None) -> typing.List[traceback.TracebackException]: """Runs through the list of `automagics` in order, allowing them to make changes to the context - :param automagics: A list of :class:`~volatility.framework.interfaces.automagic.AutomagicInterface` objects - :param context: The context (that inherits from :class:`~volatility.framework.interfaces.context.ContextInterface`) for modification - :param configurable: An object that inherits from :class:`~volatility.framework.interfaces.configuration.ConfigurableInterface` - :param config_path: The path within the `context.config` for options required by the `configurable` - :param progress_callback: A function that takes a percentage (and an optional description) that will be called periodically + Args: + automagics: A list of :class:`~volatility.framework.interfaces.automagic.AutomagicInterface` objects + context: The context (that inherits from :class:`~volatility.framework.interfaces.context.ContextInterface`) for modification + configurable: An object that inherits from :class:`~volatility.framework.interfaces.configuration.ConfigurableInterface` + config_path: The path within the `context.config` for options required by the `configurable` + progress_callback: A function that takes a percentage (and an optional description) that will be called periodically This is where any automagic is allowed to run, and alter the context in order to satisfy/improve all requirements diff --git a/volatility/framework/automagic/pdbscan.py b/volatility/framework/automagic/pdbscan.py index 9a71023a8..11e366e4d 100644 --- a/volatility/framework/automagic/pdbscan.py +++ b/volatility/framework/automagic/pdbscan.py @@ -27,8 +27,8 @@ vollog = logging.getLogger(__name__) class PdbSignatureScanner(interfaces.layers.ScannerInterface): """A :class:`~volatility.framework.interfaces.layers.ScannerInterface` based scanner use to identify Windows PDB records - :param pdb_names: A list of bytestrings, used to match pdb signatures against the pdb names within the records. - :type pdb_names: A list of :class:`bytestring` objects + Args: + pdb_names: A list of bytestrings, used to match pdb signatures against the pdb names within the records. .. note:: The pdb_names must be a list of byte strings, unicode strs will not match against the data scanned """ @@ -144,13 +144,13 @@ class KernelPDBScanner(interfaces.automagic.AutomagicInterface): Returns a list of possible kernel locations in the physical memory - :param context: The context in which the `requirement` lives - :type context: ~volatility.framework.interfaces.context.ContextInterface - :param config_path: The path within the `context` for the `requirement`'s configuration variables - :type config_path: str - :param requirement: The root of the requirement tree to search for :class:~`volatility.framework.interfaces.layers.TranslationLayerRequirement` objects to scan - :type requirement: ~volatility.framework.interfaces.configuration.RequirementInterface - :return: A list of (layer_name, scan_results) + Args: + context: The context in which the `requirement` lives + config_path: The path within the `context` for the `requirement`'s configuration variables + requirement: The root of the requirement tree to search for :class:~`volatility.framework.interfaces.layers.TranslationLayerRequirement` objects to scan + + Returns: + A list of (layer_name, scan_results) """ sub_config_path = interfaces.configuration.path_join(config_path, requirement.name) results = {} # type: typing.Dict[str, typing.Iterable] @@ -178,7 +178,8 @@ class KernelPDBScanner(interfaces.automagic.AutomagicInterface): This pass will construct any requirements that may need it in the context it was passed - :param context: Context on which to operate + Args: + context: Context on which to operate """ join = interfaces.configuration.path_join for config_path, sub_config_path, requirement in self._symbol_requirements: @@ -215,8 +216,8 @@ class KernelPDBScanner(interfaces.automagic.AutomagicInterface): """Traverses the requirement tree, looking for kernel_virtual_offset values that may need setting and sets it based on the previously identified `valid_kernels`. - :param context: Context on which to operate and provide the kernel virtual offset - :type context: ~volatility.framework.interfaces.context.ContextInterface + Args: + context: Context on which to operate and provide the kernel virtual offset """ for virtual_layer in self.valid_kernels: # Sit the virtual offset under the TranslationLayer it applies to @@ -238,13 +239,13 @@ class KernelPDBScanner(interfaces.automagic.AutomagicInterface): there is a fixed mapping between the physical and virtual addresses of the kernel. On more recent versions a search is conducted for a structure that will identify the kernel's virtual offset. - :param context: Context on which to operate - :type context: ~volatility.framework.interfaces.context.ContextInterface - :param potential_kernels: Dictionary containing `GUID`, `age`, `pdb_name` and `mz_offset` keys - :type potential_kernels: dict - :param progress_callback: Function taking a percentage and optional description to be called during expensive computations to indicate progress - :type progress_callback: function - :return: A dictionary of valid kernels + Args: + context: Context on which to operate + potential_kernels: Dictionary containing `GUID`, `age`, `pdb_name` and `mz_offset` keys + progress_callback: Function taking a percentage and optional description to be called during expensive computations to indicate progress + + Returns: + A dictionary of valid kernels """ valid_kernels = {} for virtual_layer_name in potential_kernels: diff --git a/volatility/framework/automagic/stacker.py b/volatility/framework/automagic/stacker.py index 45d1841d3..10808a579 100644 --- a/volatility/framework/automagic/stacker.py +++ b/volatility/framework/automagic/stacker.py @@ -71,11 +71,12 @@ class LayerStacker(interfaces.automagic.AutomagicInterface): progress_callback: validity.ProgressCallback) -> None: """Stacks the various layers and attaches these to a specific requirement - :param context: Context on which to operate - :param config_path: Configuration path under which to store stacking data - :param location: File URL for the underlying physical layer - :param requirements: List of requirements, each of which has the stack built on the first suitable (sub-)requirement - :param progress_callback: Function to provide callback progress + Args: + context: Context on which to operate + config_path: Configuration path under which to store stacking data + location: File URL for the underlying physical layer + requirements: List of requirements, each of which has the stack built on the first suitable (sub-)requirement + progress_callback: Function to provide callback progress """ # If we're cached, find Now we need to find where to apply the stack configuration if self._cached: @@ -158,8 +159,10 @@ class LayerStacker(interfaces.automagic.AutomagicInterface): """Looks for translation layer requirements and attempts to apply the stacked layers to it. If it succeeds it returns the configuration path and layer name where the stacked nodes were spliced into the tree. - :return: A tuple of a configuration path and layer name for the top of the stacked layers - :rtype: (str, str)""" + Returns: + A tuple of a configuration path and layer name for the top of the stacked layers + or None if suitable requirements are not found + """ child_config_path = interfaces.configuration.path_join(config_path, requirement.name) if isinstance(requirement, interfaces.configuration.TranslationLayerRequirement): if requirement.unsatisfied(context, config_path): diff --git a/volatility/framework/automagic/windows.py b/volatility/framework/automagic/windows.py index 383ee3e7d..22135d1c6 100644 --- a/volatility/framework/automagic/windows.py +++ b/volatility/framework/automagic/windows.py @@ -61,13 +61,13 @@ class DtbTest(validity.ValidityRoutines): page_offset: int) -> typing.Optional[typing.Tuple[int, typing.Any]]: """Tests a specific page in a chunk of data to see if it contains a self-referential pointer. - :param data: The chunk of data that contains the page to be scanned - :type data: bytes - :param data_offset: Where, within the layer, the chunk of data lives - :type data_offset: int - :param page_offset: Where, within the data, the page to be scanned starts - :type page_offset: int - :return: A valid DTB within this page (and an additional parameter for data) + Args: + data: The chunk of data that contains the page to be scanned + data_offset: Where, within the layer, the chunk of data lives + page_offset: Where, within the data, the page to be scanned starts + + Returns: + 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)] @@ -88,13 +88,13 @@ class DtbTest(validity.ValidityRoutines): def second_pass(self, dtb: int, data: bytes, data_offset: int) -> typing.Optional[typing.Tuple[int, typing.Any]]: """Re-reads over the whole page to validate other records based on the number of pages marked user vs super - :param dtb: The identified dtb that needs validating - :type dtb: int - :param data: The chunk of data that contains the dtb to be validated - :type data: bytes - :param data_offset: Where, within the layer, the chunk of data lives - :type data_offset: int - :return: A valid DTB within this page + Args: + dtb: The identified dtb that needs validating + data: The chunk of data that contains the dtb to be validated + data_offset: Where, within the layer, the chunk of data lives + + Returns: + A valid DTB within this page """ page = data[dtb - data_offset:dtb - data_offset + self.page_size] usr_count, sup_count = 0, 0 @@ -141,14 +141,13 @@ class DtbTestPae(DtbTest): directly after the real dtb. The value for the real DTB is therefore four page earlier (and the fourth entry should point back to the `dtb` parameter this function was originally passed. - :param dtb: The identified self-referential pointer that needs validating - :type dtb: int - :param data: The chunk of data that contains the dtb to be validated - :type data: bytes - :param data_offset: Where, within the layer, the chunk of data lives - :type data_offset: int - :return: Returns the actual DTB of the PAE space - :rtype: int + Args: + dtb: The identified self-referential pointer that needs validating + data: The chunk of data that contains the dtb to be validated + data_offset: Where, within the layer, the chunk of data lives + + Returns: + Returns the actual DTB of the PAE space """ dtb -= 0x4000 # If we're not in something that the overlap would pick up diff --git a/volatility/framework/configuration/requirements.py b/volatility/framework/configuration/requirements.py index b66b4153e..8ad1aa1d0 100644 --- a/volatility/framework/configuration/requirements.py +++ b/volatility/framework/configuration/requirements.py @@ -73,9 +73,10 @@ class ListRequirement(interfaces_configuration.RequirementInterface): min_elements: typing.Optional[int] = None, *args, **kwargs) -> None: """Constructs the object - :param element_type: The (requirement) type of each element within the list - :param max_elements; The maximum number of acceptable elements this list can contain - :param min_elements: The minimum number of acceptable elements this list can contain + Args: + element_type: The (requirement) type of each element within the list + max_elements; The maximum number of acceptable elements this list can contain + min_elements: The minimum number of acceptable elements this list can contain """ super().__init__(*args, **kwargs) if not issubclass(element_type, interfaces_configuration.BasicTypes): @@ -117,7 +118,8 @@ class ChoiceRequirement(interfaces_configuration.RequirementInterface): def __init__(self, choices: typing.List[str], *args, **kwargs) -> None: """Constructs the object - :param choices: A list of possible string options that can be chosen from + Args: + choices: A list of possible string options that can be chosen from """ super().__init__(*args, **kwargs) if not isinstance(choices, list) or any([not isinstance(choice, str) for choice in choices]): diff --git a/volatility/framework/contexts/__init__.py b/volatility/framework/contexts/__init__.py index f7adee174..97a5e229b 100644 --- a/volatility/framework/contexts/__init__.py +++ b/volatility/framework/contexts/__init__.py @@ -58,10 +58,12 @@ class Context(interfaces.context.ContextInterface): def add_layer(self, layer: interfaces.layers.DataLayerInterface) -> None: """Adds a named translation layer to the context - :param layer: The layer to be added to the memory - :type layer: volatility.framework.interfaces.layers.DataLayerInterface - :raises volatility.framework.exceptions.LayerException: if the layer is already present, or has - unmet dependencies + Args: + layer: The layer to be added to the memory + + Raises: + volatility.framework.exceptions.LayerException: if the layer is already present, or has + unmet dependencies """ self._memory.add_layer(layer) @@ -77,14 +79,14 @@ class Context(interfaces.context.ContextInterface): Looks up the layername in the context, finds the object template based on the symbol, and constructs an object using the object template on the layer at the offset. - :param symbol: The name (or template) of the symbol type on which to construct the object. If this is a name, it should contain an explicit table name. - :type symbol: str - :param layer_name: The name of the layer on which to construct the object - :type layer_name: str - :param offset: The offset within the layer at which the data used to create the object lives - :type offset: int - :return: A fully constructed object - :rtype: :py:class:`volatility.framework.interfaces.objects.ObjectInterface` + Args: + symbol: The name (or template) of the symbol type on which to construct the object. If this is a name, it should contain an explicit table name. + layer_name: The name of the layer on which to construct the object + offset: The offset within the layer at which the data used to create the object lives + + + Returns: + A fully constructed object """ if not isinstance(symbol, interfaces.objects.Template): object_template = self._symbol_space.get_type(symbol) diff --git a/volatility/framework/interfaces/automagic.py b/volatility/framework/interfaces/automagic.py index d6e7a28fd..2568892fa 100644 --- a/volatility/framework/interfaces/automagic.py +++ b/volatility/framework/interfaces/automagic.py @@ -17,14 +17,12 @@ class AutomagicInterface(interfaces_configuration.ConfigurableInterface, metacla These classes are callable with the following parameters: - :param context: The context in which to store configuration data that the automagic might populate - :type context: ~volatility.framework.interfaces.context.ContextInterface - :param config_path: Configuration path where the configurable's data under the context's config lives - :type config_path: str - :param configurable: The top level configurable whose requirements may need statisfying - :type configurable: ~volatility.framework.interfaces.configuration.ConfigurableInterface - :param progress_callback: An optional function accepting a percentage and optional description to indicate - progress during long calculations + Args: + context: The context in which to store configuration data that the automagic might populate + config_path: Configuration path where the configurable's data under the context's config lives + configurable: The top level configurable whose requirements may need statisfying + progress_callback: An optional function accepting a percentage and optional description to indicate + progress during long calculations .. note:: @@ -69,12 +67,15 @@ class AutomagicInterface(interfaces_configuration.ConfigurableInterface, metacla This ensures we do not carry out an expensive search when there is no requirement for a particular requirement - :param context: Context on which to operate - :param config_path: Configuration path of the top-level requirement - :param requirement_root: Top-level requirement whose subrequirements will all be searched - :param requirement_type: Type of requirement to find - :param shortcut: Only returns requirements that live under unsatisfied requirements - :return: A list of tuples containing the config_path, sub_config_path and requirement identifying the SymbolRequirements + Args: + context: Context on which to operate + config_path: Configuration path of the top-level requirement + requirement_root: Top-level requirement whose subrequirements will all be searched + requirement_type: Type of requirement to find + shortcut: Only returns requirements that live under unsatisfied requirements + + Returns: + A list of tuples containing the config_path, sub_config_path and requirement identifying the SymbolRequirements """ sub_config_path = interfaces_configuration.path_join(config_path, requirement_root.name) results = [] # type: typing.List[typing.Tuple[str, str, R]] @@ -105,16 +106,17 @@ class StackerLayerInterface(validity.ValidityRoutines, metaclass = ABCMeta): layer_name: str, progress_callback: validity.ProgressCallback = None) \ -> typing.Optional[interfaces.layers.DataLayerInterface]: - """Method to determine whether this builder can operate on the named layer, - If so, modify the context appropriately. - - Returns the name of any new_layer stacked on top of this layer or None - The stacking is therefore strictly linear rather than tree driven. - - Configuration options provided by the context are ignored, and defaults - are to be used by this method to build a space where possible - - :param context: Context in which to construct the higher layer - :param layer_name: Name of the layer to stack on top of - :param progress_callback: A callback function to indicate progress through a scan (if one is necessary) + """ + Method to determine whether this builder can operate on the named layer. If so, modify the context appropriately. + + Returns the name of any new_layer stacked on top of this layer or None. The stacking is therefore strictly + linear rather than tree driven. + + Configuration options provided by the context are ignored, and defaults are to be used by this method + to build a space where possible. + + Args: + context: Context in which to construct the higher layer + layer_name: Name of the layer to stack on top of + progress_callback: A callback function to indicate progress through a scan (if one is necessary) """ diff --git a/volatility/framework/interfaces/configuration.py b/volatility/framework/interfaces/configuration.py index 6e7b90a06..7744dc4c2 100644 --- a/volatility/framework/interfaces/configuration.py +++ b/volatility/framework/interfaces/configuration.py @@ -567,9 +567,9 @@ class TranslationLayerRequirement(ConstructableRequirementInterface, Configurabl The configuration option's value will be the name of the layer once it exists in the store - :param name: Name of the configuration requirement - :param layer_name: String detailing the expected name of the required layer, this can be None if it is to be randomly generated - :return: + Args: + name: Name of the configuration requirement + layer_name: String detailing the expected name of the required layer, this can be None if it is to be randomly generated """ if oses is None: oses = [] diff --git a/volatility/framework/interfaces/context.py b/volatility/framework/interfaces/context.py index 40e023a22..d25cf0457 100644 --- a/volatility/framework/interfaces/context.py +++ b/volatility/framework/interfaces/context.py @@ -48,8 +48,8 @@ class ContextInterface(object, metaclass = ABCMeta): def add_layer(self, layer: 'interfaces.layers.DataLayerInterface'): """Adds a named translation layer to the context memory - :param layer: Layer object to be added to the context memory - :type layer: ~volatility.framework.interfaces.layers.DataLayerInterface + Args: + layer: Layer object to be added to the context memory """ self.memory.add_layer(layer) diff --git a/volatility/framework/interfaces/objects.py b/volatility/framework/interfaces/objects.py index 0b057989f..cd9d0c4b4 100644 --- a/volatility/framework/interfaces/objects.py +++ b/volatility/framework/interfaces/objects.py @@ -186,13 +186,12 @@ class Template(validity.ValidityRoutines): This is effectively a class for currying object calls. It creates a callable that can be called with the following parameters: - :type context: ~volatility.framework.interfaces.context.ContextInterface - :type object_info: ObjectInformation - :param context: The context containing the memory layers and symbols required to construct the object - :param object_info: Basic information about the object, see the ObjectInformation class for more information + Args: + context: The context containing the memory layers and symbols required to construct the object + object_info: Basic information about the object, see the ObjectInformation class for more information - :return: The constructed object - :rtype: ObjectInterface + Returns: + The constructed object The keyword arguments handed to the constructor, along with the type_name are stored for later retrieval. These will be access as `object.vol.` or `template.vol.` for each object and should contain diff --git a/volatility/framework/interfaces/plugins.py b/volatility/framework/interfaces/plugins.py index c5b3195e2..3c3f6f7ad 100644 --- a/volatility/framework/interfaces/plugins.py +++ b/volatility/framework/interfaces/plugins.py @@ -89,11 +89,11 @@ class PluginInterface(interfaces_configuration.ConfigurableInterface, validity.V return [] @abstractmethod - def run(self) -> 'renderers.TreeGrid': + def run(self) -> 'interfaces.renderers.TreeGrid': """Executes the functionality of the code .. note:: This method expects `self.validate` to have been called to ensure all necessary options have been provided - :return: a TreeGrid object that can then be passed to a Renderer. - :rtype: interfaces.renderers.TreeGrid + Returns: + A TreeGrid object that can then be passed to a Renderer. """ diff --git a/volatility/framework/interfaces/renderers.py b/volatility/framework/interfaces/renderers.py index 45dfb0d84..95cf26806 100644 --- a/volatility/framework/interfaces/renderers.py +++ b/volatility/framework/interfaces/renderers.py @@ -129,8 +129,9 @@ class TreeGrid(object, metaclass = ABCMeta): The TreeGrid does *not* contain any information about formatting, these are up to the renderers and plugins. - :param columns: A list of column tuples made up of (name, type). - :param generator: A generator that populates the tree/grid structure + Args: + columns: A list of column tuples made up of (name, type). + generator: A generator that populates the tree/grid structure """ @staticmethod diff --git a/volatility/framework/objects/__init__.py b/volatility/framework/objects/__init__.py index ed1427823..725221ea2 100644 --- a/volatility/framework/objects/__init__.py +++ b/volatility/framework/objects/__init__.py @@ -158,9 +158,9 @@ class Bytes(PrimitiveObject, bytes): class String(PrimitiveObject, str): """Primitive Object that handles string values - :param max_length: specifies the maximum possible length that the string could hold within memory - (for multibyte characters, this will not be the maximum length of the string) - :type max_length: int + Args: + max_length: specifies the maximum possible length that the string could hold within memory + (for multibyte characters, this will not be the maximum length of the string) """ _struct_type = str # type: typing.ClassVar[typing.Type] diff --git a/volatility/framework/objects/utility.py b/volatility/framework/objects/utility.py index 000ef76bc..4a0653d66 100644 --- a/volatility/framework/objects/utility.py +++ b/volatility/framework/objects/utility.py @@ -55,14 +55,16 @@ def wintime_to_datetime(wintime: int) -> typing.Union[ return renderers.UnparsableValue() -def round(addr, align, up = False): +def round(addr: int, align: int, up: bool = False) -> int: """Round an address up or down based on an alignment. - :param addr: the address - :param align: the alignment value - :param up: true to round up + Args: + addr: the address + align: the alignment value + up: Whether to round up or not - :return: the aligned address + Returns: + The aligned address """ if addr % align == 0: diff --git a/volatility/framework/renderers/__init__.py b/volatility/framework/renderers/__init__.py index 7d3c82554..69d51dd24 100644 --- a/volatility/framework/renderers/__init__.py +++ b/volatility/framework/renderers/__init__.py @@ -135,8 +135,9 @@ class TreeGrid(interfaces.renderers.TreeGrid): The TreeGrid does *not* contain any information about formatting, these are up to the renderers and plugins. - :param columns: A list of column tuples made up of (name, type). - :param generator: A generator that populates the tree/grid structure + Args: + columns: A list of column tuples made up of (name, type). + generator: A generator that populates the tree/grid structure """ self._populated = False self._row_count = 0 diff --git a/volatility/framework/symbols/intermed.py b/volatility/framework/symbols/intermed.py index efb02ddfc..cd3ab84a4 100644 --- a/volatility/framework/symbols/intermed.py +++ b/volatility/framework/symbols/intermed.py @@ -64,12 +64,13 @@ class IntermediateSymbolTable(interfaces.symbols.SymbolTableInterface): appropriate schema. The validation can be disabled by passing validate = False, but this should almost never be done. - :param context: - :param config_path: - :param name: - :param isf_url: - :param native_types: - :param validate: Determines whether the ISF file will be validated against the appropriate schema + Args: + context: The volatility context for the symbol table + config_path: The configuration path for the symbol table + name: The name for the symbol table (this is used in symbols e.g. table!symbol ) + isf_url: The URL pointing to the ISF file location + native_types: The NativeSymbolTable that contains the native types for this symbol table + validate: Determines whether the ISF file will be validated against the appropriate schema """ # Check there are no obvious errors # Open the file and test the version diff --git a/volatility/framework/symbols/windows/extensions/pe.py b/volatility/framework/symbols/windows/extensions/pe.py index 7bfe02e3f..b11fa5c0e 100644 --- a/volatility/framework/symbols/windows/extensions/pe.py +++ b/volatility/framework/symbols/windows/extensions/pe.py @@ -1,15 +1,19 @@ import struct -from volatility.framework import objects +import typing + from volatility.framework import constants +from volatility.framework import objects, interfaces from volatility.framework.objects import utility + class _IMAGE_DOS_HEADER(objects.Struct): - def get_nt_header(self): + def get_nt_header(self) -> interfaces.objects.ObjectInterface: """Carve out the NT header from this DOS header. This reflects on the PE file's Machine type to create a 32- or 64-bit NT header structure. - :return: <_IMAGE_NT_HEADERS> or <_IMAGE_NT_HEADERS64> instance + Returns: + <_IMAGE_NT_HEADERS> or <_IMAGE_NT_HEADERS64> instance """ if self.e_magic != 0x5a4d: @@ -19,8 +23,8 @@ class _IMAGE_DOS_HEADER(objects.Struct): 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) + 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)) @@ -31,15 +35,21 @@ class _IMAGE_DOS_HEADER(objects.Struct): return nt_header - def replace_header_field(self, sect, header, item, value): + 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. - :param sect: <_IMAGE_SECTION_HEADER> the section instance - :param header: raw data for the section - :param item: the member of the section to replace - :param value: new value for the member + Args: + sect: the section instance + header: raw data for the section + item: the member of the section to replace + value: new value for the member - :return: raw data with the replaced header field + Returns: + The raw data with the replaced header field """ member_size = self._context.symbol_space.get_type(item.vol.type_name).size @@ -48,15 +58,17 @@ class _IMAGE_DOS_HEADER(objects.Struct): result = header[:start] + newval + header[start + member_size:] return result - def fix_image_base(self, raw_data, nt_header): + def fix_image_base(self, raw_data: bytes, nt_header: interfaces.objects.ObjectInterface) -> bytes: """Fix the _OPTIONAL_HEADER.ImageBase value (which is either an unsigned long for 32-bit PE's or unsigned long long for 64-bit PE's) to match the address where the PE file was carved out of memory. - :param raw_data: a bytes object of the PE's data - :param nt_header: <_IMAGE_NT_HEADERS> or <_IMAGE_NT_HEADERS64> instance + Args: + raw_data: a bytes object of the PE's data + nt_header: <_IMAGE_NT_HEADERS> or <_IMAGE_NT_HEADERS64> instance - :return: patched with the correct address + Returns: + patched with the correct address """ image_base_offset = nt_header.OptionalHeader.ImageBase.vol.offset - self.vol.offset @@ -65,12 +77,13 @@ class _IMAGE_DOS_HEADER(objects.Struct): newval = struct.pack(nt_header.OptionalHeader.ImageBase.vol.struct_format, int(self.vol.offset)) return raw_data[:image_base_offset] + newval + raw_data[image_base_offset + member_size:] - def reconstruct(self): + def reconstruct(self) -> typing.Tuple[int, bytes]: """This method generates the content necessary to reconstruct a PE file from memory. It preserves slack space (similar to the old --memory) and automatically fixes the ImageBase in the output PE file. - :return: of ( offset, data) + Returns: + of ( offset, data) """ nt_header = self.get_nt_header() @@ -90,8 +103,8 @@ class _IMAGE_DOS_HEADER(objects.Struct): 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) + 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) @@ -114,7 +127,7 @@ class _IMAGE_DOS_HEADER(objects.Struct): sect_sizes.append(sect.VirtualAddress - prevsect.VirtualAddress) prevsect = sect if prevsect is not None: - sect_sizes.append(utility.round(prevsect.Misc.VirtualSize, section_alignment, up=True)) + sect_sizes.append(utility.round(prevsect.Misc.VirtualSize, section_alignment, up = True)) counter = 0 start_addr = nt_header.FileHeader.SizeOfOptionalHeader + \ @@ -131,12 +144,14 @@ class _IMAGE_DOS_HEADER(objects.Struct): yield offset, sectheader counter += 1 + class _IMAGE_NT_HEADERS(objects.Struct): - def get_sections(self): + def get_sections(self) -> typing.Generator[interfaces.objects.ObjectInterface, None, None]: """Iterate through the section headers for this PE file. - :return: generator of _IMAGE_SECTION_HEADER + Returns: + generator of _IMAGE_SECTION_HEADER """ layer_name = self.vol.layer_name symbol_table_name = self.get_symbol_table().name @@ -148,5 +163,5 @@ class _IMAGE_NT_HEADERS(objects.Struct): 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) + offset = sect_addr, + layer_name = layer_name) diff --git a/volatility/framework/validity.py b/volatility/framework/validity.py index 46fc1b670..233c4a10e 100644 --- a/volatility/framework/validity.py +++ b/volatility/framework/validity.py @@ -21,10 +21,9 @@ class ValidityRoutines(object): def _check_type(cls, value: V, valid_type: typing.Type) -> V: """Checks that value is an instance of valid_type, and returns value if it is, or throws a TypeError otherwise - :param value: The value of which to validate the type - :type value: object - :param valid_type: The type against which to validate - :type valid_type: type + Args: + 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( @@ -35,10 +34,9 @@ class ValidityRoutines(object): def _check_class(cls, klass: typing.Type, valid_class: typing.Type) -> typing.Type: """Checks that class is an instance of valid_class, and returns klass if it is, or throws a TypeError otherwise - :param klass: Class to validate - :type klass: class - :param valid_class: Valid class against which to check class validity - :type valid_class: class + Args: + klass: Class to validate + valid_class: Valid class against which to check class validity """ assert issubclass(klass, valid_class), cls.__name__ + " expected " + valid_class.__name__ + ", not " + klass.__name__ diff --git a/volatility/plugins/windows/info.py b/volatility/plugins/windows/info.py index 8a4ab9a92..c047ed725 100644 --- a/volatility/plugins/windows/info.py +++ b/volatility/plugins/windows/info.py @@ -1,29 +1,32 @@ import time + import volatility.framework.interfaces.plugins as plugins +from volatility.framework import constants from volatility.framework.configuration import requirements from volatility.framework.renderers import TreeGrid from volatility.framework.symbols.windows.kdbg import KdbgIntermedSymbols from volatility.framework.symbols.windows.pe import PEIntermedSymbols -from volatility.framework import constants + class Info(plugins.PluginInterface): """Show OS & kernel details of the memory sample being analyzed""" @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")] + 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, i=0): + def get_depends(self, layer_name: str, index: int = 0): """List the dependencies of a given layer. - :param layer_name: the name of the starting layer - :param i: the index/order of the layer + Args: + layer_name: the name of the starting layer + index: the index/order of the layer """ layer = self.context.memory[layer_name] - yield i, layer + yield index, layer try: for depends in layer.dependencies: for j, dep in self.get_depends(depends, i + 1): @@ -53,13 +56,13 @@ class Info(plugins.PluginInterface): kvo = virtual_layer.config["kernel_virtual_offset"] ntkrnlmp = self.context.module(self.config["nt_symbols"], - layer_name=virtual_layer_name, offset=kvo) + 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) + "_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"]))) @@ -77,9 +80,9 @@ 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))) @@ -87,9 +90,9 @@ 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))) @@ -99,24 +102,24 @@ 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)))) + 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")) + # 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) + "_IMAGE_DOS_HEADER", offset = kvo, + layer_name = virtual_layer_name) nt_header = dos_header.get_nt_header() diff --git a/volatility/plugins/windows/malfind.py b/volatility/plugins/windows/malfind.py index 2dc334d4c..887146377 100644 --- a/volatility/plugins/windows/malfind.py +++ b/volatility/plugins/windows/malfind.py @@ -24,8 +24,9 @@ class Malfind(interfaces_plugins.PluginInterface): whose VAD flags match task._injection_filter requirements but there's no data and thus not worth reporting it. - :param proc_layer: the process layer - :param vad: the MMVAD structure to test + Args: + proc_layer: the process layer + vad: the MMVAD structure to test """ CHUNK_SIZE = 0x1000 @@ -46,8 +47,9 @@ class Malfind(interfaces_plugins.PluginInterface): """Generate memory regions for a process that may contain injected code. - :param vadinfo_plugin: an instance of the plugins.vadinfo.VadInfo plugin - :param proc: an _EPROCESS instance + Args: + vadinfo_plugin: an instance of the plugins.vadinfo.VadInfo plugin + proc: an _EPROCESS instance """ proc_layer_name = proc.add_process_layer() diff --git a/volatility/plugins/windows/moddump.py b/volatility/plugins/windows/moddump.py index 6c3677fec..a4024fda4 100644 --- a/volatility/plugins/windows/moddump.py +++ b/volatility/plugins/windows/moddump.py @@ -1,4 +1,5 @@ import logging +import typing import volatility.framework.constants as constants import volatility.framework.exceptions as exceptions @@ -20,12 +21,13 @@ class ModDump(interfaces_plugins.PluginInterface): # Reuse the requirements from the plugins we use return modules.Modules.get_requirements() - def get_session_layers(self): + def get_session_layers(self) -> typing.List[str]: """Build a cache of possible virtual layers, in priority starting with the primary/kernel layer. Then keep one layer per session by cycling through the process list. - :return: of layer names + Returns: + of layer names """ # the primary layer should be first @@ -61,14 +63,16 @@ class ModDump(interfaces_plugins.PluginInterface): return layers - def find_session_layer(self, session_layers, base_address): + def find_session_layer(self, session_layers: typing.List[str], base_address: int) -> typing.Optional[str]: """Given a base address and a list of layer names, find a layer that can access the specified address. - :param session_layers: of layer names - :param base_address: the base address + Args: + session_layers: of layer names + base_address: the base address - :return: layer name (or None) + Returns: + layer name (or None) """ for layer_name in session_layers: diff --git a/volatility/plugins/windows/verinfo.py b/volatility/plugins/windows/verinfo.py index a2fe0bc13..7bf41c233 100644 --- a/volatility/plugins/windows/verinfo.py +++ b/volatility/plugins/windows/verinfo.py @@ -40,9 +40,10 @@ class VerInfo(interfaces_plugins.PluginInterface): base_address: int) -> dict: """Get File and Product version information from PE files - :param pe_table_name: name of the PE table - :param layer_name: name of the layer containing the PE file - :param base_address: base address of the PE (where MZ is found) + Args: + pe_table_name: name of the PE table + layer_name: name of the layer containing the PE file + base_address: base address of the PE (where MZ is found) """ pe_data = io.BytesIO() @@ -85,12 +86,16 @@ class VerInfo(interfaces_plugins.PluginInterface): return entries - def _generator(self, procs: typing.Generator, mods: typing.Generator, moddump_plugin: moddump.ModDump): + def _generator(self, + procs: typing.Generator[interfaces.objects.ObjectInterface, None, None], + mods: typing.Generator[interfaces.context.Module, None, None], + moddump_plugin: moddump.ModDump): """Generates a list of PE file version info for processes, dlls, and modules. - :param procs: of processes - :param mods: of modules - :param moddump_plugin: + Args: + procs: of processes + mods: of modules + moddump_plugin: """ pe_table_name = PEIntermedSymbols.create(self.context,