## File: README.md # Volatility 3: The volatile memory extraction framework Volatility is the world's most widely used framework for extracting digital artifacts from volatile memory (RAM) samples. The extraction techniques are performed completely independent of the system being investigated but offer visibility into the runtime state of the system. The framework is intended to introduce people to the techniques and complexities associated with extracting digital artifacts from volatile memory samples and provide a platform for further work into this exciting area of research. In 2019, the Volatility Foundation released a complete rewrite of the framework, Volatility 3. The project was intended to address many of the technical and performance challenges associated with the original code base that became apparent over the previous 10 years. Another benefit of the rewrite is that Volatility 3 could be released under a custom license that was more aligned with the goals of the Volatility community, the Volatility Software License (VSL). See the [LICENSE](https://www.volatilityfoundation.org/license/vsl-v1.0) file for more details. ## Quick Start 1. Install the required dependencies: ```shell pip install --user -e ".[full]" ``` 2. See available options: ```shell vol -h ``` 3. To get more information on a Windows memory sample and to make sure Volatility supports that sample type, run `vol -f windows.info`: ```shell vol -f /home/user/samples/stuxnet.vmem windows.info ``` 4. Run some other plugins. The `-f` or `--single-location` is not strictly required, but most plugins expect a single sample. Some also require/accept other options. Run `vol -h` for more information on a particular command. ## Installing Volatility 3 requires Python 3.8.0 or later and is published on the [PyPi registry](https://pypi.org/project/volatility3). ```shell pip install volatility3 ``` If you want to use the latest development version of Volatility 3 we recommend you manually clone this repository and install an editable version of the project. We recommend you use a virtual environment to keep installed dependencies separate from system packages. The latest stable version of Volatility will always be the `stable` branch of the GitHub repository. The default branch is `develop`. ```shell git clone https://github.com/volatilityfoundation/volatility3.git cd volatility3/ python3 -m venv venv && . venv/bin/activate pip install -e ".[dev]" ``` ## Symbol Tables Symbol table packs for the various operating systems are available for download at: [windows.zip](https://github.com/volatilityfoundation/volatility3-test-data/releases/download/v0.0.1/windows.zip) [mac.zip](https://github.com/volatilityfoundation/volatility3-test-data/releases/download/v0.0.1/mac.zip) [linux.zip](https://github.com/volatilityfoundation/volatility3-test-data/releases/download/v0.0.1/linux.zip) The hashes to verify whether any of the symbol pack files have downloaded successfully or have changed can be found at: [SHA256SUMS](https://raw.githubusercontent.com/volatilityfoundation/volatility3-test-data/refs/tags/v0.0.1/symbols/SHA256SUMS) [SHA1SUMS](https://raw.githubusercontent.com/volatilityfoundation/volatility3-test-data/refs/tags/v0.0.1/symbols/SHA1SUMS) [MD5SUMS](https://raw.githubusercontent.com/volatilityfoundation/volatility3-test-data/refs/tags/v0.0.1/symbols/MD5SUMS) Symbol tables zip files must be placed, as named, into the `volatility3/symbols` directory (or just the symbols directory next to the executable file). Windows symbols that cannot be found will be queried, downloaded, generated and cached. Mac and Linux symbol tables must be manually produced by a tool such as [dwarf2json](https://github.com/volatilityfoundation/dwarf2json). Important: The first run of volatility with new symbol files will require the cache to be updated. The symbol packs contain a large number of symbol files and so may take some time to update! However, this process only needs to be run once on each new symbol file, so assuming the pack stays in the same location will not need to be done again. Please also note it can be interrupted and next run will restart itself. Please note: These are representative and are complete up to the point of creation for Windows and Mac. Due to the ease of compiling Linux kernels and the inability to uniquely distinguish them, an exhaustive set of Linux symbol tables cannot easily be supplied. ## Documentation The framework is documented through doc strings and can be built using sphinx. The latest generated copy of the documentation can be found at: ## Licensing and Copyright Copyright (C) 2007-2026 Volatility Foundation All Rights Reserved ## Bugs and Support If you think you've found a bug, please report it at: In order to help us solve your issues as quickly as possible, please include the following information when filing a bug: - The version of Volatility you're using - The operating system used to run Volatility - The version of Python used to run Volatility - The suspected operating system of the memory sample - The complete command line you used to run Volatility For community support, please join us on Slack: ## Contact For information or requests, contact: Volatility Foundation Web: Blog: Email: volatility (at) volatilityfoundation (dot) org Twitter: [@volatility](https://twitter.com/volatility) --- ## File: doc/source/basics.rst Volatility 3 Basics =================== Volatility splits memory analysis down to several components. The main ones are: * Memory layers * Templates and Objects * Symbol Tables 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 ------------- A memory layer is a body of data that can be accessed by requesting data at a specific address. At its lowest level this data is stored on a phyiscal medium (RAM) and very early computers addressed locations in memory directly. However, as the size of memory increased and it became more difficult to manage memory most architectures moved to a "paged" model of memory, where the available memory is cut into specific fixed-sized pages. To help further, programs can ask for any address and the processor will look up their (virtual) address in a map, to find out where the (physical) address that it lives at is, in the actual memory of the system. Volatility can work with these layers as long as it knows the map (so, for example that virtual address `1` looks up at physical address `9`). The automagic that runs at the start of every volatility session often locates the kernel's memory map, and creates a kernel virtual layer, which allows for kernel addresses to be looked up and the correct data returned. There can, however, be several maps, and in general there is a different map for each process (although a portion of the operating system's memory is usually mapped to the same location across all processes). The maps may take the same address but point to a different part of physical memory. It also means that two processes could theoretically share memory, both having a virtual address mapped to the same physical address. See the worked example below for more information. To translate an address on a layer, call :py:meth:`layer.mapping(offset, length, ignore_errors) ` and it will return a list of chunks without overlap, in order, for the requested range. If a portion cannot be mapped, an exception will be thrown unless `ignore_errors` is true. Each chunk will contain the original offset of the chunk, the translated offset, the original size and the translated size of the chunk, as well as the lower layer the chunk lives within. Worked example ^^^^^^^^^^^^^^ The operating system and two programs may all appear to have access to all of physical memory, but actually the maps they each have mean they each see something different: .. code-block:: :caption: Memory mapping example Operating system map Physical Memory 1 -> 9 1 - Free 2 -> 3 2 - OS.4, Process 1.4, Process 2.4 3 -> 7 3 - OS.2 4 -> 2 4 - Free 5 - Free Process 1 map 6 - Process 1.2, Process 2.3 1 -> 12 7 - OS.3 2 -> 6 8 - Process1.3 3 -> 8 9 - OS.1 4 -> 2 10 - Process2.1 11 - Free Process 2 map 12 - Process1.1 1 -> 10 13 - Free 2 -> 15 14 - Free 3 -> 6 15 - Process2.2 4 -> 2 16 - Free In this example, part of the operating system is visible across all processes (although not all processes can write to the memory, there is a permissions model for Intel addressing which is not discussed further here). In Volatility 3 mappings are represented by a directed graph of layers, whose end nodes are :py:class:`DataLayers ` and whose internal nodes are :py:class:`TranslationLayers `. 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 address into a physical address, which will then either be directed towards the swap layer or the LiME layer. Should it be directed towards the LiME layer, the LiME file format algorithm will translate the new address to determine where within the file the data is stored. When the :py:meth:`layer.read() ` method is called, the translation is done automatically and the correct data gathered and combined. .. note:: Volatility 2 had a similar concept, called address spaces, but these could only stack linearly one on top of another. The list of layers supported by Volatility can be determined by running the `frameworkinfo` plugin. 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:`~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:`~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:`~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. .. note:: Volatility 2 would re-read the data which was useful for live memory forensics but quite inefficient for the more common static memory analysis typically conducted. Volatility 3 requires that objects be manually reconstructed if the data may have changed. Volatility 3 also constructs actual Python integers and floats whereas Volatility 2 created proxy objects which would sometimes cause problems with type checking. 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 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:`~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:`~volatility3.framework.interfaces.objects.Template` or a :py:class:`Symbol `. .. 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. This made it less transferable or able to be used by other software. 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 ` (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:`~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:`~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:`~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. The renderers only need to know how to process very basic types (booleans, strings, integers, bytes) and a few additional specific ones (disassembly and various absent values). Renderers can also be added to volatility automatically. There is an additional arrow/parquet format renderer available (but requires the pyarrow dependency to be installed), but this is not shipped with the EXE version because it doubles the size of the executable. 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 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. 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 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. Automagics are a core component which consumers of the library can call or not at their discretion. .. note:: Volatility 2 used to do this as well, but it wasn't a particularly modular mechanism, and was used only for stacking address spaces (rather than identifying profiles), and it couldn't really be disabled/configured easily. --- ## File: doc/source/complex-plugin.rst Writing more advanced Plugins ============================= There are several common tasks you might wish to accomplish, there is a recommended means of achieving most of these which are discussed below. Writing Reusable Methods ------------------------ 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. As an example, an often used function is listing processes. The code lives within the :py:class:`~volatility3.plugins.windows.pslist.PsList` plugin but can be used by other plugins by providing the appropriate parameters (see :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 -------------------------------------- Occasionally plugins will want to process the output from other plugins (for example, the timeliner plugin which runs all other available plugins that feature a Timeliner interface). This can be achieved with the following example code: .. code-block:: python automagics = automagic.choose_automagic(automagic.available(self._context), plugin_class) plugin = plugins.construct_plugin(self.context, automagics, plugin_class, self.config_path, self._progress_callback, self.open) 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:`~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 * the configuration path within the context for the plugin * any callback to determine progress in lengthy operations * 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:`~volatility3.framework.interfaces.plugins.PluginInterface.run` method, or any other known method can be invoked on it. Writing plugins that output files --------------------------------- Every plugin can create files, but since the user interface must decide how to actually provide these files to the user, 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:`~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: .. code-block:: python with self.open(preferred_filename) as file_handle: file_handle.write(data) Since self.open returns a ContextManager the file is closed automatically and thus committed for the UI to process as necessary. If the file is not closed, the UI may not be able to properly process it and unexpected results may arise. In certain instances you may receive a file_handle from another plugin's method, in which case the file is unlikely to be closed to allow the preferred filename to be changed (or data to be added/modified, if necessary). Writing Scanners ---------------- 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:`~volatility3.framework.interfaces.layers.ScannerInterface`'s call 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. Scanners can technically maintain state, but it is not recommended since the ordering that the chunks are scanned is not guaranteed. Scanners may be executed in parallel if they mark themselves as `thread_safe` although the threading technique may be either standard threading or multiprocessing. Note, the only component of the scans which is parallelized are those that go on within the scan method. As such, any processing carried out on the results yielded by the scanner will be processed in serial. It should also be noted that generating the addresses to be scanned are not iterated in parallel (in full, before the scanning occurs), meaning the smaller the sections to scan the quicker the scan will run. Empirically it was found that scanners are typically not the most time intensive part of plugins (even those that do extensive scanning) and so parallelism does not offer significant gains. As such, parallelism is not enabled by default but interfaces can easily enable parallelism when desired. 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:`~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 the schemas directory. These are versioned using standard .so library versioning, so they may not increment as expected. Each schema lists an available version that can be used, which specifies five different sections: * Base_types - These are the basic type names that will make up the native / primitive types * User_types - These are the standard definitions of type structures, most will go here * Symbols - These list offsets that are associated with specific names (and can be associated with specific type names) * Enums - Enumerations that offer a number of choices * Metadata - This is information about the generator, when the file was generated and similar Constructing an appropriate file, the file can be loaded into a symbol table as follows: .. code-block:: python table_name = intermed.IntermediateSymbolTable.create(context, config_path, 'sub_path', 'filename') This code will load a JSON file from one of the standard symbol paths (volatility3/symbols and volatility3/framework/symbols) under the additional directory sub_path, with a name matching filename.json (the extension should not be included in the filename). The `sub_path` parameter acts as a filter, so that similarly named symbol tables for each operating system can be addressed separately. The top level directories which sub_path filters are also checked as zipfiles to determine any symbols within them. As such, group of symbol tables can be included in a single zip file. The filename for the symbol tables should not contain an extension, as extensions for JSON (and compressed JSON files) will be tested to find a match. Additional parameters exist, such as `native_types` which can be used to provide pre-populated native types. Another useful parameter is `table_mapping` which allows for type referenced inside the JSON (such as `one_table!type_name`) would allow remapping of `one_table` to `another_table` by providing a dictionary as follows: .. code-block:: python table_name = intermed.IntermediateSymbolTable.create(context, config_path, 'sub_path', 'filename', 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:`~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: .. code-block:: python context.symbol_space[table_name] Writing new Translation Layers ------------------------------ Translation layers offer a way for data to be translated from a higher (domain) layer to a lower (range) layer. 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:`~volatility3.framework.layers.linear.LinearlyMappedLayer` where they can define a mapping method as follows: .. code-block:: python def mapping(self, offset: int, length: int, ignore_errors: bool = False) -> Iterable[Tuple[int, int, int, int, str]]: This takes a (domain) offset and a length of block, and returns a sorted list of chunks that cover the requested amount of data. Each chunk contains the following information, in order: **offset (domain offset)** requested offset in the domain **chunk length** the length of the data in the domain **mapped offset (range offset)** where the data lives in the lower layer **mapped length** the length of the data in the range **layer_name** the layer that this data comes from An example (and the most common layer encountered in memory forensics) would be an Intel layer, which models the Intel page mapping system. Based on a series of tables stored within the layer itself, an intel layer can convert a virtual address to a physical address. It should be noted that intel layers allow multiple virtual addresses to map to the same physical address (but a single virtual address cannot ever map to more than one physical address). As a simple example, in a virtual layer which looks like `abracadabra` but maps to a physical layer that looks like `abcdr`, requesting `mapping(5, 4)` would return: .. code-block:: python [(5,1,0,1, 'physical_layer'), (6,1,3,1, 'physical_layer'), (7,2,0,2, 'physical_layer') ] This mapping mechanism allows for great flexibility because chunks making up a virtual layer can come from multiple different range layers, allowing for swap space to be used to construct the virtual layer, for example. Also, by defining the mapping method, the read and write methods (which read and write into the domain layer) are defined for you to write to the lower layers (which in turn can write to layers even lower than that) until eventually they arrive at a DataLayer, such as a file or a buffer. This mechanism also allowed for some minor optimization in scanning such a layer, but should further control over the 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:`~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 take a chunk and process it from its original value into its final value (such as decompressing for read and compressing for write). These methods are private to the class, and are used within the standard `read` and `write` methods of a layer. A non-linear layer's mapping method should return the data required to be able to return the original data. As an example, a run length encoded layer, whose domain data looks like `aaabbbbbcdddd` could be stored as `3a5b1c4d`. The mapping method call for `mapping(5,4)` should return all the regions that encompass the data required. The layer would return the following data: .. code-block:: python [(5, 4, 2, 4, 'rle layer')] It would then define `_decode` and `_encode` methods that could convert from one to the other. In the case of `read(5, 4)`, the `_decode` method would be provided with the following parameters: .. code-block:: python data = "5b1c" mapped_offset = 2 offset = 5 output_length = 4 This requires that the `_decode` method can unpack the encoding back to `bbbbbc` and also know that the decoded block starts at 3, so that it can return just `bbbc`, as required. Such layers therefore typically need to keep much more internal state, to keep track of which offset of encoded data relates to which decoded offset for both the mapping and `_encode` and `_decode` methods. If the data processing produces known fixed length values, then it is possible to write an `_encode` method in much the same way as the decode method. `_encode` is provided with the data to encode, the mapped_offset to write it to the lower (range) layer, the original offset of the data in the higher (domain) layer and the value of the not yet encoded data to write. The encoded result, regardless of length will be written over the current image at the mapped_offset. No other changes or updates to tables, etc are carried out. `_encode` is much more difficult if the encoded data can be variable length, as it may involve rewriting most, if not all of the data in the image. Such a situation is not currently supported with this API and it is strongly recommended to raise NotImplementedError in this method. Communicating between layers ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Layers can ask for information from lower layers using the `layer.metadata` lookup. In the following example, a LayerStacker automagic that generates the intel TranslationLayer requests whether the base layer knows what the `page_map_offset` value should be, a CrashDumpLayer would have that information. As such the TranslationLayer would just lookup the `page_map_offset` value in the `base_layer.metadata` dictionary: .. code-block:: python if base_layer.metadata.get('page_layer_offset', None) is not None: Most layers will return `None`, since this is the default, but the CrashDumpLayer may know what the value should be, so it therefore populates the `metadata` property. This is defined as a read-only mapping to ensure that every layer includes data from every underlying layer. As such, CrashDumpLayer would actually specify this value by setting it in the protected dictionary by `self._direct_metadata['page_map_offset']`. There is, unfortunately, no easy way to form consensus between what a particular layer may want and what a particular layer may be able to provide. At the moment, the main information that layers may populate are: * `os` with values of `Windows`, `Linux`, `Mac` or `unknown` * `architecture` with values of `Intel32`, `Intel64` or `unknown` * `pae` a boolean specifying whether the PAE mode is enabled for windows * `page_map_offset` the value pointing to the intel page_map_offset Any value can be specified and used by layers but consideration towards ambiguity should be used to ensure that overly generic names aren't used for something and then best describe something else that may be needed later on. .. note:: The data stored in metadata is *not* restored when constructed from a configuration, so metadata should only be used as a temporary means of storing information to be used in constructing later objects and all information required to recreate an object must be written through the requirements mechanism. 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:`~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: .. code-block:: python symbol_table = contexts.symbol_space[symbol_table_name] symbol_table.set_type_class('', NewStructureClass) This will mean that when a specific structure is loaded from the symbol_space, it is not constructed as a standard `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:`~volatility3.framework.objects.PrimitiveObject` 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:`~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:`~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:`~volatility3.framework.interfaces.objects.ObjectInformation` class contains all the basic elements that define an object, which include: * layer_name * offset * member_name * parent * native_layer_name * size The layer_name and offset are how volatility reads the data of the object. Since objects can reference other objects (specifically pointers), and contain values that are used as offsets in a particular layer, there is also the concept of a native_layer_name. The native_layer_name allows an object to be constructed based on physical data (for instance) but to reference virtual addresses, or for an object in the kernel virtual layer to reference offsets in a process virtual layer. The member_name and parent are optional and are used for when an object is constructed as a member of a structure. The parent points back to the object that created this one, and member_name is the name of the attribute of the parent used to get to this object. Finally, some objects are dynamically sized, and this size parameter allows a constructor to specify how big the object should be. Note, the size can change throughout the lifespan of the object, and the object will need to ensure that it compensates for such a change. Objects must also contain a specific class called `VolTemplateProxy` which must inherit from :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:`~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 to be defined for very specific objects. --- ## File: doc/source/development.rst Writing Plugins =============== .. toctree:: simple-plugin complex-plugin using-as-a-library --- ## File: doc/source/getting-started-linux-tutorial.rst Linux Tutorial ============== This guide will give you a brief overview of how volatility3 works as well as a demonstration of several of the plugins available in the suite. Acquiring memory ---------------- Volatility3 does not provide the ability to acquire memory. Below is an example of a tool that can be used to acquire memory on Linux systems: * `AVML - Acquire Volatile Memory for Linux `_ Other tools may exist, but please verify their maintenance status and compatibility with volatility3 before use. Procedure to create symbol tables for Linux ------------------------------------------- It is recommended to first check the repository `volatility3-symbols `_ for pre-generated JSON.xz symbol table files. This repository provides files organized by kernel version for popular Linux distributions such as Debian, Ubuntu, and AlmaLinux. If you cannot find a suitable symbol table for your kernel version there, please refer to :ref:`symbol-tables:Mac or Linux symbol tables` to create one manually. After creating the file, place it under the directory ``volatility3/symbols``. Volatility3 will automatically detect and use symbol tables from this location. Listing plugins --------------- Volatility3 currently supports over 40 Linux-specific plugins covering a wide range of forensic analysis needs, such as process enumeration, memory-mapped file inspection, loaded modules, and kernel tracing features. Some representative plugins include: - ``linux.pslist``: Lists running processes with their PIDs and PPIDs. - ``linux.bash``: Recovers bash command history from memory. - ``linux.lsmod``: Displays loaded kernel modules. - ``linux.kmsg``: Reads messages from the kernel log buffer. - ``linux.elfs``: Lists all memory-mapped ELF files. - ``linux.check_creds``: Checks for suspicious credential structures. - ``linux.vmayarascan``: Scans process memory using YARA signatures. For a full list of supported plugins, run the following command: .. code-block:: shell-session $ python3 vol.py --help | grep -i linux. .. note:: You can also filter and inspect available plugins using more sophisticated patterns or tools like ``grep``, ``awk``, or simply explore the source under ``volatility3/framework/plugins/linux``. Using plugins ------------- The following is the syntax to run the volatility CLI. .. code-block:: shell-session $ python3 vol.py -f Example ------- banners ~~~~~~~ In this example we will be using a memory dump from the Insomni'hack teaser 2020 CTF Challenge called Getdents. We will limit the discussion to memory forensics with volatility 3 and not extend it to other parts of the challenge. Thanks go to `stuxnet `_ for providing this memory dump and `writeup `_. .. code-block:: shell-session $ python3 vol.py -f memory.vmem banners Volatility 3 Framework 2.26.0 Progress: 100.00 PDB scanning finished Offset Banner 0x141c1390 Linux version 4.15.0-42-generic (buildd@lgw01-amd64-023) (gcc version 7.3.0 (Ubuntu 7.3.0-16ubuntu3)) #45-Ubuntu SMP Thu Nov 15 19:32:57 UTC 2018 (Ubuntu 4.15.0-42.45-generic 4.15.18) 0x63a00160 Linux version 4.15.0-72-generic (buildd@lcy01-amd64-026) (gcc version 7.4.0 (Ubuntu 7.4.0-1ubuntu1~18.04.1)) #81-Ubuntu SMP Tue Nov 26 12:20:02 UTC 2019 (Ubuntu 4.15.0-72.81-generic 4.15.18) 0x6455c4d4 Linux version 4.15.0-72-generic (buildd@lcy01-amd64-026) (gcc version 7.4.0 (Ubuntu 7.4.0-1ubuntu1~18.04.1)) #81-Ubuntu SMP Tue Nov 26 12:20:02 UTC 2019 (Ubuntu 4.15.0-72.81-generic 4.15.18) 0x6e1e055f Linux version 4.15.0-72-generic (buildd@lcy01-amd64-026) (gcc version 7.4.0 (Ubuntu 7.4.0-1ubuntu1~18.04.1)) #81-Ubuntu SMP Tue Nov 26 12:20:02 UTC 2019 (Ubuntu 4.15.0-72.81-generic 4.15.18) 0x7fde0010 Linux version 4.15.0-72-generic (buildd@lcy01-amd64-026) (gcc version 7.4.0 (Ubuntu 7.4.0-1ubuntu1~18.04.1)) #81-Ubuntu SMP Tue Nov 26 12:20:02 UTC 2019 (Ubuntu 4.15.0-72.81-generic 4.15.18) The above command helps us identify the kernel version and distribution from the memory dump. Using this information, follow the instructions in :ref:`getting-started-linux-tutorial:Procedure to create symbol tables for linux` to generate the required ISF file. Once created, place the file under the ``volatility3/symbols`` directory so that Volatility3 can recognize it automatically. linux.boottime ~~~~~~~~~~~~~~ This plugin provides the system boot time extracted from memory. It is useful for establishing a timeline, particularly when analyzing incident response scenarios or determining system uptime. .. code-block:: shell-session $ python3 vol.py -f memory.vmem linux.boottime Volatility 3 Framework 2.26.0 Progress: 100.00 Stacking attempts finished TIME NS Boot Time - 2022-02-10 06:50:16.450008 UTC This timestamp can serve as a reference point for correlating system events, such as process start times, logs, or malicious activity. linux.pslist ~~~~~~~~~~~~ This plugin lists active processes by walking the task list from memory. It provides detailed metadata for each process, including identifiers and user/group information. .. code-block:: shell-session $ python3 vol.py -f memory.vmem linux.pslist Volatility 3 Framework 2.26.0 Progress: 100.00 Stacking attempts finished OFFSET (V) PID TID PPID COMM UID GID EUID EGID CREATION TIME File output 0x8ca6db1aac80 1 1 0 systemd 0 0 0 0 2022-02-10 06:50:16.364213 UTC Disabled 0x8ca6db1a9640 2 2 0 kthreadd 0 0 0 0 2022-02-10 06:50:16.364213 UTC Disabled 0x8ca6db1ac2c0 3 3 2 rcu_gp 0 0 0 0 2022-02-10 06:50:16.372213 UTC Disabled ... This detailed view allows investigators to correlate user privileges, startup times, and relationships between processes more precisely than before. linux.pstree ~~~~~~~~~~~~ This plugin presents the process hierarchy as a tree, clearly showing parent-child relationships between processes. .. code-block:: shell-session $ python3 vol.py -f memory.vmem linux.pstree Volatility 3 Framework 2.26.0 Progress: 100.00 Stacking attempts finished OFFSET (V) PID TID PPID COMM 0x8ca6db1aac80 1 1 0 systemd * 0x8ca6db3342c0 278 278 1 systemd-journal * 0x8ca6d005ac80 315 315 1 systemd-udevd * 0x8ca6d0eac2c0 478 478 1 systemd-resolve * ... *** 0x8ca67108c2c0 1507 1507 1438 gdm-x-session **** 0x8ca671215900 1527 1527 1507 Xorg **** 0x8ca671210000 1608 1608 1507 gnome-session-b ***** 0x8ca66fba42c0 1765 1765 1608 ssh-agent It helps identify unusual or suspicious process structures such as orphaned child processes, injected children under legitimate parents, or long chains of shell execution. The tree view is particularly useful for spotting anomalies in process launch sequences or privilege escalations by inspecting unexpected parent-child relationships. linux.bash ~~~~~~~~~~ Now to find the commands that were run in the bash shell by using ``linux.bash``. .. code-block:: shell-session $ python3 vol.py -f memory.vmem linux.bash Volatility 3 Framework 2.26.0 Progress: 100.00 Stacking attempts finished PID Process CommandTime Command 1733 bash 2020-01-16 14:00:36.000000 sudo reboot 1733 bash 2020-01-16 14:00:36.000000 AWAVH�� 1733 bash 2020-01-16 14:00:36.000000 sudo apt upgrade 1733 bash 2020-01-16 14:00:36.000000 sudo apt upgrade 1733 bash 2020-01-16 14:00:36.000000 sudo reboot 1733 bash 2020-01-16 14:00:36.000000 uname -a 1733 bash 2020-01-16 14:00:41.000000 chmod +x meterpreter 1733 bash 2020-01-16 14:00:42.000000 sudo ./meterpreter linux.ip.Addr and linux.ip.Link ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Network configuration is an essential aspect of memory forensics. Analyzing the network interfaces and their IP assignments can reveal active connections, misconfigured settings, or even artifacts of malicious activity. Volatility3 provides the following two plugins to examine this information: **linux.ip.Addr** displays IP-related metadata for each interface, including IPv4/IPv6 addresses, MAC, scope, and interface status. .. code-block:: shell-session $ python3 vol.py -f memory.vmem linux.ip.Addr NetNS Index Interface MAC Promiscuous IP Prefix Scope Type State 4026531992 2 enp0s3 08:00:27:8a:4d:eb False 10.0.2.15 24 global UP ... **linux.ip.Link** shows lower-level link information such as MTU, Qdisc, and interface flags. .. code-block:: shell-session $ python3 vol.py -f memory.vmem linux.ip.Link NS Interface MAC State MTU Qdisc Qlen Flags 4026531992 enp0s3 08:00:27:8a:4d:eb UP 1500 fq_codel 1000 BROADCAST,LOWER_UP,MULTICAST,UP Together, these plugins help investigators assess the system’s network exposure and identify anomalies such as multiple network namespaces, unexpected IP addresses, or active interfaces in promiscuous mode. linux.malfind ~~~~~~~~~~~~~ This plugin scans process memory for suspicious executable regions that may indicate code injection or malicious payloads. It is particularly useful for detecting fileless malware, injected shellcode, or unpacked runtime payloads that do not correspond to legitimate binary files on disk. .. code-block:: shell-session $ python3 vol.py -f memory.vmem linux.malfind Volatility 3 Framework 2.26.0 Progress: 100.00 Stacking attempts finished PID Process Start End Path Protection Hexdump Disasm 540 networkd-dispat 0x7f1506482000 0x7f1506483000 Anonymous Mapping rwx 00 00 00 00 00 00 00 00 43 00 00 00 00 00 00 00 ........C....... 4c 8d 15 f9 ff ff ff ff 25 03 00 00 00 0f 1f 00 L.......%....... ... 0x7f1506482000: add byte ptr [rax], al 0x7f1506482002: add byte ptr [rax], al ... 0x7f1506482013: stc In this output: - **PID / Process**: Identifies the target process (in this case, `networkd-dispat`, PID 540) - **Start / End**: The memory address range of the suspicious region - **Path**: Indicates that the region is an anonymous memory mapping (i.e., not backed by a file) - **Protection**: The region is marked `rwx` (read-write-execute), which is uncommon for legitimate memory regions - **Disasm**: Shows the disassembled machine code found in that memory region **Key indicators to focus on:** - **Anonymous Mapping + rwx**: Memory that is not backed by a file and has execute permissions is often used for injected code - **Disassembly patterns**: Repetitive `add` instructions, `nop`, or unusual instruction sequences can be artifacts of shellcode, packer stubs, or JIT-compiled code - **Process context**: The suspicious memory is found in `networkd-dispat`, a system service — if this service is not expected to have dynamic executable memory regions, it may be compromised Use this plugin early in an investigation to flag processes for deeper inspection. Further Exploration and Contribution ------------------------------------ This guide has introduced several key Linux plugins available in Volatility 3 for memory forensics. However, many more plugins are available, covering topics such as kernel modules, page cache analysis, tracing frameworks, and malware detection. If you identify gaps in plugin functionality or wish to extend support for a specific analysis use case, you are encouraged to contribute new plugins or enhancements. Your insights can help shape the future of Linux memory forensics. --- ## File: doc/source/getting-started-mac-tutorial.rst macOS Tutorial ============== .. warning:: As of the Volatility 3 parity release, macOS analysis support is no longer actively maintained. The existing macOS plugins remain available but may not receive future updates or bug fixes. For more details, see the `official announcement `_. This guide will give you a brief overview of how volatility3 works as well as a demonstration of several of the plugins available in the suite. Acquiring memory ---------------- Volatility3 does not provide the ability to acquire memory. The example below is an open source tool. Other commercial tools are also available. * `osxpmem `_ Procedure to create symbol tables for macOS -------------------------------------------- To create a symbol table please refer to :ref:`symbol-tables:Mac or Linux symbol tables`. .. tip:: It may be possible to locate pre-made ISF files from the `download link `_ , which is built and maintained by `volatilityfoundation `_. After creating the file or downloading it from the link, place the file under the directory ``volatility3/symbols/``. Listing plugins --------------- The following is a sample of the macOS plugins available for volatility3, it is not complete and more plugins may be added. For a complete reference, please see the volatility 3 :doc:`list of plugins `. For plugin requests, please create an issue with a description of the requested plugin. .. code-block:: shell-session $ python3 vol.py --help | grep -i mac. | head -n 4 mac.bash.Bash Recovers bash command history from memory. mac.check_syscall.Check_syscall mac.check_sysctl.Check_sysctl mac.check_trap_table.Check_trap_table .. note:: Here the command is piped to grep and head to provide the start of the list of macOS plugins. Using plugins ------------- The following is the syntax to run the volatility CLI. .. code-block:: shell-session $ python3 vol.py -f Example ------- banners ~~~~~~~ In this example we will be using a memory dump from the Securinets CTF Quals 2019 Challenge called Contact_me. We will limit the discussion to memory forensics with volatility 3 and not extend it to other parts of the challenge. Thanks go to `stuxnet `_ for providing this memory dump and `writeup `_. .. code-block:: shell-session $ python3 vol.py -f contact_me banners.Banners Volatility 3 Framework 2.4.2 Progress: 100.00 PDB scanning finished Offset Banner 0x4d2c7d0 Darwin Kernel Version 16.7.0: Thu Jun 15 17:36:27 PDT 2017; root:xnu-3789.70.16~2/RELEASE_X86_64 0xb42b180 Darwin Kernel Version 16.7.0: Thu Jun 15 17:36:27 PDT 2017; root:xnu-3789.70.16~2/RELEASE_X86_64 0xcda9100 Darwin Kernel Version 16.7.0: Thu Jun 15 17:36:27 PDT 2017; root:xnu-3789.70.16~2/RELEASE_X86_64 0x1275e7d0 Darwin Kernel Version 16.7.0: Thu Jun 15 17:36:27 PDT 2017; root:xnu-3789.70.16~2/RELEASE_X86_64 0x1284fba4 Darwin Kernel Version 16.7.0: Thu Jun 15 17:36:27 PDT 2017; root:xnu-3789.70.16~2/RELEASE_X86_64 0x34ad0180 Darwin Kernel Version 16.7.0: Thu Jun 15 17:36:27 PDT 2017; root:xnu-3789.70.16~2/RELEASE_X86_64 The above command helps us to find the memory dump's Darwin kernel version. Now using the above banner we can search for the needed ISF file. If an ISF file cannot be found then, follow the instructions on :ref:`getting-started-mac-tutorial:Procedure to create symbol tables for macOS`. After that, place the ISF file under the ``volatility3/symbols`` directory. mac.pslist ~~~~~~~~~~ .. code-block:: shell-session $ python3 vol.py -f contact_me mac.pslist.PsList Volatility 3 Framework 2.4.2 Progress: 100.00 Stacking attempts finished PID PPID COMM 0 0 kernel_task 1 0 launchd 35 1 UserEventAgent 38 1 kextd 39 1 fseventsd 37 1 uninstalld 45 1 configd 46 1 powerd 52 1 logd 58 1 warmd ..... ``mac.pslist`` helps us to list the processes which are running, their PIDs and PPIDs. mac.pstree ~~~~~~~~~~ .. code-block:: shell-session $ python3 vol.py -f contact_me mac.pstree.PsTree Volatility 3 Framework 2.4.2 Progress: 100.00 Stacking attempts finished PID PPID COMM 35 1 UserEventAgent 38 1 kextd 39 1 fseventsd 37 1 uninstalld 204 1 softwareupdated * 449 204 SoftwareUpdateCo 337 1 system_installd * 455 337 update_dyld_shar ``mac.pstree`` helps us to display the parent-child relationships between processes. mac.ifconfig ~~~~~~~~~~~~ .. code-block:: shell-session $ python3 vol.py -f contact_me mac.ifconfig.Ifconfig Volatility 3 Framework 2.4.2 Progress: 100.00 Stacking attempts finished Interface IP Address Mac Address Promiscuous lo0 False lo0 127.0.0.1 False lo0 ::1 False lo0 fe80:1::1 False gif0 False stf0 False en0 00:0C:29:89:8B:F0 00:0C:29:89:8B:F0 False en0 fe80:4::10fb:c89d:217f:52ae 00:0C:29:89:8B:F0 False en0 192.168.140.128 00:0C:29:89:8B:F0 False utun0 False utun0 fe80:5::2a95:bb15:87e3:977c False We can use the ``mac.ifconfig`` plugin to get information about the configuration of the network interfaces of the host under investigation. --- ## File: doc/source/getting-started-windows-tutorial.rst Windows Tutorial ================ This guide provides a brief introduction to how volatility3 works as a demonstration of several of the plugins available in the suite. Acquiring memory ---------------- Volatility does not provide the ability to acquire memory. Memory can be acquired using a number of tools, below are some examples but others exist: * `WinPmem `_ * `FTK Imager `_ Listing Plugins --------------- The following is a sample of the windows plugins available for volatility3, it is not complete and more plugins may be added. For a complete reference, please see the volatility 3 :doc:`list of plugins `. For plugin requests, please create an issue with a description of the requested plugin. .. code-block:: shell-session $ python3 vol.py --help | grep windows | head -n 4 windows.bigpools.BigPools windows.cmdline.CmdLine windows.crashinfo.Crashinfo windows.dlllist.DllList .. note:: Here the command is piped to grep and head to provide the start of a list of the available windows plugins. Using plugins ------------- The following is the syntax to run the volatility CLI. .. code-block:: shell-session $ python3 vol.py -f plugin_name plugin_option Example ------- windows.pslist ~~~~~~~~~~~~~~ In this example we will be using a memory dump from the PragyanCTF'22. We will limit the discussion to memory forensics with volatility 3 and not extend it to other parts of the challenges. When using windows plugins in volatility 3, the required ISF file can often be generated from PDB files automatically downloaded from Microsoft servers, and therefore does not require locating or adding specific ISF files to the volatility 3 symbols directory. .. code-block:: shell-session $ python3 vol.py -f MemDump.DMP windows.pslist | head -n 10 Volatility 3 Framework 2.0.1 PDB scanning finished PID PPID ImageFileName Offset(V) Threads Handles SessionId Wow64 CreateTime ExitTime File output 4 0 System 0xfa8000cbc040 85 492 N/A False 2022-02-07 16:30:12.000000 N/A Disabled 276 4 smss.exe 0xfa8001e04040 2 29 N/A False 2022-02-07 16:30:12.000000 N/A Disabled 352 336 csrss.exe 0xfa8002110b30 9 375 0 False 2022-02-07 16:30:13.000000 N/A Disabled 404 336 wininit.exe 0xfa800219f060 3 74 0 False 2022-02-07 16:30:13.000000 N/A Disabled 412 396 csrss.exe 0xfa80021c5b30 9 224 1 False 2022-02-07 16:30:13.000000 N/A Disabled 468 396 winlogon.exe 0xfa8002284060 5 113 1 False 2022-02-07 16:30:14.000000 N/A Disabled ``windows.pslist`` helps list the processes running while the memory dump was taken. windows.pstree ~~~~~~~~~~~~~~ .. code-block:: shell-session $ python3 vol.py -f MemDump.DMP windows.pstree | head -n 20 Volatility 3 Framework 2.0.1 PDB scanning finished PID PPID ImageFileName Offset(V) Threads Handles SessionId Wow64 CreateTime ExitTime 4 0 System 0xfa8000cbc040 85 492 N/A False 2022-02-07 16:30:12.000000 N/A * 276 4 smss.exe 0xfa8001e04040 2 29 N/A False 2022-02-07 16:30:12.000000 N/A 352 336 csrss.exe 0xfa8002110b30 9 375 0 False 2022-02-07 16:30:13.000000 N/A 404 336 wininit.exe 0xfa800219f060 3 74 0 False 2022-02-07 16:30:13.000000 N/A * 504 404 services.exe 0xfa80022ccb30 7 190 0 False 2022-02-07 16:30:14.000000 N/A ** 960 504 svchost.exe 0xfa8001c17b30 39 1003 0 False 2022-02-07 16:30:14.000000 N/A ** 1216 504 svchost.exe 0xfa80026e0b30 18 311 0 False 2022-02-07 16:30:15.000000 N/A ** 1312 504 svchost.exe 0xfa8002740380 19 287 0 False 2022-02-07 16:30:15.000000 N/A ** 1984 504 taskhost.exe 0xfa8002eb1b30 8 129 1 False 2022-02-07 16:30:27.000000 N/A ** 804 504 svchost.exe 0xfa80024ca5f0 20 450 0 False 2022-02-07 16:30:14.000000 N/A *** 100 804 audiodg.exe 0xfa80025b4b30 6 131 0 False 2022-02-07 16:30:14.000000 N/A ** 1568 504 SearchIndexer. 0xfa800254b480 12 616 0 False 2022-02-07 16:30:32.000000 N/A ** 744 504 svchost.exe 0xfa8002477b30 8 265 0 False 2022-02-07 16:30:14.000000 N/A ** 1096 504 svchost.exe 0xfa800260db30 14 357 0 False 2022-02-07 16:30:14.000000 N/A ** 616 504 svchost.exe 0xfa8002b86ab0 13 314 0 False 2022-02-07 16:32:16.000000 N/A ** 624 504 svchost.exe 0xfa8002410630 10 350 0 False 2022-02-07 16:30:14.000000 N/A ``windows.pstree`` helps to display the parent-child relationships between processes. .. note:: Here the command is piped to head to provide smaller output, here listing only the first 20. windows.hashdump ~~~~~~~~~~~~~~~~ .. code-block:: shell-session $ python3 vol.py -f MemDump.DMP windows.hashdump Volatility 3 Framework 2.0.3 Progress: 100.00 PDB scanning finished User rid lmhash nthash Administrator 500 aad3b435b51404eeaad3b435b51404ee 31d6cfe0d16ae931b73c59d7e0c089c0 Guest 501 aad3b435b51404eeaad3b435b51404ee 31d6cfe0d16ae931b73c59d7e0c089c0 Frank Reynolds 1000 aad3b435b51404eeaad3b435b51404ee a88d1e18706d3aa676e01e5943d15911 HomeGroupUser$ 1002 aad3b435b51404eeaad3b435b51404ee af10ecac6ea817d2bb56e3e5c33ce1cd Dennis 1003 aad3b435b51404eeaad3b435b51404ee cf96684bbc7877920adaa9663698bf54 ``windows.hashdump`` helps to list the hashes of the users in the system. --- ## File: doc/source/glossary.rst Glossary ======== There are many terms when talking about memory forensics, this list hopes to define the common ones and provide some commonality on how to refer to particular ideas within the field. A - .. _Address: An address is another name for an :ref:`offset`, specifically an offset within memory. Offsets can be both relative or absolute, whereas addresses are almost always absolute. .. _Address Space: Address Space This is the name in volatility 2 for what's referred to as a :ref:`Translation Layer`. It encompasses all values that can be addresses, usually in reference to addresses in memory. .. _Alignment: Alignment This value is what all data :ref:`offsets` will typically be a multiple of within a :ref:`type`. .. _Array: Array This represents a list of items, which can be accessed by an index, which is zero-based (meaning the first element has index 0). Items in arrays are almost always the same size (it is not a generic list, as in python) even if they are :ref:`pointers` to different sized objects. D - .. _Data Layer: Data Layer A group of bytes, where each byte can be addressed by a specific offset. Data layers are usually contiguous chunks of data. .. _Dereference: Dereference The act of taking the value of a pointer, and using it as an offset to another object, as a reference. .. _Domain: Domain The set of input values for a mapping or mathematical function. I - .. _Intermediate Symbol File (ISF): Intermediate Symbol File (ISF) They contain kernel structures and specific offsets formatted as JSON. For macOS and Linux analysis, the kernel needs to be added as an ISF file to the volatility 3 symbols directory. For Windows, the required ISF file can often be generated from PDB files automatically downloaded from Microsoft servers, and therefore does not require manual intervention. M - .. _Map: Map, mapping A mapping is a relationship between two sets (where elements of the :ref:`Domain` map to elements of the :ref:`Range`). Mappings can be seen as a mathematical function, and therefore volatility 3 attempts to use mathematical functional notation where possible. Within volatility a mapping is most often used to refer to the function for translating addresses from a higher layer (domain) to a lower layer (range). For further information, please see `Function (mathematics) in Wikipedia_`. .. _Member: Member The name of subcomponents of a type, similar to attributes of objects in common programming parlance. These are usually recorded as :ref:`offset` and :ref:`type` pairs within a :ref:`structure`. O - .. _Object: Object This has a specific meaning within computer programming (as in object-oriented programming), but within the world of Volatility it is used to refer to a type that has been associated with a chunk of data, or a specific instance of a type. See also :ref:`Type`. .. _Offset: Offset A numeric value that identifies a distance within a group of bytes, to uniquely identify a single byte, or the start of a run of bytes. An offset is often relative (offset from another object/item) but can be absolute (offset from the start of a region of data). P - .. _Packed: Packed Structures are often :ref:`aligned` meaning that the various members (subtypes) are always aligned at particular values (usually multiples of 2, 4 or 8). Thus if the data used to represent a particular value has an odd number of bytes, not a multiple of the chosen number, there will be :ref:`padding` between it and the next member. In packed structs, no padding is used and the offset of the next member depends on the length of the previous one. .. _Padding: Padding Data that (usually) contains no useful information. The typical value used for padding is 0 (sometimes called a null byte). As an example, if a string :ref:`object` that has been allocated a particular number of bytes, actually contains fewer bytes, the rest of the data (to make up the original length) will be padded with null (0) bytes. .. _Page: Page A specific chunk of contiguous data. It is an organizational quantity of memory (usually 0x1000, or 4096 bytes). Pages, like pages in a book, make up the whole, but allow for specific chunks to be allocated and used as necessary. Operating systems uses pages as a means to have granular control over chunks of memory. This allows them to be reordered and reused as necessary (without having to move large chunks of data around), and allows them to have access controls placed upon them, limiting actions such as reading and writing. .. _Page Table: Page Table A table that points to a series of :ref:`pages`. Each page table is typically the size of a single page, and page tables can point to pages that are in fact other page tables. Using tables that point to tables, it's possible to use them as a way to map a particular address within a (potentially larger, but sparsely populated) virtual space to a concrete (and usually contiguous) physical space, through the process of :ref:`mapping`. .. _Plugin: Plugin Plugins are the "functions" of the volatility framework. They carry out algorithms on data stored in layers using objects constructed from symbols. Broadly, plugins take in a number of TranslationLayers (the data, which is a representation of part of an image, in a specified type described by templates) and outputs a TreeGrid. .. _Pointer: Pointer A value within memory that points to a different area of memory. This allows objects to contain references to other objects without containing all the data of the other object. Following a pointer is known as :ref:`dereferencing` a pointer. Pointers are usually the same length as the maximum address of the address space, since they should be able to point to any address within the space. R - .. _Range: Range This is the set of the possible output values for a mapping or mathematical function. S - .. _Struct: Struct, Structure A means of containing multiple different :ref:`type` associated together. A struct typically contains other :ref:`type`, usually :ref:`aligned` (unless :ref:`packing` is involved). In this way the :ref:`members` of a type can be accessed by finding the data at the relative :ref:`offset` to the start of the structure. .. _Symbol: Symbol This is used in many different contexts, as a short term for many things. Within Volatility, a symbol is a construct that usually encompasses a specific :ref:`type` at a specific :ref:`offset`, representing a particular instance of that type within the memory of a compiled and running program. An example would be the location in memory of a list of active TCP endpoints maintained by the networking stack within an operating system. T - .. _Template: Template Within volatility 3, the term template applies to a :ref:`type` that has not yet been instantiated or linked to any data or a specific location within memory. Once a type has been tied to a particular chunk of data, it is called an :ref:`object`. .. _Translation Layer: Translation Layer This is a type of data layer which allows accessing data from lower layers using addresses different to those used by the lower layers themselves. When accessing data in a translation layer, it translates (or :ref:`maps`) addresses from its own :ref:`address space
` to the address space of the lower layer and returns the corresponding data from the lower layer. Note that multiple addresses in the higher layer might refer to the same address in the lower layer. Conversely, some addresses in the higher layer might have no corresponding address in the lower layer at all. Translation layers most commonly handle the translation from virtual to physical addresses, but can be used to translate data to and from a compressed form or translate data from a particular file format into another format. .. _Type: Type This is a structure definition of multiple elements that expresses how data is laid out. Basic types define how the data should be interpreted in terms of a run of bits (or more commonly a collection of 8 bits at a time, called bytes). New types can be constructed by combining other types at specific relative offsets, forming something called a :ref:`struct`, or by repeating the same type, known as an :ref:`array`. They can even contain other types at the same offset depending on the data itself, known as :ref:`Unions`. Once a type has been linked to a specific chunk of data, the result is referred to as an :ref:`object`. U - .. _Union: Union A union is a type that can hold multiple different subtypes, whose relative offsets specifically overlap. A union is a means for holding multiple different types within the same size of data, the relative offsets of the types within the union specifically overlap. This means that the data in a union object is interpreted differently based on the types of the union used to access it. --- ## File: doc/source/index.rst Volatility 3 ============ This is the documentation for Volatility 3, the most advanced memory forensics framework in the world. Like previous versions of the Volatility framework, Volatility 3 is Open Source. :doc:`List of plugins ` Below is the main documentation regarding volatility 3: .. toctree:: :caption: Documentation basics development symbol-tables vol2to3 volshell glossary There is also some information to get you started quickly: .. toctree:: :caption: Getting Started getting-started-linux-tutorial getting-started-mac-tutorial getting-started-windows-tutorial .. toctree:: :caption: Python Packages volatility3 Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` --- ## File: doc/source/simple-plugin.rst 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:`~volatility3.plugins.windows.dlllist.DllList`, which features the main traits of a normal plugin, and reuses other plugins appropriately. .. note:: This document will not include the complete code necessary for a working plugin (such as imports, etc) since it's designed to focus on the necessary components for writing a plugin. For complete and functioning plugins, the ``framework/plugins`` directory should be consulted. Inherit from 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:`~volatility3.framework.interfaces.plugins.PluginInterface`. :: from volatility3.framework import interfaces class DllList(interfaces.plugins.PluginInterface): The next step is to define the requirements of the plugin, these will be converted into options the user can provide based on the User Interface. Define the plugin requirements ------------------------------ These requirements are the names of variables that will need to be populated in the configuration tree for the plugin to be able to run properly. Any that are defined as optional need not necessarily be provided. :: _version = (1, 0, 0) _required_framework_version = (2, 0, 0) @classmethod def get_requirements(cls): return [ requirements.ModuleRequirement( name = 'kernel', description = 'Windows kernel', architectures = ["Intel32", "Intel64"] ), requirements.ListRequirement( name = 'pid', element_type = int, description = "Process IDs to include (all other processes are excluded)", optional = True ), requirements.VersionRequirement( name = 'pslist', component = pslist.PsList, version = (2, 0, 0) ), ] This is a classmethod, so it can be called before the specific plugin object has been instantiated (in order to know how to instantiate the plugin). At the moment these requirements are fairly straightforward: :: requirements.ModuleRequirement( name = 'kernel', description = 'Windows kernel', architectures = ["Intel32", "Intel64"] ), This requirement specifies the need for a particular submodule. Each module requires a :py:class:`TranslationLayer ` and a :py:class:`SymbolTable `, which are fulfilled by two subrequirements: a :py:class:`~volatility3.framework.configuration.requirements.TranslationLayerRequirement` and a :py:class:`~volatility3.framework.configuration.requirements.SymbolTableRequirement`. At the moment, the automagic only fills `ModuleRequirements` with kernels, and so has relatively few parameters. It requires the architecture for the underlying TranslationLayer, and the offset of the module within that layer. The name of the module will be stored in the ``kernel`` configuration option, and the module object itself can be accessed from the ``context.modules`` collection. This requirement is a Complex Requirement and therefore will not be requested directly from the user. .. note:: In previous versions of volatility 3, there was no `ModuleRequirement`, and instead two requirements were defined a :py:class:`TranslationLayer ` and a `SymbolTableRequirement`. These still exist, and can be used, most plugins just define a single `ModuleRequirement` for the kernel, which the automagic will populate. The `ModuleRequirement` has two automatic sub-requirements, a `TranslationLayerRequirement` and a `SymbolTableRequirement`, but the module also includes the offset of the module, and will allow future expansion to specify specific modules when application level plugins become more common. Below are how the requirements would be specified: :: requirements.TranslationLayerRequirement( name = 'primary', description = 'Memory layer for the kernel', architectures = ["Intel32", "Intel64"] ), This requirement indicates that the plugin will operate on a single :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']``). .. note:: The name itself is dynamic depending on the other layers already present in the Context. Always use the value from the configuration rather than attempting to guess what the layer will be called. Finally, this defines that the translation layer must be on the Intel Architecture. At the moment, this acts as a filter, failing to be satisfied by memory images that do not match the architecture required. Most plugins will only operate on a single layer, but it is entirely possible for a plugin to request two different layers, for example a plugin that carries out some form of difference or statistics against multiple memory images. 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:`~volatility3.framework.configuration.requirements.TranslationLayerRequirement` is the string name of a layer present in the context's memory that satisfies the requirement. :: requirements.SymbolTableRequirement( name = "nt_symbols", description = "Windows kernel symbols" ), This requirement specifies the need for a particular :py:class:`SymbolTable ` to be loaded. This gets populated by various :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. :: requirements.ListRequirement( name = 'pid', description = 'Filter on specific process IDs', element_type = int, optional = True ), The next requirement is a List Requirement, populated by integers. The description will be presented to the user to describe what the value represents. The optional flag indicates that the plugin can function without the ``pid`` value being defined within the configuration tree at all. :: requirements.PluginRequirement( name = 'pslist', plugin = pslist.PsList, version = (2, 0, 0) ) This requirement indicates that the plugin will make use of another plugin's code, and specifies the version requirements on that plugin. The version is specified in terms of Semantic Versioning meaning that, to be compatible, the major versions must be identical and the minor version must be equal to or higher than the one provided. This requirement does not make use of any data from the configuration, even if it were provided, it is merely a functional check before running the plugin. To define the version of a plugin, populate the `_version` class variable as a tuple of version numbers `(major, minor, patch)`. So for example: :: _version = (1, 0, 0) The plugin may also require a specific version of the framework, and this also uses Semantic Versioning, and can be set by defining the `_required_framework_version`. The major version should match the version of volatility the plugin is to be used with, which at the time of writing would be 2.2.0, and so would be specified as below. If only features, for example, from 2.0.0 are used, then the lowest applicable version number should be used to support the greatest number of installations: :: _required_framework_version = (2, 0, 0) 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:`~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:`~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`. :: def run(self): filter_func = pslist.PsList.create_pid_filter(self.config.get('pid', None)) return renderers.TreeGrid( [ ("PID", int), ("Process", str), ("Base", format_hints.Hex), ("Size", format_hints.Hex), ("Name", str), ("Path", str), ], self._generator( pslist.PsList.list_processes( context=self.context, kernel_module_name=self.config['kernel'], filter_func = filter_func ) ) ) 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:`~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 hexadecimal number, using :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:`~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 value from the configuration for the kernel module name, constructed from the ``kernel`` configuration requirement. This will generate a list 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:`~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. :: def _generator(self, procs): for proc in procs: for entry in proc.load_order_modules(): BaseDllName = FullDllName = renderers.UnreadableValue() try: BaseDllName = entry.BaseDllName.get_string() # We assume that if the BaseDllName points to an invalid buffer, so will FullDllName FullDllName = entry.FullDllName.get_string() except exceptions.InvalidAddressException: pass yield (0, (proc.UniqueProcessId, proc.ImageFileName.cast("string", max_length = proc.ImageFileName.vol.count, errors = 'replace'), format_hints.Hex(entry.DllBase), format_hints.Hex(entry.SizeOfImage), BaseDllName, FullDllName)) 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:`~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: * **Unreadable**: values which are empty because the data cannot be read * **Unparsable**: values which are empty because the data cannot be interpreted correctly * **NotApplicable**: values which are empty because they don't make sense for this particular entry * **NotAvailable**: values which cannot be provided now (but might in a future run, via new symbols or an updated plugin) 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:`~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 attributes 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) and are therefore always methods and prepended with ``get_``, in this example ``BaseDllName.get_string()``. Finally, ``FullDllName`` is populated. These operations read from memory, and as such, the memory image may be unable to read the data at a particular offset. This will cause an exception to be thrown. In Volatility 3, exceptions are 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:`~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:`~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:`~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 type string) and could not have been a special Structure such as ``_UNICODE``. For the format hint columns, the format hint type must be used to ensure the error checking does not fail.