diff --git a/volatility/cli/__init__.py b/volatility/cli/__init__.py index d3e106d88..963104879 100644 --- a/volatility/cli/__init__.py +++ b/volatility/cli/__init__.py @@ -14,7 +14,7 @@ import json import logging import os import sys -import typing +from typing import Union, Type, Dict from urllib import parse, request import volatility.plugins @@ -41,7 +41,7 @@ class PrintedProgress(object): def __init__(self): self._max_message_len = 0 - def __call__(self, progress: typing.Union[int, float], description: str = None): + def __call__(self, progress: Union[int, float], description: str = None): """ A simple function for providing text-based feedback .. warning:: Only for development use. @@ -58,7 +58,7 @@ class PrintedProgress(object): class MuteProgress(PrintedProgress): """A dummy progress handler that produces no output when called""" - def __call__(self, progress: typing.Union[int, float], description: str = None): + def __call__(self, progress: Union[int, float], description: str = None): pass @@ -225,7 +225,7 @@ class CommandLine(interfaces.plugins.FileConsumerInterface): def populate_config(self, context: interfaces.context.ContextInterface, - configurables_list: typing.Dict[str, interfaces.configuration.ConfigurableInterface], + configurables_list: Dict[str, interfaces.configuration.ConfigurableInterface], args: argparse.Namespace, plugin_config_path: str) -> None: """Populate the context config based on the returned args @@ -279,8 +279,8 @@ class CommandLine(interfaces.plugins.FileConsumerInterface): vollog.warning("Refusing to overwrite an existing file: {}".format(output_filename)) def populate_requirements_argparse(self, - parser: typing.Union[argparse.ArgumentParser, argparse._ArgumentGroup], - configurable: typing.Type[interfaces.configuration.ConfigurableInterface]): + parser: Union[argparse.ArgumentParser, argparse._ArgumentGroup], + configurable: Type[interfaces.configuration.ConfigurableInterface]): """Adds the plugin's simple requirements to the provided parser Args: @@ -293,7 +293,7 @@ class CommandLine(interfaces.plugins.FileConsumerInterface): # Construct an argparse group for requirement in configurable.get_requirements(): - additional = {} # type: typing.Dict[str, typing.Any] + additional = {} # type: Dict[str, Any] if not isinstance(requirement, interfaces.configuration.RequirementInterface): raise TypeError( "Plugin contains requirements that are not RequirementInterfaces: {}".format(configurable.__name__)) diff --git a/volatility/cli/text_renderer.py b/volatility/cli/text_renderer.py index 5f0950069..2998d0fd3 100644 --- a/volatility/cli/text_renderer.py +++ b/volatility/cli/text_renderer.py @@ -1,7 +1,7 @@ import datetime import logging import sys -import typing +from typing import Callable, Any from volatility.framework.renderers import format_hints @@ -45,10 +45,10 @@ def hex_bytes_as_text(value: bytes) -> str: class Optional(object): - def __init__(self, func: typing.Callable[[typing.Any], str]) -> None: + def __init__(self, func: Callable[[Any], str]) -> None: self._func = func - def __call__(self, x: typing.Any) -> str: + def __call__(self, x: Any) -> str: if isinstance(x, interfaces.renderers.BaseAbsentValue): if isinstance(x, renderers.NotApplicableValue): return "N/A" diff --git a/volatility/cli/volshell/shellplugin.py b/volatility/cli/volshell/shellplugin.py index fca79edc4..25838f849 100644 --- a/volatility/cli/volshell/shellplugin.py +++ b/volatility/cli/volshell/shellplugin.py @@ -1,6 +1,6 @@ import code import inspect -import typing +from typing import Any, Callable, Dict from volatility.framework import renderers, interfaces from volatility.framework.configuration import requirements @@ -15,7 +15,7 @@ class Volshell(interfaces.plugins.PluginInterface): description = 'Kernel Address Space', architectures = ["Intel32", "Intel64"])] - def run(self, additional_locals: typing.Dict[str, typing.Any] = None) -> interfaces.renderers.TreeGrid: + def run(self, additional_locals: Dict[str, Any] = None) -> interfaces.renderers.TreeGrid: """Runs the interactive volshell plugin Returns: @@ -32,7 +32,7 @@ class Volshell(interfaces.plugins.PluginInterface): # Determine locals curframe = inspect.currentframe() - vars = {} # type: typing.Dict[str, typing.Any] + vars = {} # type: Dict[str, Any] if curframe: vars = curframe.f_globals.copy() vars.update(curframe.f_locals) @@ -59,11 +59,12 @@ class Volshell(interfaces.plugins.PluginInterface): return renderers.TreeGrid([], None) - def load_functions(self) -> typing.Dict[str, typing.Callable]: + def load_functions(self) -> Dict[str, Callable]: """Returns a dictionary listing the functions to be added to the environment""" return {"dt": self.display_type} - def display_type(self, object: interfaces.objects.ObjectInterface): + @staticmethod + def display_type(object: interfaces.objects.ObjectInterface): """Display Type""" longest_member = longest_offset = 0 for member in object.vol.members: diff --git a/volatility/cli/volshell/windows.py b/volatility/cli/volshell/windows.py index b6afd782b..6acaf91ee 100644 --- a/volatility/cli/volshell/windows.py +++ b/volatility/cli/volshell/windows.py @@ -1,5 +1,5 @@ import inspect -import typing +from typing import Callable, Dict from volatility.cli.volshell import shellplugin from volatility.framework.configuration import requirements @@ -44,7 +44,7 @@ class Volshell(shellplugin.Volshell): for proc in eproc.ActiveProcessLinks: yield proc - def load_functions(self) -> typing.Dict[str, typing.Callable]: + def load_functions(self) -> Dict[str, Callable]: result = super().load_functions() result.update({ 'ps': lambda: list(self.list_processes()) diff --git a/volatility/framework/__init__.py b/volatility/framework/__init__.py index caa7111e2..6c3beff73 100644 --- a/volatility/framework/__init__.py +++ b/volatility/framework/__init__.py @@ -4,7 +4,7 @@ import inspect import logging import os import sys -import typing +from typing import Any, Dict, Generator, List, Type, TypeVar from volatility.framework import interfaces, constants @@ -51,11 +51,11 @@ def require_interface_version(*args) -> None: class noninheritable(object): - def __init__(self, value: typing.Any, cls: typing.Type) -> None: + def __init__(self, value: Any, cls: Type) -> None: self.default_value = value self.cls = cls - def __get__(self, obj: typing.Any, type: typing.Type = None) -> typing.Any: + def __get__(self, obj: Any, type: Type = None) -> Any: if type == self.cls: if hasattr(self.default_value, '__get__'): return self.default_value.__get__(obj, type) @@ -63,15 +63,15 @@ class noninheritable(object): raise AttributeError -def hide_from_subclasses(cls: typing.Type) -> typing.Type: +def hide_from_subclasses(cls: Type) -> Type: cls.hidden = noninheritable(True, cls) return cls -T = typing.TypeVar('T', bound = typing.Type) +T = TypeVar('T', bound = Type) -def class_subclasses(cls: T) -> typing.Generator[T, None, None]: +def class_subclasses(cls: T) -> Generator[T, None, None]: """Returns all the (recursive) subclasses of a given class""" if not inspect.isclass(cls): raise TypeError("class_subclasses parameter not a valid class: {}".format(cls)) @@ -83,7 +83,7 @@ def class_subclasses(cls: T) -> typing.Generator[T, None, None]: yield return_value -def import_files(base_module, ignore_errors = False) -> typing.List[str]: +def import_files(base_module, ignore_errors = False) -> List[str]: """Imports all plugins present under plugins module namespace""" failures = [] if not isinstance(base_module.__path__, list): @@ -114,7 +114,7 @@ def import_files(base_module, ignore_errors = False) -> typing.List[str]: return failures -def list_plugins() -> typing.Dict[str, typing.Type[interfaces.plugins.PluginInterface]]: +def list_plugins() -> Dict[str, Type[interfaces.plugins.PluginInterface]]: plugin_list = {} for plugin in class_subclasses(interfaces.plugins.PluginInterface): plugin_name = plugin.__module__ + "." + plugin.__name__ diff --git a/volatility/framework/automagic/__init__.py b/volatility/framework/automagic/__init__.py index 5f78e8c2b..44d093c75 100644 --- a/volatility/framework/automagic/__init__.py +++ b/volatility/framework/automagic/__init__.py @@ -10,7 +10,7 @@ loading of file format types) as well as a module to reconstruct layers based on import logging import sys import traceback -import typing +from typing import List, Type, Union from volatility.framework import class_subclasses, import_files, interfaces, validity, constants from volatility.framework.automagic import construct_layers, stacker, windows, pdbscan @@ -35,8 +35,7 @@ mac_automagic = ['ConstructionMagic', 'MacSymbolFinder'] -def available(context: interfaces.context.ContextInterface) \ - -> typing.List[interfaces.automagic.AutomagicInterface]: +def available(context: interfaces.context.ContextInterface) -> List[interfaces.automagic.AutomagicInterface]: """Returns an ordered list of all subclasses of :class:`~volatility.framework.interfaces.automagic.AutomagicInterface`. The order is based on the priority attributes of the subclasses, in order to ensure the automagics are listed in @@ -73,12 +72,12 @@ def choose_automagic(automagics, plugin): return output -def run(automagics: typing.List[interfaces.automagic.AutomagicInterface], +def run(automagics: List[interfaces.automagic.AutomagicInterface], context: interfaces.context.ContextInterface, - configurable: typing.Union[interfaces.configuration.ConfigurableInterface, - typing.Type[interfaces.configuration.ConfigurableInterface]], + configurable: Union[interfaces.configuration.ConfigurableInterface, + Type[interfaces.configuration.ConfigurableInterface]], config_path: str, - progress_callback: validity.ProgressCallback = None) -> typing.List[traceback.TracebackException]: + progress_callback: validity.ProgressCallback = None) -> List[traceback.TracebackException]: """Runs through the list of `automagics` in order, allowing them to make changes to the context Args: @@ -105,7 +104,7 @@ def run(automagics: typing.List[interfaces.automagic.AutomagicInterface], # TODO: Fix need for top level config element just because we're using a MultiRequirement to group the # configurable's config requirements - # configurable_class: typing.Type[interfaces.configuration.ConfigurableInterface] + # configurable_class: Type[interfaces.configuration.ConfigurableInterface] if isinstance(configurable, interfaces.configuration.ConfigurableInterface): configurable_class = configurable.__class__ else: diff --git a/volatility/framework/automagic/construct_layers.py b/volatility/framework/automagic/construct_layers.py index 7eee0605d..49d69fc25 100644 --- a/volatility/framework/automagic/construct_layers.py +++ b/volatility/framework/automagic/construct_layers.py @@ -2,7 +2,7 @@ of a :class:`~volatility.framework.interfaces.configuration.ConfigurableInterface`.""" import logging -import typing +from typing import List from volatility.framework import constants from volatility.framework import interfaces @@ -25,8 +25,8 @@ class ConstructionMagic(interfaces.automagic.AutomagicInterface): context: interfaces.context.ContextInterface, config_path: str, requirement: interfaces.configuration.RequirementInterface, - progress_callback = None, optional = False) -> typing.List[str]: - result = [] # type: typing.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 # but also ensures that TranslationLayerRequirements have got the correct subrequirements if their class is populated diff --git a/volatility/framework/automagic/linux.py b/volatility/framework/automagic/linux.py index 5e564cb82..7651b6fd4 100644 --- a/volatility/framework/automagic/linux.py +++ b/volatility/framework/automagic/linux.py @@ -1,5 +1,5 @@ import logging -import typing +from typing import List, Optional, Tuple, Type import volatility.framework.objects.utility from volatility.framework import interfaces, constants, validity, exceptions, layers @@ -34,8 +34,7 @@ class LintelStacker(interfaces.automagic.StackerLayerInterface): def stack(cls, context: interfaces.context.ContextInterface, layer_name: str, - progress_callback: validity.ProgressCallback = None) \ - -> typing.Optional[interfaces.layers.DataLayerInterface]: + progress_callback: validity.ProgressCallback = None) -> Optional[interfaces.layers.DataLayerInterface]: """Attempts to identify linux within this layer""" # Bail out by default unless we can stack properly layer = context.memory[layer_name] @@ -62,8 +61,8 @@ class LintelStacker(interfaces.automagic.StackerLayerInterface): kaslr_shift, _ = LinuxUtilities.find_aslr(context, table_name, layer_name, progress_callback = progress_callback) - layer_class = intel.Intel # type: typing.Type - if ('init_level4_pgt' in table.symbols): + layer_class = intel.Intel # type: Type + if 'init_level4_pgt' in table.symbols: layer_class = intel.Intel32e dtb_symbol_name = 'init_level4_pgt' else: @@ -99,7 +98,7 @@ class LinuxUtilities(object): except exceptions.InvalidDataException: return "" - ret_path = [] # type: typing.List[str] + ret_path = [] # type: List[str] while dentry != rdentry or vfsmnt != rmnt: dname = dentry.path() @@ -268,7 +267,7 @@ class LinuxUtilities(object): symbol_table: str, layer_name: str, progress_callback: validity.ProgressCallback = None) \ - -> typing.Tuple[int, int]: + -> Tuple[int, int]: """Determines the offset of the actual DTB in physical space and its symbol offset""" init_task_symbol = symbol_table + constants.BANG + 'init_task' init_task_json_address = context.symbol_space.get_symbol(init_task_symbol).address diff --git a/volatility/framework/automagic/mac.py b/volatility/framework/automagic/mac.py index a7d4ba683..c2939d3da 100644 --- a/volatility/framework/automagic/mac.py +++ b/volatility/framework/automagic/mac.py @@ -1,6 +1,6 @@ import logging import struct -import typing +from typing import Optional, Tuple from volatility.framework import interfaces, constants, validity, layers from volatility.framework import symbols @@ -33,8 +33,7 @@ class MacintelStacker(interfaces.automagic.StackerLayerInterface): def stack(cls, context: interfaces.context.ContextInterface, layer_name: str, - progress_callback: validity.ProgressCallback = None) \ - -> typing.Optional[interfaces.layers.DataLayerInterface]: + progress_callback: validity.ProgressCallback = None) -> Optional[interfaces.layers.DataLayerInterface]: """Attempts to identify mac within this layer""" # Bail out by default unless we can stack properly layer = context.memory[layer_name] @@ -146,7 +145,7 @@ class MacUtilities(object): compare_banner: str = "", compare_banner_offset: int = 0, progress_callback: validity.ProgressCallback = None) \ - -> typing.Tuple[int, int]: + -> Tuple[int, int]: """Determines the offset of the actual DTB in physical space and its symbol offset""" version_symbol = symbol_table + constants.BANG + 'version' version_json_address = context.symbol_space.get_symbol(version_symbol).address diff --git a/volatility/framework/automagic/pdbscan.py b/volatility/framework/automagic/pdbscan.py index b655f9b6a..c4ace914b 100644 --- a/volatility/framework/automagic/pdbscan.py +++ b/volatility/framework/automagic/pdbscan.py @@ -8,11 +8,10 @@ import logging import math import os import struct -import typing +from typing import Any, Dict, Generator, Iterable, List, Optional, Set, Tuple, Union -from volatility.framework import constants, exceptions, layers, validity +from volatility.framework import constants, exceptions, interfaces, layers, validity from volatility.framework.configuration import requirements -from volatility.framework.interfaces import configuration from volatility.framework.layers import intel, scanners from volatility.framework.symbols import intermed, native @@ -21,12 +20,10 @@ if __name__ == "__main__": sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))) -from volatility.framework import interfaces - vollog = logging.getLogger(__name__) -ValidKernelsType = typing.Dict[str, typing.Tuple[int, typing.Dict]] -KernelsType = typing.Iterable[typing.Dict[str, typing.Any]] +ValidKernelsType = Dict[str, Tuple[int, Dict]] +KernelsType = Iterable[Dict[str, Any]] class PdbSignatureScanner(interfaces.layers.ScannerInterface): @@ -44,12 +41,11 @@ class PdbSignatureScanner(interfaces.layers.ScannerInterface): _RSDS_format = struct.Struct("<16BI") - def __init__(self, pdb_names: typing.List[bytes]) -> None: + def __init__(self, pdb_names: List[bytes]) -> None: super().__init__() self._pdb_names = pdb_names - def __call__(self, data: bytes, data_offset: int) \ - -> typing.Generator[typing.Tuple[str, typing.Any, bytes, int], None, None]: + def __call__(self, data: bytes, data_offset: int) -> Generator[Tuple[str, Any, bytes, int], None, None]: sig = data.find(b"RSDS") while sig >= 0: null = data.find(b'\0', sig + 4 + self._RSDS_format.size) @@ -73,9 +69,8 @@ def scan(ctx: interfaces.context.ContextInterface, layer_name: str, page_size: int, progress_callback: validity.ProgressCallback = None, - start: typing.Optional[int] = None, - end: typing.Optional[int] = None) \ - -> typing.Generator[typing.Dict[str, typing.Optional[typing.Union[bytes, str, int]]], None, None]: + start: Optional[int] = None, + end: Optional[int] = None) -> Generator[Dict[str, Optional[Union[bytes, str, int]]], None, None]: """Scans through `layer_name` at `ctx` looking for RSDS headers that indicate one of four common pdb kernel names (as listed in `self.pdb_names`) and returns the tuple (GUID, age, pdb_name, signature_offset, mz_offset) @@ -141,8 +136,7 @@ class KernelPDBScanner(interfaces.automagic.AutomagicInterface): context: interfaces.context.ContextInterface, config_path: str, requirement: interfaces.configuration.RequirementInterface, - progress_callback: validity.ProgressCallback = None) \ - -> typing.Dict[str, KernelsType]: + progress_callback: validity.ProgressCallback = None) -> Dict[str, KernelsType]: """Traverses the requirement tree, rooted at `requirement` looking for virtual layers that might contain a windows PDB. Returns a list of possible kernel locations in the physical memory @@ -156,7 +150,7 @@ class KernelPDBScanner(interfaces.automagic.AutomagicInterface): A list of (layer_name, scan_results) """ sub_config_path = interfaces.configuration.path_join(config_path, requirement.name) - results = {} # type: typing.Dict[str, KernelsType] + results = {} # type: Dict[str, KernelsType] if isinstance(requirement, requirements.TranslationLayerRequirement): # Check for symbols in this layer # FIXME: optionally allow a full (slow) scan @@ -288,7 +282,7 @@ class KernelPDBScanner(interfaces.automagic.AutomagicInterface): # 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) - seen = set() # type: typing.Set[int] + 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 @@ -321,7 +315,7 @@ class KernelPDBScanner(interfaces.automagic.AutomagicInterface): physical_layer = context.memory[physical_layer_name] results = physical_layer.scan(context, scanners.BytesScanner(b"KDBG"), progress_callback = progress_callback) - seen = set() # type: typing.Set[int] + 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", @@ -349,7 +343,7 @@ class KernelPDBScanner(interfaces.automagic.AutomagicInterface): def determine_valid_kernels(self, context: interfaces.context.ContextInterface, - potential_kernels: typing.Dict[str, KernelsType], + potential_kernels: Dict[str, KernelsType], progress_callback: validity.ProgressCallback = None) -> ValidKernelsType: """Runs through the identified potential kernels and verifies their suitability @@ -393,7 +387,7 @@ class KernelPDBScanner(interfaces.automagic.AutomagicInterface): requirement, requirements.SymbolRequirement) for sub_config_path, symbol_req in self._symbol_requirements: - parent_path = configuration.parent_path(sub_config_path) + parent_path = interfaces.configuration.parent_path(sub_config_path) if symbol_req.unsatisfied(context, parent_path): potential_kernels = self.recurse_pdb_finder(context, config_path, requirement, progress_callback) valid_kernels = self.determine_valid_kernels(context, potential_kernels, progress_callback) diff --git a/volatility/framework/automagic/stacker.py b/volatility/framework/automagic/stacker.py index 8b3d677d7..d21481f1e 100644 --- a/volatility/framework/automagic/stacker.py +++ b/volatility/framework/automagic/stacker.py @@ -9,7 +9,7 @@ once a layer successfully stacks on top of the existing layers, it is removed fr import logging import traceback -import typing +from typing import List, Optional, Tuple from volatility import framework from volatility.framework import interfaces, constants, validity @@ -42,8 +42,7 @@ class LayerStacker(interfaces.automagic.AutomagicInterface): context: interfaces.context.ContextInterface, config_path: str, requirement: interfaces.configuration.RequirementInterface, - progress_callback: validity.ProgressCallback = None) \ - -> typing.Optional[typing.List[str]]: + progress_callback: validity.ProgressCallback = None) -> Optional[List[str]]: """Runs the automagic over the configurable""" # Quick exit if we're not needed @@ -155,7 +154,7 @@ class LayerStacker(interfaces.automagic.AutomagicInterface): context: interfaces.context.ContextInterface, config_path: str, requirement: interfaces.configuration.RequirementInterface, - stacked_layers: typing.List[str]) -> typing.Optional[typing.Tuple[str, str]]: + 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 it returns the configuration path and layer name where the stacked nodes were spliced into the tree. @@ -186,7 +185,7 @@ class LayerStacker(interfaces.automagic.AutomagicInterface): return None @classmethod - def get_requirements(cls) -> typing.List[interfaces.configuration.RequirementInterface]: + 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", diff --git a/volatility/framework/automagic/symbol_cache.py b/volatility/framework/automagic/symbol_cache.py index f12767123..6bd744789 100644 --- a/volatility/framework/automagic/symbol_cache.py +++ b/volatility/framework/automagic/symbol_cache.py @@ -1,17 +1,17 @@ import logging import os import pickle -import typing import urllib import urllib.parse import urllib.request +from typing import Dict, List from volatility.framework import constants, exceptions, interfaces from volatility.framework.symbols import intermed vollog = logging.getLogger(__name__) -BannersType = typing.Dict[bytes, typing.List[str]] +BannersType = Dict[bytes, List[str]] class SymbolBannerCache(interfaces.automagic.AutomagicInterface): diff --git a/volatility/framework/automagic/symbol_finder.py b/volatility/framework/automagic/symbol_finder.py index b7bf71a6b..c72afbe8d 100644 --- a/volatility/framework/automagic/symbol_finder.py +++ b/volatility/framework/automagic/symbol_finder.py @@ -1,5 +1,5 @@ import logging -import typing +from typing import Any, Iterable, List, Tuple from volatility.framework import interfaces, validity from volatility.framework.automagic import symbol_cache @@ -21,7 +21,7 @@ class SymbolFinder(interfaces.automagic.AutomagicInterface): context: interfaces.context.ContextInterface, config_path: str) -> None: super().__init__(context, config_path) - self._requirements = [] # type: typing.List[typing.Tuple[str, interfaces.configuration.ConstructableRequirementInterface]] + self._requirements = [] # type: List[Tuple[str, interfaces.configuration.ConstructableRequirementInterface]] self._banners = {} # type: symbol_cache.BannersType @property @@ -84,7 +84,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: typing.Iterable[typing.Any] + (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 c1f7bdef2..4211c6e93 100644 --- a/volatility/framework/automagic/windows.py +++ b/volatility/framework/automagic/windows.py @@ -24,7 +24,7 @@ The self-referential indices for older versions of windows are listed below: """ import logging import struct -import typing +from typing import Any, Generator, List, Optional, Tuple, Type from volatility.framework import interfaces, layers, validity from volatility.framework.configuration import requirements @@ -41,7 +41,7 @@ class DtbTest(validity.ValidityRoutines): """ def __init__(self, - layer_type: typing.Type[layers.intel.Intel], + layer_type: Type[layers.intel.Intel], ptr_struct: str, ptr_reference: int, mask: int) -> None: @@ -58,7 +58,7 @@ class DtbTest(validity.ValidityRoutines): def __call__(self, data: bytes, data_offset: int, - page_offset: int) -> typing.Optional[typing.Tuple[int, typing.Any]]: + 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: @@ -85,7 +85,7 @@ class DtbTest(validity.ValidityRoutines): return self.second_pass(dtb, data, data_offset) return None - def second_pass(self, dtb: int, data: bytes, data_offset: int) -> typing.Optional[typing.Tuple[int, typing.Any]]: + def second_pass(self, dtb: int, data: bytes, data_offset: int) -> Optional[Tuple[int, Any]]: """Re-reads over the whole page to validate other records based on the number of pages marked user vs super Args: @@ -134,7 +134,7 @@ class DtbTestPae(DtbTest): ptr_reference = 0x3, mask = 0x3FFFFFFFFFF000) - def second_pass(self, dtb: int, data: bytes, data_offset: int) -> typing.Optional[typing.Tuple[int, typing.Any]]: + 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 level of tables (so as not to use up a full quarter of the space). This is very high in the space, and occurs in the fourht (last quarter) second-level table. The second-level tables appear always to come sequentially @@ -163,7 +163,7 @@ 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: typing.Type[layers.intel.Intel], + layer_type: Type[layers.intel.Intel], ptr_struct: str, ptr_reference: int, mask: int) -> None: @@ -172,8 +172,7 @@ class DtbSelfReferential(DtbTest): ptr_reference = ptr_reference, mask = mask) - def __call__(self, data: bytes, data_offset: int, page_offset: int) \ - -> typing.Optional[typing.Tuple[int, int]]: + def __call__(self, data: bytes, data_offset: int, page_offset: int) -> Optional[Tuple[int, int]]: page = data[page_offset:page_offset + self.page_size] if not page: return None @@ -209,14 +208,13 @@ class PageMapScanner(interfaces.layers.ScannerInterface): tests = [DtbTest32bit(), DtbTest64bit(), DtbTestPae()] """The default tests to run when searching for DTBs""" - def __init__(self, tests: typing.List[DtbTest]) -> None: + def __init__(self, tests: List[DtbTest]) -> None: super().__init__() for value in tests: self._check_type(value, DtbTest) self.tests = tests - def __call__(self, data: bytes, data_offset: int) \ - -> typing.Generator[typing.Tuple[DtbTest, int], None, None]: + def __call__(self, data: bytes, data_offset: int) -> Generator[Tuple[DtbTest, int], None, None]: for test in self.tests: for page_offset in range(0, len(data), 0x1000): result = test(data, data_offset, page_offset) @@ -240,8 +238,7 @@ class WintelHelper(interfaces.automagic.AutomagicInterface): context: interfaces.context.ContextInterface, config_path: str, requirement: interfaces.configuration.RequirementInterface, - progress_callback: validity.ProgressCallback = None) \ - -> None: + progress_callback: validity.ProgressCallback = None) -> None: useful = [] sub_config_path = interfaces.configuration.path_join(config_path, requirement.name) if (isinstance(requirement, requirements.TranslationLayerRequirement) and @@ -287,8 +284,7 @@ class WintelStacker(interfaces.automagic.StackerLayerInterface): def stack(cls, context: interfaces.context.ContextInterface, layer_name: str, - progress_callback: validity.ProgressCallback = None) \ - -> typing.Optional[interfaces.layers.DataLayerInterface]: + progress_callback: validity.ProgressCallback = None) -> Optional[interfaces.layers.DataLayerInterface]: """Attempts to determine and stack an intel layer on a physical layer where possible Where the DTB scan fails, it attempts a heuristic of checking for the DTB within a specific range. @@ -311,7 +307,7 @@ class WintelStacker(interfaces.automagic.StackerLayerInterface): if arch not in ['Intel32', 'Intel64']: return None # Set the layer type - layer_type = intel.WindowsIntel # type: typing.Type + layer_type = intel.WindowsIntel # type: Type if arch == 'Intel64': layer_type = intel.WindowsIntel32e elif base_layer.metadata.get('pae', False): @@ -377,8 +373,7 @@ class WinSwapLayers(interfaces.automagic.AutomagicInterface): context: interfaces.context.ContextInterface, config_path: str, requirement: interfaces.configuration.RequirementInterface, - progress_callback: validity.ProgressCallback = None) \ - -> None: + 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, @@ -419,10 +414,10 @@ class WinSwapLayers(interfaces.automagic.AutomagicInterface): swap_req.construct(context, swap_config) - def find_swap_requirement(self, - config: str, + @staticmethod + def find_swap_requirement(config: str, requirement: requirements.TranslationLayerRequirement) \ - -> typing.Tuple[str, typing.Optional[requirements.LayerListRequirement]]: + -> Tuple[str, Optional[requirements.LayerListRequirement]]: """Takes a Translation layer and returns its swap_layer requirement""" swap_req = None for req_name in requirement.requirements: @@ -435,7 +430,7 @@ class WinSwapLayers(interfaces.automagic.AutomagicInterface): return swap_config, swap_req @classmethod - def get_requirements(cls) -> typing.List[interfaces.configuration.RequirementInterface]: + def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: """Returns the requirements of this plugin""" return [requirements.ListRequirement(name = "single_swap_locations", element_type = str, diff --git a/volatility/framework/configuration/requirements.py b/volatility/framework/configuration/requirements.py index 0e1086d19..4e22821c8 100644 --- a/volatility/framework/configuration/requirements.py +++ b/volatility/framework/configuration/requirements.py @@ -6,7 +6,7 @@ etc) as well as indicating what they expect to be in the context (such as partic """ import abc import logging -import typing +from typing import Any, ClassVar, List, Optional, Type from volatility.framework import constants, interfaces from volatility.framework.interfaces import configuration @@ -22,7 +22,7 @@ class MultiRequirement(configuration.RequirementInterface): def unsatisfied(self, context: configuration.ContextInterface, - config_path: str) -> typing.List[str]: + config_path: str) -> List[str]: return self.unsatisfied_children(context, config_path) @@ -33,13 +33,13 @@ class BooleanRequirement(configuration.SimpleTypeRequirement): class IntRequirement(configuration.SimpleTypeRequirement): """A requirement type that contains a single integer""" - instance_type = int # type: typing.ClassVar[typing.Type] + instance_type = int # type: ClassVar[Type] class StringRequirement(configuration.SimpleTypeRequirement): """A requirement type that contains a single unicode string""" # TODO: Maybe add string length limits? - instance_type = str # type: typing.ClassVar[typing.Type] + instance_type = str # type: ClassVar[Type] class URIRequirement(StringRequirement): @@ -49,7 +49,7 @@ class URIRequirement(StringRequirement): class BytesRequirement(configuration.SimpleTypeRequirement): """A requirement type that contains a byte string""" - instance_type = bytes # type: typing.ClassVar[typing.Type] + instance_type = bytes # type: ClassVar[Type] class ListRequirement(configuration.RequirementInterface): @@ -63,9 +63,9 @@ class ListRequirement(configuration.RequirementInterface): """ def __init__(self, - element_type: typing.Type[configuration.SimpleTypes] = str, - max_elements: typing.Optional[int] = 0, - min_elements: typing.Optional[int] = None, *args, **kwargs) -> None: + element_type: Type[configuration.SimpleTypes] = str, + max_elements: Optional[int] = 0, + min_elements: Optional[int] = None, *args, **kwargs) -> None: """Constructs the object Args: @@ -76,11 +76,11 @@ class ListRequirement(configuration.RequirementInterface): super().__init__(*args, **kwargs) if not issubclass(element_type, configuration.BasicTypes): raise TypeError("ListRequirements can only be populated with simple InstanceRequirements") - self.element_type = element_type # type: typing.Type + self.element_type = element_type # type: Type self.min_elements = min_elements or 0 # type: int - self.max_elements = max_elements # type: typing.Optional[int] + self.max_elements = max_elements # type: Optional[int] - def unsatisfied(self, context: interfaces.context.ContextInterface, config_path: str) -> typing.List[str]: + def unsatisfied(self, context: interfaces.context.ContextInterface, config_path: str) -> List[str]: """Check the types on each of the returned values and their number and then call the element type's check for each one""" config_path = configuration.path_join(config_path, self.name) default = None @@ -111,7 +111,7 @@ class ListRequirement(configuration.RequirementInterface): class ChoiceRequirement(configuration.RequirementInterface): """Allows one from a choice of strings""" - def __init__(self, choices: typing.List[str], *args, **kwargs) -> None: + def __init__(self, choices: List[str], *args, **kwargs) -> None: """Constructs the object Args: @@ -122,7 +122,7 @@ class ChoiceRequirement(configuration.RequirementInterface): raise TypeError("ChoiceRequirement takes a list of strings as choices") self.choices = choices - def unsatisfied(self, context: interfaces.context.ContextInterface, config_path: str) -> typing.List[str]: + def unsatisfied(self, context: interfaces.context.ContextInterface, config_path: str) -> List[str]: """Validates the provided value to ensure it is one of the available choices""" config_path = configuration.path_join(config_path, self.name) value = self.config_value(context, config_path) @@ -135,7 +135,7 @@ class ChoiceRequirement(configuration.RequirementInterface): 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) -> typing.List[str]: + def unsatisfied(self, context: interfaces.context.ContextInterface, config_path: str) -> List[str]: """Validates the provided value to ensure it is one of the available choices""" config_path = configuration.path_join(config_path, self.name) ret_list = super().unsatisfied(context, config_path) @@ -147,7 +147,7 @@ class ComplexListRequirement(MultiRequirement, configuration.ConfigurableRequire return [] @classmethod - def get_requirements(cls) -> typing.List[interfaces.configuration.RequirementInterface]: + 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", @@ -164,7 +164,7 @@ class ComplexListRequirement(MultiRequirement, configuration.ConfigurableRequire def build_configuration(self, context: interfaces.context.ContextInterface, config_path: str, - _: typing.Any) -> configuration.HierarchicalDict: + _: Any) -> configuration.HierarchicalDict: result = configuration.HierarchicalDict() num_elem_config_path = configuration.path_join(config_path, self.name, 'number_of_elements') num_elements = context.config.get(num_elem_config_path, None) @@ -212,8 +212,8 @@ class TranslationLayerRequirement(configuration.ConstructableRequirementInterfac description: str = None, default: configuration.ConfigSimpleType = None, optional: bool = False, - oses: typing.List = None, - architectures: typing.List = None) -> None: + oses: List = None, + architectures: List = None) -> None: """Constructs a Translation Layer Requirement The configuration option's value will be the name of the layer once it exists in the store @@ -232,7 +232,7 @@ class TranslationLayerRequirement(configuration.ConstructableRequirementInterfac def unsatisfied(self, context: interfaces.context.ContextInterface, - config_path: str) -> typing.List[str]: + 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) @@ -292,7 +292,7 @@ class TranslationLayerRequirement(configuration.ConstructableRequirementInterfac def build_configuration(self, context: interfaces.context.ContextInterface, _: str, - value: typing.Any) -> configuration.HierarchicalDict: + value: Any) -> configuration.HierarchicalDict: """Builds the appropriate configuration for the specified requirement""" return context.memory[value].build_configuration() @@ -301,7 +301,7 @@ class SymbolRequirement(configuration.ConstructableRequirementInterface, configuration.ConfigurableRequirementInterface): """Class maintaining the limitations on what sort of symbol spaces are acceptable""" - def unsatisfied(self, context: interfaces.context.ContextInterface, config_path: str) -> typing.List[str]: + def unsatisfied(self, context: interfaces.context.ContextInterface, config_path: str) -> List[str]: """Validate that the value is a valid within the symbol space of the provided context""" config_path = configuration.path_join(config_path, self.name) value = self.config_value(context, config_path, None) @@ -348,6 +348,6 @@ class SymbolRequirement(configuration.ConstructableRequirementInterface, def build_configuration(self, context: interfaces.context.ContextInterface, _: str, - value: typing.Any) -> configuration.HierarchicalDict: + value: Any) -> configuration.HierarchicalDict: """Builds the appropriate configuration for the specified requirement""" return context.symbol_space[value].build_configuration() diff --git a/volatility/framework/contexts/__init__.py b/volatility/framework/contexts/__init__.py index bfa05e6b0..e8a6961be 100644 --- a/volatility/framework/contexts/__init__.py +++ b/volatility/framework/contexts/__init__.py @@ -5,7 +5,7 @@ to act on multiple different contexts without them interfering eith each other. """ import functools import hashlib -import typing +from typing import Callable, Dict, Iterable, List, Optional, Set, Tuple, Union from volatility.framework import constants, interfaces, symbols, validity @@ -71,10 +71,10 @@ class Context(interfaces.context.ContextInterface): # ## Object Factory Functions def object(self, - symbol: typing.Union[str, interfaces.objects.Template], + symbol: Union[str, interfaces.objects.Template], layer_name: str, offset: int, - native_layer_name: typing.Optional[str] = None, + native_layer_name: Optional[str] = None, **arguments) -> interfaces.objects.ObjectInterface: """Object factory, takes a context, symbol, offset and optional layername @@ -108,8 +108,8 @@ class Context(interfaces.context.ContextInterface): module_name: str, layer_name: str, offset: int, - native_layer_name: typing.Optional[str] = None, - size: typing.Optional[int] = None) -> interfaces.context.ModuleInterface: + native_layer_name: Optional[str] = None, + size: Optional[int] = None) -> interfaces.context.ModuleInterface: """Creates a module object""" if size: return SizedModule(self, @@ -125,10 +125,10 @@ class Context(interfaces.context.ContextInterface): native_layer_name = native_layer_name) -def get_module_wrapper(method: str) -> typing.Callable: +def get_module_wrapper(method: str) -> Callable: """Returns a symbol using the symbol_table_name of the Module""" - def wrapper(self, name: str) -> typing.Callable: + def wrapper(self, name: str) -> Callable: self._check_type(name, str) if constants.BANG in name: raise ValueError("Name cannot reference another module") @@ -139,10 +139,10 @@ def get_module_wrapper(method: str) -> typing.Callable: class Module(interfaces.context.ModuleInterface): def object(self, - symbol_name: typing.Optional[str] = None, - type_name: typing.Optional[str] = None, - offset: typing.Optional[int] = None, - native_layer_name: typing.Optional[str] = None, + symbol_name: Optional[str] = None, + type_name: Optional[str] = None, + offset: Optional[int] = None, + native_layer_name: Optional[str] = None, **kwargs) -> interfaces.objects.ObjectInterface: """Returns an object created using the symbol_table_name and layer_name of the Module @@ -153,7 +153,7 @@ class Module(interfaces.context.ModuleInterface): @param offset: The location (absolute within memory), type_name must be specified and symbol_name must not @type offset: int """ - type_arg = None # type: typing.Optional[typing.Union[str, interfaces.objects.Template]] + type_arg = None # type: Optional[Union[str, interfaces.objects.Template]] if symbol_name is not None: self._check_type(symbol_name, str) if constants.BANG in symbol_name: @@ -192,8 +192,8 @@ class SizedModule(Module): layer_name: str, offset: int, size: int, - symbol_table_name: typing.Optional[str] = None, - native_layer_name: typing.Optional[str] = None) -> None: + symbol_table_name: Optional[str] = None, + native_layer_name: Optional[str] = None) -> None: super().__init__(context, module_name = module_name, layer_name = layer_name, @@ -220,7 +220,7 @@ class SizedModule(Module): 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) -> typing.List[str]: + 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""" if size < 0: raise ValueError("Size must be strictly non-negative") @@ -233,7 +233,7 @@ class SizedModule(Module): class ModuleCollection(validity.ValidityRoutines): """Class to contain a collection of SizedModules and reason about their contents""" - def __init__(self, modules: typing.List[SizedModule]) -> None: + def __init__(self, modules: List[SizedModule]) -> None: for module in modules: self._check_type(module, SizedModule) self._modules = modules @@ -244,7 +244,7 @@ class ModuleCollection(validity.ValidityRoutines): All 0 sized modules will have identical hashes and are therefore included in the deduplicated version """ new_modules = [] - seen = set() # type: typing.Set[str] + seen = set() # type: Set[str] for mod in self._modules: if mod.hash not in seen or mod.size == 0: new_modules.append(mod) @@ -252,21 +252,20 @@ class ModuleCollection(validity.ValidityRoutines): return ModuleCollection(new_modules) @property - def modules(self) -> typing.Dict[str, typing.List[SizedModule]]: + def modules(self) -> Dict[str, List[SizedModule]]: """A name indexed dictionary of modules using that name in this collection""" return self._generate_module_dict(self._modules) @classmethod - def _generate_module_dict(cls, modules: typing.List[SizedModule]) -> typing.Dict[str, typing.List[SizedModule]]: - result = {} # type: typing.Dict[str, typing.List[SizedModule]] + def _generate_module_dict(cls, modules: List[SizedModule]) -> Dict[str, List[SizedModule]]: + result = {} # type: Dict[str, List[SizedModule]] for module in modules: modlist = result.get(module.name, []) modlist.append(module) result[module.name] = modlist return result - def get_module_symbols_by_absolute_location(self, offset: int, size: int = 0) -> \ - typing.Iterable[typing.Tuple[str, typing.List[str]]]: + def get_module_symbols_by_absolute_location(self, offset: int, size: int = 0) -> Iterable[Tuple[str, List[str]]]: """Returns a tuple of (module_name, list_of_symbol_names) for each module, where symbols live at the absolute offset in memory provided""" if size < 0: raise ValueError("Size must be strictly non-negative") diff --git a/volatility/framework/exceptions.py b/volatility/framework/exceptions.py index 1a5718067..5fbb2cc9c 100644 --- a/volatility/framework/exceptions.py +++ b/volatility/framework/exceptions.py @@ -4,7 +4,7 @@ These include exceptions that can be thrown on errors by the symbol space or sym an address is invalid. The :class:`PagedInvalidAddressException` contains information about the size of the invalid page. """ -import typing +from typing import List class VolatilityException(Exception): @@ -87,6 +87,6 @@ class MissingStructureException(VolatilityException): class UnsatisfiedException(VolatilityException): - def __init__(self, unsatisfied: typing.List[str]) -> None: + 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 1758a53eb..d3902247f 100644 --- a/volatility/framework/interfaces/automagic.py +++ b/volatility/framework/interfaces/automagic.py @@ -2,13 +2,13 @@ Automagic objects attempt to automatically fill configuration values that a user has not filled. """ -import typing from abc import ABCMeta +from typing import TypeVar, Any, List, Optional, Tuple, Union, Type from volatility.framework import interfaces, validity from volatility.framework.configuration import requirements -R = typing.TypeVar('R', bound = interfaces.configuration.RequirementInterface) +R = TypeVar('R', bound = interfaces.configuration.RequirementInterface) class AutomagicInterface(interfaces.configuration.ConfigurableInterface, metaclass = ABCMeta): @@ -48,20 +48,19 @@ class AutomagicInterface(interfaces.configuration.ConfigurableInterface, metacla context: interfaces.context.ContextInterface, config_path: str, requirement: interfaces.configuration.RequirementInterface, - progress_callback: validity.ProgressCallback = None) -> typing.Optional[typing.List[typing.Any]]: + progress_callback: validity.ProgressCallback = None) -> Optional[List[Any]]: """Runs the automagic over the configurable""" return [] - # TODO: requirement_type can be made typing.Union[typing.Type[T], typing.Tuple[typing.Type[T], ...]] + # TODO: requirement_type can be made Union[Type[T], Tuple[Type[T], ...]] # once mypy properly supports Tuples in instance def find_requirements(self, context: interfaces.context.ContextInterface, config_path: str, requirement_root: interfaces.configuration.RequirementInterface, - requirement_type: typing.Union[typing.Tuple[typing.Type[R], ...], typing.Type[R]], - shortcut: bool = True) \ - -> typing.List[typing.Tuple[str, R]]: + requirement_type: Union[Tuple[Type[R], ...], Type[R]], + shortcut: bool = True) -> List[Tuple[str, R]]: """Determines if there is actually an unfulfilled requirement waiting This ensures we do not carry out an expensive search when there is no requirement for a particular requirement @@ -77,7 +76,7 @@ class AutomagicInterface(interfaces.configuration.ConfigurableInterface, metacla 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, R]] + results = [] # type: List[Tuple[str, R]] recurse = not shortcut if isinstance(requirement_root, requirement_type): if recurse or requirement_root.unsatisfied(context, config_path): @@ -103,8 +102,7 @@ class StackerLayerInterface(validity.ValidityRoutines, metaclass = ABCMeta): def stack(self, context: interfaces.context.ContextInterface, layer_name: str, - progress_callback: validity.ProgressCallback = None) \ - -> typing.Optional[interfaces.layers.DataLayerInterface]: + progress_callback: validity.ProgressCallback = None) -> Optional[interfaces.layers.DataLayerInterface]: """ Method to determine whether this builder can operate on the named layer. If so, modify the context appropriately. diff --git a/volatility/framework/interfaces/configuration.py b/volatility/framework/interfaces/configuration.py index 5640e35be..1f4289dbd 100644 --- a/volatility/framework/interfaces/configuration.py +++ b/volatility/framework/interfaces/configuration.py @@ -15,8 +15,8 @@ import logging import random import string import sys -import typing from abc import ABCMeta, abstractmethod +from typing import Any, Dict, Generator, List, Optional, Type, Union from volatility.framework import constants, interfaces, validity from volatility.framework.interfaces.context import ContextInterface @@ -27,8 +27,8 @@ CONFIG_SEPARATOR = "." vollog = logging.getLogger(__name__) BasicTypes = (int, bool, bytes, str) -SimpleTypes = typing.Union[int, bool, bytes, str] -ConfigSimpleType = typing.Union[SimpleTypes, typing.List[SimpleTypes]] +SimpleTypes = Union[int, bool, bytes, str] +ConfigSimpleType = Union[SimpleTypes, List[SimpleTypes]] def path_join(*args) -> str: @@ -58,13 +58,13 @@ class HierarchicalDict(collections.abc.Mapping): """ def __init__(self, - initial_dict: typing.Dict = None, + 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 - self._data = {} # type: typing.Dict[str, ConfigSimpleType] - self._subdict = {} # type: typing.Dict[str, 'HierarchicalDict'] + self._data = {} # type: Dict[str, ConfigSimpleType] + self._subdict = {} # type: Dict[str, 'HierarchicalDict'] if isinstance(initial_dict, str): initial_dict = json.loads(initial_dict) if isinstance(initial_dict, dict): @@ -80,7 +80,7 @@ class HierarchicalDict(collections.abc.Mapping): return self._separator @property - def data(self) -> typing.Dict: + def data(self) -> Dict: """Returns just the data-containing mappings on this level of the Hierarchy""" return self._data.copy() @@ -105,7 +105,7 @@ class HierarchicalDict(collections.abc.Mapping): """Returns an iterator object that supports the iterator protocol""" return self.generator() - def generator(self) -> typing.Generator[str, None, None]: + def generator(self) -> Generator[str, None, None]: """A generator for the data in this level and lower levels of this mapping""" for key in self._data: yield key @@ -124,11 +124,11 @@ class HierarchicalDict(collections.abc.Mapping): except KeyError: raise KeyError(key) - def __setitem__(self, key: str, value: typing.Any) -> None: + def __setitem__(self, key: str, value: Any) -> None: """Sets an item or creates a subdict and sets the item within that""" self._setitem(key, value) - def _setitem(self, key: str, value: typing.Any, is_data: bool = True) -> None: + def _setitem(self, key: str, value: Any, is_data: bool = True) -> None: """Set an item or appends a whole subtree at a key location""" if self.separator in key: subdict = self._subdict.get(self._key_head(key), HierarchicalDict(separator = self.separator)) @@ -155,7 +155,7 @@ class HierarchicalDict(collections.abc.Mapping): except KeyError: raise KeyError(key) - def __contains__(self, key: typing.Any) -> bool: + def __contains__(self, key: Any) -> bool: """Determines whether the key is present in the hierarchy""" if self.separator in key: try: @@ -243,7 +243,7 @@ class RequirementInterface(validity.ValidityRoutines, metaclass = ABCMeta): def __init__(self, name: str, description: str = None, - default: typing.Optional[ConfigSimpleType] = None, + default: Optional[ConfigSimpleType] = None, optional: bool = False) -> None: super().__init__() self._check_type(name, str) @@ -253,7 +253,7 @@ class RequirementInterface(validity.ValidityRoutines, metaclass = ABCMeta): self._description = description or "" self._default = default self._optional = optional - self._requirements = {} # type: typing.Dict[str, RequirementInterface] + self._requirements = {} # type: Dict[str, RequirementInterface] def __repr__(self) -> str: return "<" + self.__class__.__name__ + ": " + self.name + ">" @@ -269,7 +269,7 @@ class RequirementInterface(validity.ValidityRoutines, metaclass = ABCMeta): return self._description @property - def default(self) -> typing.Optional[ConfigSimpleType]: + def default(self) -> Optional[ConfigSimpleType]: """Returns the default value if one is set""" return self._default @@ -292,7 +292,7 @@ class RequirementInterface(validity.ValidityRoutines, metaclass = ABCMeta): # Child operations @property - def requirements(self) -> typing.Dict[str, 'RequirementInterface']: + def requirements(self) -> Dict[str, 'RequirementInterface']: """Returns a dictionary of all the child requirements, indexed by name""" return self._requirements.copy() @@ -308,7 +308,7 @@ class RequirementInterface(validity.ValidityRoutines, metaclass = ABCMeta): def unsatisfied_children(self, context: interfaces.context.ContextInterface, - config_path: str) -> typing.List[str]: + config_path: str) -> List[str]: """Method that will validate all child requirements""" result = [] for requirement in self.requirements.values(): @@ -322,7 +322,7 @@ class RequirementInterface(validity.ValidityRoutines, metaclass = ABCMeta): @abstractmethod def unsatisfied(self, context: interfaces.context.ContextInterface, - config_path: str) -> typing.List[str]: + 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 @@ -331,7 +331,7 @@ class RequirementInterface(validity.ValidityRoutines, metaclass = ABCMeta): class SimpleTypeRequirement(RequirementInterface): """Class to represent a single simple type (such as a boolean, a string, an integer or a series of bytes)""" - instance_type = bool # type: typing.ClassVar[typing.Type] + instance_type = bool # type: ClassVar[Type] def add_requirement(self, requirement: RequirementInterface): """Always raises a TypeError as instance requirements cannot have children""" @@ -341,7 +341,7 @@ class SimpleTypeRequirement(RequirementInterface): """Always raises a TypeError as instance requirements cannot have children""" raise TypeError("Instance Requirements cannot have subrequirements") - def unsatisfied(self, context: interfaces.context.ContextInterface, config_path: str) -> typing.List[str]: + def unsatisfied(self, context: interfaces.context.ContextInterface, config_path: str) -> List[str]: """Validates the instance requirement based upon its `instance_type`.""" config_path = path_join(config_path, self.name) @@ -364,10 +364,10 @@ class ClassRequirement(RequirementInterface): self._cls = None @property - def cls(self) -> typing.Type: + def cls(self) -> Type: return self._cls - def unsatisfied(self, context: interfaces.context.ContextInterface, config_path: str) -> typing.List[str]: + def unsatisfied(self, context: interfaces.context.ContextInterface, config_path: str) -> List[str]: """Checks to see if a class can be recovered""" config_path = path_join(config_path, self.name) @@ -428,8 +428,7 @@ class ConstructableRequirementInterface(RequirementInterface): def _construct_class(self, context: interfaces.context.ContextInterface, config_path: str, - requirement_dict: typing.Dict[str, object] = None) \ - -> typing.Optional['interfaces.objects.ObjectInterface']: + requirement_dict: Dict[str, object] = None) -> Optional['interfaces.objects.ObjectInterface']: """Constructs the class, handing args and the subrequirements as parameters to __init__""" if self.requirements["class"].unsatisfied(context, config_path): return None @@ -461,7 +460,7 @@ class ConfigurableRequirementInterface(RequirementInterface): def build_configuration(self, context: interfaces.context.ContextInterface, config_path: str, - value: typing.Any) -> HierarchicalDict: + value: Any) -> HierarchicalDict: """Proxies to a ConfigurableInterface if necessary""" @@ -520,12 +519,12 @@ class ConfigurableInterface(validity.ValidityRoutines, metaclass = ABCMeta): return result @classmethod - def get_requirements(cls) -> typing.List[RequirementInterface]: + def get_requirements(cls) -> List[RequirementInterface]: """Returns a list of RequirementInterface objects required by this object""" return [] @classmethod - def unsatisfied(cls, context: interfaces.context.ContextInterface, config_path: str) -> typing.List[str]: + def unsatisfied(cls, context: interfaces.context.ContextInterface, config_path: str) -> List[str]: """Returns a list of the names of all unsatisfied requirements Since a satisfied set of requirements will return [], it can be used in tests as follows: diff --git a/volatility/framework/interfaces/context.py b/volatility/framework/interfaces/context.py index ed1fd0d6f..774c61c94 100644 --- a/volatility/framework/interfaces/context.py +++ b/volatility/framework/interfaces/context.py @@ -5,8 +5,8 @@ of symbols that can be used to interpret data in a layer. The context also prov notably the object constructor function, `object`, which will construct a symbol on a layer at a particular offset. """ import copy -import typing from abc import ABCMeta, abstractmethod +from typing import Optional, Union from volatility.framework import interfaces, validity @@ -55,7 +55,7 @@ class ContextInterface(object, metaclass = ABCMeta): @abstractmethod def object(self, - symbol: typing.Union[str, 'interfaces.objects.Template'], + symbol: Union[str, 'interfaces.objects.Template'], layer_name: str, offset: int, native_layer_name: str = None, @@ -79,7 +79,7 @@ class ContextInterface(object, metaclass = ABCMeta): module_name: str, layer_name: str, offset: int, - size: typing.Optional[int] = None) -> 'ModuleInterface': + size: Optional[int] = None) -> 'ModuleInterface': """Create a module object """ @@ -94,8 +94,8 @@ class ModuleInterface(validity.ValidityRoutines, metaclass = ABCMeta): module_name: str, layer_name: str, offset: int, - symbol_table_name: typing.Optional[str] = None, - native_layer_name: typing.Optional[str] = None) -> None: + symbol_table_name: Optional[str] = None, + native_layer_name: Optional[str] = None) -> None: self._context = self._check_type(context, ContextInterface) self._module_name = self._check_type(module_name, str) self._layer_name = self._check_type(layer_name, str) diff --git a/volatility/framework/interfaces/layers.py b/volatility/framework/interfaces/layers.py index 8d103ee40..7193d08cc 100644 --- a/volatility/framework/interfaces/layers.py +++ b/volatility/framework/interfaces/layers.py @@ -6,11 +6,10 @@ import logging import math import multiprocessing import traceback -import typing from abc import ABCMeta, abstractmethod +from typing import Any, Callable, ChainMap, Dict, Iterable, List, Mapping, Optional, Tuple, Union from volatility.framework import constants, exceptions, interfaces, validity -from volatility.framework.interfaces import configuration, context vollog = logging.getLogger(__name__) @@ -23,8 +22,8 @@ try: except ImportError: pass -ProgressValue = typing.Union['DummyProgress', multiprocessing.Value] -IteratorValue = typing.Tuple[typing.List[typing.Tuple[str, int, int]], int] +ProgressValue = Union['DummyProgress', multiprocessing.Value] +IteratorValue = Tuple[List[Tuple[str, int, int]], int] class ScannerInterface(validity.ValidityRoutines, metaclass = ABCMeta): @@ -57,20 +56,20 @@ class ScannerInterface(validity.ValidityRoutines, metaclass = ABCMeta): def __init__(self) -> None: self.chunk_size = 0x1000000 # Default to 16Mb chunks self.overlap = 0x1000 # A page of overlap by default - self._context = None # type: typing.Optional[interfaces.context.ContextInterface] - self._layer_name = None # type: typing.Optional[str] + self._context = None # type: Optional[interfaces.context.ContextInterface] + self._layer_name = None # type: Optional[str] @property - def context(self) -> typing.Optional['interfaces.context.ContextInterface']: + def context(self) -> Optional['interfaces.context.ContextInterface']: return self._context @context.setter def context(self, ctx: 'interfaces.context.ContextInterface') -> None: """Stores the context locally in case the scanner needs to access the layer""" - self._context = self._check_type(ctx, context.ContextInterface) + self._context = self._check_type(ctx, interfaces.context.ContextInterface) @property - def layer_name(self) -> typing.Optional[str]: + def layer_name(self) -> Optional[str]: return self._layer_name @layer_name.setter @@ -79,7 +78,7 @@ class ScannerInterface(validity.ValidityRoutines, metaclass = ABCMeta): self._layer_name = self._check_type(layer_name, str) @abstractmethod - def __call__(self, data: bytes, data_offset: int) -> typing.Iterable[typing.Any]: + def __call__(self, data: bytes, data_offset: int) -> Iterable[Any]: """Searches through a chunk of data for a particular value/pattern/etc Always returns an iterator of the same type of object (need not be a volatility object) @@ -88,18 +87,19 @@ class ScannerInterface(validity.ValidityRoutines, metaclass = ABCMeta): """ -class DataLayerInterface(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: typing.ChainMap[str, str] + 'os': 'Unknown'}) # type: ChainMap[str, str] def __init__(self, context: 'interfaces.context.ContextInterface', config_path: str, name: str, - metadata: typing.Optional[typing.Dict[str, typing.Any]] = None) -> None: + metadata: Optional[Dict[str, Any]] = None) -> None: super().__init__(context, config_path) self._name = self._check_type(name, str) if metadata: @@ -156,12 +156,12 @@ class DataLayerInterface(configuration.ConfigurableInterface, validity.ValidityR pass @classmethod - def get_requirements(cls) -> typing.List[interfaces.configuration.RequirementInterface]: + def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: """Returns a list of Requirement objects for this type of layer""" return [] @property - def dependencies(self) -> typing.List[str]: + def dependencies(self) -> List[str]: """DataLayers must never define on other layers""" return [] @@ -171,8 +171,7 @@ class DataLayerInterface(configuration.ConfigurableInterface, validity.ValidityR context: interfaces.context.ContextInterface, scanner: ScannerInterface, progress_callback: validity.ProgressCallback = None, - sections: typing.Iterable[typing.Tuple[int, int]] = None) -> \ - typing.Iterable[typing.Any]: + sections: Iterable[Tuple[int, int]] = None) -> Iterable[Any]: """Scans a Translation layer by chunk Note: this will skip missing/unmappable chunks of memory @@ -223,10 +222,9 @@ class DataLayerInterface(configuration.ConfigurableInterface, validity.ValidityR "\n".join(traceback.TracebackException.from_exception(e).format(chain = True))) def _coalesce_sections(self, - sections: typing.Iterable[typing.Tuple[int, int]]) \ - -> typing.Iterable[typing.Tuple[int, int]]: + sections: Iterable[Tuple[int, int]]) -> Iterable[Tuple[int, int]]: """Take a list of (start, length) sections and coalesce any adjacent sections""" - result = [] # type: typing.List[typing.Tuple[int, int]] + result = [] # type: List[Tuple[int, int]] position = 0 for (start, length) in sorted(sections): if result and start <= position: @@ -252,8 +250,7 @@ class DataLayerInterface(configuration.ConfigurableInterface, validity.ValidityR def _scan_iterator(self, scanner: 'ScannerInterface', - sections: typing.Iterable[typing.Tuple[int, int]]) \ - -> typing.Iterable[IteratorValue]: + sections: Iterable[Tuple[int, int]]) -> Iterable[IteratorValue]: """Iterator that indicates which blocks in the layer are to be read by for the scanning Returns a list of blocks (potentially in lower layers) that make up this chunk contiguously. @@ -276,7 +273,7 @@ class DataLayerInterface(configuration.ConfigurableInterface, validity.ValidityR def _scan_chunk(self, scanner: 'ScannerInterface', progress: 'ProgressValue', - iterator_value: IteratorValue) -> typing.List[typing.Any]: + iterator_value: IteratorValue) -> List[Any]: data_to_scan, chunk_end = iterator_value data = b'' for layer_name, address, chunk_size in data_to_scan: @@ -292,7 +289,7 @@ class DataLayerInterface(configuration.ConfigurableInterface, validity.ValidityR def _scan_metric(self, _scanner: 'ScannerInterface', - sections: typing.List[typing.Tuple[int, int]]) -> typing.Callable[[int], float]: + sections: List[Tuple[int, int]]) -> Callable[[int], float]: if not sections: raise ValueError("Sections have no size, nothing to scan") @@ -315,7 +312,7 @@ class DataLayerInterface(configuration.ConfigurableInterface, validity.ValidityR # ## Metadata methods @property - def metadata(self) -> typing.Mapping: + def metadata(self) -> Mapping: """Returns a ReadOnly copy of the metadata published by this layer""" maps = [self.context.memory[layer_name].metadata for layer_name in self.dependencies] return interfaces.objects.ReadOnlyMapping(collections.ChainMap({}, self._direct_metadata, *maps)) @@ -330,7 +327,7 @@ class TranslationLayerInterface(DataLayerInterface, metaclass = ABCMeta): def mapping(self, offset: int, length: int, - ignore_errors: bool = False) -> typing.Iterable[typing.Tuple[int, int, int, str]]: + 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 @@ -340,14 +337,13 @@ class TranslationLayerInterface(DataLayerInterface, metaclass = ABCMeta): @property @abstractmethod - def dependencies(self) -> typing.List[str]: + def dependencies(self) -> List[str]: """Returns a list of layer names that this layer translates onto""" return [] ### Translation layer convenience function - def translate(self, offset: int, ignore_errors: bool = False) \ - -> typing.Tuple[typing.Optional[int], typing.Optional[str]]: + def translate(self, offset: int, ignore_errors: bool = False) -> Tuple[Optional[int], Optional[str]]: mapping = self.mapping(offset, 0, ignore_errors) if mapping: _, mapped_offset, _, layer = list(mapping)[0] @@ -364,7 +360,7 @@ class TranslationLayerInterface(DataLayerInterface, metaclass = ABCMeta): def read(self, offset: int, length: int, pad: bool = False) -> bytes: """Reads an offset for length bytes and returns 'bytes' (not 'str') of length size""" current_offset = offset - output = [] # type: typing.List[bytes] + 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, @@ -398,8 +394,7 @@ class TranslationLayerInterface(DataLayerInterface, metaclass = ABCMeta): def _scan_iterator(self, scanner: 'ScannerInterface', - sections: typing.Iterable[typing.Tuple[int, int]]) \ - -> typing.Iterable[IteratorValue]: + 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): offset, mapped_offset, length, layer_name = mapped @@ -418,7 +413,7 @@ class Memory(validity.ValidityRoutines, collections.abc.Mapping): """Container for multiple layers of data""" def __init__(self) -> None: - self._layers = {} # type: typing.Dict[str, DataLayerInterface] + self._layers = {} # type: Dict[str, DataLayerInterface] def read(self, layer: str, diff --git a/volatility/framework/interfaces/objects.py b/volatility/framework/interfaces/objects.py index 5575decd1..8a5aa1ed3 100644 --- a/volatility/framework/interfaces/objects.py +++ b/volatility/framework/interfaces/objects.py @@ -4,8 +4,8 @@ import collections import collections.abc import logging -import typing from abc import ABCMeta, abstractmethod +from typing import Any, List, Mapping from volatility.framework import constants, validity, interfaces from volatility.framework.interfaces import context as interfaces_context @@ -19,10 +19,10 @@ class ReadOnlyMapping(validity.ValidityRoutines, collections.abc.Mapping): This ensures that the data stored in the mapping should not be modified, making an immutable mapping. """ - def __init__(self, dictionary: typing.Mapping[str, typing.Any]) -> None: + def __init__(self, dictionary: Mapping[str, Any]) -> None: self._dict = dictionary - def __getattr__(self, attr: str) -> typing.Any: + def __getattr__(self, attr: str) -> Any: """Returns the item as an attribute""" if attr == '_dict': return super().__getattribute__(attr) @@ -30,7 +30,7 @@ class ReadOnlyMapping(validity.ValidityRoutines, collections.abc.Mapping): return self._dict[attr] raise AttributeError("Object has no attribute: {}.{}".format(self.__class__.__name__, attr)) - def __getitem__(self, name: str) -> typing.Any: + def __getitem__(self, name: str) -> Any: """Returns the item requested""" return self._dict[name] @@ -100,7 +100,7 @@ class ObjectInterface(validity.ValidityRoutines, metaclass = ABCMeta): return ReadOnlyMapping(self._vol) @abstractmethod - def write(self, value: typing.Any): + def write(self, value: Any): """Writes the new value into the format at the offset the object currently resides at""" def validate(self) -> bool: @@ -161,7 +161,7 @@ class ObjectInterface(validity.ValidityRoutines, metaclass = ABCMeta): """Returns the size of the template object""" @classmethod - def children(cls, template: 'Template') -> 'typing.List[Template]': + def children(cls, template: 'Template') -> List['Template']: """Returns the children of the template""" return [] @@ -215,7 +215,7 @@ class Template(validity.ValidityRoutines): # Allow the updating of template arguments whilst still in template form super().__init__() self._arguments = arguments - empty_dict = {} # type: typing.Dict[str, typing.Any] + empty_dict = {} # type: Dict[str, Any] self._vol = collections.ChainMap(empty_dict, self._arguments, {'type_name': type_name}) @property @@ -224,7 +224,7 @@ class Template(validity.ValidityRoutines): return ReadOnlyMapping(self._vol) @property - def children(self) -> typing.List['Template']: + def children(self) -> List['Template']: """The children of this template (such as member types, sub-types and base-types where they are relevant). Used to traverse the template tree. """ @@ -256,7 +256,7 @@ class Template(validity.ValidityRoutines): """Updates the keyword arguments with values that will **not** be carried across to clones""" self._vol.update(new_arguments) - def __getattr__(self, attr: str) -> typing.Any: + def __getattr__(self, attr: str) -> Any: """Exposes any other values stored in ._vol as attributes (for example, enumeration choices)""" if attr != '_vol': if attr in self._vol: diff --git a/volatility/framework/interfaces/plugins.py b/volatility/framework/interfaces/plugins.py index 3c3f6f7ad..9b93626e8 100644 --- a/volatility/framework/interfaces/plugins.py +++ b/volatility/framework/interfaces/plugins.py @@ -6,8 +6,8 @@ They are called and carry out some algorithms on data stored in layers using obj # Configuration interfaces must be imported separately, since we're part of interfaces and can't import ourselves import io import logging -import typing from abc import ABCMeta, abstractmethod +from typing import TYPE_CHECKING, List from volatility.framework import exceptions from volatility.framework import validity @@ -15,7 +15,7 @@ from volatility.framework.interfaces import configuration as interfaces_configur vollog = logging.getLogger(__name__) -if typing.TYPE_CHECKING: +if TYPE_CHECKING: from volatility.framework import interfaces, renderers @@ -71,7 +71,7 @@ class PluginInterface(interfaces_configuration.ConfigurableInterface, validity.V if self.unsatisfied(context, config_path): vollog.warning("Plugin failed validation") raise exceptions.PluginRequirementException("The plugin configuration failed to validate") - self._file_consumer = None # type: typing.Optional[FileConsumerInterface] + self._file_consumer = None # type: Optional[FileConsumerInterface] def set_file_consumer(self, consumer: FileConsumerInterface) -> None: self._file_consumer = self._check_type(consumer, FileConsumerInterface) @@ -84,7 +84,7 @@ class PluginInterface(interfaces_configuration.ConfigurableInterface, validity.V vollog.debug("No file consumer specified to consume: {}".format(filedata.preferred_filename)) @classmethod - def get_requirements(cls) -> typing.List['interfaces.configuration.RequirementInterface']: + def get_requirements(cls) -> List['interfaces.configuration.RequirementInterface']: """Returns a list of Requirement objects for this plugin""" return [] diff --git a/volatility/framework/interfaces/renderers.py b/volatility/framework/interfaces/renderers.py index 95cf26806..3b8e2f1e3 100644 --- a/volatility/framework/interfaces/renderers.py +++ b/volatility/framework/interfaces/renderers.py @@ -4,25 +4,25 @@ which can interact with a TreeGrid to produce suitable output.""" import collections import datetime -import typing from abc import abstractmethod, ABCMeta +from typing import Any, Callable, ClassVar, Generator, Iterable, List, NamedTuple, Optional, TypeVar, Type, Tuple, Union from volatility.framework import validity -Column = typing.NamedTuple('Column', [('index', int), ('name', str), ('type', typing.Any)]) +Column = NamedTuple('Column', [('index', int), ('name', str), ('type', Any)]) -RenderOption = typing.Any +RenderOption = Any class Renderer(validity.ValidityRoutines, metaclass = ABCMeta): """Class that defines the interface that all output renderers must support""" - def __init__(self, options: typing.List[RenderOption]) -> None: + def __init__(self, options: List[RenderOption]) -> None: """Accepts an options object to configure the renderers""" # FIXME: Once the config option objects are in place, put the _type_check in place @abstractmethod - def get_render_options(self) -> typing.List[RenderOption]: + def get_render_options(self) -> List[RenderOption]: """Returns a list of rendering options""" @abstractmethod @@ -34,7 +34,7 @@ class ColumnSortKey(metaclass = ABCMeta): ascending = True # type: bool @abstractmethod - def __call__(self, values: typing.List[typing.Any]) -> typing.Any: + def __call__(self, values: List[Any]) -> Any: """The key function passed as a sort key to the TreeGrid's visit function""" @@ -44,7 +44,7 @@ class TreeNode(collections.Sequence, metaclass = ABCMeta): @property @abstractmethod - def values(self) -> typing.Iterable['BaseTypes']: + def values(self) -> Iterable['BaseTypes']: """Returns the list of values from the particular node, based on column.index""" @property @@ -58,7 +58,7 @@ class TreeNode(collections.Sequence, metaclass = ABCMeta): @property @abstractmethod - def parent(self) -> typing.Optional['TreeNode']: + def parent(self) -> Optional['TreeNode']: """Returns the parent node of this node or None""" @property @@ -95,16 +95,16 @@ class Disassembly(object): # We don't class these off a shared base, because the BaseTypes must only # contain the types that the validator will accept (which would not include the base) -_Type = typing.TypeVar("_Type", bound = typing.Type) -ColumnsType = typing.List[typing.Tuple[str, typing.Type]] -BaseTypes = typing.Union[typing.Type[int], - typing.Type[str], - typing.Type[float], - typing.Type[bytes], - typing.Type[datetime.datetime], - typing.Type[BaseAbsentValue], - typing.Type[Disassembly]] -VisitorSignature = typing.Callable[[TreeNode, _Type], _Type] +_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], + Type[Disassembly]] +VisitorSignature = Callable[[TreeNode, _Type], _Type] class TreeGrid(object, metaclass = ABCMeta): @@ -120,9 +120,9 @@ class TreeGrid(object, metaclass = ABCMeta): and to create cycles. """ - base_types = (int, str, float, bytes, datetime.datetime, Disassembly) # type: typing.ClassVar[typing.Tuple] + base_types = (int, str, float, bytes, datetime.datetime, Disassembly) # type: ClassVar[Tuple] - def __init__(self, columns: ColumnsType, generator: typing.Generator) -> None: + def __init__(self, columns: ColumnsType, generator: Generator) -> None: """Constructs a TreeGrid object using a specific set of columns The TreeGrid itself is a root element, that can have children but no values. @@ -142,7 +142,7 @@ class TreeGrid(object, metaclass = ABCMeta): @abstractmethod def populate(self, func: VisitorSignature = None, - initial_accumulator: typing.Any = None) -> 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 @@ -156,15 +156,15 @@ class TreeGrid(object, metaclass = ABCMeta): @property @abstractmethod - def columns(self) -> typing.List[Column]: + def columns(self) -> List[Column]: """Returns the available columns and their ordering and types""" @abstractmethod - def children(self, node: TreeNode) -> typing.List[TreeNode]: + def children(self, node: TreeNode) -> List[TreeNode]: """Returns the subnodes of a particular node in order""" @abstractmethod - def values(self, node: TreeNode) -> typing.Tuple[BaseTypes, ...]: + def values(self, node: TreeNode) -> Tuple[BaseTypes, ...]: """Returns the values for a particular node The values returned are mutable, diff --git a/volatility/framework/interfaces/symbols.py b/volatility/framework/interfaces/symbols.py index 87f9f305e..555cc7f42 100644 --- a/volatility/framework/interfaces/symbols.py +++ b/volatility/framework/interfaces/symbols.py @@ -2,8 +2,8 @@ """ import bisect import collections.abc -import typing -from abc import abstractmethod +from abc import abstractmethod, ABC +from typing import Any, Dict, Iterable, List, Optional, Tuple, Type from volatility.framework import constants, exceptions, validity from volatility.framework.interfaces import configuration, objects, context as interfaces_context @@ -15,8 +15,8 @@ class SymbolInterface(validity.ValidityRoutines): def __init__(self, name: str, address: int, - type: typing.Optional[objects.Template] = None, - constant_data: typing.Optional[bytes] = None) -> None: + type: Optional[objects.Template] = None, + constant_data: Optional[bytes] = None) -> None: self._name = self._check_type(name, str) if constants.BANG in self._name: raise ValueError("Symbol names cannot contain the symbol differentiator ({})".format(constants.BANG)) @@ -39,7 +39,7 @@ class SymbolInterface(validity.ValidityRoutines): return self._name @property - def type_name(self) -> typing.Optional[str]: + def type_name(self) -> Optional[str]: """Returns the name of the type that the symbol represents""" # Objects and ObjectTemplates should *always* get a type_name when they're constructed, so allow the IndexError if self.type is None: @@ -47,7 +47,7 @@ class SymbolInterface(validity.ValidityRoutines): return self.type.vol['type_name'] @property - def type(self) -> typing.Optional[objects.Template]: + def type(self) -> Optional[objects.Template]: """Returns the type that the symbol represents""" return self._type @@ -57,7 +57,7 @@ class SymbolInterface(validity.ValidityRoutines): return self._address @property - def constant_data(self) -> typing.Optional[bytes]: + def constant_data(self) -> Optional[bytes]: return self._constant_data @@ -73,13 +73,13 @@ class BaseSymbolTableInterface(validity.ValidityRoutines): def __init__(self, name: str, native_types: 'NativeTableInterface', - table_mapping: typing.Optional[typing.Dict[str, str]] = None) -> None: + table_mapping: Optional[Dict[str, str]] = None) -> None: self.name = self._check_type(name, str) if table_mapping is None: table_mapping = {} self.table_mapping = self._check_type(table_mapping, dict) self._native_types = self._check_type(native_types, NativeTableInterface) - self._sort_symbols = [] # type: typing.List[typing.Tuple[int, str]] + self._sort_symbols = [] # type: List[Tuple[int, str]] # ## Required Symbol functions @@ -91,14 +91,14 @@ class BaseSymbolTableInterface(validity.ValidityRoutines): raise NotImplementedError("Abstract property get_symbol not implemented by subclass.") @property - def symbols(self) -> typing.Iterable[str]: + def symbols(self) -> Iterable[str]: """Returns an iterator of the Symbol names""" raise NotImplementedError("Abstract property symbols not implemented by subclass.") # ## Required Type functions @property - def types(self) -> typing.Iterable[str]: + def types(self) -> Iterable[str]: """Returns an iterator of the Symbol type names""" raise NotImplementedError("Abstract property types not implemented by subclass.") @@ -112,7 +112,7 @@ class BaseSymbolTableInterface(validity.ValidityRoutines): # ## Required Symbol enumeration functions @property - def enumerations(self) -> typing.Iterable[typing.Any]: + def enumerations(self) -> Iterable[Any]: """Returns an iterator of the Enumeration names""" raise NotImplementedError("Abstract property enumerations not implemented by subclass.") @@ -134,14 +134,14 @@ class BaseSymbolTableInterface(validity.ValidityRoutines): # ## Functions for overriding classes - def set_type_class(self, name: str, clazz: typing.Type[objects.ObjectInterface]) -> None: + def set_type_class(self, name: str, clazz: Type[objects.ObjectInterface]) -> None: """Overrides the object class for a specific Symbol type Name *must* be present in self.types """ raise NotImplementedError("Abstract method set_type_class not implemented yet.") - def get_type_class(self, name: str) -> typing.Type[objects.ObjectInterface]: + def get_type_class(self, name: str) -> Type[objects.ObjectInterface]: """Returns the class associated with a Symbol type""" raise NotImplementedError("Abstract method get_type_class not implemented yet.") @@ -151,14 +151,14 @@ class BaseSymbolTableInterface(validity.ValidityRoutines): # ## Convenience functions for location symbols - def get_symbol_type(self, name: str) -> typing.Optional[objects.Template]: + def get_symbol_type(self, name: str) -> Optional[objects.Template]: """Resolves a symbol name into a symbol and then resolves the symbol's type""" type_name = self.get_symbol(name).type_name if type_name is None: return None return self.get_type(type_name) - def get_symbols_by_type(self, type_name: str) -> typing.Iterable[str]: + def get_symbols_by_type(self, type_name: str) -> Iterable[str]: """Returns the name of all symbols in this table that have type matching type_name""" for symbol_name in self.symbols: # This allows for searching with and without the table name (in case multiple tables contain @@ -168,7 +168,7 @@ class BaseSymbolTableInterface(validity.ValidityRoutines): 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) -> typing.Iterable[str]: + def get_symbols_by_location(self, offset: int, size: int = 0) -> Iterable[str]: """Returns the name of all symbols in this table that live at a particular offset""" if size < 0: raise ValueError("Size must be strictly non-negative") @@ -189,14 +189,14 @@ class SymbolSpaceInterface(collections.abc.Mapping): """Returns an unused table name to ensure no collision occurs when inserting a symbol table""" @abstractmethod - def get_symbols_by_type(self, type_name: str) -> typing.Iterable[str]: + def get_symbols_by_type(self, type_name: str) -> Iterable[str]: """Returns all symbols based on the type of the symbol""" @abstractmethod def get_symbols_by_location(self, offset: int, size: int = 0, - table_name: typing.Optional[str] = None) -> typing.Iterable[str]: + table_name: Optional[str] = None) -> Iterable[str]: """Returns all symbols that exist at a specific relative address""" @abstractmethod @@ -208,7 +208,7 @@ class SymbolSpaceInterface(collections.abc.Mapping): """Look-up a symbol name across all the contained symbol tables""" @abstractmethod - def get_enumeration(self, enum_name: str) -> typing.Dict[str, typing.Any]: + def get_enumeration(self, enum_name: str) -> Dict[str, Any]: """Look-up an enumeration across all the contained symbol tables""" @abstractmethod @@ -228,7 +228,7 @@ class SymbolSpaceInterface(collections.abc.Mapping): """Adds a symbol_list to the end of the space""" -class SymbolTableInterface(BaseSymbolTableInterface, configuration.ConfigurableInterface): +class SymbolTableInterface(BaseSymbolTableInterface, configuration.ConfigurableInterface, ABC): """Handles a table of symbols""" # FIXME: native_types and table_mapping aren't recorded in the configuration @@ -237,7 +237,7 @@ class SymbolTableInterface(BaseSymbolTableInterface, configuration.ConfigurableI config_path: str, name: str, native_types: 'NativeTableInterface', - table_mapping: typing.Optional[typing.Dict[str, str]] = None) -> None: + table_mapping: Optional[Dict[str, str]] = None) -> None: configuration.ConfigurableInterface.__init__(self, context, config_path) BaseSymbolTableInterface.__init__(self, name, native_types, table_mapping) @@ -256,20 +256,20 @@ class NativeTableInterface(BaseSymbolTableInterface): raise exceptions.SymbolError("NativeTables never hold symbols") @property - def symbols(self) -> typing.Iterable[str]: + def symbols(self) -> Iterable[str]: return [] - def get_enumeration(self, name: str) -> typing.Dict[str, typing.Any]: + def get_enumeration(self, name: str) -> Dict[str, Any]: raise exceptions.SymbolError("NativeTables never hold enumerations") @property - def enumerations(self) -> typing.Iterable[str]: + def enumerations(self) -> Iterable[str]: return [] class MetadataInterface(object): """Interface for accessing metadata stored within a symbol table""" - def __init__(self, json_data: typing.Dict) -> None: + def __init__(self, json_data: Dict) -> None: """Constructor that accepts json_data""" self._json_data = json_data diff --git a/volatility/framework/layers/__init__.py b/volatility/framework/layers/__init__.py index 48844b2bd..978e8649a 100644 --- a/volatility/framework/layers/__init__.py +++ b/volatility/framework/layers/__init__.py @@ -6,10 +6,10 @@ import logging import lzma import os import ssl -import typing import urllib.parse import urllib.request import zipfile +from typing import List, Optional try: import magic @@ -37,15 +37,15 @@ class ResourceAccessor(object): """Object for openning URLs as files (downloading locally first if necessary)""" def __init__(self, - progress_callback: typing.Optional[validity.ProgressCallback] = None, - context: typing.Optional[ssl.SSLContext] = None) -> None: + progress_callback: Optional[validity.ProgressCallback] = None, + context: Optional[ssl.SSLContext] = None) -> None: """Creates a resource accessor Note: context is an SSL context, not a volatility context """ self._progress_callback = progress_callback self._context = context - self._cached_files = [] # type: typing.List[str] + self._cached_files = [] # type: List[str] self._handlers = list(framework.class_subclasses(urllib.request.BaseHandler)) vollog.log(constants.LOGLEVEL_VVV, "Available URL handlers: {}".format(", ".join([x.__name__ for x in self._handlers]))) diff --git a/volatility/framework/layers/crash.py b/volatility/framework/layers/crash.py index 3312e6aca..bf06c520b 100644 --- a/volatility/framework/layers/crash.py +++ b/volatility/framework/layers/crash.py @@ -7,7 +7,7 @@ # This file is part of Volatility 3. import struct -import typing +from typing import Tuple, Optional from volatility.framework import constants, exceptions, interfaces, validity from volatility.framework.layers import segmented @@ -89,7 +89,7 @@ class WindowsCrashDump32Layer(segmented.SegmentedLayer): @classmethod def _check_header(cls, base_layer: interfaces.layers.DataLayerInterface, - offset: int = 0) -> typing.Tuple[int, int]: + offset: int = 0) -> Tuple[int, int]: # Verify the Window's crash dump file magic try: @@ -116,7 +116,7 @@ class WindowsCrashDump32Stacker(interfaces.automagic.StackerLayerInterface): context: interfaces.context.ContextInterface, layer_name: str, progress_callback: validity.ProgressCallback = None) \ - -> typing.Optional[interfaces.layers.DataLayerInterface]: + -> Optional[interfaces.layers.DataLayerInterface]: try: WindowsCrashDump32Layer._check_header(context.memory[layer_name]) except WindowsCrashDump32FormatException: diff --git a/volatility/framework/layers/intel.py b/volatility/framework/layers/intel.py index 9a6c576a1..9b0b678cc 100644 --- a/volatility/framework/layers/intel.py +++ b/volatility/framework/layers/intel.py @@ -2,15 +2,15 @@ import collections import logging import math import struct -import typing +from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple, TypeVar from volatility.framework import exceptions, interfaces from volatility.framework.configuration import requirements vollog = logging.getLogger(__name__) -_T = typing.TypeVar("_T") -_S = typing.TypeVar("_S") +_T = TypeVar("_T") +_S = TypeVar("_S") class classproperty(object): @@ -18,7 +18,7 @@ class classproperty(object): Note this will change the return type """ - def __init__(self, func: typing.Callable[[_S], _T]) -> None: + def __init__(self, func: Callable[[_S], _T]) -> None: self._func = func def __get__(self, _owner_self, owner_cls: _S) -> _T: @@ -44,10 +44,10 @@ class Intel(interfaces.layers.TranslationLayerInterface): context: interfaces.context.ContextInterface, config_path: str, name: str, - metadata: typing.Optional[typing.Dict[str, typing.Any]] = None) -> None: + metadata: Optional[Dict[str, Any]] = None) -> None: super().__init__(context = context, config_path = config_path, name = name, metadata = metadata) self._base_layer = self._check_type(self.config["memory_layer"], str) - self._swap_layers = [] # type: typing.List[str] + self._swap_layers = [] # type: List[str] self._check_type(self.config.get("swap_layers", False), bool) self._page_map_offset = self._check_type(self.config["page_map_offset"], int) @@ -75,7 +75,7 @@ class Intel(interfaces.layers.TranslationLayerInterface): return (1 << cls._maxvirtaddr) - 1 @classproperty - def structure(cls) -> typing.List[typing.Tuple[str, int, bool]]: + def structure(cls) -> List[Tuple[str, int, bool]]: return cls._structure @staticmethod @@ -92,7 +92,7 @@ class Intel(interfaces.layers.TranslationLayerInterface): """Returns whether a particular page is valid based on its entry""" return bool(entry & 1) - def _translate(self, offset: int) -> typing.Tuple[int, int, str]: + def _translate(self, offset: int) -> Tuple[int, int, str]: """Translates a specific offset based on paging tables Returns the translated offset, the contiguous pagesize that the translated address lives in and the layer_name that the address lives in @@ -165,7 +165,7 @@ class Intel(interfaces.layers.TranslationLayerInterface): def mapping(self, offset: int, length: int, - ignore_errors: bool = False) -> typing.Iterable[typing.Tuple[int, int, int, str]]: + 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 @@ -205,13 +205,13 @@ class Intel(interfaces.layers.TranslationLayerInterface): offset += chunk_size @property - def dependencies(self) -> typing.List[str]: + def dependencies(self) -> List[str]: """Returns a list of the lower layer names that this layer is dependent upon""" # TODO: Add in the whole buffalo return [self._base_layer] + self._swap_layers @classmethod - def get_requirements(cls) -> typing.List[interfaces.configuration.RequirementInterface]: + def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: return [requirements.TranslationLayerRequirement(name = 'memory_layer', optional = False), requirements.LayerListRequirement(name = 'swap_layers', diff --git a/volatility/framework/layers/lime.py b/volatility/framework/layers/lime.py index 1eea64170..9be7ade0b 100644 --- a/volatility/framework/layers/lime.py +++ b/volatility/framework/layers/lime.py @@ -5,7 +5,7 @@ Created on 6 Apr 2016 """ import struct -import typing +from typing import Optional, Tuple from volatility.framework import exceptions, interfaces, validity from volatility.framework.layers import segmented @@ -66,7 +66,7 @@ class LimeLayer(segmented.SegmentedLayer): @classmethod def _check_header(cls, base_layer: interfaces.layers.DataLayerInterface, - offset: int = 0) -> typing.Tuple[int, int]: + offset: int = 0) -> Tuple[int, int]: try: header_data = base_layer.read(offset, cls._header_struct.size) except exceptions.InvalidAddressException: @@ -87,7 +87,7 @@ class LimeStacker(interfaces.automagic.StackerLayerInterface): context: interfaces.context.ContextInterface, layer_name: str, progress_callback: validity.ProgressCallback = None) \ - -> typing.Optional[interfaces.layers.DataLayerInterface]: + -> Optional[interfaces.layers.DataLayerInterface]: try: LimeLayer._check_header(context.memory[layer_name]) except LimeFormatException: diff --git a/volatility/framework/layers/physical.py b/volatility/framework/layers/physical.py index 95c70bcdf..411b7730c 100644 --- a/volatility/framework/layers/physical.py +++ b/volatility/framework/layers/physical.py @@ -1,4 +1,4 @@ -import typing +from typing import Any, Dict, IO, List, Optional from volatility.framework import exceptions, interfaces, layers from volatility.framework.configuration import requirements @@ -14,7 +14,7 @@ class BufferDataLayer(interfaces.layers.DataLayerInterface): config_path: str, name: str, buffer: bytes, - metadata: typing.Optional[typing.Dict[str, typing.Any]] = None) -> None: + metadata: Optional[Dict[str, Any]] = None) -> None: super().__init__(context = context, config_path = config_path, name = name, metadata = metadata) self._buffer = self._check_type(buffer, bytes) @@ -49,7 +49,7 @@ class BufferDataLayer(interfaces.layers.DataLayerInterface): self._buffer = self._buffer[:address] + data + self._buffer[address + len(data):] @classmethod - def get_requirements(cls) -> typing.List[interfaces.configuration.RequirementInterface]: + 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)] @@ -64,13 +64,13 @@ class FileLayer(interfaces.layers.DataLayerInterface): context: interfaces.context.ContextInterface, config_path: str, name: str, - metadata: typing.Optional[typing.Dict[str, typing.Any]] = None) -> None: + metadata: Optional[Dict[str, Any]] = None) -> None: super().__init__(context = context, config_path = config_path, name = name, metadata = metadata) self._location = self.config["location"] self._accessor = layers.ResourceAccessor() - self._file_ = None # type: typing.Optional[typing.IO[typing.Any]] - self._size = None # type: typing.Optional[int] + self._file_ = None # type: Optional[IO[Any]] + self._size = None # type: Optional[int] # Instantiate the file to throw exceptions if the file doesn't open _ = self._file @@ -80,7 +80,7 @@ class FileLayer(interfaces.layers.DataLayerInterface): return self._location @property - def _file(self) -> typing.IO[typing.Any]: + def _file(self) -> IO[Any]: """Property to prevent the initializer storing an unserializable open file (for context cloning)""" # FIXME: Add "+" to the mode once we've determined whether write mode is enabled mode = "rb" @@ -144,7 +144,7 @@ class FileLayer(interfaces.layers.DataLayerInterface): self._file.seek(offset) self._file.write(data) - def __getstate__(self) -> typing.Dict[str, typing.Any]: + def __getstate__(self) -> Dict[str, Any]: """Do not store the open _file_ attribute, our property will ensure the file is open when needed This is necessary for multi-processing @@ -157,5 +157,5 @@ class FileLayer(interfaces.layers.DataLayerInterface): self._file.close() @classmethod - def get_requirements(cls) -> typing.List[interfaces.configuration.RequirementInterface]: + def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: return [requirements.StringRequirement(name = 'location', optional = False)] diff --git a/volatility/framework/layers/registry.py b/volatility/framework/layers/registry.py index 02f9e1772..df25d053c 100644 --- a/volatility/framework/layers/registry.py +++ b/volatility/framework/layers/registry.py @@ -1,5 +1,5 @@ import logging -import typing +from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple, Union from volatility.framework import constants, exceptions, interfaces, objects from volatility.framework.configuration import requirements @@ -24,7 +24,7 @@ class RegistryHive(interfaces.layers.TranslationLayerInterface): context: interfaces.context.ContextInterface, config_path: str, name: str, - metadata: typing.Optional[typing.Dict[str, typing.Any]] = None) -> None: + metadata: Optional[Dict[str, Any]] = None) -> None: super().__init__(context = context, config_path = config_path, name = name, metadata = metadata) self._base_layer = self.config["base_layer"] @@ -111,8 +111,7 @@ class RegistryHive(interfaces.layers.TranslationLayerInterface): "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) -> typing.Union[ - typing.List[objects.Struct], objects.Struct]: + def get_key(self, key: str, return_list: bool = False) -> Union[List[objects.Struct], objects.Struct]: """Gets a specific registry key by key path return_list specifies whether the return result will be a single node (default) or a list of nodes from @@ -122,7 +121,7 @@ class RegistryHive(interfaces.layers.TranslationLayerInterface): if key.endswith("\\"): key = key[:-1] key_array = key.split('\\') - found_key = [] # type: typing.List[str] + found_key = [] # type: List[str] while key_array and node_key: subkeys = node_key[-1].get_subkeys() for subkey in subkeys: @@ -141,8 +140,8 @@ class RegistryHive(interfaces.layers.TranslationLayerInterface): return node_key[-1] def visit_nodes(self, - visitor: typing.Callable[[objects.Struct], None], - node: typing.Optional[objects.Struct] = None) -> None: + 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) @@ -160,7 +159,7 @@ class RegistryHive(interfaces.layers.TranslationLayerInterface): return value & mask @classmethod - def get_requirements(cls) -> typing.List[interfaces.configuration.RequirementInterface]: + 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)] @@ -185,7 +184,7 @@ class RegistryHive(interfaces.layers.TranslationLayerInterface): def mapping(self, offset: int, length: int, - ignore_errors: bool = False) -> typing.Iterable[typing.Tuple[int, int, int, str]]: + 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): @@ -216,7 +215,7 @@ class RegistryHive(interfaces.layers.TranslationLayerInterface): return response @property - def dependencies(self) -> typing.List[str]: + def dependencies(self) -> List[str]: """Returns a list of layer names that this layer translates onto""" return [self.config['base_layer']] diff --git a/volatility/framework/layers/scanners/__init__.py b/volatility/framework/layers/scanners/__init__.py index caaf362c3..e38f00263 100644 --- a/volatility/framework/layers/scanners/__init__.py +++ b/volatility/framework/layers/scanners/__init__.py @@ -1,5 +1,5 @@ import re -import typing +from typing import Generator, List, Tuple, Union from volatility.framework.interfaces import layers from volatility.framework.layers.scanners import multiregexp @@ -12,7 +12,7 @@ class BytesScanner(layers.ScannerInterface): super().__init__() self.needle = self._check_type(needle, bytes) - def __call__(self, data: bytes, data_offset: int) -> typing.Generator[int, None, None]: + def __call__(self, data: bytes, data_offset: int) -> Generator[int, None, None]: """Runs through the data looking for the needle, and yields all offsets where the needle is found """ find_pos = data.find(self.needle) @@ -30,7 +30,7 @@ class RegExScanner(layers.ScannerInterface): super().__init__() self.regex = re.compile(self._check_type(pattern, bytes), self._check_type(flags, int)) - def __call__(self, data: bytes, data_offset: int) -> typing.Generator[int, None, None]: + def __call__(self, data: bytes, data_offset: int) -> Generator[int, None, None]: """Runs through the data looking for the needle, and yields all offsets where the needle is found """ find_pos = self.regex.finditer(data) @@ -43,7 +43,7 @@ class RegExScanner(layers.ScannerInterface): class MultiStringScanner(layers.ScannerInterface): thread_safe = True - def __init__(self, patterns: typing.List[bytes]) -> None: + def __init__(self, patterns: List[bytes]) -> None: super().__init__() self._check_type(patterns, list) self._patterns = multiregexp.MultiRegexp() @@ -52,8 +52,7 @@ class MultiStringScanner(layers.ScannerInterface): self._patterns.add_pattern(pattern) self._patterns.preprocess() - def __call__(self, data: bytes, data_offset: int) \ - -> typing.Generator[typing.Tuple[int, typing.Union[str, bytes]], None, None]: + def __call__(self, data: bytes, data_offset: int) -> Generator[Tuple[int, Union[str, bytes]], None, None]: """Runs through the data looking for the needles""" for offset, pattern in self._patterns.search(data): if offset < self.chunk_size: diff --git a/volatility/framework/layers/scanners/multiregexp.py b/volatility/framework/layers/scanners/multiregexp.py index c44e5ddd7..02dd7e10c 100644 --- a/volatility/framework/layers/scanners/multiregexp.py +++ b/volatility/framework/layers/scanners/multiregexp.py @@ -1,12 +1,12 @@ import re -import typing +from typing import Generator, List, Tuple, Union class MultiRegexp(object): """Algorithm for multi-string matching""" def __init__(self) -> None: - self._pattern_strings = [] # type: typing.List[bytes] + self._pattern_strings = [] # type: List[bytes] self._regex = re.compile(b'') def add_pattern(self, pattern: bytes) -> None: @@ -16,7 +16,7 @@ class MultiRegexp(object): self._regex = re.compile(b'|'.join(map(re.escape, self._pattern_strings))) def search(self, haystack: bytes) \ - -> typing.Generator[typing.Tuple[int, typing.Union[str, bytes]], None, None]: + -> Generator[Tuple[int, Union[str, bytes]], None, None]: if not isinstance(haystack, bytes): raise TypeError("Search haystack must be a byte string") for match in re.finditer(self._regex, haystack): diff --git a/volatility/framework/layers/scanners/wumanber.py b/volatility/framework/layers/scanners/wumanber.py index b26fdd8ce..90bcfc318 100644 --- a/volatility/framework/layers/scanners/wumanber.py +++ b/volatility/framework/layers/scanners/wumanber.py @@ -1,4 +1,4 @@ -import typing +from typing import Generator, List, Optional, Set, Tuple, Union class WuManber(object): @@ -11,9 +11,9 @@ class WuManber(object): self._block_size = block_size self._maximum_hash = self._hash_function(b"\xff\xff\xff") + 1 # This depends on the hash function used - self._patterns = [] # type: typing.List[bytes] - self._shift = None # type: typing.Optional[typing.List[int]] - self._hashes = [set() for _ in range(self._maximum_hash)] # type: typing.List[typing.Set[bytes]] + self._patterns = [] # type: List[bytes] + self._shift = None # type: Optional[List[int]] + self._hashes = [set() for _ in range(self._maximum_hash)] # type: List[Set[bytes]] def add_pattern(self, pattern: bytes) -> None: if not isinstance(pattern, bytes): @@ -35,7 +35,7 @@ class WuManber(object): max_jump = self.minimum_pattern_length - self._block_size + 1 self._shift = [max_jump] * self._maximum_hash - self.hashes = [set() for _ in range(self._maximum_hash)] # type: typing.List[typing.Set[bytes]] + self.hashes = [set() for _ in range(self._maximum_hash)] # type: List[Set[bytes]] for pattern in self._patterns: for i in range(self._block_size, self.minimum_pattern_length + 1): @@ -53,7 +53,7 @@ class WuManber(object): return (value_bytes[0] << 5) + (value_bytes[1] << 3) + value_bytes[2] def search(self, haystack: bytes) \ - -> typing.Generator[typing.Tuple[int, typing.Union[str, bytes]], None, None]: + -> Generator[Tuple[int, Union[str, bytes]], None, None]: """Search through a large body of data for patterns previously added with add_pattern""" if not isinstance(haystack, bytes): raise TypeError("Search haystack must be a byte string") diff --git a/volatility/framework/layers/segmented.py b/volatility/framework/layers/segmented.py index dcc96cecb..eb5202a63 100644 --- a/volatility/framework/layers/segmented.py +++ b/volatility/framework/layers/segmented.py @@ -1,6 +1,6 @@ -import typing from abc import ABCMeta, abstractmethod from bisect import bisect_right +from typing import Any, Dict, Iterable, List, Optional, Tuple from volatility.framework import exceptions, interfaces from volatility.framework.configuration import requirements @@ -16,13 +16,13 @@ class SegmentedLayer(interfaces.layers.TranslationLayerInterface, metaclass = AB context: interfaces.configuration.ContextInterface, config_path: str, name: str, - metadata: typing.Optional[typing.Dict[str, typing.Any]] = None) -> None: + metadata: Optional[Dict[str, Any]] = None) -> None: super().__init__(context = context, config_path = config_path, name = name, metadata = metadata) self._base_layer = self.config["base_layer"] - self._segments = [] # type: typing.List[typing.Tuple[int, int, int]] - self._minaddr = None # type: typing.Optional[int] - self._maxaddr = None # type: typing.Optional[int] + self._segments = [] # type: List[Tuple[int, int, int]] + self._minaddr = None # type: Optional[int] + self._maxaddr = None # type: Optional[int] self._load_segments() @@ -41,7 +41,7 @@ class SegmentedLayer(interfaces.layers.TranslationLayerInterface, metaclass = AB except exceptions.InvalidAddressException: return False - def _find_segment(self, offset: int, next: bool = False) -> typing.Tuple[int, int, int]: + def _find_segment(self, offset: int, next: bool = False) -> Tuple[int, int, int]: """Finds the segment containing a given offset Returns the segment tuple (offset, mapped_offset, length) @@ -62,8 +62,7 @@ class SegmentedLayer(interfaces.layers.TranslationLayerInterface, metaclass = AB return self._segments[i] raise exceptions.InvalidAddressException(self.name, offset, "Invalid address at {:0x}".format(offset)) - def mapping(self, offset: int, length: int, ignore_errors: bool = False) \ - -> typing.Iterable[typing.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""" done = False current_offset = offset @@ -118,11 +117,11 @@ class SegmentedLayer(interfaces.layers.TranslationLayerInterface, metaclass = AB return self._maxaddr @property - def dependencies(self) -> typing.List[str]: + def dependencies(self) -> List[str]: """Returns a list of the lower layers that this layer is dependent upon""" return [self._base_layer] @classmethod - def get_requirements(cls) -> typing.List[interfaces.configuration.RequirementInterface]: + def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: return [requirements.TranslationLayerRequirement(name = 'base_layer', optional = False)] diff --git a/volatility/framework/layers/vmware.py b/volatility/framework/layers/vmware.py index ad99c46b3..74c5eb03d 100644 --- a/volatility/framework/layers/vmware.py +++ b/volatility/framework/layers/vmware.py @@ -1,6 +1,6 @@ import os import struct -import typing +from typing import Any, Dict, List, Optional from volatility.framework import interfaces, validity from volatility.framework.configuration import requirements @@ -18,7 +18,7 @@ class VmwareLayer(segmented.SegmentedLayer): context: interfaces.context.ContextInterface, config_path: str, name: str, - metadata: typing.Optional[typing.Dict[str, typing.Any]] = None) -> None: + metadata: Optional[Dict[str, Any]] = None) -> None: # Construct these so we can use self.config self._context = context self._config_path = config_path @@ -90,11 +90,11 @@ class VmwareLayer(segmented.SegmentedLayer): self._segments.append((offset, mapped_offset, length)) @property - def dependencies(self) -> typing.List[str]: + def dependencies(self) -> List[str]: return [self._base_layer, self._meta_layer] @classmethod - def get_requirements(cls) -> typing.List[interfaces.configuration.RequirementInterface]: + 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), @@ -109,7 +109,7 @@ class VmwareStacker(interfaces.automagic.StackerLayerInterface): context: interfaces.context.ContextInterface, layer_name: str, progress_callback: validity.ProgressCallback = None) \ - -> typing.Optional[interfaces.layers.DataLayerInterface]: + -> Optional[interfaces.layers.DataLayerInterface]: """Attempt to stack this based on the starting information""" memlayer = context.memory[layer_name] if not isinstance(memlayer, physical.FileLayer): diff --git a/volatility/framework/objects/__init__.py b/volatility/framework/objects/__init__.py index 5fc6244af..1e9d21af3 100644 --- a/volatility/framework/objects/__init__.py +++ b/volatility/framework/objects/__init__.py @@ -1,8 +1,8 @@ import collections import logging import struct -import typing from collections import abc +from typing import Any, ClassVar, Dict, List, Iterable, Optional, Tuple, Type, Union, overload from volatility.framework import interfaces from volatility.framework.interfaces.objects import ObjectInformation @@ -14,8 +14,8 @@ DataFormatInfo = collections.namedtuple('DataFormatInfo', ['length', 'byteorder' def convert_data_to_value(data: bytes, - struct_type: typing.Type[typing.Union[int, float, bytes, str, bool]], - data_format: DataFormatInfo) -> typing.Union[int, float, bytes, str, bool]: + 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, @@ -37,8 +37,8 @@ def convert_data_to_value(data: bytes, return struct.unpack(struct_format, data)[0] -def convert_value_to_data(value: typing.Union[int, float, bytes, str, bool], - struct_type: typing.Type[typing.Union[int, float, bytes, str, bool]], +def convert_value_to_data(value: Union[int, float, bytes, str, bool], + struct_type: Type[Union[int, float, bytes, str, bool]], data_format: DataFormatInfo) -> bytes: """Converts a particular value to a series of bytes""" if not isinstance(value, struct_type): @@ -74,7 +74,7 @@ class Void(interfaces.objects.ObjectInterface): """Dummy size for Void objects""" raise TypeError("Void types are incomplete, cannot contain data and do not have a size") - def write(self, value: typing.Any) -> None: + def write(self, value: Any) -> None: """Dummy method that does nothing for Void objects""" raise TypeError("Cannot write data to a void, recast as another object") @@ -85,7 +85,7 @@ class Function(interfaces.objects.ObjectInterface): class PrimitiveObject(interfaces.objects.ObjectInterface): """PrimitiveObject is an interface for any objects that should simulate a Python primitive""" - _struct_type = int # type: typing.ClassVar[typing.Type] + _struct_type = int # type: ClassVar[Type] def __init__(self, context: interfaces.context.ContextInterface, @@ -98,13 +98,13 @@ class PrimitiveObject(interfaces.objects.ObjectInterface): data_format = data_format) self._data_format = data_format - def __new__(cls: typing.Type, + def __new__(cls: 'PrimitiveObject', context: interfaces.context.ContextInterface, type_name: str, object_info: interfaces.objects.ObjectInformation, data_format: DataFormatInfo, - new_value: typing.Union[int, float, bool, bytes, str] = None, - **kwargs) -> typing.Type['PrimitiveObject']: + new_value: Union[int, float, bool, bytes, str] = None, + **kwargs) -> 'PrimitiveObject': """Creates the appropriate class and returns it so that the native type is inherited The only reason the **kwargs is added, is so that the inherriting types can override __init__ @@ -140,7 +140,7 @@ class PrimitiveObject(interfaces.objects.ObjectInterface): def _unmarshall(cls, context: interfaces.context.ContextInterface, data_format: DataFormatInfo, - object_info: ObjectInformation) -> typing.Union[int, float, bool, bytes, str]: + 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) @@ -150,7 +150,7 @@ class PrimitiveObject(interfaces.objects.ObjectInterface): """Returns the size of the templated object""" return template.vol.data_format.length - def write(self, value: typing.Union[int, float, bool, bytes, str]) -> None: + def write(self, value: Union[int, float, bool, bytes, str]) -> None: """Writes the object into the layer of the context at the current offset""" data = convert_value_to_data(value, self._struct_type, self._data_format) return self._context.memory.write(self.vol.layer_name, self.vol.offset, data) @@ -158,7 +158,7 @@ class PrimitiveObject(interfaces.objects.ObjectInterface): class Boolean(PrimitiveObject, int): """Primitive Object that handles boolean types""" - _struct_type = bool # type: typing.ClassVar[typing.Type] + _struct_type = bool # type: ClassVar[Type] class Integer(PrimitiveObject, int): @@ -167,17 +167,17 @@ class Integer(PrimitiveObject, int): class Float(PrimitiveObject, float): """Primitive Object that handles double or floating point numbers""" - _struct_type = float # type: typing.ClassVar[typing.Type] + _struct_type = float # type: ClassVar[Type] class Char(PrimitiveObject, bytes): """Primitive Object that handles characters""" - _struct_type = bytes # type: typing.ClassVar[typing.Type] + _struct_type = bytes # type: ClassVar[Type] class Bytes(PrimitiveObject, bytes): """Primitive Object that handles specific series of bytes""" - _struct_type = bytes # type: typing.ClassVar[typing.Type] + _struct_type = bytes # type: ClassVar[Type] def __init__(self, context: interfaces.context.ContextInterface, @@ -190,12 +190,12 @@ class Bytes(PrimitiveObject, bytes): data_format = DataFormatInfo(length, "big", False)) self._vol['length'] = length - def __new__(cls: typing.Type, + def __new__(cls: 'Bytes', context: interfaces.context.ContextInterface, type_name: str, object_info: interfaces.objects.ObjectInformation, length: int = 1, - **kwargs) -> typing.Type['Bytes']: + **kwargs) -> 'Bytes': """Creates the appropriate class and returns it so that the native type is inherritted The only reason the **kwargs is added, is so that the inherriting types can override __init__ @@ -214,7 +214,7 @@ class String(PrimitiveObject, str): (for multibyte characters, this will not be the maximum length of the string) """ - _struct_type = str # type: typing.ClassVar[typing.Type] + _struct_type = str # type: ClassVar[Type] def __init__(self, context: interfaces.context.ContextInterface, @@ -269,7 +269,7 @@ class Pointer(Integer): type_name: str, object_info: interfaces.objects.ObjectInformation, data_format: DataFormatInfo, - subtype: typing.Optional[templates.ObjectTemplate] = None) -> None: + subtype: Optional[templates.ObjectTemplate] = None) -> None: self._check_type(subtype, templates.ObjectTemplate) super().__init__(context = context, object_info = object_info, @@ -281,7 +281,7 @@ class Pointer(Integer): def _unmarshall(cls, context: interfaces.context.ContextInterface, data_format: DataFormatInfo, - object_info: ObjectInformation) -> typing.Any: + object_info: ObjectInformation) -> Any: """Ensure that pointer values always fall within the address space of the layer they're constructed on If there's a need for all the data within the address, the pointer should be recast. The "pointer" @@ -295,7 +295,7 @@ class Pointer(Integer): value = int.from_bytes(data, byteorder = endian, signed = signed) return value & mask - def dereference(self, layer_name: typing.Optional[str] = None) -> interfaces.objects.ObjectInterface: + def dereference(self, layer_name: Optional[str] = None) -> interfaces.objects.ObjectInterface: """Dereferences the pointer Layer_name is identifies the appropriate layer within the context that the pointer points to. @@ -310,12 +310,12 @@ class Pointer(Integer): offset = offset, parent = self)) - def is_readable(self, layer_name: typing.Optional[str] = None) -> bool: + def is_readable(self, layer_name: Optional[str] = None) -> bool: """Determines whether the address of this pointer can be read from memory""" layer_name = layer_name or self.vol.layer_name return self._context.memory[layer_name].is_valid(self) - def __getattr__(self, attr: str) -> typing.Any: + def __getattr__(self, attr: str) -> Any: """Convenience function to access unknown attributes by getting them from the subtype object""" return getattr(self.dereference(), attr) @@ -329,7 +329,7 @@ class Pointer(Integer): return Integer.VolTemplateProxy.size(template) @classmethod - def children(cls, template: interfaces.objects.Template) -> typing.List[interfaces.objects.Template]: + def children(cls, template: interfaces.objects.Template) -> List[interfaces.objects.Template]: """Returns the children of the template""" if 'subtype' in template.vol: return [template.vol.subtype] @@ -388,7 +388,7 @@ class BitField(interfaces.objects.ObjectInterface, int): return Integer.VolTemplateProxy.size(template) @classmethod - def children(cls, template: interfaces.objects.Template) -> typing.List[interfaces.objects.Template]: + def children(cls, template: interfaces.objects.Template) -> List[interfaces.objects.Template]: """Returns the children of the template""" if 'base_type' in template.vol: return [template.vol.base_type] @@ -413,8 +413,8 @@ class Enumeration(interfaces.objects.ObjectInterface, int): type_name: str, object_info: interfaces.objects.ObjectInformation, base_type: interfaces.objects.Template, - choices: typing.Dict[str, int], - **kwargs) -> typing.Type: + choices: Dict[str, int], + **kwargs) -> 'Enumeration': cls._check_class(base_type.vol.object_class, Integer) value = base_type(context = context, object_info = object_info) @@ -425,10 +425,10 @@ class Enumeration(interfaces.objects.ObjectInterface, int): type_name: str, object_info: interfaces.objects.ObjectInformation, base_type: Integer, - choices: typing.Dict[str, int]) -> None: + choices: Dict[str, int]) -> None: super().__init__(context, type_name, object_info) - self._inverse_choices = {} # type: typing.Dict[int, str] + self._inverse_choices = {} # type: Dict[int, str] for k, v in self._check_type(choices, dict).items(): self._check_type(k, str) self._check_type(v, int) @@ -454,7 +454,7 @@ class Enumeration(interfaces.objects.ObjectInterface, int): return self.lookup(self) @property - def choices(self) -> typing.Dict[str, int]: + def choices(self) -> Dict[str, int]: return self._vol['choices'] def __getattr__(self, attr: str) -> str: @@ -469,10 +469,10 @@ class Enumeration(interfaces.objects.ObjectInterface, int): class VolTemplateProxy(interfaces.objects.ObjectInterface.VolTemplateProxy): @classmethod def size(cls, template: interfaces.objects.Template) -> int: - return template._vol['base_type'].size + return template.vol['base_type'].size @classmethod - def children(cls, template: interfaces.objects.Template) -> typing.List[interfaces.objects.Template]: + def children(cls, template: interfaces.objects.Template) -> List[interfaces.objects.Template]: """Returns the children of the template""" if 'base_type' in template.vol: return [template.vol.base_type] @@ -526,7 +526,7 @@ class Array(interfaces.objects.ObjectInterface, abc.Sequence): return template.vol.get('subtype', None).size * template.vol.get('count', 0) @classmethod - def children(cls, template: interfaces.objects.Template) -> typing.List[interfaces.objects.Template]: + def children(cls, template: interfaces.objects.Template) -> List[interfaces.objects.Template]: """Returns the children of the template""" if 'subtype' in template.vol: return [template.vol.subtype] @@ -551,17 +551,17 @@ class Array(interfaces.objects.ObjectInterface, abc.Sequence): return 0 raise IndexError("Member not present in array template: {}".format(child)) - @typing.overload + @overload def __getitem__(self, i: int) -> interfaces.objects.Template: ... - @typing.overload - def __getitem__(self, s: slice) -> typing.List[interfaces.objects.Template]: + @overload + def __getitem__(self, s: slice) -> List[interfaces.objects.Template]: ... def __getitem__(self, i): """Returns the i-th item from the array""" - result = [] # type: typing.List[interfaces.objects.Template] + result = [] # type: List[interfaces.objects.Template] mask = self._context.memory[self.vol.layer_name].address_mask # We use the range function to deal with slices for us series = range(self.vol.count)[i] @@ -598,14 +598,14 @@ class Struct(interfaces.objects.ObjectInterface): type_name: str, object_info: interfaces.objects.ObjectInformation, size: int, - members: typing.Dict[str, typing.Tuple[int, interfaces.objects.Template]]) -> None: + 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) self._check_members(members) - self._concrete_members = {} # type: typing.Dict[str, typing.Dict] + self._concrete_members = {} # type: Dict[str, Dict] def has_member(self, member_name: str) -> bool: """Returns whether the object would contain a member called member_name""" @@ -620,7 +620,7 @@ class Struct(interfaces.objects.ObjectInterface): return template.vol.size @classmethod - def children(cls, template: interfaces.objects.Template) -> typing.List[interfaces.objects.Template]: + def children(cls, template: interfaces.objects.Template) -> List[interfaces.objects.Template]: """Method to list children of a template""" return [member for _, member in template.vol.members.values()] @@ -661,7 +661,7 @@ class Struct(interfaces.objects.ObjectInterface): @classmethod def _check_members(cls, - members: typing.Dict[str, typing.Tuple[int, interfaces.objects.Template]]) -> None: + 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): @@ -673,7 +673,7 @@ class Struct(interfaces.objects.ObjectInterface): """Specifically named method for retrieving members.""" return self.__getattr__(attr) - def __getattr__(self, attr: str) -> typing.Any: + def __getattr__(self, attr: str) -> Any: """Method for accessing members of the type""" if attr in self._concrete_members: return self._concrete_members[attr] @@ -691,7 +691,7 @@ class Struct(interfaces.objects.ObjectInterface): return member raise AttributeError("Struct has no attribute: {}.{}".format(self.vol.type_name, attr)) - def __dir__(self) -> typing.Iterable[str]: + def __dir__(self) -> Iterable[str]: """Returns a complete list of members when dir is called""" return list(super().__dir__()) + list(self.vol.members) diff --git a/volatility/framework/objects/templates.py b/volatility/framework/objects/templates.py index bf3dc74fd..53510a1c2 100644 --- a/volatility/framework/objects/templates.py +++ b/volatility/framework/objects/templates.py @@ -1,5 +1,5 @@ import logging -import typing +from typing import Any, ClassVar, Dict, List, Type from volatility.framework import interfaces, validity, exceptions @@ -18,7 +18,7 @@ class ObjectTemplate(interfaces.objects.Template, validity.ValidityRoutines): """ def __init__(self, - object_class: typing.Type[interfaces.objects.ObjectInterface], + object_class: Type[interfaces.objects.ObjectInterface], type_name: str, **arguments) -> None: super().__init__(type_name = type_name, **arguments) @@ -31,7 +31,7 @@ class ObjectTemplate(interfaces.objects.Template, validity.ValidityRoutines): return self.vol.object_class.VolTemplateProxy.size(self) @property - def children(self) -> typing.List[interfaces.objects.Template]: + def children(self) -> List[interfaces.objects.Template]: """Returns the children of the templated object (see :class:`~volatility.framework.interfaces.objects.ObjectInterface.VolTemplateProxy`) """ return self.vol.object_class.VolTemplateProxy.children(self) @@ -60,7 +60,7 @@ class ObjectTemplate(interfaces.objects.Template, validity.ValidityRoutines): Returns: an object adhereing to the :class:`~volatility.framework.interfaces.objects.ObjectInterface` """ - arguments = {} # type: typing.Dict[str, typing.Any] + arguments = {} # type: Dict[str, Any] for arg in self.vol: if arg != 'object_class': arguments[arg] = self.vol[arg] @@ -77,20 +77,20 @@ class ReferenceTemplate(interfaces.objects.Template): """ @property - def children(self) -> typing.List[interfaces.objects.Template]: + def children(self) -> List[interfaces.objects.Template]: return [] - def _unresolved(self, *args, **kwargs) -> typing.Any: + def _unresolved(self, *args, **kwargs) -> Any: """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)) - size = property(_unresolved) # type: typing.ClassVar[typing.Any] - replace_child = _unresolved # type: typing.ClassVar[typing.Any] - relative_child_offset = _unresolved # type: typing.ClassVar[typing.Any] - has_member = _unresolved # type: typing.ClassVar[typing.Any] + 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, diff --git a/volatility/framework/objects/utility.py b/volatility/framework/objects/utility.py index 9c5266af8..d9f4c10a0 100644 --- a/volatility/framework/objects/utility.py +++ b/volatility/framework/objects/utility.py @@ -1,10 +1,10 @@ -import typing +from typing import Optional, Union from volatility.framework import interfaces, objects, constants def array_to_string(array: objects.Array, - count: typing.Optional[int] = None, + 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 @@ -30,7 +30,7 @@ def pointer_to_string(pointer: objects.Pointer, def array_of_pointers(array: interfaces.objects.ObjectInterface, count: int, - subtype: typing.Union[str, interfaces.objects.Template], + 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""" symbol_table = array.vol.type_name.split(constants.BANG)[0] diff --git a/volatility/framework/plugins/__init__.py b/volatility/framework/plugins/__init__.py index b4e47e208..70cc94106 100644 --- a/volatility/framework/plugins/__init__.py +++ b/volatility/framework/plugins/__init__.py @@ -4,7 +4,7 @@ These modules should only be imported from volatility.plugins NOT volatility.fra """ import logging -import typing +from typing import List, Type from volatility.framework import interfaces, automagic, exceptions, constants, validity @@ -12,8 +12,8 @@ vollog = logging.getLogger(__name__) def run_plugin(context: interfaces.context.ContextInterface, - automagics: typing.List[interfaces.automagic.AutomagicInterface], - plugin: typing.Type[interfaces.plugins.PluginInterface], + 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: diff --git a/volatility/framework/renderers/__init__.py b/volatility/framework/renderers/__init__.py index 69d51dd24..0d8814715 100644 --- a/volatility/framework/renderers/__init__.py +++ b/volatility/framework/renderers/__init__.py @@ -3,7 +3,7 @@ Renderers display the unified output format in some manner (be it text or file or graphical output""" import collections import datetime -import typing +from typing import Any, Callable, Iterable, List, Optional, Tuple, TypeVar, Union from volatility.framework import interfaces @@ -36,8 +36,8 @@ class TreeNode(interfaces.renderers.TreeNode): def __init__(self, path: str, treegrid: 'TreeGrid', - parent: typing.Optional['TreeNode'], - values: typing.List[interfaces.renderers.BaseTypes]) -> None: + parent: Optional['TreeNode'], + values: List[interfaces.renderers.BaseTypes]) -> None: if not isinstance(treegrid, TreeGrid): raise TypeError("Treegrid must be an instance of TreeGrid") self._treegrid = treegrid @@ -49,13 +49,13 @@ class TreeNode(interfaces.renderers.TreeNode): def __repr__(self) -> str: return "".format(self.path, self._values) - def __getitem__(self, item: typing.Union[int, slice]) -> typing.Any: + def __getitem__(self, item: Union[int, slice]) -> Any: return self._treegrid.children(self).__getitem__(item) def __len__(self) -> int: return len(self._treegrid.children(self)) - def _validate_values(self, values: typing.List[interfaces.renderers.BaseTypes]) -> None: + def _validate_values(self, values: List[interfaces.renderers.BaseTypes]) -> None: """A function for raising exceptions if a given set of values is invalid according to the column properties.""" if not (isinstance(values, collections.Sequence) and len(values) == len(self._treegrid.columns)): raise TypeError( @@ -75,7 +75,7 @@ class TreeNode(interfaces.renderers.TreeNode): # tznaive = val.tzinfo is None or val.tzinfo.utcoffset(val) is None @property - def values(self) -> typing.Iterable[interfaces.renderers.BaseTypes]: + def values(self) -> Iterable[interfaces.renderers.BaseTypes]: """Returns the list of values from the particular node, based on column.index""" return self._values @@ -89,7 +89,7 @@ class TreeNode(interfaces.renderers.TreeNode): return self._path @property - def parent(self) -> typing.Optional['TreeNode']: + def parent(self) -> Optional['TreeNode']: """Returns the parent node of this node or None""" return self._parent @@ -127,8 +127,8 @@ class TreeGrid(interfaces.renderers.TreeGrid): path_sep = "|" def __init__(self, - columns: typing.List[typing.Tuple[str, interfaces.renderers.BaseTypes]], - generator: typing.Optional[typing.Iterable[typing.Tuple[int, typing.Tuple]]]) -> None: + columns: List[Tuple[str, interfaces.renderers.BaseTypes]], + generator: Optional[Iterable[Tuple[int, Tuple]]]) -> None: """Constructs a TreeGrid object using a specific set of columns The TreeGrid itself is a root element, that can have children but no values. @@ -141,8 +141,8 @@ class TreeGrid(interfaces.renderers.TreeGrid): """ self._populated = False self._row_count = 0 - self._children = [] # type: typing.List[TreeNode] - converted_columns = [] # type: typing.List[interfaces.renderers.Column] + self._children = [] # type: List[TreeNode] + converted_columns = [] # type: List[interfaces.renderers.Column] if len(columns) < 1: raise ValueError("Columns must be a list containing at least one column") for (name, column_type) in columns: @@ -170,7 +170,7 @@ class TreeGrid(interfaces.renderers.TreeGrid): def populate(self, func: interfaces.renderers.VisitorSignature = None, - initial_accumulator: typing.Any = None) -> 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,11 +178,11 @@ class TreeGrid(interfaces.renderers.TreeGrid): """ accumulator = initial_accumulator if func is None: - def func(_x: interfaces.renderers.TreeNode, _y: typing.Any) -> typing.Any: + def func(_x: interfaces.renderers.TreeNode, _y: Any) -> Any: return None if not self.populated: - prev_nodes = [] # type: typing.List[TreeNode] + prev_nodes = [] # type: List[TreeNode] for (level, item) in self._generator: parent_index = min(len(prev_nodes), level) parent = prev_nodes[parent_index - 1] if parent_index > 0 else None @@ -199,7 +199,7 @@ class TreeGrid(interfaces.renderers.TreeGrid): return self._populated @property - def columns(self) -> typing.List[interfaces.renderers.Column]: + def columns(self) -> List[interfaces.renderers.Column]: """Returns the available columns and their ordering and types""" return self._columns @@ -208,7 +208,7 @@ class TreeGrid(interfaces.renderers.TreeGrid): """Returns the number of rows populated""" return self._row_count - def children(self, node) -> typing.List[interfaces.renderers.TreeNode]: + def children(self, node) -> List[interfaces.renderers.TreeNode]: """Returns the subnodes of a particular node in order""" return [node for node, _ in self._find_children(node)] @@ -261,13 +261,13 @@ class TreeGrid(interfaces.renderers.TreeGrid): """Returns the maximum depth of the tree""" return self.visit(None, lambda n, a: max(a, self.path_depth(n)), ) - _T = typing.TypeVar("_T") + _T = TypeVar("_T") def visit(self, - node: typing.Optional[interfaces.renderers.TreeNode], - function: typing.Callable[[interfaces.renderers.TreeNode, _T], _T], + node: Optional[interfaces.renderers.TreeNode], + function: Callable[[interfaces.renderers.TreeNode, _T], _T], initial_accumulator: _T, - sort_key: typing.Optional[interfaces.renderers.ColumnSortKey] = None): + sort_key: Optional[interfaces.renderers.ColumnSortKey] = None): """Visits all the nodes in a tree, calling function on each one. function should have the signature function(node, accumulator) and return new_accumulator @@ -292,29 +292,23 @@ class TreeGrid(interfaces.renderers.TreeGrid): accumulator = function(node, initial_accumulator) if children is not None: if sort_key is not None: - # FIXME: mypy #4973 or #2608 - # key_func is only needed as a separate variable to pass mypy's None logic - key_func = lambda x: sort_key(x[0].values) - children = sorted(children, key = key_func) + children = sorted(children, key = lambda x: sort_key(x[0].values)) if not sort_key.ascending: children = reversed(children) accumulator = self._visit(children, function, accumulator, sort_key) return accumulator def _visit(self, - list_of_children: typing.List['TreeNode'], - function: typing.Callable, + list_of_children: List['TreeNode'], + function: Callable, accumulator: _T, - sort_key: typing.Optional[interfaces.renderers.ColumnSortKey] = None) -> _T: + sort_key: Optional[interfaces.renderers.ColumnSortKey] = None) -> _T: """Visits all the nodes in a tree, calling function on each one""" if list_of_children is not None: for n, children in list_of_children: accumulator = function(n, accumulator) if sort_key is not None: - # FIXME: mypy #4973 or #2608 - # key_func is only needed as a separate variable to pass mypy's None logic - key_func = lambda x: sort_key(x[0].values) - children = sorted(children, key = key_func) + children = sorted(children, key = lambda x: sort_key(x[0].values)) if not sort_key.ascending: children = reversed(children) accumulator = self._visit(children, function, accumulator, sort_key) @@ -334,7 +328,7 @@ class ColumnSortKey(interfaces.renderers.ColumnSortKey): raise ValueError("Column not found in TreeGrid columns: {}".format(column_name)) self._index = _index - def __call__(self, values: typing.List[typing.Any]) -> typing.Any: + def __call__(self, values: List[Any]) -> Any: """The key function passed as the sort key""" value = values[self._index] if isinstance(value, interfaces.renderers.BaseAbsentValue): diff --git a/volatility/framework/renderers/conversion.py b/volatility/framework/renderers/conversion.py index 0558e1ade..869c5bce5 100644 --- a/volatility/framework/renderers/conversion.py +++ b/volatility/framework/renderers/conversion.py @@ -1,11 +1,10 @@ import datetime -import typing +from typing import Union from volatility.framework import interfaces, renderers -def wintime_to_datetime(wintime: int) -> typing.Union[ - interfaces.renderers.BaseAbsentValue, datetime.datetime]: +def wintime_to_datetime(wintime: int) -> Union[interfaces.renderers.BaseAbsentValue, datetime.datetime]: unix_time = wintime // 10000000 if unix_time == 0: return renderers.NotApplicableValue() @@ -16,8 +15,8 @@ def wintime_to_datetime(wintime: int) -> typing.Union[ return renderers.UnparsableValue() -def unixtime_to_datetime(unixtime: int) -> typing.Union[interfaces.renderers.BaseAbsentValue, datetime.datetime]: - ret = renderers.UnparsableValue() # type: typing.Union[interfaces.renderers.BaseAbsentValue, datetime.datetime] +def unixtime_to_datetime(unixtime: int) -> Union[interfaces.renderers.BaseAbsentValue, datetime.datetime]: + ret = renderers.UnparsableValue() # type: Union[interfaces.renderers.BaseAbsentValue, datetime.datetime] if unixtime > 0: try: diff --git a/volatility/framework/symbols/__init__.py b/volatility/framework/symbols/__init__.py index 9c7940158..e1fcef00a 100644 --- a/volatility/framework/symbols/__init__.py +++ b/volatility/framework/symbols/__init__.py @@ -2,7 +2,7 @@ import collections import collections.abc import enum import logging -import typing +from typing import Any, Dict, Iterable, Iterator, Set, TypeVar from volatility.framework import constants, exceptions, interfaces, objects, validity @@ -15,10 +15,10 @@ class SymbolType(enum.Enum): ENUM = 3 -SymbolSpaceReturnType = typing.TypeVar("SymbolSpaceReturnType", - interfaces.objects.Template, - interfaces.symbols.SymbolInterface, - typing.Dict[str, typing.Any]) +SymbolSpaceReturnType = TypeVar("SymbolSpaceReturnType", + interfaces.objects.Template, + interfaces.symbols.SymbolInterface, + Dict[str, Any]) class SymbolSpace(interfaces.symbols.SymbolSpaceInterface, validity.ValidityRoutines): @@ -30,10 +30,10 @@ class SymbolSpace(interfaces.symbols.SymbolSpaceInterface, validity.ValidityRout def __init__(self) -> None: super().__init__() - self._dict = collections.OrderedDict() # type: typing.Dict[str, interfaces.symbols.BaseSymbolTableInterface] + self._dict = collections.OrderedDict() # type: Dict[str, interfaces.symbols.BaseSymbolTableInterface] # Permanently cache all resolved symbols - self._resolved = {} # type: typing.Dict[str, interfaces.objects.Template] - self._resolved_symbols = set() # type: typing.Set[str] + self._resolved = {} # type: Dict[str, interfaces.objects.Template] + self._resolved_symbols = set() # type: Set[str] def free_table_name(self, prefix: str = "layer") -> str: """Returns an unused table name to ensure no collision occurs when inserting a symbol table""" @@ -46,15 +46,15 @@ class SymbolSpace(interfaces.symbols.SymbolSpaceInterface, validity.ValidityRout ### Symbol functions - def get_symbols_by_type(self, type_name: str) -> typing.Iterable[str]: + def get_symbols_by_type(self, type_name: str) -> Iterable[str]: """Returns all symbols based on the type of the symbol""" for table in self._dict: for symbol_name in self._dict[table].get_symbols_by_type(type_name): yield table + constants.BANG + symbol_name - def get_symbols_by_location(self, offset: int, size: int = 0, table_name: str = None) -> typing.Iterable[str]: + def get_symbols_by_location(self, offset: int, size: int = 0, table_name: str = None) -> Iterable[str]: """Returns all symbols that exist at a specific relative address""" - table_list = self._dict.values() # type: typing.Iterable[interfaces.symbols.BaseSymbolTableInterface] + table_list = self._dict.values() # type: Iterable[interfaces.symbols.BaseSymbolTableInterface] if table_name is not None: if table_name in self._dict: table_list = [self._dict[table_name]] @@ -70,11 +70,11 @@ class SymbolSpace(interfaces.symbols.SymbolSpaceInterface, validity.ValidityRout """Returns the number of tables within the space""" return len(self._dict) - def __getitem__(self, i: str) -> typing.Any: + def __getitem__(self, i: str) -> Any: """Returns a specific table from the space""" return self._dict[i] - def __iter__(self) -> typing.Iterator[str]: + def __iter__(self) -> Iterator[str]: """Iterates through all available tables in the symbol space""" return iter(self._dict) @@ -188,7 +188,7 @@ class SymbolSpace(interfaces.symbols.SymbolSpaceInterface, validity.ValidityRout raise exceptions.SymbolError("Unresolvable Symbol: {}".format(symbol_name)) return retval - def get_enumeration(self, enum_name: str) -> typing.Dict[str, typing.Any]: + def get_enumeration(self, enum_name: str) -> Dict[str, Any]: """Look-up a set of enumeration choices from a specific symbol table""" retval = self._weak_resolve(SymbolType.ENUM, enum_name) if not isinstance(retval, dict): @@ -232,7 +232,7 @@ def mask_symbol_table(symbol_table: interfaces.symbols.SymbolTableInterface, table_aslr_shift: int = 0): """Alters a symbol table, such that all symbols returned have their address masked by the address mask""" original_get_symbol = symbol_table.get_symbol - cached_symbols = {} # type: typing.Dict[interfaces.symbols.SymbolInterface, interfaces.symbols.SymbolInterface] + cached_symbols = {} # type: Dict[interfaces.symbols.SymbolInterface, interfaces.symbols.SymbolInterface] def address_masked_get_symbol(*args, **kwargs): symbol = original_get_symbol(*args, **kwargs) diff --git a/volatility/framework/symbols/generic/__init__.py b/volatility/framework/symbols/generic/__init__.py index 899659d23..a608918a3 100644 --- a/volatility/framework/symbols/generic/__init__.py +++ b/volatility/framework/symbols/generic/__init__.py @@ -1,6 +1,6 @@ import random import string -import typing +from typing import Union from volatility.framework import objects, interfaces @@ -8,7 +8,7 @@ from volatility.framework import objects, interfaces class GenericIntelProcess(objects.Struct): def _add_process_layer(self, context: interfaces.context.ContextInterface, - dtb: typing.Union[int, interfaces.objects.ObjectInterface], + dtb: Union[int, interfaces.objects.ObjectInterface], config_prefix: str = None, preferred_name: str = None) -> str: """Constructs a new layer based on the process's DirectoryTableBase""" diff --git a/volatility/framework/symbols/intermed.py b/volatility/framework/symbols/intermed.py index 0b954d59f..14b0709d3 100644 --- a/volatility/framework/symbols/intermed.py +++ b/volatility/framework/symbols/intermed.py @@ -5,9 +5,9 @@ import json import logging import os import pathlib -import typing import zipfile from abc import ABCMeta +from typing import Any, Dict, Generator, Iterable, List, Optional, Type, Tuple import volatility from volatility import schemas, symbols @@ -42,7 +42,7 @@ vollog = logging.getLogger(__name__) # for container types # -def _construct_delegate_function(name: str, is_property: bool = False) -> typing.Any: +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) @@ -60,7 +60,7 @@ class IntermediateSymbolTable(interfaces.symbols.SymbolTableInterface): name: str, isf_url: str, native_types: interfaces.symbols.NativeTableInterface = None, - table_mapping: typing.Optional[typing.Dict[str, str]] = None, + table_mapping: Optional[Dict[str, str]] = None, validate: bool = True) -> None: """Instantiates an SymbolTable based on an IntermediateSymbolFormat JSON file. This is validated against the appropriate schema. The validation can be disabled by passing validate = False, but this should almost never be @@ -100,10 +100,9 @@ class IntermediateSymbolTable(interfaces.symbols.SymbolTableInterface): super().__init__(context, config_path, name, native_types or self._delegate.natives, table_mapping = table_mapping) - def _closest_version(self, - version: str, - versions: typing.Dict[typing.Tuple[int, int, int], typing.Type['ISFormatTable']]) \ - -> typing.Type['ISFormatTable']: + @staticmethod + def _closest_version(version: str, versions: Dict[Tuple[int, int, int], Type['ISFormatTable']]) \ + -> Type['ISFormatTable']: """Determines the highest suitable handler for specified version format An interface version such as (Current-Age).Age.Revision means that (Current - Age) of the provider must be equal to that of the @@ -131,7 +130,7 @@ class IntermediateSymbolTable(interfaces.symbols.SymbolTableInterface): @classmethod def file_symbol_url(cls, sub_path: str, - filename: typing.Optional[str] = None) -> typing.Generator[str, None, None]: + 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 @@ -178,8 +177,8 @@ class IntermediateSymbolTable(interfaces.symbols.SymbolTableInterface): config_path: str, sub_path: str, filename: str, - native_types: typing.Optional[interfaces.symbols.NativeTableInterface] = None, - table_mapping: typing.Optional[typing.Dict[str, str]] = None) -> str: + native_types: Optional[interfaces.symbols.NativeTableInterface] = None, + table_mapping: Optional[Dict[str, str]] = None) -> str: """Takes a context and loads an intermediate symbol table based on a filename. Args: @@ -206,7 +205,7 @@ class IntermediateSymbolTable(interfaces.symbols.SymbolTableInterface): return table_name @classmethod - def get_requirements(cls) -> typing.List[interfaces.configuration.RequirementInterface]: + 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")] @@ -219,9 +218,9 @@ class ISFormatTable(interfaces.symbols.SymbolTableInterface, metaclass = ABCMeta context: interfaces.context.ContextInterface, config_path: str, name: str, - json_object: typing.Any, + json_object: Any, native_types: interfaces.symbols.NativeTableInterface = None, - table_mapping: typing.Optional[typing.Dict[str, str]] = None) -> None: + table_mapping: Optional[Dict[str, str]] = None) -> None: self._json_object = json_object self._validate_json() self.name = self._check_type(name, str) @@ -230,10 +229,10 @@ class ISFormatTable(interfaces.symbols.SymbolTableInterface, metaclass = ABCMeta raise ValueError("Native table not provided") nt.name = name + "_natives" super().__init__(context, config_path, name, nt, table_mapping = table_mapping) - self._overrides = {} # type: typing.Dict[str, typing.Type[interfaces.objects.ObjectInterface]] - self._symbol_cache = {} # type: typing.Dict[str, interfaces.symbols.SymbolInterface] + self._overrides = {} # type: Dict[str, Type[interfaces.objects.ObjectInterface]] + self._symbol_cache = {} # type: Dict[str, interfaces.symbols.SymbolInterface] - def _get_natives(self) -> typing.Optional[interfaces.symbols.NativeTableInterface]: + def _get_natives(self) -> Optional[interfaces.symbols.NativeTableInterface]: """Determines the appropriate native_types to use from the JSON data""" # TODO: Consider how to generate the natives entirely from the ISF classes = {"x64": native.x64NativeTable, "x86": native.x86NativeTable} @@ -261,7 +260,7 @@ class ISFormatTable(interfaces.symbols.SymbolTableInterface, metaclass = ABCMeta not 'enums' in self._json_object): raise exceptions.SymbolSpaceError("Malformed JSON file provided") - def metadata(self) -> typing.Optional[interfaces.symbols.MetadataInterface]: + def metadata(self) -> Optional[interfaces.symbols.MetadataInterface]: """Returns a metadata object containing information about the symbol table""" return None @@ -286,24 +285,24 @@ class Version1Format(ISFormatTable): return self._symbol_cache[name] @property - def symbols(self) -> typing.Iterable[str]: + def symbols(self) -> Iterable[str]: """Returns an iterator of the symbol names""" return list(self._json_object.get('symbols', {})) @property - def enumerations(self) -> typing.Iterable[str]: + def enumerations(self) -> Iterable[str]: """Returns an iterator of the available enumerations""" return list(self._json_object.get('enums', {})) @property - def types(self) -> typing.Iterable[str]: + def types(self) -> Iterable[str]: """Returns an iterator of the symbol type names""" return list(self._json_object.get('user_types', {})) + list(self.natives.types) - def get_type_class(self, name: str) -> typing.Type[interfaces.objects.ObjectInterface]: + def get_type_class(self, name: str) -> Type[interfaces.objects.ObjectInterface]: return self._overrides.get(name, objects.Struct) - def set_type_class(self, name: str, clazz: typing.Type[interfaces.objects.ObjectInterface]) -> None: + def set_type_class(self, name: str, clazz: Type[interfaces.objects.ObjectInterface]) -> None: if name not in self.types: raise ValueError("Symbol type not in {} SymbolTable: {}".format(self.name, name)) self._overrides[name] = clazz @@ -312,7 +311,7 @@ class Version1Format(ISFormatTable): if name in self._overrides: del self._overrides[name] - def _interdict_to_template(self, dictionary: typing.Dict[str, typing.Any]) -> interfaces.objects.Template: + def _interdict_to_template(self, dictionary: Dict[str, Any]) -> interfaces.objects.Template: """Converts an intermediate format dict into an object template""" if not dictionary: raise exceptions.SymbolSpaceError("Invalid intermediate dictionary: {}".format(dictionary)) @@ -356,7 +355,7 @@ class Version1Format(ISFormatTable): return objects.templates.ReferenceTemplate(type_name = reference_name) - def _lookup_enum(self, name: str) -> typing.Dict[str, typing.Any]: + def _lookup_enum(self, name: str) -> Dict[str, Any]: """Looks up an enumeration and returns a dictionary of __init__ parameters for an Enum""" lookup = self._json_object['enums'].get(name, None) if not lookup: @@ -407,7 +406,7 @@ class Version2Format(Version1Format): age = 0 version = (current - age, age, revision) - def _get_natives(self) -> typing.Optional[interfaces.symbols.NativeTableInterface]: + def _get_natives(self) -> Optional[interfaces.symbols.NativeTableInterface]: """Determines the appropriate native_types to use from the JSON data""" classes = {"x64": native.x64NativeTable, "x86": native.x86NativeTable} for nc in sorted(classes): @@ -482,7 +481,7 @@ class Version4Format(Version3Format): 'bool': objects.Boolean, 'char': objects.Char} - def _get_natives(self) -> typing.Optional[interfaces.symbols.NativeTableInterface]: + def _get_natives(self) -> Optional[interfaces.symbols.NativeTableInterface]: """Determines the appropriate native_types to use from the JSON data""" native_dict = {} base_types = self._json_object['base_types'] @@ -535,7 +534,7 @@ class Version6Format(Version5Format): version = (current - age, age, revision) @property - def metadata(self) -> typing.Optional[interfaces.symbols.MetadataInterface]: + def metadata(self) -> Optional[interfaces.symbols.MetadataInterface]: """Returns a MetadataInterface object""" if self._json_object.get('metadata', {}).get('windows'): return metadata.WindowsMetadata(self._json_object['metadata']['windows']) diff --git a/volatility/framework/symbols/linux/__init__.py b/volatility/framework/symbols/linux/__init__.py index e32bde5f7..8c8b3bd69 100644 --- a/volatility/framework/symbols/linux/__init__.py +++ b/volatility/framework/symbols/linux/__init__.py @@ -1,7 +1,4 @@ -import typing - from volatility.framework import interfaces -from volatility.framework.configuration import requirements from volatility.framework.symbols import intermed from volatility.framework.symbols.linux import extensions diff --git a/volatility/framework/symbols/linux/extensions/__init__.py b/volatility/framework/symbols/linux/extensions/__init__.py index 7760b028d..caafc5006 100644 --- a/volatility/framework/symbols/linux/extensions/__init__.py +++ b/volatility/framework/symbols/linux/extensions/__init__.py @@ -1,6 +1,6 @@ import collections.abc import logging -import typing +from typing import Generator, Iterable, Iterator, Optional, Tuple import volatility.framework.objects.utility from volatility.framework import constants @@ -36,7 +36,7 @@ class module(generic.GenericIntelProcess): class task_struct(generic.GenericIntelProcess): def add_process_layer(self, config_prefix: str = None, - preferred_name: str = None) -> typing.Optional[str]: + preferred_name: str = None) -> Optional[str]: """Constructs a new layer based on the process's DTB. Returns the name of the Layer or None. """ @@ -57,8 +57,7 @@ class task_struct(generic.GenericIntelProcess): # Add the constructed layer and return the name return self._add_process_layer(self._context, dtb, config_prefix, preferred_name) - def get_process_memory_sections(self, heap_only: bool = False) -> \ - typing.Generator[typing.Tuple[int, int], None, None]: + def get_process_memory_sections(self, heap_only: bool = False) -> Generator[Tuple[int, int], None, None]: """Returns a list of sections based on the memory manager's view of this task's virtual memory""" for vma in self.mm.mmap_iter: start = int(vma.vm_start) @@ -95,7 +94,7 @@ class fs_struct(objects.Struct): class mm_struct(objects.Struct): @property - def mmap_iter(self) -> typing.Iterable[interfaces.objects.ObjectInterface]: + def mmap_iter(self) -> Iterable[interfaces.objects.ObjectInterface]: """Returns an iterator for the mmap list member of an mm_struct.""" if not self.mmap: @@ -267,7 +266,7 @@ class list_head(objects.Struct, collections.abc.Iterable): member: str, forward: bool = True, sentinel: bool = True, - layer: typing.Optional[str] = None) -> typing.Iterator[interfaces.objects.ObjectInterface]: + layer: Optional[str] = None) -> Iterator[interfaces.objects.ObjectInterface]: """Returns an iterator of the entries in the list.""" layer = layer or self.vol.layer_name @@ -290,7 +289,7 @@ class list_head(objects.Struct, collections.abc.Iterable): seen.add(link.vol.offset) link = getattr(link, direction).dereference() - def __iter__(self) -> typing.Iterator[interfaces.objects.ObjectInterface]: + def __iter__(self) -> Iterator[interfaces.objects.ObjectInterface]: return self.to_list(self.vol.parent.vol.type_name, self.vol.member_name) diff --git a/volatility/framework/symbols/mac/extensions/__init__.py b/volatility/framework/symbols/mac/extensions/__init__.py index c5b5542e0..615ea12e5 100644 --- a/volatility/framework/symbols/mac/extensions/__init__.py +++ b/volatility/framework/symbols/mac/extensions/__init__.py @@ -1,12 +1,8 @@ -import collections.abc -import typing +from typing import Optional -import volatility.framework.objects.utility -from volatility.framework import constants -from volatility.framework import exceptions, objects, interfaces -from volatility.framework.automagic import mac +from volatility.framework import exceptions, interfaces from volatility.framework.symbols import generic -from volatility.framework.objects import utility + class proc(generic.GenericIntelProcess): def get_task(self): @@ -14,12 +10,12 @@ class proc(generic.GenericIntelProcess): def add_process_layer(self, config_prefix: str = None, - preferred_name: str = None) -> typing.Optional[str]: + preferred_name: str = None) -> Optional[str]: """Constructs a new layer based on the process's DTB. Returns the name of the Layer or None. """ parent_layer = self._context.memory[self.vol.layer_name] - + if not isinstance(parent_layer, interfaces.layers.TranslationLayerInterface): raise TypeError("Parent layer is not a translation layer, unable to construct process layer") @@ -30,4 +26,3 @@ class proc(generic.GenericIntelProcess): # Add the constructed layer and return the name return self._add_process_layer(self._context, dtb, config_prefix, preferred_name) - diff --git a/volatility/framework/symbols/metadata.py b/volatility/framework/symbols/metadata.py index 0b2e0a9f2..d88cf7dce 100644 --- a/volatility/framework/symbols/metadata.py +++ b/volatility/framework/symbols/metadata.py @@ -1,4 +1,4 @@ -import typing +from typing import Optional, Tuple from volatility.framework import interfaces @@ -7,7 +7,7 @@ class WindowsMetadata(interfaces.symbols.MetadataInterface): """Class to handle the metadata from a Windows symbol table""" @property - def pe_version(self) -> typing.Optional[typing.Tuple]: + def pe_version(self) -> Optional[Tuple]: build = self._json_data.get('pe', {}).get('build', None) revision = self._json_data.get('pe', {}).get('revision', None) minor = self._json_data.get('pe', {}).get('minor', None) @@ -15,21 +15,21 @@ class WindowsMetadata(interfaces.symbols.MetadataInterface): if revision is None or minor is None or major is None: return None if build is None: - return (major, minor, revision) - return (major, minor, revision, build) + return major, minor, revision + return major, minor, revision, build @property - def pe_version_string(self) -> typing.Optional[str]: + def pe_version_string(self) -> Optional[str]: if self.pe_version is None: return None return ".".join(self.pe_version) @property - def pdb_guid(self) -> typing.Optional[str]: + def pdb_guid(self) -> Optional[str]: return self._json_data.get('pdb', {}).get('GUID', None) @property - def pdb_age(self) -> typing.Optional[int]: + def pdb_age(self) -> Optional[int]: return self._json_data.get('pdb', {}).get('age', None) diff --git a/volatility/framework/symbols/native.py b/volatility/framework/symbols/native.py index aeaadad86..156f4c132 100644 --- a/volatility/framework/symbols/native.py +++ b/volatility/framework/symbols/native.py @@ -1,5 +1,5 @@ import copy -import typing +from typing import Any, Dict, Iterable, Optional, Type from volatility.framework import constants, interfaces, objects @@ -7,13 +7,13 @@ from volatility.framework import constants, interfaces, objects class NativeTable(interfaces.symbols.NativeTableInterface): """Symbol List that handles Native types""" - # FIXME: typing the native_dictionary as typing.Tuple[interfaces.objects.ObjectInterface, str] throws many errors + # FIXME: typing the native_dictionary as Tuple[interfaces.objects.ObjectInterface, str] throws many errors def __init__(self, name: str, - native_dictionary: typing.Dict[str, typing.Any]) -> None: + native_dictionary: Dict[str, Any]) -> None: super().__init__(name, self) self._native_dictionary = copy.deepcopy(native_dictionary) - self._overrides = {} # type: typing.Dict[str, interfaces.objects.ObjectInterface] + self._overrides = {} # type: Dict[str, interfaces.objects.ObjectInterface] for native_type in self._native_dictionary: native_class, _native_struct = self._native_dictionary[native_type] self._overrides[native_type] = native_class @@ -21,12 +21,12 @@ class NativeTable(interfaces.symbols.NativeTableInterface): self._types = set(self._native_dictionary).union( {'enum', 'array', 'bitfield', 'void', 'string', 'bytes', 'function'}) - def get_type_class(self, name: str) -> typing.Type[interfaces.objects.ObjectInterface]: + def get_type_class(self, name: str) -> Type[interfaces.objects.ObjectInterface]: ntype, _ = self._native_dictionary.get(name, (objects.Integer, None)) return ntype @property - def types(self) -> typing.Iterable[str]: + def types(self) -> Iterable[str]: """Returns an iterator of the symbol type names""" return self._types @@ -45,8 +45,8 @@ class NativeTable(interfaces.symbols.NativeTableInterface): table_name, type_name = name_split prefix = table_name + constants.BANG - additional = {} # type: typing.Dict[str, typing.Any] - obj = None # type: typing.Optional[typing.Type[interfaces.objects.ObjectInterface]] + additional = {} # type: Dict[str, Any] + obj = None # type: Optional[Type[interfaces.objects.ObjectInterface]] if type_name == 'void' or type_name == 'function': obj = objects.Void elif type_name == 'array': diff --git a/volatility/framework/symbols/windows/extensions/__init__.py b/volatility/framework/symbols/windows/extensions/__init__.py index a6128f313..c985a0020 100644 --- a/volatility/framework/symbols/windows/extensions/__init__.py +++ b/volatility/framework/symbols/windows/extensions/__init__.py @@ -2,7 +2,7 @@ import collections.abc import datetime import functools import logging -import typing +from typing import Iterable, Iterator, Optional, Union from volatility.framework import constants, exceptions, interfaces, objects, renderers, symbols from volatility.framework.layers import intel @@ -22,10 +22,9 @@ class _POOL_HEADER(objects.Struct): type_name: str, type_map: dict, use_top_down: bool, - native_layer_name: typing.Optional[str] = None, - object_type: typing.Optional[str] = None, - cookie: typing.Optional[int] = None) \ - -> typing.Optional[interfaces.objects.ObjectInterface]: + native_layer_name: Optional[str] = None, + object_type: Optional[str] = None, + cookie: Optional[int] = None) -> Optional[interfaces.objects.ObjectInterface]: """Carve an object or data structure from a kernel pool allocation. :param type_name: the data structure type name @@ -419,8 +418,8 @@ class _FILE_OBJECT(objects.Struct, ExecutiveObject): """Determine if the object is valid""" return self.FileName.Length > 0 and self._context.memory[self.vol.layer_name].is_valid(self.FileName.Buffer) - def file_name_with_device(self) -> typing.Union[str, interfaces.renderers.BaseAbsentValue]: - name = renderers.UnreadableValue() # type: typing.Union[str, interfaces.renderers.BaseAbsentValue] + def file_name_with_device(self) -> Union[str, interfaces.renderers.BaseAbsentValue]: + name = renderers.UnreadableValue() # type: Union[str, interfaces.renderers.BaseAbsentValue] if self._context.memory[self.vol.layer_name].is_valid(self.DeviceObject): name = "\\Device\\{}".format(self.DeviceObject.get_device_name()) @@ -587,7 +586,7 @@ class _EPROCESS(generic.GenericIntelProcess, ExecutiveObject): # Add the constructed layer and return the name return self._add_process_layer(self._context, dtb, config_prefix, preferred_name) - def load_order_modules(self) -> typing.Iterable[int]: + def load_order_modules(self) -> Iterable[int]: """Generator for DLLs in the order that they were loaded""" if constants.BANG not in self.vol.type_name: @@ -690,7 +689,7 @@ class _LIST_ENTRY(objects.Struct, collections.abc.Iterable): member: str, forward: bool = True, sentinel: bool = True, - layer: typing.Optional[str] = None) -> typing.Iterator[interfaces.objects.ObjectInterface]: + layer: Optional[str] = None) -> Iterator[interfaces.objects.ObjectInterface]: """Returns an iterator of the entries in the list""" layer = layer or self.vol.layer_name @@ -720,5 +719,5 @@ class _LIST_ENTRY(objects.Struct, collections.abc.Iterable): seen.add(link.vol.offset) link = getattr(link, direction).dereference() - def __iter__(self) -> typing.Iterator[interfaces.objects.ObjectInterface]: + def __iter__(self) -> Iterator[interfaces.objects.ObjectInterface]: return self.to_list(self.vol.parent.vol.type_name, self.vol.member_name) diff --git a/volatility/framework/symbols/windows/extensions/pe.py b/volatility/framework/symbols/windows/extensions/pe.py index 56aa5311c..76ccd9917 100644 --- a/volatility/framework/symbols/windows/extensions/pe.py +++ b/volatility/framework/symbols/windows/extensions/pe.py @@ -1,4 +1,4 @@ -import typing +from typing import Generator, Tuple from volatility.framework import constants from volatility.framework import objects, interfaces @@ -77,7 +77,7 @@ class _IMAGE_DOS_HEADER(objects.Struct): nt_header.OptionalHeader.ImageBase.vol.data_format) return raw_data[:image_base_offset] + newval + raw_data[image_base_offset + member_size:] - def reconstruct(self) -> typing.Generator[typing.Tuple[int, bytes], None, None]: + def reconstruct(self) -> Generator[Tuple[int, bytes], None, None]: """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. @@ -147,7 +147,7 @@ class _IMAGE_DOS_HEADER(objects.Struct): class _IMAGE_NT_HEADERS(objects.Struct): - def get_sections(self) -> typing.Generator[interfaces.objects.ObjectInterface, None, None]: + def get_sections(self) -> Generator[interfaces.objects.ObjectInterface, None, None]: """Iterate through the section headers for this PE file. Yields: diff --git a/volatility/framework/symbols/windows/extensions/registry.py b/volatility/framework/symbols/windows/extensions/registry.py index 9ee7cd28e..3b29f9c4a 100644 --- a/volatility/framework/symbols/windows/extensions/registry.py +++ b/volatility/framework/symbols/windows/extensions/registry.py @@ -1,7 +1,7 @@ import enum import logging import struct -import typing +from typing import Optional, Iterable, Union from volatility.framework import constants, exceptions, objects, interfaces from volatility.framework.layers.registry import RegistryHive @@ -64,7 +64,7 @@ class _HMAP_ENTRY(objects.Struct): class _CMHIVE(objects.Struct): - def get_name(self) -> typing.Optional[interfaces.objects.ObjectInterface]: + 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, so we check all possibilities and take the first one that's not empty""" @@ -122,7 +122,7 @@ class _CM_KEY_NODE(objects.Struct): raise ValueError("Cannot determine volatility of registry key without an offset in a RegistryHive layer") return bool(self.vol.offset & 0x80000000) - def get_subkeys(self) -> typing.Iterable[interfaces.objects.ObjectInterface]: + def get_subkeys(self) -> Iterable[interfaces.objects.ObjectInterface]: """Returns a list of the key nodes""" hive = self._context.memory[self.vol.layer_name] if not isinstance(hive, RegistryHive): @@ -161,7 +161,7 @@ class _CM_KEY_NODE(objects.Struct): vollog.log(constants.LOGLEVEL_VVV, "Node found with address outside the valid Hive size: {}".format(key_offset)) - def get_values(self) -> typing.Iterable[interfaces.objects.ObjectInterface]: + def get_values(self) -> Iterable[interfaces.objects.ObjectInterface]: """Returns a list of the Value nodes for a key""" hive = self._context.memory[self.vol.layer_name] if not isinstance(hive, RegistryHive): @@ -197,7 +197,7 @@ class _CM_KEY_VALUE(objects.Struct): self.Name.count = self.NameLength return self.Name.cast("string", max_length = self.NameLength, encoding = "latin-1") - def decode_data(self) -> typing.Union[str, bytes]: + def decode_data(self) -> Union[str, bytes]: """Since this is just a casting convenience, it can be a property""" # Determine if the data is stored inline datalen = self.DataLength & 0x7fffffff diff --git a/volatility/framework/symbols/windows/kdbg.py b/volatility/framework/symbols/windows/kdbg.py index 4ce49b2c8..27bb331fb 100644 --- a/volatility/framework/symbols/windows/kdbg.py +++ b/volatility/framework/symbols/windows/kdbg.py @@ -1,12 +1,10 @@ -import typing -from volatility.framework import interfaces -from volatility.framework import exceptions from volatility.framework.symbols import intermed from volatility.framework.symbols.windows.extensions import kdbg + class KdbgIntermedSymbols(intermed.IntermediateSymbolTable): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.set_type_class('_KDDEBUGGER_DATA64', kdbg._KDDEBUGGER_DATA64) \ No newline at end of file + self.set_type_class('_KDDEBUGGER_DATA64', kdbg._KDDEBUGGER_DATA64) diff --git a/volatility/framework/symbols/wrappers.py b/volatility/framework/symbols/wrappers.py index 4760ce3ec..e7b24a1b9 100644 --- a/volatility/framework/symbols/wrappers.py +++ b/volatility/framework/symbols/wrappers.py @@ -1,5 +1,5 @@ import collections -import typing +from typing import List, Mapping from volatility.framework import interfaces, validity @@ -7,7 +7,7 @@ from volatility.framework import interfaces, validity class Flags(validity.ValidityRoutines): """Object that converts an integer into a set of flags based on their masks""" - def __init__(self, choices: typing.Mapping[str, int]) -> None: + def __init__(self, choices: Mapping[str, int]) -> None: self._check_type(choices, collections.Mapping) for k, v in choices.items(): self._check_type(k, str) @@ -18,7 +18,7 @@ class Flags(validity.ValidityRoutines): def choices(self) -> interfaces.objects.ReadOnlyMapping: return self._choices - def __call__(self, value: int) -> typing.List[str]: + def __call__(self, value: int) -> List[str]: """Return the appropriate Flags """ result = [] for k, v in self.choices.items(): diff --git a/volatility/framework/validity.py b/volatility/framework/validity.py index 233c4a10e..381c96f86 100644 --- a/volatility/framework/validity.py +++ b/volatility/framework/validity.py @@ -1,8 +1,8 @@ """A set of classes providing consistent type checking and error handling for type/class validity """ -import typing +from typing import Callable, Optional, TypeVar, Type -ProgressCallback = typing.Optional[typing.Callable[[float, str], None]] +ProgressCallback = Optional[Callable[[float, str], None]] class ValidityRoutines(object): @@ -15,10 +15,10 @@ class ValidityRoutines(object): These are currently implemented by assertions that will be optimized out of production code. """ - V = typing.TypeVar('V') + V = TypeVar('V') @classmethod - def _check_type(cls, value: V, valid_type: typing.Type) -> V: + def _check_type(cls, value: V, valid_type: Type) -> V: """Checks that value is an instance of valid_type, and returns value if it is, or throws a TypeError otherwise Args: @@ -31,7 +31,7 @@ class ValidityRoutines(object): return value @classmethod - def _check_class(cls, klass: typing.Type, valid_class: typing.Type) -> typing.Type: + def _check_class(cls, klass: Type, valid_class: Type) -> Type: """Checks that class is an instance of valid_class, and returns klass if it is, or throws a TypeError otherwise Args: diff --git a/volatility/plugins/configwriter.py b/volatility/plugins/configwriter.py index b7b9b5831..eb5152dce 100644 --- a/volatility/plugins/configwriter.py +++ b/volatility/plugins/configwriter.py @@ -1,6 +1,6 @@ import json import logging -import typing +from typing import List from volatility.framework import renderers, interfaces from volatility.framework.configuration import requirements @@ -13,7 +13,7 @@ class ConfigWriter(plugins.PluginInterface): """Runs the automagics and both prints and outputs configuration in the output directory""" @classmethod - def get_requirements(cls) -> typing.List[interfaces.configuration.RequirementInterface]: + def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: return [requirements.TranslationLayerRequirement(name = 'primary', description = 'Kernel Address Space', architectures = ["Intel32", "Intel64"]), diff --git a/volatility/plugins/linux/bash.py b/volatility/plugins/linux/bash.py index 07babfe46..cceea9911 100644 --- a/volatility/plugins/linux/bash.py +++ b/volatility/plugins/linux/bash.py @@ -4,7 +4,7 @@ typically found in Linux's /proc file system. import datetime import struct -import typing +from typing import List from volatility.framework import constants, renderers, symbols, interfaces from volatility.framework.configuration import requirements @@ -20,7 +20,7 @@ class Bash(plugins.PluginInterface, timeliner.TimeLinerInterface): """Recovers bash command history from memory""" @classmethod - def get_requirements(cls) -> typing.List[interfaces.configuration.RequirementInterface]: + def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: return [requirements.TranslationLayerRequirement(name = 'primary', description = 'Kernel Address Space', architectures = ["Intel32", "Intel64"]), diff --git a/volatility/plugins/linux/check_afinfo.py b/volatility/plugins/linux/check_afinfo.py index 3ab50e7c1..6cf774f1b 100644 --- a/volatility/plugins/linux/check_afinfo.py +++ b/volatility/plugins/linux/check_afinfo.py @@ -2,7 +2,7 @@ typically found in Linux's /proc file system. """ import logging -import typing +from typing import List from volatility.framework import exceptions, interfaces from volatility.framework import renderers @@ -18,7 +18,7 @@ class Check_afinfo(plugins.PluginInterface): """Verifies the operation function pointers of network protocols""" @classmethod - def get_requirements(cls) -> typing.List[interfaces.configuration.RequirementInterface]: + def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: return [requirements.TranslationLayerRequirement(name = 'primary', description = 'Kernel Address Space', architectures = ["Intel32", "Intel64"]), diff --git a/volatility/plugins/linux/check_syscall.py b/volatility/plugins/linux/check_syscall.py index bc40e1e77..04391d6fd 100644 --- a/volatility/plugins/linux/check_syscall.py +++ b/volatility/plugins/linux/check_syscall.py @@ -2,7 +2,7 @@ typically found in Linux's /proc file system. """ import logging -import typing +from typing import List from volatility.framework import exceptions, interfaces from volatility.framework import renderers, constants @@ -25,7 +25,7 @@ class Check_syscall(plugins.PluginInterface): """Check system call table for hooks""" @classmethod - def get_requirements(cls) -> typing.List[interfaces.configuration.RequirementInterface]: + def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: return [requirements.TranslationLayerRequirement(name = 'primary', description = 'Kernel Address Space', architectures = ["Intel32", "Intel64"]), diff --git a/volatility/plugins/linux/elfs.py b/volatility/plugins/linux/elfs.py index 69f1d23cf..eaaafa4d0 100644 --- a/volatility/plugins/linux/elfs.py +++ b/volatility/plugins/linux/elfs.py @@ -1,7 +1,8 @@ """A module containing a collection of plugins that produce data typically found in Linux's /proc file system. """ -import typing + +from typing import List from volatility.framework import renderers, interfaces from volatility.framework.configuration import requirements @@ -15,7 +16,7 @@ class Elfs(plugins.PluginInterface): """Lists all memory mapped ELF files for all processes""" @classmethod - def get_requirements(cls) -> typing.List[interfaces.configuration.RequirementInterface]: + def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: return [requirements.TranslationLayerRequirement(name = 'primary', description = 'Kernel Address Space', architectures = ["Intel32", "Intel64"]), diff --git a/volatility/plugins/linux/malfind.py b/volatility/plugins/linux/malfind.py index 3198e8898..b31f8024c 100644 --- a/volatility/plugins/linux/malfind.py +++ b/volatility/plugins/linux/malfind.py @@ -1,4 +1,4 @@ -import typing +from typing import List import volatility.framework.interfaces.plugins as interfaces_plugins import volatility.framework.interfaces.renderers as interfaces_renderers @@ -14,7 +14,7 @@ class Malfind(interfaces_plugins.PluginInterface): """Lists process memory ranges that potentially contain injected code""" @classmethod - def get_requirements(cls) -> typing.List[interfaces.configuration.RequirementInterface]: + def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: return [requirements.TranslationLayerRequirement(name = 'primary', description = 'Kernel Address Space', architectures = ["Intel32", "Intel64"]), diff --git a/volatility/plugins/linux/pslist.py b/volatility/plugins/linux/pslist.py index a3ef39fde..00d47b134 100644 --- a/volatility/plugins/linux/pslist.py +++ b/volatility/plugins/linux/pslist.py @@ -1,4 +1,4 @@ -import typing +from typing import Callable, Iterable, List import volatility.framework.interfaces.plugins as interfaces_plugins from volatility.framework import renderers, interfaces @@ -11,7 +11,7 @@ class PsList(interfaces_plugins.PluginInterface): """Lists the processes present in a particular linux memory image""" @classmethod - def get_requirements(cls) -> typing.List[interfaces.configuration.RequirementInterface]: + def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: return [requirements.TranslationLayerRequirement(name = 'primary', description = 'Kernel Address Space', architectures = ["Intel32", "Intel64"]), @@ -19,7 +19,7 @@ class PsList(interfaces_plugins.PluginInterface): description = "Linux Kernel")] @classmethod - def create_filter(cls, pid_list: typing.List[int] = None) -> typing.Callable[[int], bool]: + def create_filter(cls, pid_list: List[int] = None) -> Callable[[int], bool]: filter = lambda _: False # FIXME: mypy #4973 or #2608 pid_list = pid_list or [] @@ -45,8 +45,7 @@ class PsList(interfaces_plugins.PluginInterface): context: interfaces.context.ContextInterface, layer_name: str, vmlinux_symbols: str, - filter: typing.Callable[[int], bool] = lambda _: False) -> \ - typing.Iterable[interfaces.objects.ObjectInterface]: + filter: Callable[[int], bool] = lambda _: False) -> Iterable[interfaces.objects.ObjectInterface]: """Lists all the tasks in the primary layer""" diff --git a/volatility/plugins/mac/psaux.py b/volatility/plugins/mac/psaux.py index 67a4f0d5f..5ad7398c7 100644 --- a/volatility/plugins/mac/psaux.py +++ b/volatility/plugins/mac/psaux.py @@ -1,5 +1,5 @@ """In-memory artifacts from OSX systems""" -import typing +from typing import Iterator, Tuple, Any, Generator, List from volatility.framework import exceptions, renderers, interfaces from volatility.framework.configuration import requirements @@ -12,15 +12,14 @@ class Psaux(plugins.PluginInterface): """Recovers program command line arguments""" @classmethod - def get_requirements(cls) -> typing.List[interfaces.configuration.RequirementInterface]: + 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")] - def _generator(self, tasks: typing.Iterator[typing.Any]) -> \ - typing.Iterator[typing.Tuple[int, typing.Tuple[int, str, int, str]]]: + def _generator(self, tasks: Iterator[Any]) -> Generator[Tuple[int, Tuple[int, str, int, str]], None, None]: for task in tasks: proc_layer_name = task.add_process_layer() if proc_layer_name is None: diff --git a/volatility/plugins/mac/pslist.py b/volatility/plugins/mac/pslist.py index 65a2dcc35..cbcb1e095 100644 --- a/volatility/plugins/mac/pslist.py +++ b/volatility/plugins/mac/pslist.py @@ -1,5 +1,5 @@ -import typing import logging +from typing import Callable, Generator, List import volatility.framework.interfaces.plugins as interfaces_plugins from volatility.framework import renderers, interfaces @@ -21,7 +21,7 @@ class PsList(interfaces_plugins.PluginInterface): description = "Mac Kernel")] @classmethod - def create_filter(cls, pid_list: typing.List[int] = None) -> typing.Callable[[int], bool]: + def create_filter(cls, pid_list: List[int] = None) -> Callable[[int], bool]: filter = lambda _: False # FIXME: mypy #4973 or #2608 pid_list = pid_list or [] @@ -45,8 +45,8 @@ class PsList(interfaces_plugins.PluginInterface): context: interfaces.context.ContextInterface, layer_name: str, mac_symbols: str, - filter: typing.Callable[[int], bool] = lambda _: False) -> \ - typing.Iterable[interfaces.objects.ObjectInterface]: + filter: Callable[[int], bool] = lambda _: False) \ + -> Generator[interfaces.objects.ObjectInterface, None, None]: """Lists all the tasks in the primary layer""" diff --git a/volatility/plugins/timeliner.py b/volatility/plugins/timeliner.py index 3bca79cfd..7a2751ed4 100644 --- a/volatility/plugins/timeliner.py +++ b/volatility/plugins/timeliner.py @@ -5,12 +5,11 @@ import io import json import logging import traceback -import typing +from typing import Generator, Iterable, List, Optional, Tuple, Type from volatility import framework from volatility.framework import renderers, automagic, interfaces, plugins, exceptions from volatility.framework.configuration import requirements -from volatility.framework.interfaces import configuration vollog = logging.getLogger(__name__) @@ -22,12 +21,11 @@ class TimeLinerType(enum.IntEnum): CHANGED = 4 -class TimeLinerInterface(object, metaclass = abc.ABCMeta): +class TimeLinerInterface(metaclass = abc.ABCMeta): """Interface defining methods that timeliner will use to generate a body file""" @abc.abstractmethod - def generate_timeline(self) -> typing.Generator[ - typing.Tuple[str, TimeLinerType, datetime.datetime], None, None]: + def generate_timeline(self) -> Generator[Tuple[str, TimeLinerType, datetime.datetime], None, None]: """Method generates Tuples of (description, timestamp_type, timestamp) These need not be generated in any particular order, sorting will be done later @@ -44,8 +42,7 @@ class Timeliner(interfaces.plugins.PluginInterface): self.automagics = None @classmethod - def get_usable_plugins(cls, selected_list: typing.List[str] = None) \ - -> typing.List[typing.Type]: + def get_usable_plugins(cls, selected_list: List[str] = None) -> List[Type]: # Initialize for the run plugin_list = list(framework.class_subclasses(TimeLinerInterface)) @@ -67,8 +64,7 @@ class Timeliner(interfaces.plugins.PluginInterface): optional = True, default = False)] - def _generator(self, runable_plugins: typing.List[TimeLinerInterface]) \ - -> typing.Optional[typing.Iterable[typing.Tuple[int, typing.Tuple]]]: + 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""" # Generate the results for each plugin for plugin in runable_plugins: diff --git a/volatility/plugins/windows/cmdline.py b/volatility/plugins/windows/cmdline.py index 2ce6c6500..d61c1ee28 100644 --- a/volatility/plugins/windows/cmdline.py +++ b/volatility/plugins/windows/cmdline.py @@ -1,4 +1,4 @@ -import typing +from typing import List import volatility.framework.constants as constants import volatility.framework.interfaces.plugins as interfaces_plugins @@ -12,7 +12,7 @@ class CmdLine(interfaces_plugins.PluginInterface): """Lists process command line arguments""" @classmethod - def get_requirements(cls) -> typing.List[interfaces.configuration.RequirementInterface]: + 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', diff --git a/volatility/plugins/windows/dlldump.py b/volatility/plugins/windows/dlldump.py index 0398532d2..221b024f9 100644 --- a/volatility/plugins/windows/dlldump.py +++ b/volatility/plugins/windows/dlldump.py @@ -1,6 +1,6 @@ import logging import ntpath -import typing +from typing import List import volatility.framework.constants as constants import volatility.framework.interfaces.plugins as interfaces_plugins @@ -19,7 +19,7 @@ class DllDump(interfaces_plugins.PluginInterface): """Dumps process memory ranges as DLLs""" @classmethod - def get_requirements(cls) -> typing.List[interfaces.configuration.RequirementInterface]: + 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', diff --git a/volatility/plugins/windows/dlllist.py b/volatility/plugins/windows/dlllist.py index 2938031e1..122c7c82d 100644 --- a/volatility/plugins/windows/dlllist.py +++ b/volatility/plugins/windows/dlllist.py @@ -1,4 +1,4 @@ -import typing +from typing import List import volatility.framework.interfaces.plugins as interfaces_plugins from volatility.framework import exceptions, renderers, interfaces @@ -11,7 +11,7 @@ class DllList(interfaces_plugins.PluginInterface): """Lists the loaded modules in a particular windows memory image""" @classmethod - def get_requirements(cls) -> typing.List[interfaces.configuration.RequirementInterface]: + 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', diff --git a/volatility/plugins/windows/handles.py b/volatility/plugins/windows/handles.py index f3cf1b80f..6efa07995 100644 --- a/volatility/plugins/windows/handles.py +++ b/volatility/plugins/windows/handles.py @@ -1,5 +1,5 @@ import logging -import typing +from typing import Optional import volatility.framework.interfaces.plugins as interfaces_plugins import volatility.plugins.windows.pslist as pslist @@ -168,7 +168,7 @@ class Handles(interfaces_plugins.PluginInterface): def find_cookie(cls, context: interfaces.context.ContextInterface, layer_name: str, - symbol_table: str) -> typing.Optional[interfaces.objects.ObjectInterface]: + symbol_table: str) -> Optional[interfaces.objects.ObjectInterface]: """Find the ObHeaderCookie value (if it exists)""" try: diff --git a/volatility/plugins/windows/info.py b/volatility/plugins/windows/info.py index 9fad7fb12..70e281bb0 100644 --- a/volatility/plugins/windows/info.py +++ b/volatility/plugins/windows/info.py @@ -1,8 +1,8 @@ import time -import typing +from typing import List import volatility.framework.interfaces.plugins as plugins -from volatility.framework import constants, interfaces +from volatility.framework import constants, interfaces, layers from volatility.framework.configuration import requirements from volatility.framework.renderers import TreeGrid from volatility.framework.symbols.windows.kdbg import KdbgIntermedSymbols @@ -13,7 +13,7 @@ class Info(plugins.PluginInterface): """Show OS & kernel details of the memory sample being analyzed""" @classmethod - def get_requirements(cls) -> typing.List[interfaces.configuration.RequirementInterface]: + def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: return [requirements.TranslationLayerRequirement(name = 'primary', description = 'Kernel Address Space', architectures = ["Intel32", "Intel64"]), diff --git a/volatility/plugins/windows/moddump.py b/volatility/plugins/windows/moddump.py index 02cc97472..a8484949c 100644 --- a/volatility/plugins/windows/moddump.py +++ b/volatility/plugins/windows/moddump.py @@ -1,5 +1,5 @@ import logging -import typing +from typing import List, Generator, Iterable import volatility.framework.constants as constants import volatility.framework.exceptions as exceptions @@ -19,7 +19,7 @@ class ModDump(interfaces_plugins.PluginInterface): """Dumps kernel modules""" @classmethod - def get_requirements(cls) -> typing.List[interfaces.configuration.RequirementInterface]: + 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', @@ -31,7 +31,7 @@ class ModDump(interfaces_plugins.PluginInterface): context: interfaces.context.ContextInterface, layer_name: str, symbol_table: str, - pids: typing.List[int] = None) -> typing.Generator[str, None, None]: + pids: List[int] = None) -> Generator[str, None, None]: """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. @@ -39,11 +39,7 @@ class ModDump(interfaces_plugins.PluginInterface): Returns: of layer names """ - - # the primary layer should be first - layers = [layer_name] - - seen_ids = [] # type: typing.List[interfaces.objects.ObjectInterface] + seen_ids = [] # type: List[interfaces.objects.ObjectInterface] filter_func = pslist.PsList.create_filter(pids or []) for proc in pslist.PsList.list_processes(context = context, @@ -74,7 +70,7 @@ class ModDump(interfaces_plugins.PluginInterface): @classmethod def find_session_layer(cls, context: interfaces.context.ContextInterface, - session_layers: typing.Iterable[str], + 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. diff --git a/volatility/plugins/windows/poolscanner.py b/volatility/plugins/windows/poolscanner.py index dc0fe00af..4aeea282c 100644 --- a/volatility/plugins/windows/poolscanner.py +++ b/volatility/plugins/windows/poolscanner.py @@ -1,6 +1,6 @@ import enum import logging -import typing +from typing import Optional, Tuple, List, Generator from volatility.framework import constants, interfaces, renderers, validity, exceptions, symbols from volatility.framework.configuration import requirements @@ -35,11 +35,11 @@ class PoolConstraint(validity.ValidityRoutines): def __init__(self, tag: bytes, type_name: str, - object_type: typing.Optional[str] = None, - page_type: typing.Optional[PoolType] = None, - size: typing.Optional[typing.Tuple[typing.Optional[int], typing.Optional[int]]] = None, - index: typing.Optional[typing.Tuple[typing.Optional[int], typing.Optional[int]]] = None, - alignment: typing.Optional[int] = 1) -> None: + object_type: Optional[str] = None, + page_type: Optional[PoolType] = None, + size: Optional[Tuple[Optional[int], Optional[int]]] = None, + index: Optional[Tuple[Optional[int], Optional[int]]] = None, + alignment: Optional[int] = 1) -> None: self.tag = self._check_type(tag, bytes) self.type_name = type_name self.object_type = object_type @@ -154,14 +154,14 @@ class PoolScanner(plugins.PluginInterface): context: interfaces.context.ContextInterface, layer_name: str, symbol_table: str, - pool_constraints: typing.List[PoolConstraint], + pool_constraints: List[PoolConstraint], alignment: int = 8, - progress_callback: typing.Optional[validity.ProgressCallback] = None) \ - -> typing.Generator[typing.Tuple[PoolConstraint, interfaces.objects.ObjectInterface], None, None]: + progress_callback: Optional[validity.ProgressCallback] = None) \ + -> Generator[Tuple[PoolConstraint, interfaces.objects.ObjectInterface], None, None]: """Returns the _POOL_HEADER object (based on the symbol_table template) after scanning through layer_name returning all headers that match any of the constraints provided. Only one constraint can be provided per tag""" # Setup the pattern - constraint_lookup = {} # type: typing.Dict[bytes, typing.List[PoolConstraint]] + constraint_lookup = {} # type: Dict[bytes, List[PoolConstraint]] for constraint in pool_constraints: temp_list = constraint_lookup.get(constraint.tag, []) temp_list.append(constraint) diff --git a/volatility/plugins/windows/procdump.py b/volatility/plugins/windows/procdump.py index fc0d4d5ae..027fa3dc3 100644 --- a/volatility/plugins/windows/procdump.py +++ b/volatility/plugins/windows/procdump.py @@ -1,5 +1,5 @@ import logging -import typing +from typing import List import volatility.framework.constants as constants import volatility.framework.exceptions as exceptions @@ -18,7 +18,7 @@ class ProcDump(interfaces_plugins.PluginInterface): """Dumps process executable images""" @classmethod - def get_requirements(cls) -> typing.List[interfaces.configuration.RequirementInterface]: + 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', diff --git a/volatility/plugins/windows/pslist.py b/volatility/plugins/windows/pslist.py index 1b54fd845..4c1782cd2 100644 --- a/volatility/plugins/windows/pslist.py +++ b/volatility/plugins/windows/pslist.py @@ -1,5 +1,5 @@ import datetime -import typing +from typing import Callable, Iterable, List import volatility.framework.interfaces.plugins as plugins from volatility.framework import renderers, interfaces @@ -29,7 +29,7 @@ class PsList(plugins.PluginInterface, timeliner.TimeLinerInterface): optional = True)] @classmethod - def create_filter(cls, pid_list: typing.List[int] = None) -> typing.Callable[[int], bool]: + def create_filter(cls, pid_list: List[int] = None) -> Callable[[int], bool]: filter_func = lambda _: False # FIXME: mypy #4973 or #2608 pid_list = pid_list or [] @@ -43,8 +43,8 @@ class PsList(plugins.PluginInterface, timeliner.TimeLinerInterface): context: interfaces.context.ContextInterface, layer_name: str, symbol_table: str, - filter_func: typing.Callable[[int], bool] = lambda _: False) -> \ - typing.Iterable[interfaces.objects.ObjectInterface]: + filter_func: Callable[[int], bool] = lambda _: False) -> \ + Iterable[interfaces.objects.ObjectInterface]: """Lists all the processes in the primary layer that are in the pid config option""" # We only use the object factory to demonstrate how to use one diff --git a/volatility/plugins/windows/registry/hivelist.py b/volatility/plugins/windows/registry/hivelist.py index 9641c28fd..463356cad 100644 --- a/volatility/plugins/windows/registry/hivelist.py +++ b/volatility/plugins/windows/registry/hivelist.py @@ -1,4 +1,4 @@ -import typing +from typing import Iterator, List, Tuple import volatility.framework.interfaces.plugins as plugins from volatility.framework import renderers, interfaces @@ -10,7 +10,7 @@ class HiveList(plugins.PluginInterface): """Lists the registry hives present in a particular memory image""" @classmethod - def get_requirements(cls) -> typing.List[interfaces.configuration.RequirementInterface]: + def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: return [requirements.TranslationLayerRequirement(name = 'primary', description = 'Kernel Address Space', architectures = ["Intel32", "Intel64"]), @@ -20,7 +20,7 @@ class HiveList(plugins.PluginInterface): optional = True, default = None)] - def _generator(self) -> typing.Iterator[typing.Tuple[int, typing.Tuple[int, str]]]: + 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"], @@ -34,7 +34,7 @@ class HiveList(plugins.PluginInterface): context: interfaces.context.ContextInterface, layer_name: str, symbol_table: str, - filter_string: None = None) -> typing.Iterator[interfaces.objects.ObjectInterface]: + filter_string: None = None) -> Iterator[interfaces.objects.ObjectInterface]: """Lists all the hives in the primary layer""" # We only use the object factory to demonstrate how to use one diff --git a/volatility/plugins/windows/registry/printkey.py b/volatility/plugins/windows/registry/printkey.py index 34e53e5e6..28d140e92 100644 --- a/volatility/plugins/windows/registry/printkey.py +++ b/volatility/plugins/windows/registry/printkey.py @@ -1,6 +1,6 @@ import datetime import logging -import typing +from typing import Generator, Sequence import volatility.framework.interfaces.plugins as plugins from volatility.framework import objects, renderers, exceptions @@ -35,8 +35,10 @@ class PrintKey(plugins.PluginInterface): default = False, optional = True)] - def hive_walker(self, hive: RegistryHive, node_path: typing.Sequence[objects.Struct] = None, key_path: str = None) \ - -> typing.Generator: + 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 """ diff --git a/volatility/plugins/windows/registry/userassist.py b/volatility/plugins/windows/registry/userassist.py index 90e72cb75..28cefaaa5 100644 --- a/volatility/plugins/windows/registry/userassist.py +++ b/volatility/plugins/windows/registry/userassist.py @@ -3,7 +3,7 @@ import datetime import json import logging import os -import typing +from typing import List from volatility.framework import exceptions, renderers, constants, interfaces from volatility.framework.configuration import requirements @@ -28,7 +28,7 @@ class UserAssist(interfaces.plugins.PluginInterface): self._folder_guids = json.load(open(os.path.join(os.path.dirname(__file__), "userassist.json"), "rb")) @classmethod - def get_requirements(cls) -> typing.List[interfaces.configuration.RequirementInterface]: + def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: return [requirements.TranslationLayerRequirement(name = 'primary', description = 'Kernel Address Space', architectures = ["Intel32", "Intel64"]), @@ -153,7 +153,7 @@ class UserAssist(interfaces.plugins.PluginInterface): renderers.NotApplicableValue(), renderers.NotApplicableValue(), renderers.NotApplicableValue(), - renderers.NotApplicableValue())) # type: typing.Tuple[int, typing.Tuple[format_hints.Hex, typing.Any, typing.Any, typing.Any, typing.Any, typing.Any, typing.Any, typing.Any, typing.Any, typing.Any, typing.Any, typing.Any]] + 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 diff --git a/volatility/plugins/windows/ssdt.py b/volatility/plugins/windows/ssdt.py index 7fd7706b2..033909920 100644 --- a/volatility/plugins/windows/ssdt.py +++ b/volatility/plugins/windows/ssdt.py @@ -1,5 +1,5 @@ import os -import typing +from typing import Any, Iterator, List, Tuple from volatility.framework import constants, interfaces from volatility.framework import contexts @@ -16,19 +16,18 @@ class SSDT(plugins.PluginInterface): """Lists the system call table""" @classmethod - def get_requirements(cls) -> typing.List[interfaces.configuration.RequirementInterface]: + 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")] - def _generator(self, modules: typing.Iterator[typing.Any]) -> \ - typing.Iterator[typing.Tuple[int, typing.Tuple[int, int, str, str]]]: + def _generator(self, mods: Iterator[Any]) -> Iterator[Tuple[int, Tuple[int, int, str, str]]]: layer_name = self.config['primary'] context_modules = [] - for mod in modules: + for mod in mods: try: module_name_with_ext = mod.BaseDllName.get_string() diff --git a/volatility/plugins/windows/statistics.py b/volatility/plugins/windows/statistics.py index 45aa84653..a93350f63 100644 --- a/volatility/plugins/windows/statistics.py +++ b/volatility/plugins/windows/statistics.py @@ -1,4 +1,4 @@ -import typing +from typing import List from volatility.framework import renderers, exceptions, interfaces from volatility.framework.configuration import requirements @@ -9,7 +9,7 @@ from volatility.framework.layers import intel class Statistics(plugins.PluginInterface): @classmethod - def get_requirements(cls) -> typing.List[interfaces.configuration.RequirementInterface]: + def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: return [requirements.TranslationLayerRequirement(name = 'primary', description = 'Kernel Address Space', architectures = ["Intel32", "Intel64"])] diff --git a/volatility/plugins/windows/strings.py b/volatility/plugins/windows/strings.py index 0a3d7ecea..8425efae4 100644 --- a/volatility/plugins/windows/strings.py +++ b/volatility/plugins/windows/strings.py @@ -1,6 +1,6 @@ import logging import re -import typing +from typing import Dict, Generator, List, Set, Tuple from volatility.framework import interfaces, renderers, layers from volatility.framework.configuration import requirements @@ -14,7 +14,7 @@ vollog = logging.getLogger(__name__) class Strings(interfaces.plugins.PluginInterface): @classmethod - def get_requirements(cls) -> typing.List[interfaces.configuration.RequirementInterface]: + def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: return [requirements.TranslationLayerRequirement(name = 'primary', description = 'Kernel Address Space', architectures = ["Intel32", "Intel64"]), @@ -29,7 +29,7 @@ class Strings(interfaces.plugins.PluginInterface): ("Result", str)], self._generator()) - def _generator(self) -> typing.Generator[typing.Tuple, None, None]: + def _generator(self) -> Generator[Tuple, None, None]: """Generates results from a strings file""" revmap = self.generate_mapping(self.config['primary']) @@ -47,7 +47,8 @@ class Strings(interfaces.plugins.PluginInterface): vollog.error("Strings file is in the wrong format") return - def _parse_line(self, line: bytes) -> typing.Tuple[int, bytes]: + @staticmethod + def _parse_line(line: bytes) -> Tuple[int, bytes]: """Parses a single line from a strings file""" pattern = re.compile(rb"(?:\W*)([0-9]+)(?:\W*)(\w[\w\W]+)") match = pattern.search(line) @@ -56,10 +57,10 @@ class Strings(interfaces.plugins.PluginInterface): offset, string = match.group(1, 2) return int(offset), string - def generate_mapping(self, layer_name: str) -> typing.Dict[int, typing.Set[typing.Tuple[str, int]]]: + def generate_mapping(self, layer_name: str) -> Dict[int, Set[Tuple[str, int]]]: """Creates a reverse mapping between virtual addresses and physical addresses""" layer = self._context.memory[layer_name] - reverse_map = dict() # type: typing.Dict[int, typing.Set[typing.Tuple[str, int]]] + reverse_map = dict() # type: Dict[int, Set[Tuple[str, int]]] if isinstance(layer, intel.Intel): # We don't care about errors, we just wanted chunks that map correctly for mapval in layer.mapping(0x0, layer.maximum_address, ignore_errors = True): diff --git a/volatility/plugins/windows/vaddump.py b/volatility/plugins/windows/vaddump.py index cbef9a820..daa016a58 100644 --- a/volatility/plugins/windows/vaddump.py +++ b/volatility/plugins/windows/vaddump.py @@ -1,10 +1,10 @@ import logging -import typing +from typing import List import volatility.framework.interfaces.plugins as interfaces_plugins import volatility.plugins.windows.pslist as pslist import volatility.plugins.windows.vadinfo as vadinfo -from volatility.framework import renderers, interfaces +from volatility.framework import renderers, interfaces, exceptions from volatility.framework.configuration import requirements from volatility.framework.objects import utility @@ -15,7 +15,7 @@ class VadDump(interfaces_plugins.PluginInterface): """Dumps process memory ranges""" @classmethod - def get_requirements(cls) -> typing.List[interfaces.configuration.RequirementInterface]: + 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', diff --git a/volatility/plugins/windows/vadinfo.py b/volatility/plugins/windows/vadinfo.py index 69e6e5bd9..f7d76e14d 100644 --- a/volatility/plugins/windows/vadinfo.py +++ b/volatility/plugins/windows/vadinfo.py @@ -1,5 +1,5 @@ import logging -import typing +from typing import Callable, Generator, Iterable import volatility.framework.interfaces.plugins as interfaces_plugins import volatility.plugins.windows.pslist as pslist @@ -52,7 +52,7 @@ class VadInfo(interfaces_plugins.PluginInterface): def protect_values(cls, context: interfaces.context.ContextInterface, virtual_layer: str, - nt_symbols: str) -> typing.Iterable[int]: + 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 # dynamically versus hard-coding here will ensure we parse them properly.""" @@ -67,8 +67,8 @@ class VadInfo(interfaces_plugins.PluginInterface): @classmethod def list_vads(cls, proc: interfaces.objects.ObjectInterface, - filter_func: typing.Callable[[int], bool] = lambda _: False) -> \ - typing.Generator[interfaces.objects.ObjectInterface, None, None]: + filter_func: Callable[[int], bool] = lambda _: False) -> \ + Generator[interfaces.objects.ObjectInterface, None, None]: for vad in proc.get_vad_root().traverse(): if not filter_func(vad): diff --git a/volatility/plugins/windows/vadyarascan.py b/volatility/plugins/windows/vadyarascan.py index ee7dd219a..89faf9ad1 100644 --- a/volatility/plugins/windows/vadyarascan.py +++ b/volatility/plugins/windows/vadyarascan.py @@ -1,5 +1,5 @@ import logging -import typing +from typing import Any, Iterable, List, Tuple from volatility.framework import interfaces, layers, renderers from volatility.framework.configuration import requirements @@ -19,7 +19,7 @@ except ImportError: class VadYaraScan(interfaces.plugins.PluginInterface): @classmethod - def get_requirements(cls) -> typing.List[interfaces.configuration.RequirementInterface]: + def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: return [requirements.TranslationLayerRequirement(name = 'primary', description = "Primary kernel address space", architectures = ["Intel32", "Intel64"]), @@ -69,7 +69,7 @@ class VadYaraScan(interfaces.plugins.PluginInterface): sections = self.get_vad_maps(task)): yield format_hints.Hex(offset), name - def get_vad_maps(self, task: typing.Any) -> typing.Iterable[typing.Tuple[int, int]]: + def get_vad_maps(self, task: Any) -> Iterable[Tuple[int, int]]: task = self._check_type(task, extensions._EPROCESS) diff --git a/volatility/plugins/windows/verinfo.py b/volatility/plugins/windows/verinfo.py index edd647751..a59157266 100644 --- a/volatility/plugins/windows/verinfo.py +++ b/volatility/plugins/windows/verinfo.py @@ -1,6 +1,6 @@ import io import logging -import typing +from typing import Generator, List, Tuple import volatility.framework.interfaces.plugins as interfaces_plugins import volatility.plugins.windows.moddump as moddump @@ -24,7 +24,7 @@ class VerInfo(interfaces_plugins.PluginInterface): """Lists version information from PE files""" @classmethod - def get_requirements(cls) -> typing.List[interfaces.configuration.RequirementInterface]: + 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', @@ -37,7 +37,7 @@ class VerInfo(interfaces_plugins.PluginInterface): context: interfaces.context.ContextInterface, pe_table_name: str, layer_name: str, - base_address: int) -> typing.Tuple[int, int, int, int]: + base_address: int) -> Tuple[int, int, int, int]: """Get File and Product version information from PE files Args: @@ -72,9 +72,9 @@ class VerInfo(interfaces_plugins.PluginInterface): return (major, minor, product, build) def _generator(self, - procs: typing.Generator[interfaces.objects.ObjectInterface, None, None], - mods: typing.Generator[interfaces.objects.ObjectInterface, None, None], - session_layers: typing.Generator[str, None, None]): + 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. Args: @@ -96,7 +96,7 @@ 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: typing.Tuple[typing.Union[int, interfaces.renderers.BaseAbsentValue],typing.Union[int, interfaces.renderers.BaseAbsentValue],typing.Union[int, interfaces.renderers.BaseAbsentValue],typing.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, diff --git a/volatility/plugins/yarascan.py b/volatility/plugins/yarascan.py index 48caa4f62..4d300fe06 100644 --- a/volatility/plugins/yarascan.py +++ b/volatility/plugins/yarascan.py @@ -1,5 +1,5 @@ import logging -import typing +from typing import Iterable, Tuple, List from volatility.framework import interfaces, renderers, layers from volatility.framework.configuration import requirements @@ -22,7 +22,7 @@ class YaraScanner(interfaces.layers.ScannerInterface): super().__init__() self._rules = rules - def __call__(self, data: bytes, data_offset: int) -> typing.Iterable[typing.Tuple[int, str]]: + def __call__(self, data: bytes, data_offset: int) -> Iterable[Tuple[int, str]]: for match in self._rules.match(data = data): for offset, name, value in match.strings: yield (offset + data_offset, name) @@ -32,7 +32,7 @@ class YaraScan(plugins.PluginInterface): """Runs all relevant plugins that provide time related information and orders the results by time""" @classmethod - def get_requirements(cls) -> typing.List[interfaces.configuration.RequirementInterface]: + def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: return [requirements.TranslationLayerRequirement(name = 'primary', description = "Primary kernel address space", architectures = ["Intel32", "Intel64"]), diff --git a/volatility/schemas/__init__.py b/volatility/schemas/__init__.py index 5827bd7bd..5cdb99fff 100644 --- a/volatility/schemas/__init__.py +++ b/volatility/schemas/__init__.py @@ -2,7 +2,7 @@ import hashlib import json import logging import os -import typing +from typing import Set, Any, Dict from volatility.framework import constants @@ -11,7 +11,7 @@ vollog = logging.getLogger(__name__) cached_validation_filepath = os.path.join(constants.CACHE_PATH, "valid_isf.cache") -def load_cached_validations() -> typing.Set[str]: +def load_cached_validations() -> Set[str]: """Loads up the list of successfully cached json objects, so we don't need to revalidate them""" validhashes = set() if os.path.exists(cached_validation_filepath): @@ -29,7 +29,7 @@ def record_cached_validations(validations): cached_validations = load_cached_validations() -def validate(input: typing.Dict[str, typing.Any], use_cache: bool = True) -> bool: +def validate(input: Dict[str, Any], use_cache: bool = True) -> bool: """Validates an input JSON file based upon """ format = input.get('metadata', {}).get('format', None) if not format: @@ -45,12 +45,12 @@ def validate(input: typing.Dict[str, typing.Any], use_cache: bool = True) -> boo return valid(input, schema, use_cache) -def create_json_hash(input: typing.Dict[str, typing.Any], schema: typing.Dict[str, typing.Any]) -> str: +def create_json_hash(input: Dict[str, Any], schema: Dict[str, Any]) -> str: """Constructs the hash of the input and schema to create a unique indentifier for a particular JSON file""" return hashlib.sha1(bytes(json.dumps((input, schema), sort_keys = True), 'utf-8')).hexdigest() -def valid(input: typing.Dict[str, typing.Any], schema: typing.Dict[str, typing.Any], use_cache: bool = True) -> bool: +def valid(input: Dict[str, Any], schema: Dict[str, Any], use_cache: bool = True) -> bool: """Validates a json schema""" input_hash = create_json_hash(input, schema) if input_hash in cached_validations and use_cache: