Windows Memory Analysis With Volatility
Windows Memory Analysis With Volatility
Windows Memory
Analysis with
Volatility
Version 20171116
Windows Memory Analysis with Volatility
Table of Contents
Table of Volatility Modules 3
Before You Start 4
Types of Files That Can Be Analyzed 5
Volatility Command Syntax 7
Analyzing Network Connections 8
Analyzing Processes 9
Examining Running Services 16
Dumping Process Memory for Further Analysis 17
Detecting Kernel Loaded DLLs 18
Registry Artifacts in Memory 19
Special Use Plugins 21
cmdscan modscan
consoles netscan
dlldump notepad
dlllist printkey
envars privs
getsids procdump
handles pslist
hivelist psscan
imagesinfo pstree
kdbgscan psxview
ldrmodules shellbags
Isadump shimcache
malfind svcscan
moddump symlinkscan
modules userassist
Contents of RAM are also stored in a hyberfil.sys hibernation file when a Windows system
enters hibernation mode to facilitate the system restarting in its previous state. Windows crash
dumps store memory contents to disk to facilitate debugging activities, and these files can likewise
be used by examiners to recover memory artifacts from the time when the crash occurred. Much
like with page files, not all crash dumps will contain sufficient information for meaningful analysis to
occur.
Virtual Machine memory can be acquired as if it were a running on bare metal system or in
some cases through the hypervisor itself. For example, VMWare can create memory dump files in
its own format by taking a snapshot or suspending the virtual machine. Depending on the version of
VMWare and how the files are created, RAM data may be found in files with extensions .vmem, .vmss,
or .vmsn.
Analyzing Processes
A process can be thought of as a container that holds executable program code, imported
libraries, allocated memory, execution threads, and other elements necessary for a computer program
to function. A process receives its own allocation of memory and enables an instance of a computer
program to run on the system. Malicious code can run on a victim system either as its own process
or by injecting code into the context of an already running process. Therefore, analysis of processes is
an important aspect of memory forensics. For additional information about processes on a Windows
system, consult Windows Internals Part 1 (now in its 7th exceptional edition) by Mark Russinovich,
et. al. (https://docs.microsoft.com/en-us/sysinternals/learn/windows-internals).
Listing Processes
On Windows systems, the kernel tracks the currently active processes using a doubly-linked
list. Each running process is found in this list, and therefore most standard Windows calls to list
processes accomplish this by walking this list and printing each process found in it. Some malware
will attempt to hide by delinking its process from this list. In those instances, most live tools run on
the system will fail to detect the malware process. When working with a memory dump, different
approaches can be taken to locate processes. For example, each process has a fixed format header
that contains a key or tag of “Proc” on Windows systems. By searching through all the memory in
a RAM dump for the known structure of a process object’s header and other attributes, Volatility
can detect processes that are not linked in the standard doubly-linked process list. By using and
comparing different methods of identifying processes, an examiner can identify processes that were
attempting to hide their presence.
One of the easiest ways to get a list of processes that were running at the time a RAM dump
was made is:
vol.py -f [image] –profile=[profile] pslist
The pslist plugin walks the doubly-linked list of processes in the same way as most commands
that run on the live system. It therefore provides a useful baseline of what would have been seen by
commands like pslist or tasklist when the system was running, but will not give any information about
processes that were hidden by removing themselves from the process list or those that had already
terminated before the dump was captured.
The pstree plugin will place the list of processes in a tree format to show which processes
spawned other processes and make their parent/child relationship clearer. However, it also relies on
walking the doubly-linked process list, and therefore suffers from the same limitations as the pslist
plugin. It can, however, be a useful command to run, particularly to understand the relationship
between processes. For example, if a particular process is identified as malicious, understanding
what other processes it spawned helps identify other processes that may be acting maliciously (fruit
of the poisonous tree, if you will). Also, a process that spawns in an abnormal way (such as explorer.
exe being used to launch a svchost process) may also signal anomalies caused by malicious activity.
The syntax to run the pstree module is simply:
vol.py -f [image] –profile=[profile] pstree
As mentioned earlier, Volatility is not limited to using only the doubly-linked process list to
identify processes. The entire memory dump can be scanned for known signatures of process objects,
and anything that matches that pattern can be displayed. This is an extremely helpful method to find
processes that have delinked from the process list to avoid detection. Since it does not rely on the
doubly-linked process list, it can also uncover information about processes that were once running
but that terminated before the dump was captured. A process scan can be run with the syntax:
vol.py -f [image] –profile=[profile] psscan
The output from the psscan plugin does not provide the hierarchical view of the parent/child
relationship in the way that the pstree plugin does. To get a similar effect, you can output the results
of psscan into a dot file, and use a program like graphviz to display it graphically. This can be both
an informative investigative approach and also makes illustrative graphs for report purposes. To
accomplish this, a command like the following can be used:
vol.py -f [image] –profile=[profile] psscan --output=dot --output-file=processes.dot
This command will create the list of process in the dot format. To then convert that to a format
such as JPEG, the dot command can be used as follows:
dot -Tjpg processes.dot > processes.jpg
There are many structures within a Windows system that need to track running processes.
While the doubly-linked process list is the most commonly used method for enumerating running
processes, it is also the most likely to be targeted by processes that are attempting to evade detection.
As a result, comparing the results of the doubly-linked list to other structures within the operating
system and other methods of detecting processes can help identify processes that are maliciously
hiding their presence. For such comparative analysis, the command vol.py -f [image] –profile=[profile]
psxview uses multiple methods for detecting processes and lists which processes are and are not
detected by each method. This comparison can help identify processes that are maliciously trying to
avoid detection. Some methods will not detect certain processes, such as those that were started
before the object upon which the detection method relies. Similarly processes that have terminated
will not be detected by methods that only track running processes. To help account for these expected
variations, the command
vol.py -f [image] –profile=[profile] –apply-rules psxview
Will show True when a method detects the process, False when the method does not detect
the process, and Okay when the process is expectedly absent due to a known limitation of the method
being used. Keep in mind that only the psscan method will detect terminated processes.
Obtaining a list of processes from a memory dump file can be an important way to identify
suspicious activity on a system. However, once a process has been identified as potentially malicious,
additional steps are often needed to confirm those suspicions and to determine the nature of the
process itself. A number of different methods can be used to learn more about a particular process.
For a process to access other elements of the system it must first acquire a handle to the
objects that it wants to manipulate. Whether reading a file, writing to a registry key, or opening a
connection to a remote share, the process must have permission to access the object and secure a
handle to that object. Permissions are determined based on the user or group that is attempting to
perform an action, and the permissions that have been assigned to that user and/or the groups of
which it is a member. A process is assigned a security token based on the user or service account
context from which it was run. This token lists the user and/or groups for which the process is
working, which in turn determines which files it may access and other security permissions. The
operating system uniquely refers to each user or group with a numeric Security Identifier (SID). To
determine the SIDs that are associated with a process’ token, use the following command:
vol.py -f [image] –profile=[profile] getsids -p [PID]
Where PID is the process identifier of the process that you wish to examine.
In addition to permissions, a process may also be assigned privileges by the operating system
to perform certain tasks. Privileges include things like the ability to bypass file permissions in order to
read files to make backup copies, the ability to access memory of any process to perform debugging
operations, the ability to shutdown or restart the system, or the ability to load kernel drivers. These
privileges are determined in accordance with local computer policies set by the system administrator.
Malware will frequently attempt to enable privileges to allow a malicious process to perform additional
tasks. To list the privileges assigned or enabled for a particular process use the following command:
vol.py -f [image] –profile=[profile] privs -p [PID]
Where PID is once again the process identifier of the process that you wish to examine. The
output of this command will list the various privileges that are present (allowed) for that process, an
indicator of whether each privilege is enabled, a note as to whether the system enabled the privilege
by default, and a description of what the privilege allows the process to do. Before a privilege may
be used, it must first be enabled. Therefore, your analysis should pay particular attention to enabled
privileges, particularly those that were not enabled by default as they indicate a privilege that the
malware bothered to specifically enable and has therefore likely used or intended to use. The –silent
option can be added to only show those privileges that were enabled.
In addition to understanding the permission and privilege context of a process, it is important
to understand which handles it has opened to other system resources. A handle is a mechanism used
by the operating system to allow access from one resource to another, and to ensure that different
resources are not attempting to make conflicting changes at the same time. Specifically, a handle
controls access to kernel objects that represent other resources on the system like files, registry keys,
processes, etc. To list the handles opened by a process use the command:
vol.py -f [image] –profile=[profile] handles -p [PID]
A process may have many handles opened, so the -t option can be used to restrict the output
to a certain type of handle. Examples include key, file and thread. To list only the handles to registry
keys, use the command:
vol.py -f [image] –profile=[profile] handles -p [PID] -t key
File objects can obviously represent files stored on disk, but can also be used to represent
network connections. The type of device involved should be apparent when looking at the path to
the object. Some items that may be less obvious include:
• \Device\Ip \Device\Tcp and \Device\Afd\Endpoint all refer to handles for network connections.
• \Device\LanmanRedirector and \Device\Mup both refer to handles to SMB network shares.
Searching for these devices may help you locate indications of network activity by
the process being examined. Alternatively, the following command can be used to identify drive
letter assignments, such as the C or D drives being assigned to hard drive or optical drives, but also
assignment of drive letters to mapped network drives, along with the time when the mapping was
created.
vol.py -f [image] –profile=[profile] symlinkscan
If you know that a malicious process is storing data in a certain file, you can search through all
the process file handles to determine which process is using that file. For example, if the file name
was hiddenfile.txt, you can use the following command to identify processes that may be using that
file:
vol.py -f [image] –profile=[profile] handles -t file | grep hiddenfile.txt
In addition to handles, it may be of use to examine the environment variables set by a process.
The basic syntax of the envars plugin is:
vol.py -f [image] –profile=[profile] envars
This will list all environment variables for all processes that were running at the time of the
dump. However, the plugin can be restricted to a single process with the -p [PID] switch as seen
previously with plugins like handles, privs, etc. Finally, the –silent option can be employed to have
volatility compare the results of the envars plugin and compare it to a list of known, normal values
and then only display items that do not match the known values as programmed into the module.
When analyzing a process, it is important to know which DLLs (Dynamic Linked Libraries) are
imported into the process itself. A DLL contains executable code that can provide a process with
specific functionality, so understanding which DLLs a process incorporates may give insight into its
capabilities. In addition, malicious software may inject rogue DLLs into otherwise benign processes
to introduce malicious activity without standing up a new process on the system, so examining
processes for the presence of malicious DLLs or other code injection is an important analysis step.
Volatility supports this type of analysis with a few different plugins.
Within a process’ memory space is the Process Environment Block or PEB. The PEB contains
a number of different items of interest including but not limited to:
• The path to the process’ executable on disk;
• The command line used to invoke the process;
• Three different lists of DLLs associated with the process:
• One that lists the order in which each DLL was loaded into the process;
• One that lists the DLLs based on their order in process memory;
• One that lists the order in which they are executed by the program code.
• The standard input, output, and error for the process;
• The process’ working directory.
Most tools that run on a live system determine the DLLs used by a process by consulting the
first of the three DLL lists stored in the PEB, which tracks the order in which each DLL is loaded. As
a result, malware will sometimes modify that list to hide the presence of a DLL. Volatility has a plugin
that also parses this same list, which can be run with the following command:
vol.py -f [image] –profile=[profile] dlllist -p [PID]
This plugin will list any executable code module, including the program itself. The program
executable will load first and should therefore be the first item in the results of this plugin. As a side
benefit, the original command line and any arguments used to originally launch the process is also
pulled from the PEB and displayed by this module. Ntdll.dll and kernel32.dll are frequently found
DLLs that load early in the invocation of many processes. After that, the Import Address Table (IAT)
of the process is used to begin loading other DLLS as specified for the process. The dlllist plugin will
report a load count of -1 (0xFFFF) for items loaded from the IAT. Other counts will be present for
other methods of loading DLLs into the process’ memory space.
To help detect DLLs that have unlinked for the load order list in the PEB, Volatility also has
a ldrmodules plugin. This plugin acts similarly to the psxview plugin for processes in that it will
enumerate the results of DLLs listed in all three lists in the PEB and present a comparison of the
results. This helps an analyst to detect anomalies that may be indicative of an attempt to hide the
presence of a DLL. In addition, the ldrmodules plugin also manually scans the process’ executive
object in kernel memory looking for signatures of DLLs or other types of executable code modules
and presents a list of all items that it detects. In this way, even if the process memory itself has been
tampered with, the lists of modules stored about the process in kernel memory can be used to help
identify any tampering. One thing to be aware of in the output from this plugin is that the executable
itself will by default only appear in two out of the three PEB lists since it is not a separately loaded
DLL but is rather the main executable code. The ldrmodules plugin can be run with the following
syntax
vol.py -f [image] –profile=[profile] ldrmodules -p [PID]
Another plugin that may come in handy in detecting malicious code that has been injected
into a process is malfind. This plugin looks for suspicious memory areas within a process and displays
them along with their associated assembly code so that an analyst can determine if it is suspicious.
If desired, the procdump plugin can be used to dump contents of process memory.
vol.py -f [image] –profile=[profile] procdump -p [PID] –dump-dir=[directory/]
The above procdump will dump the entire contents of the process memory to a file in the
directory specified by –dump-dir= option. With addition of the –memory switch, any memory that
is not able to be dumped due to paging or other reasons is filled in with zeros to keep the relative
location of other objects consistent with the original process. Similar to the procdump plugin, the
and moddump plugins can be used to dump specific DLLs from within a process’ memory
dlldump
space.
Similarly, information about executables that were previously present on the system can be
gleaned from the shimcache and shellbags keys of the registry. The shimcache and shellbags plugins
respectively will parse and present this information.
If needed, password hashes can be dumped from memory for external password cracking.
Volatility is able to obtain the system key from the SYSTEM hive and use it to extract the hashes from
the SAM hive. The syntax of the command is
vol.py -f [image] –profile=[profile] hashdump
Additional user password data may be recoverable from the LSA Secrets stored in the registry.
Again, Volatility automates that extraction with the lsadump plugin, with the following syntax:
vol.py -f [image] –profile=[profile] lsadump