diff --git a/doc/source/basics.rst b/doc/source/basics.rst index 77dedf63b..d493c61b3 100644 --- a/doc/source/basics.rst +++ b/doc/source/basics.rst @@ -7,7 +7,7 @@ Volatility splits memory analysis down to several components: * Templates and Objects * Symbol Tables -Volatility 3 stores all of these within a :py:class:`Context `, +Volatility 3 stores all of these within a :py:class:`Context `, which acts as a container for all the various layers and tables necessary to conduct memory analysis. Memory layers @@ -21,8 +21,8 @@ two other sources. These are typically handled by programs that process file fo processor, but these are all translations (either in the geometric or linguistic sense) of the original data. In Volatility 3 this is represented by a directed graph, whose end nodes are -:py:class:`DataLayers ` and whose internal nodes are -specifically called a :py:class:`TranslationLayer `. +:py:class:`DataLayers ` and whose internal nodes are +specifically called a :py:class:`TranslationLayer `. In this way, a raw memory image in the LiME file format and a page file can be combined to form a single Intel virtual memory layer. When requesting addresses from the Intel layer, it will use the Intel memory mapping algorithm, along with the address of the directory table base or page table map, to translate that @@ -39,17 +39,17 @@ Templates and Objects Once we can address contiguous chunks of memory with a means to translate a virtual address (as seen by the programs) into the actual data used by the processor, we can start pulling out -:py:class:`Objects ` by taking a -:py:class:`~volatility.framework.interfaces.objects.Template` and constructing -it on the memory layer at a specific offset. A :py:class:`~volatility.framework.interfaces.objects.Template` contains +:py:class:`Objects ` by taking a +:py:class:`~volatility3.framework.interfaces.objects.Template` and constructing +it on the memory layer at a specific offset. A :py:class:`~volatility3.framework.interfaces.objects.Template` contains all the information you can know about the structure of the object without actually being populated by any data. -As such a :py:class:`~volatility.framework.interfaces.objects.Template` can tell you the size of a structure and its +As such a :py:class:`~volatility3.framework.interfaces.objects.Template` can tell you the size of a structure and its members, how far into the structure a particular member lives and potentially what various values in that field would mean, but not what resides in a particular member. -Using a :py:class:`~volatility.framework.interfaces.objects.Template` on a memory layer at a particular offset, an -:py:class:`Object ` can be constructed. In Volatility 3, once an -:py:class:`Object ` has been created, the data has been read from the +Using a :py:class:`~volatility3.framework.interfaces.objects.Template` on a memory layer at a particular offset, an +:py:class:`Object ` can be constructed. In Volatility 3, once an +:py:class:`Object ` has been created, the data has been read from the layer and is not read again. An object allows its members to be interrogated and in particular allows pointers to be followed, providing easy access to the data contained in the object. @@ -62,23 +62,23 @@ Symbol Tables ------------- Most compiled programs know of their own templates, and define the structure (and location within the program) of these -templates as a :py:class:`Symbol `. A -:py:class:`Symbol ` is often an address and a template and can +templates as a :py:class:`Symbol `. A +:py:class:`Symbol ` is often an address and a template and can be used to refer to either independently. Lookup tables of these symbols are often produced as debugging information alongside the compilation of the program. Volatility 3 provides access to these through a -:py:class:`SymbolTable `, many of which can be collected -within a :py:class:`~volatility.framework.contexts.Context` as a :py:class:`SymbolSpace `. -A :py:class:`~volatility.framework.contexts.Context` can store only one :py:class:`~volatility.framework.symbols.SymbolSpace` -at a time, although a :py:class:`~volatility.framework.symbols.SymbolSpace` can store as -many :py:class:`~volatility.framework.symbols.SymbolTable` items as necessary. +:py:class:`SymbolTable `, many of which can be collected +within a :py:class:`~volatility3.framework.contexts.Context` as a :py:class:`SymbolSpace `. +A :py:class:`~volatility3.framework.contexts.Context` can store only one :py:class:`~volatility.framework.symbols.SymbolSpace` +at a time, although a :py:class:`~volatility3.framework.symbols.SymbolSpace` can store as +many :py:class:`~volatility3.framework.symbols.SymbolTable` items as necessary. Volatility 3 uses the de facto naming convention for symbols of `module!symbol` to refer to them. It reads them from its own JSON formatted file, which acts as a common intermediary between Windows PDB files, Linux DWARF files, other symbol formats and the internal Python format that Volatility 3 uses to represent -a :py:class:`~volatility.framework.interfaces.objects.Template` or -a :py:class:`Symbol `. +a :py:class:`~volatility3.framework.interfaces.objects.Template` or +a :py:class:`Symbol `. -.. note:: Volatility 2's name for a :py:class:`~volatility.framework.symbols.SymbolSpace` was a profile, but it could +.. note:: Volatility 2's name for a :py:class:`~volatility3.framework.symbols.SymbolSpace` was a profile, but it could not differentiate between symbols from different modules and required special handling for 32-bit programs that used Wow64 on Windows. This meant that all symbols lived in a single namespace with the possibility of symbol name collisions. It read the symbols using a format called *vtypes*, written in Python code directly. @@ -88,18 +88,18 @@ Plugins ------- A plugin acts as a means of requesting data from the user interface (and so the user) and then using it to carry out a -specific form of analysis on the :py:class:`Context ` +specific form of analysis on the :py:class:`Context ` (containing whatever symbol tables and memory layers it may). The means of communication between the user interface and -the library is the configuration tree, which is used by components within the :py:class:`~volatility.framework.contexts.Context` +the library is the configuration tree, which is used by components within the :py:class:`~volatility3.framework.contexts.Context` to store configurable data. After the plugin has been run, it then returns the results in a specific format known as a -:py:class:`~volatility.framework.interfaces.renderers.TreeGrid`. This ensures that the data can be handled by consumers of +:py:class:`~volatility3.framework.interfaces.renderers.TreeGrid`. This ensures that the data can be handled by consumers of the library, without knowing exactly what the data is or how it's formatted. Output Renderers ---------------- User interfaces can choose how best to present the output of the results to their users. The library always responds from -every plugin with a :py:class:`~volatility.framework.renderers.TreeGrid`, and the user interface can then determine how +every plugin with a :py:class:`~volatility3.framework.renderers.TreeGrid`, and the user interface can then determine how best to display it. For the Command Line Interface, that might be via text output as a table, or it might output to an SQLite database or a CSV file. For a web interface, the best output is probably as JSON where it could be displayed as a table, or inserted into a database like Elastic Search and trawled using an existing frontend such as Kibana. @@ -111,9 +111,9 @@ Configuration Tree ------------------ The configuration tree acts as the interface between the calling program and Volatility 3 library. Elements of the -library (such as a :py:class:`Plugin `, -a :py:class:`TranslationLayer `, -an :py:class:`Automagic `, etc.) can use the configuration +library (such as a :py:class:`Plugin `, +a :py:class:`TranslationLayer `, +an :py:class:`Automagic `, etc.) can use the configuration tree to inform the calling program of the options they require and/or optionally support, and allows the calling program to provide that information when the library is then called. @@ -122,7 +122,7 @@ Automagic There are certain setup tasks that establish the context in a way favorable to a plugin before it runs, removing several tasks that are repetitive and also easy to get wrong. These are called -:py:class:`Automagic `, since they do things like magically +:py:class:`Automagic `, since they do things like magically taking a raw memory image and automatically providing the plugin with an appropriate Intel translation layer and an accurate symbol table without either the plugin or the calling program having to specify all the necessary details. diff --git a/doc/source/complex-plugin.rst b/doc/source/complex-plugin.rst index 23a45f079..f06b398e8 100644 --- a/doc/source/complex-plugin.rst +++ b/doc/source/complex-plugin.rst @@ -6,17 +6,17 @@ which are discussed below. Writing Reusable Methods ------------------------ -Classes which inherit from :py:class:`~volatility.framework.interfaces.plugins.PluginInterface` all have a :py:meth:`run()` method -which takes no parameters and will return a :py:class:`~volatility.framework.interfaces.renderers.TreeGrid`. Since most useful +Classes which inherit from :py:class:`~volatility3.framework.interfaces.plugins.PluginInterface` all have a :py:meth:`run()` method +which takes no parameters and will return a :py:class:`~volatility3.framework.interfaces.renderers.TreeGrid`. Since most useful functions are parameterized, to provide parameters to a plugin the `configuration` for the context must be appropriately manipulated. There is scope for this, in order to run multiple plugins (see `Writing plugins that run other plugins`) but a much simpler method is to provide a parameterized `classmethod` within the plugin, which will allow the method to yield whatever kind of output it will generate and take whatever parameters it might need. This is how processes are listed, which is an often used function. The code lives within the -:py:class:`~volatility.plugins.windows.pslist.PsList` plugin but can be used by other plugins by providing the +:py:class:`~volatility3.plugins.windows.pslist.PsList` plugin but can be used by other plugins by providing the appropriate parameters (see -:py:meth:`~volatility.plugins.windows.pslist.PsList.list_processes`). +:py:meth:`~volatility3.plugins.windows.pslist.PsList.list_processes`). It is up to the author of a plugin to validate that any required plugins are present and are the appropriate version. Writing plugins that run other plugins @@ -34,7 +34,7 @@ available plugins that feature a Timeliner interface). This can be achieved wit This code will first generate suitable automagics for running against the context. Unfortunately this must be re-run for each plugin in order to populate the context's configuration correctly based on the plugin's requirements (which may vary between plugins). Once the automagics have been constructed, the plugin can be instantiated using the helper function -:py:func:`~volatility.framework.plugins.construct_plugin` providing: +:py:func:`~volatility3.framework.plugins.construct_plugin` providing: * the base context (containing the configuration and any already loaded layers or symbol tables), * the plugin class to run, @@ -43,7 +43,7 @@ between plugins). Once the automagics have been constructed, the plugin can be * an open method for the plugin to create files during the run With the constructed plugin, it can either be run by calling its -:py:meth:`~volatility.framework.interfaces.plugins.PluginInterface.run` method, or any other known method can +:py:meth:`~volatility3.framework.interfaces.plugins.PluginInterface.run` method, or any other known method can be invoked on it. Writing plugins that output files @@ -55,7 +55,7 @@ an abstraction layer is used. The user interface specifies an open_method (which is actually a class constructor that can double as a python ContextManager, so it can be used by the python `with` keyword). This is set on the plugin using `plugin.set_open_method` and can then be called or accessed using `plugin.open(preferred_filename)`. There are no additional options -that can be set on the filename, and a :py:class:`~volatility.framework.interfaces.plugins.FileHandlerInterface` is the result. +that can be set on the filename, and a :py:class:`~volatility3.framework.interfaces.plugins.FileHandlerInterface` is the result. This mimics an `IO[bytes]` object, which closely mimics a standard python file-like object. As such code for outputting to a file would be expected to look something like: @@ -73,10 +73,10 @@ closed to allow the preferred filename to be changed (or data to be added/modifi Writing Scanners ---------------- -Scanners are objects that adhere to the :py:class:`~volatility.framework.interfaces.layers.ScannerInterface`. They are -passed to the :py:meth:`~volatility.framework.interfaces.layers.TranslationLayerInterface.scan` method on layers which will +Scanners are objects that adhere to the :py:class:`~volatility3.framework.interfaces.layers.ScannerInterface`. They are +passed to the :py:meth:`~volatility3.framework.interfaces.layers.TranslationLayerInterface.scan` method on layers which will divide the provided range of sections (or the entire layer -if none are provided) and call the :py:meth:`~volatility.framework.interfaces.layers.ScannerInterface`'s call method +if none are provided) and call the :py:meth:`~volatility3.framework.interfaces.layers.ScannerInterface`'s call method method with each chunk as a parameter, ensuring a suitable amount of overlap (as defined by the scanner). The offset of the chunk, within the layer, is also provided as a parameter. @@ -96,7 +96,7 @@ Writing/Using Intermediate Symbol Format Files ---------------------------------------------- It can occasionally be useful to create a data file containing the static structures that can create a -:py:class:`~volatility.framework.interfaces.objects.Template` to be instantiated on a layer. +:py:class:`~volatility3.framework.interfaces.objects.Template` to be instantiated on a layer. Volatility has all the machinery necessary to construct these for you from properly formatted JSON data. The JSON format is documented by the JSON schema files located in schemas. These are versioned using standard .so @@ -136,7 +136,7 @@ Another useful parameter is `table_mapping` which allows for type referenced ins table_mapping = {'one_table': 'another_table'}) The last parameter that can be used is called `class_types` which allows a particular structure to be instantiated on -a class other than :py:class:`~volatility.framework.objects.StructType`, allowing for additional methods to be defined +a class other than :py:class:`~volatility3.framework.objects.StructType`, allowing for additional methods to be defined and associated with the type. The table name can then by used to access the constructed table from the context, such as: @@ -152,7 +152,7 @@ Translation layers offer a way for data to be translated from a higher (domain) The main method that must be overloaded for a translation layer is the `mapping` method. Usually this is a linear mapping whereby a value at an offset in the domain maps directly to an offset in the range. -Most new layers should inherit from :py:class:`~volatility.framework.layers.linear.LinearlyMappedLayer` where they +Most new layers should inherit from :py:class:`~volatility3.framework.layers.linear.LinearlyMappedLayer` where they can define a mapping method as follows: .. code-block:: python @@ -205,7 +205,7 @@ This mechanism also allowed for some minor optimization in scanning such a layer scanning of layers be needed, please refer to the Layer Scanning page. Whilst it may seem as though some of the data seems redundant (the length values are always the same) this is not the -case for :py:class:`~volatility.framework.layers.segmented.NonLinearlySegmentedLayer`. These layers do not guarantee +case for :py:class:`~volatility3.framework.layers.segmented.NonLinearlySegmentedLayer`. These layers do not guarantee that each domain address maps directly to a range address, and in fact can carry out processing on the data. These layers are most commonly encountered as compression or encryption layers (whereby a domain address may map into a chunk of the range, but not directly). In this instance, the mapping will likely define additional methods that can @@ -285,8 +285,8 @@ Writing new Templates and Objects --------------------------------- In most cases, a whole new type of object is unnecessary. It will usually be derived from an -:py:class:`~volatility.framework.objects.StructType` (which is itself just another name for a -:py:class:`~volatility.framework.objects.AggregateType`, but it's better to use `StructType` for readability). +:py:class:`~volatility3.framework.objects.StructType` (which is itself just another name for a +:py:class:`~volatility3.framework.objects.AggregateType`, but it's better to use `StructType` for readability). This can be used as a class override for a particular symbol table, so that an existing structure can be augmented with additional methods. An example of this would be: @@ -300,27 +300,27 @@ This will mean that when a specific structure is loaded from the symbol_space, i `StructType`, but instead is instantiated using the NewStructureClass, meaning new methods can be called directly on it. If the situation really calls for an entirely new object, that isn't covered by one of the existing -:py:class:`~volatility.framework.objects.PrimativeObject` objects (such as -:py:class:`~volatility.framework.objects.Integer`, -:py:class:`~volatility.framework.objects.Boolean`, -:py:class:`~volatility.framework.objects.Float`, -:py:class:`~volatility.framework.objects.Char`, -:py:class:`~volatility.framework.objects.Bytes`) +:py:class:`~volatility3.framework.objects.PrimativeObject` objects (such as +:py:class:`~volatility3.framework.objects.Integer`, +:py:class:`~volatility3.framework.objects.Boolean`, +:py:class:`~volatility3.framework.objects.Float`, +:py:class:`~volatility3.framework.objects.Char`, +:py:class:`~volatility3.framework.objects.Bytes`) or the other builtins (such as -:py:class:`~volatility.framework.objects.Array`, -:py:class:`~volatility.framework.objects.Bitfield`, -:py:class:`~volatility.framework.objects.Enumeration`, -:py:class:`~volatility.framework.objects.Pointer`, -:py:class:`~volatility.framework.objects.String`, -:py:class:`~volatility.framework.objects.Void`) then you can review the following information about defining an entirely +:py:class:`~volatility3.framework.objects.Array`, +:py:class:`~volatility3.framework.objects.Bitfield`, +:py:class:`~volatility3.framework.objects.Enumeration`, +:py:class:`~volatility3.framework.objects.Pointer`, +:py:class:`~volatility3.framework.objects.String`, +:py:class:`~volatility3.framework.objects.Void`) then you can review the following information about defining an entirely new object. -All objects must inherit from :py:class:`~volatility.framework.interfaces.objects.ObjectInterface` which defines a -constructor that takes a context, a `type_name`, an :py:class:`~volatility.framework.interfaces.objects.ObjectInformation` +All objects must inherit from :py:class:`~volatility3.framework.interfaces.objects.ObjectInterface` which defines a +constructor that takes a context, a `type_name`, an :py:class:`~volatility3.framework.interfaces.objects.ObjectInformation` object and then can accept additional keywords (which will not necessarily be provided if the object is constructed from a JSON reference). -The :py:class:`~volatility.framework.interfaces.objects.ObjectInformation` class contains all the basic elements that +The :py:class:`~volatility3.framework.interfaces.objects.ObjectInformation` class contains all the basic elements that define an object, which include: * layer_name @@ -345,10 +345,10 @@ should be. Note, the size can change throughout the lifespan of the object, and it compensates for such a change. Objects must also contain a specific class called `VolTemplateProxy` which must inherit from -:py:class:`~volatility.framework.interfaces.objects.ObjectInterface`. This is used to access information about +:py:class:`~volatility3.framework.interfaces.objects.ObjectInterface`. This is used to access information about a structure before it has been associated with data and becomes an Object. The -:py:class:`~volatility.framework.interfaces.objects.ObjectInterface.VolTemplateProxy` class contains a number of -abstract classmethods, which take a :py:class:`~volatility.framework.interfaces.objects.Template`. The main method +:py:class:`~volatility3.framework.interfaces.objects.ObjectInterface.VolTemplateProxy` class contains a number of +abstract classmethods, which take a :py:class:`~volatility3.framework.interfaces.objects.Template`. The main method that is likely to need overwriting is the `size` method, which should return the size of the object (for the template of a dynamically-sized object, this should be a suitable value, and calculated based on the best available information). For most objects, this can be determined from the JSON data used to construct a normal `Struct` and therefore only needs diff --git a/doc/source/simple-plugin.rst b/doc/source/simple-plugin.rst index e857e830c..52dabfd4f 100644 --- a/doc/source/simple-plugin.rst +++ b/doc/source/simple-plugin.rst @@ -3,19 +3,19 @@ How to Write a Simple Plugin This guide will step through how to construct a simple plugin using Volatility 3. -The example plugin we'll use is :py:class:`~volatility.plugins.windows.dlllist.DllList`, which features the main traits +The example plugin we'll use is :py:class:`~volatility3.plugins.windows.dlllist.DllList`, which features the main traits of a normal plugin, and reuses other plugins appropriately. Inherit from PluginInterface ---------------------------- -The first step is to define a class that inherits from :py:class:`~volatility.framework.interfaces.plugins.PluginInterface`. +The first step is to define a class that inherits from :py:class:`~volatility3.framework.interfaces.plugins.PluginInterface`. Volatility automatically finds all plugins defined under the various plugin directories by importing them and then -making use of any classes that inherit from :py:class:`~volatility.framework.interfaces.plugins.PluginInterface`. +making use of any classes that inherit from :py:class:`~volatility3.framework.interfaces.plugins.PluginInterface`. :: - from volatility.framework import interfaces + from volatility3.framework import interfaces class DllList(interfaces.plugins.PluginInterface): @@ -56,7 +56,7 @@ to instantiate the plugin). At the moment these requirements are fairly straigh architectures = ["Intel32", "Intel64"]), This requirement indicates that the plugin will operate on a single -:py:class:`TranslationLayer `. The name of the +:py:class:`TranslationLayer `. The name of the loaded layer will appear in the plugin's configuration under the name ``primary``. Requirement values can be accessed within the plugin through the plugin's `config` attribute (for example ``self.config['pid']``). @@ -71,7 +71,7 @@ layers, for example a plugin that carries out some form of difference or statist This requirement (and the next two) are known as Complex Requirements, and user interfaces will likely not directly request a value for this from a user. The value stored in the configuration tree for a -:py:class:`~volatility.framework.configuration.requirements.TranslationLayerRequirement` is +:py:class:`~volatility3.framework.configuration.requirements.TranslationLayerRequirement` is the string name of a layer present in the context's memory that satisfies the requirement. :: @@ -80,14 +80,14 @@ the string name of a layer present in the context's memory that satisfies the re description = "Windows kernel symbols"), This requirement specifies the need for a particular -:py:class:`SymbolTable ` +:py:class:`SymbolTable ` to be loaded. This gets populated by various -:py:class:`Automagic ` as the nearest sibling to a particular -:py:class:`~volatility.framework.configuration.requirements.TranslationLayerRequirement`. -This means that if the :py:class:`~volatility.framework.configuration.requirements.TranslationLayerRequirement` -is satisfied and the :py:class:`Automagic ` can determine -the appropriate :py:class:`SymbolTable `, the -name of the :py:class:`SymbolTable ` will be stored in the configuration. +:py:class:`Automagic ` as the nearest sibling to a particular +:py:class:`~volatility3.framework.configuration.requirements.TranslationLayerRequirement`. +This means that if the :py:class:`~volatility3.framework.configuration.requirements.TranslationLayerRequirement` +is satisfied and the :py:class:`Automagic ` can determine +the appropriate :py:class:`SymbolTable `, the +name of the :py:class:`SymbolTable ` will be stored in the configuration. This requirement is also a Complex Requirement and therefore will not be requested directly from the user. @@ -119,10 +119,10 @@ Define the `run` method The run method is the primary method called on a plugin. It takes no parameters (these have been passed through the context's configuration tree, and the context is provided at plugin initialization time) and returns an unpopulated -:py:class:`~volatility.framework.interfaces.renderers.TreeGrid` object. These are typically constructed based on a +:py:class:`~volatility3.framework.interfaces.renderers.TreeGrid` object. These are typically constructed based on a generator that carries out the bulk of the plugin's processing. The -:py:class:`~volatility.framework.interfaces.renderers.TreeGrid` also specifies the column names and types -that will be output as part of the :py:class:`~volatility.framework.interfaces.renderers.TreeGrid`. +:py:class:`~volatility3.framework.interfaces.renderers.TreeGrid` also specifies the column names and types +that will be output as part of the :py:class:`~volatility3.framework.interfaces.renderers.TreeGrid`. :: @@ -143,28 +143,28 @@ that will be output as part of the :py:class:`~volatility.framework.interfaces.r In this instance, the plugin constructs a filter (using the PsList plugin's *classmethod* for creating filters). It checks the plugin's configuration for the ``pid`` value, and passes it in as a list if it finds it, or None if -it does not. The :py:func:`~volatility.plugins.windows.pslist.PsList.create_pid_filter` method accepts a list of process +it does not. The :py:func:`~volatility3.plugins.windows.pslist.PsList.create_pid_filter` method accepts a list of process identifiers that are included in the list. If the list is empty, all processes are returned. The next line specifies the columns by their name and type. The types are simple types (int, str, bytes, float, and bool) but can also provide hints as to how the output should be displayed (such as a hexidecimal number, using -:py:class:`volatility.framework.renderers.format_hints.Hex`). +:py:class:`volatility3.framework.renderers.format_hints.Hex`). This indicates to user interfaces that the value should be displayed in a particular way, but does not guarantee that the value will be displayed that way (for example, if it doesn't make sense to do so in a particular interface). Finally, the generator is provided. The generator accepts a list of processes, which is gathered using a different plugin, -the :py:class:`~volatility.plugins.windows.pslist.PsList` plugin. That plugin features a *classmethod*, +the :py:class:`~volatility3.plugins.windows.pslist.PsList` plugin. That plugin features a *classmethod*, so that other plugins can call it. As such, it takes all the necessary parameters rather than accessing them from a configuration. Since it must be portable code, it takes a context, as well as the layer name, symbol table and optionally a filter. In this instance we unconditionally pass it the values from the configuration for the ``primary`` and ``nt_symbols`` requirements. This will generate a list -of :py:class:`~volatility.framework.symbols.windows.extensions.EPROCESS` objects, as provided by the :py:class:`~volatility.plugins.windows.pslist.PsList` plugin, +of :py:class:`~volatility3.framework.symbols.windows.extensions.EPROCESS` objects, as provided by the :py:class:`~volatility.plugins.windows.pslist.PsList` plugin, and is not covered here but is used as an example for how to share code across plugins (both as the provider and the consumer of the shared code). Define the generator -------------------- -The :py:class:`~volatility.framework.interfaces.renderers.TreeGrid` can be populated without a generator, +The :py:class:`~volatility3.framework.interfaces.renderers.TreeGrid` can be populated without a generator, but it is quite a common model to use. This is where the main processing for this plugin lives. :: @@ -189,10 +189,10 @@ but it is quite a common model to use. This is where the main processing for th format_hints.Hex(entry.DllBase), format_hints.Hex(entry.SizeOfImage), BaseDllName, FullDllName)) -This iterates through the list of processes and for each one calls the :py:meth:`~volatility.framework.symbols.windows.extensions.EPROCESS.load_order_modules` method on it. This provides +This iterates through the list of processes and for each one calls the :py:meth:`~volatility3.framework.symbols.windows.extensions.EPROCESS.load_order_modules` method on it. This provides a list of the loaded modules within the process. -The plugin then defaults the ``BaseDllName`` and ``FullDllName`` variables to an :py:class:`~volatility.framework.renderers.UnreadableValue`, +The plugin then defaults the ``BaseDllName`` and ``FullDllName`` variables to an :py:class:`~volatility3.framework.renderers.UnreadableValue`, which is a way of indicating to the user interface that the value couldn't be read for some reason (but that it isn't fatal). There are currently four different reasons a value may be unreadable: @@ -204,7 +204,7 @@ There are currently four different reasons a value may be unreadable: This is a safety provision to ensure that the data returned by the Volatility library is accurate and describes why information may not be provided. -The plugin then takes the process's ``BaseDllName`` value, and calls :py:meth:`~volatility.framework.symbols.windows.extensions.UNICODE_STRING.get_string` on it. All structure attributes, +The plugin then takes the process's ``BaseDllName`` value, and calls :py:meth:`~volatility3.framework.symbols.windows.extensions.UNICODE_STRING.get_string` on it. All structure attributes, as defined by the symbols, are directly accessible and use the case-style of the symbol library it came from (in Windows, attributes are CamelCase), such as ``entry.BaseDllName`` in this instance. Any attribtues not defined by the symbol but added by Volatility extensions cannot be properties (in case they overlap with the attributes defined in the symbol libraries) @@ -215,16 +215,16 @@ read the data at a particular offset. This will cause an exception to be thrown as a means of communicating when something exceptional happens. It is the responsibility of the plugin developer to appropriately catch and handle any non-fatal exceptions and otherwise allow the exception to be thrown by the user interface. -In this instance, the :py:class:`~volatility.framework.exceptions.InvalidAddressException` class is caught, which is thrown +In this instance, the :py:class:`~volatility3.framework.exceptions.InvalidAddressException` class is caught, which is thrown by any layer which cannot access an offset requested of it. Since we have already populated both values with ``UnreadableValue`` we do not need to write code for the exception handler. -Finally, we yield the record in the format required by the :py:class:`~volatility.framework.interfaces.renderers.TreeGrid`, +Finally, we yield the record in the format required by the :py:class:`~volatility3.framework.interfaces.renderers.TreeGrid`, a tuple, listing the indentation level (for trees) and then the list of values for each column. This plugin demonstrates casting a value ``ImageFileName`` to ensure it's returned as a string with a specific maximum length, rather than its original type (potentially an array of characters, etc). -This is carried out using the :py:meth:`~volatility.framework.interfaces.objects.ObjectInterface.cast` method which takes a type (either a native type, such as string or pointer, or a -structure type defined in a :py:class:`SymbolTable ` +This is carried out using the :py:meth:`~volatility3.framework.interfaces.objects.ObjectInterface.cast` method which takes a type (either a native type, such as string or pointer, or a +structure type defined in a :py:class:`SymbolTable ` such as ``!_UNICODE``) and the parameters to that type. Since the cast value must populate a string typed column, it had to be a Python string (such as being cast to the native diff --git a/doc/source/using-as-a-library.rst b/doc/source/using-as-a-library.rst index abed65225..ded861de4 100644 --- a/doc/source/using-as-a-library.rst +++ b/doc/source/using-as-a-library.rst @@ -25,7 +25,7 @@ from versions 1.1 or 1.2: :: - volatility.framework.require_interface_version(1, 0, 0) + volatility3.framework.require_interface_version(1, 0, 0) Contexts can be spun up quite easily, just construct one. It's not a singleton, so multiple contexts can be constructed and operate independently, but be aware of which context you're handing where and make sure to use @@ -42,20 +42,20 @@ Determine what plugins are available ------------------------------------ You can also interrogate the framework to see which plugins are available. First we have to try to load all -available plugins. The :py:func:`~volatility.framework.import_files` method will automatically use the module -paths for the provided module (in this case, volatility.plugins) and walk the directory (or directories) loading up +available plugins. The :py:func:`~volatility3.framework.import_files` method will automatically use the module +paths for the provided module (in this case, volatility3.plugins) and walk the directory (or directories) loading up all python files. Any import failures will be provided in the failures return value, unless the second parameter is False in which case the call will raise any exceptions encountered. Any additional directories containing plugins -should be added to the `__path__` attribute for the `volatility.plugins` module. The standard paths should generally -also be included, which can be found in `volatility.constants.PLUGINS_PATH`. +should be added to the `__path__` attribute for the `volatility3.plugins` module. The standard paths should generally +also be included, which can be found in `volatility3.constants.PLUGINS_PATH`. :: - volatility.plugins.__path__ = + constants.PLUGINS_PATH - failures = framework.import_files(volatility.plugins, True) + volatility3.plugins.__path__ = + constants.PLUGINS_PATH + failures = framework.import_files(volatility3.plugins, True) Once the plugins have been imported, we can interrogate which plugins are available. The -:py:func:`~volatility.framework.list_plugins` call will +:py:func:`~volatility3.framework.list_plugins` call will return a dictionary of plugin names and the plugin classes. :: @@ -68,9 +68,9 @@ Determine what configuration options a plugin requires ------------------------------------------------------ For each plugin class, we can call the classmethod `requirements` on it, which will return a list of objects that -adhere to the :py:class:`~volatility.framework.interfaces.configuration.RequirementInterface` method. The various +adhere to the :py:class:`~volatility3.framework.interfaces.configuration.RequirementInterface` method. The various types of Requirement are split roughly in two, -:py:class:`~volatility.framework.interfaces.configuration.SimpleTypeRequirement` (such as integers, booleans, floats +:py:class:`~volatility3.framework.interfaces.configuration.SimpleTypeRequirement` (such as integers, booleans, floats and strings) and more complex requirements (such as lists, choices, multiple requirements, translation layer requirements or symbol table requirements). A requirement just specifies a type of data and a name, and must be combined with a configuration hierarchy to have meaning. @@ -98,7 +98,7 @@ underneaths its own branch). To set the hierarchy, you'll need to know where th For this example, we'll assume plugins' base_config_path is set as `plugins`, and that automagics are configured under the `automagic` tree. We'll see later how to ensure this matches up with the plugins and automagic when they're constructed. Joining configuration options should always be carried out using -:py:func:`~volatility.framework.interfaces.configuration.path_join` +:py:func:`~volatility3.framework.interfaces.configuration.path_join` in case the separator value gets changed in the future. Configuration items can then be set as follows: :: @@ -170,7 +170,7 @@ be called whenever a plugin produces an auxiliary file. constructed = plugin(context, plugin_config_path, progress_callback = progress_callback) constructed.set_open_method(file_handler) -The file_handler must adhere to the :py:class:`~volatility.framework.interfaces.plugins.FileHandlerInterface`, +The file_handler must adhere to the :py:class:`~volatility3.framework.interfaces.plugins.FileHandlerInterface`, which represents an IO[bytes] object but also contains a `preferred_filename` attribute as a hint. All of this functionality has been condensed into a framework method called `construct_plugin` which will @@ -181,7 +181,7 @@ accepts an optional progress_callback and an optional file_consumer. constructed = plugins.construct_plugin(ctx, automagics, plugin, base_config_path, progress_callback, file_consumer) -Finally the plugin can be run, and will return a :py:class:`~volatility.framework.interfaces.renderers.TreeGrid`. +Finally the plugin can be run, and will return a :py:class:`~volatility3.framework.interfaces.renderers.TreeGrid`. :: @@ -201,22 +201,22 @@ does the actual work. This can return an exception if one occurs during the run The results can be accessed either as the results are being processed, or by visiting the nodes in the tree once it is fully populated. In either case, a visitor method will be required. The visitor method -should accept a :py:class:`~volatility.framework.interfaces.renderers.TreeNode` and an `accumulator`. It will +should accept a :py:class:`~volatility3.framework.interfaces.renderers.TreeNode` and an `accumulator`. It will return an updated accumulator. -When provided a :py:class:`~volatility.framework.interfaces.renderers.TreeNode`, it can be accessed as a dictionary +When provided a :py:class:`~volatility3.framework.interfaces.renderers.TreeNode`, it can be accessed as a dictionary based on the column names that the treegrid contains. It should be noted that each column can contain only the type specified in the `column.type` field (which can be a simple type like string, integer, float, bytes or a more complex type, like a DateTime, a Disassembly or a descendant of -:py:class:`~volatility.framework.interfaces.renderers.BaseAbsentValue`). The various fields may also be wrapped in +:py:class:`~volatility3.framework.interfaces.renderers.BaseAbsentValue`). The various fields may also be wrapped in `format_hints` designed to tell the user interface how to render the data. These hints can be things like Bin, Hex or HexBytes, so that fields like offsets are displayed in hex form or so that bytes are displayed in their hex form rather -than their raw form. Descendants of :py:class:`~volatility.framework.interfaces.renderers.BaseAbsentValue` can currently +than their raw form. Descendants of :py:class:`~volatility3.framework.interfaces.renderers.BaseAbsentValue` can currently be one of -:py:class:`~volatility.framework.renderers.UnreadableValue`, -:py:class:`~volatility.framework.renderers.UnparsableValue`, -:py:class:`~volatility.framework.renderers.NotApplicableValue` or -:py:class:`~volatility.framework.renderers.NotAvailableValue`. These indicate that data could not be read from the +:py:class:`~volatility3.framework.renderers.UnreadableValue`, +:py:class:`~volatility3.framework.renderers.UnparsableValue`, +:py:class:`~volatility3.framework.renderers.NotApplicableValue` or +:py:class:`~volatility3.framework.renderers.NotAvailableValue`. These indicate that data could not be read from the memory for some reason, could not be parsed properly, was not applicable or was not available. A simple text renderer (that returns output immediately) would appear as follows. This doesn't use @@ -240,5 +240,5 @@ the accumulator, but instead uses print to directly produce the output. This is grid.populate(visitor, None) More complex examples of renderers can be found in the default CLI implementation, such as the -:py:class:`~volatility.cli.text_renderer.QuickTextRenderer` or the -:py:class:`~volatility.cli.text_renderer.PrettyTextRenderer`. +:py:class:`~volatility3.cli.text_renderer.QuickTextRenderer` or the +:py:class:`~volatility3.cli.text_renderer.PrettyTextRenderer`. diff --git a/doc/source/vol2to3.rst b/doc/source/vol2to3.rst index 8e82ba8a2..bc1733dcf 100644 --- a/doc/source/vol2to3.rst +++ b/doc/source/vol2to3.rst @@ -6,7 +6,7 @@ Library and Context Volatility 3 has been designed from the ground up to be a library, this means the components are independent and all state required to run a particular plugin at a particular time is self-contained in an object derived from -a :py:class:`~volatility.framework.interfaces.context.ContextInterface`. +a :py:class:`~volatility3.framework.interfaces.context.ContextInterface`. The context contains the two core components that make up Volatility, layers of data and the available symbols. @@ -14,7 +14,7 @@ Symbols and Types ----------------- Volatility 3 no longer uses profiles, it comes with an extensive library of -:py:class:`symbol tables `, and can generate new symbol +:py:class:`symbol tables `, and can generate new symbol tables for most windows memory images, based on the memory image itself. This allows symbol tables to include specific offsets for locations (symbol locations) based on that operating system in particular. This means it is easier and quicker to identify structures within an operating system, by having known offsets for those structures provided by the official @@ -37,11 +37,11 @@ re-read many times over for no benefit (particularly since each re-read could re from following page table translations). Finally, in order to provide Volatility specific information without impact on the ability for structures to have members -with arbitrary names, all the metadata about the object (such as its layer or offset) have been moved to a read-only :py:meth:`~volatility.framework.interfaces.objects.ObjectInterface.vol` +with arbitrary names, all the metadata about the object (such as its layer or offset) have been moved to a read-only :py:meth:`~volatility3.framework.interfaces.objects.ObjectInterface.vol` dictionary. -Further the distinction between a :py:class:`~volatility.framework.interfaces.objects.Template` (the thing that -constructs an object) and the :py:class:`Object ` itself has +Further the distinction between a :py:class:`~volatility3.framework.interfaces.objects.Template` (the thing that +constructs an object) and the :py:class:`Object ` itself has been made more explicit. In Volatility 2, some information (such as size) could only be determined from a constructed object, leading to instantiating a template on an empty buffer, just to determine the size. In Volatility 3, templates contain information such as their size, which can be queried directly without constructing the object. @@ -49,7 +49,7 @@ information such as their size, which can be queried directly without constructi Layer and Layer dependencies ---------------------------- Address spaces in Volatility 2, are now more accurately referred to as -:py:class:`Translation Layers `, since each one typically sits +:py:class:`Translation Layers `, since each one typically sits atop another and can translate addresses between the higher logical layer and the lower physical layer. Address spaces in Volatility 2 were strictly limited to a stack, one on top of one other. In Volatility 3, layers can have multiple "dependencies" (lower layers), which allows for the integration of features such as swap space. @@ -65,13 +65,13 @@ included a stacker automagic to emulate the most common feature of Volatility 2, Searching and Scanning ---------------------- Scanning is very similar to scanning in Volatility 2, a scanner object (such as a -:py:class:`~volatility.framework.layers.scanners.BytesScanner` or :py:class:`~volatility.framework.layers.scanners.RegExScanner`) is -primed with the data to be searched for, and the :py:meth:`~volatility.framework.interfaces.layers.DataLayerInterface.scan` method is called on the layer to be searched. +:py:class:`~volatility3.framework.layers.scanners.BytesScanner` or :py:class:`~volatility.framework.layers.scanners.RegExScanner`) is +primed with the data to be searched for, and the :py:meth:`~volatility3.framework.interfaces.layers.DataLayerInterface.scan` method is called on the layer to be searched. Output Rendering ---------------- This is extremely similar to Volatility 2, because we were developing it for Volatility 3 when we added it to Volatility 2. -We now require that all plugins produce output in a :py:class:`~volatility.framework.interfaces.renderers.TreeGrid` object, +We now require that all plugins produce output in a :py:class:`~volatility3.framework.interfaces.renderers.TreeGrid` object, which ensure that the library can be used regardless of which interface is driving it. An example web GUI is also available called Volumetric which allows all the plugins that can be run from the command line to be run from a webpage, and offers features such as automatic formatting and sorting of the data, which previously couldn't be provided easily from the CLI.