The benefits of analyzing malware in live memory are well known. What we’ll see here is how to leverage the power of the Volatility framework to automate the task of extracting a malware’s configuration file.

Useful links

How plugins work

The Calculate function

This is the main plugin core. The goal of the function is to perform all the heavy lifting and to provide structured output to a render function (such as render_text)

The render function

This takes the output provided by the calculate function and renders it according to its type.

render_text will render it as text

render_table will make a table

render_custom_format will render the output using a custom output format

output format can be called with --output [text|table|custom_format]

A note on “list” vs. “scan” plugins

Volatility has two main approaches to plugins, which are sometimes reflected in their names. “list” plugins will try to navigate through Windows Kernel structures to retrieve information like processes (locate and walk the linked list of _EPROCESS structures in memory), OS handles (locating and listing the handle table, dereferencing any pointers found, etc). They more or less behave like the Windows API would if requested to, for example, list processes.

That makes “list” plugins pretty fast, but just as vulnerable as the Windows API to manipulation by malware. For instance, if malware uses DKOM to unlink a process from the _EPROCESS linked list, it won’t show up in the Task Manager and neither will it in the pslist.

“scan” plugins, on the other hand, will take an approach similar to carving the memory for things that might make sense when dereferenced as specific structures. psscan for instance will read the memory and try to make out _EPROCESS objects out of it (it uses pool-tag scanning, which is basically searching for 4-byte strings that indicate the presence of a structure of interest). The advantage is that it can dig up processes that have exited, and even if malware tampers with the _EPROCESS linked list, the plugin will still find the structure lying around in memory (since it still needs to exist for the process to run). The downfall is that “scan” plugins are a bit slower than “list” plugins, and can sometimes yield false-positives (a process that exited too long ago and had parts of its structure overwritten by other operations).

Yara signatures FTW

Scanning the memory for structures can take some time, especially now that memory dumps can regularly be over 8 GB in size, especially when the structures you’re looking for are small or don’t have lots of constraints. A good approach for searching for specific patterns in memory are Yara rules, which can be leveraged with the yarascan plugin. Besides being faster, it has the added bonus of being able to be re-used as Yara rules outside Volatility!

Hands-on: Building a Locky configuration extractor

Implementation strategy

Based on available information, the implementation strategy for your plugin may change. Unfortunately, there is no silver bullet for locating interesting stuff in memory. You’ll need to have a basic understanding of how your sample works and what it does in memory; depending on your reverse engineering skills this might be more or less easy.

As most forensic investigations, it’s important to have anchor or pivot points. In the case of most plugins bundled with Volatility, these anchor points are the Kernel. Since malware does not register its crown jewels in Kernel entries, you’ll have to work through the sample in order to find how it references interesting data, and try to find the point where it references it in a way where it is as generic as possible.

In the case of Locky, our analysis tells us that one of the places it accesses its configuration looks like this:

This looks like a good place to start.

Based on the opcodes relevant to our code, use yarascan to find the interesting process

Extracting relevant information from memory

We found the instance of our code in memory. Time to access the relevant data! We’re going to need to read raw bytes from memory and also be able to dereference pointers. The bytes we’re after are the address of the pointer to the configuration file, the ones which were left as wildcards in the Yara rule.

This is 0x73e42370 in little endian. What’s the value of this variable?

In [4]: db(0x73e42370, 4)
0x73e42370 00 00 16 00 ....

In little endian again, this means that our configuration file is located at 0x00160000. This nice, round, and page-aligned number also happens to be it’s own memory segment. Check the output of vaddump, you’ll see something like rundll32.exe.99155060.0x0000000000160000-0x0000000000166fff.dmp which actually contains all of our configuration file.

Since it can become quite tedious to copy and paste values from vollshell, so we’re going to use two simple functions to read bytes from memory and dereference pointers. Copy and paste the following lines into the prompt:

Using vtypes to convert objects

Now that we have the address for our configuration file, we can easily parse it and use the render_output function to give the user some feedback. Before that, let’s explore a cool feature of Volatiliy : vtypes. vtypes are structures that can be “applied” to memory, yielding objects that can then be easily manipulated. The advantage of using vtypes over standard string slicing to parse structures is manyfold:

It’s auto-documenting

It’s easier to maintain should the structure change in the future

It’s easier for a third party to understand what’s going on

No need for special code for strings, integers (unpacking), binary code, etc.

The good news is that vtypes are pretty easy to build. To make things easier, load the VAD dump corresponding to the configuration file in a hex editor (you’ll be playing around with offsets in that file, which correspond to the offsets you will be defining in the vtype).

Rendering the output

Time to use render text and take those nasty print statements out of the calculate function! You need to make a minor adjustment to calculate: is has to yield any data that will be passed on to the render function (thus becoming a generator).