Monday, March 23, 2009

Using Volatility for Introspection

This post could also be titled "Teaser", part 2 :)

As part of my research at GT, I've been looking at using Volatility to examine the state of running virtual machines. Using PyXa, a wrapper around Bryan Payne's XenAccess library (available in the tools directory of the latest XenAccess release), you can get access to the memory of Xen guest VMs in Python. From there, it's just a small step to create a new address space that Volatility can use to examine virtual machines just as if they were any other memory image.

One application of this is using introspection to find out the state of windows on screen. This has advanced significantly since the last time I mentioned it, and it's now possible to track windows, including their z-order and some on-screen text, in near-real time. To demo this I used Volatility to examine the internal data structures of Win32k.sys and extract the locations and sizes of all visible windows, and then used PyGame to draw them on screen. The script keeps looping and re-drawing, allowing a near real-time view of what's going on inside the guest VM.

Here's a video of it in action. Notice how the reconstructed view updates to match what's actually going on on screen:



Cool, huh? :D

Thursday, March 12, 2009

Quick Response to Guidance

Everyone's been (rightfully) beating up on Guidance for their recent FUD-laden e-mail about F-Response; you should check out the excellent rebuttals by Harlan Carvey and hogfly. I'm not going to address most of the e-mail, but I thought I should tackle some things that are simply factually wrong about Volatility. I'm hardly an unbiased party (being a developer on Volatility), but unlike Guidance, I'm going to provide verifiable information to back up my claims.

From the Guidance mail:
While these utilities [included in the Volatility Framework] can identify running processes, open files and registry handles for running processes and open network sockets and connections, they cannot identify hidden processes, injected DLLs and NIC information.
There are three factual inaccuracies in this statement:
  • Volatility cannot identify hidden processes.
    In fact, Volatility can list processes using multiple methods. The pslist module walks the list of active processess, and will find any processes that have not been hidden with DKOM. The psscan2 module scans memory looking for signatures of process data structures; it will find even those processes that have been hidden using DKOM-like techniques. Together, these can be used to find any hidden processes on the machine.
  • Volatility cannot find injected DLLs.
    Michael Hale Ligh recently released a plugin called malfind that automates the work of doing exactly this. In fact, it is advanced enough that it can detect many types of generic code injection as well as simple DLL injection. I'm not familiar with Guidance's offering in this area, but I strongly suspect that they do not handle as many types of code injection.
  • Volatility cannot get NIC information.
    Again, this is false. My own registry tools can examine the registry keys that describe the network interfaces on the machine. If this is too much work for an investigator, the recent integration with RegRipper will make this task even easier. In the example RegRipper log I posted, you can see the network card information has been gathered from the memory image.
So, the moral of the story is, don't believe everything you read, even when it comes from a large security vendor.

Tuesday, March 3, 2009

Updates and a New Home for Plugins

As I've now released a number of plugins for Volatility, and some have gone through a couple revisions, I thought I'd put them all up on a single page, which can point to the latest versions and act as a sort of one-stop shop.

I've also updated the registry tools yet again, to fix some bugs and add new functionality, and also made some enhancements to volshell. You can read about the changes below:

Changes to VolReg:
  • New command hivedump: dump keys and timestamps (and optionally value data) from all hives to a CSV file.
  • Many improvements to robustness and error handling when reading key and value data.
  • When checking the registry hive names, catch exceptions and try to continue anyway (reported by chris).
Changes to volshell:
  • A new command, dis, is available. If distorm is installed, it will disassemble bytes from a given memory address as x86 code.
  • db no longer rounds length to a multiple of 4.
  • Use a single profile object throughout all commands (speed improvement)
  • dt can now overlay an arbitrary structure at an address, for example: dt('_EPROCESS', 0x81234567)
Enjoy!

Sunday, March 1, 2009

RegRipper and Volatility Prototype

When I first released the registry tools for Volatility, I discussed the possibility of interoperating with Harlan Carvey's excellent RegRipper. Now, thanks to Inline::Python and a bit of hackery, you can now run RegRipper against a memory image! Unfortunately, since Inline::Python only seems to work on Linux, you'll need to have a working Linux box around to use this (if anyone knows of a cross-platform way to use Python code from Perl, please let me know!).

I'll get to the details of how this works later, but for now let's talk about how you actually use this stuff. First of all, since we depend on Inline::Python to manage the unholy union of Perl and Python, you'll need to get it from CPAN or your distribution's package manager. No need to install Parse::Win32Registry; I've replaced it with my own registry code that will run against memory.

Next, you should download the latest version of the registry tools [tarball, zip] (side note: I updated them yet again, fixing a couple bugs and adding some basic checking to make sure you've got the right hives when using the credential dumping plugins), as well as the VolRip package [tarball, zip]. Unpack both into your Volatility directory.

Finally, you'll need a list of the virtual addresses of each registry hive in the image you want to examine. You can generate this list by first running the hivescan plugin to find the physical address of any hive, and then passing that to the hivelist plugin. You can see the results for the xp-laptop-2005-07-04 image here. For this example, we'll be using the SYSTEM hive, which is at address 0xe1035b60 in that image.

Now, let's run RegRipper! We're going to run the system plugins against the xp-laptop-2005-07-04 image, like so:

perl rip.pl -r xp-laptop-2005-07-04-1430.img@0xe1035b60 -f system

You can see the results here, if you can't follow along directly at home. If you're familiar with RegRipper, you'll notice that where we usually give the path to the registry hive, we've instead given the path to the memory image, and the virtual address of the hive we want to examine (here, the SYSTEM hive).

That's really about all there is to it! You use rip.pl just as you always would, but instead of giving it the hive filename, you instead pass the image and address of the hive, separated by an "@" sign. You can still run individual plugins using -p, use the "hive guessing" feature with -g, or run a whole batch of plugins using -f. Now, if you want to know more about how this works, read on...

The basic idea was to create a set of Python objects that emulated the interface provided by James Macfarlane's Parse::Win32Registry as closely as possible. This is what regwrap.py does: provides a translation layer between my own registry API and the one exposed by Parse::Win32Registry. Once we've done that, we can drop this emulated object into rip.pl, and the Perl code will run happily, thinking it's operating on normal hive files.

I had to make the following changes to rip.pl to get this to work:
  1. Instead of importing Parse::Win32Registry, use Inline::Python to import my own wrapper class and bind it to the name "Parse::Win32Registry".
  2. Comment out the lines that check to make sure the hive file exists -- since we're smushing the memory image and hive address into a single "filename", those checks will now fail.
  3. Minor changes so that rip.pl works on Linux.
As you can see, not many changes were required. With just these modifications, most RegRipper plugins run perfectly.

However, there was still one small wart that I couldn't get rid of just by emulating the library. See, in Perl, you can call a function in two contexts: "scalar" and "array". This basically means, "is the function result being stored in an array, or in a scalar variable"--and functions can decide to do different things depending on what context they're called from. An example of this is the get_data method of Value objects in Parse::Win32Registry.

The get_data method, when called on a REG_MULTI_SZ value, will return an array of strings if called from array context, but returns a string with all the strings separated by spaces if called in a scalar context. Unfortuantely, the Python code has no way of telling what Perl context it's being called from, so my wrapper always returns a list. This means that a couple of plugins (shares.pl and nic_mst2.pl) would print "ARRAY(0x12345)" instead of the actual data in some cases.

Instead of trying to come up with a convoluted way around this, I opted to just change the two plugins in question to remove any ambiguity as to how the function was called. I'm still not sure I've identified all the plugins that do this (I tried to run them all to check, but may have missed something), but the results look good to me now.

So, to summarize: it's now possible to run RegRipper against memory images! The modifications required were pretty minimal, so it should be easy to keep things updated as new versions of RegRipper come out. In particular, aside from the two plugins I mentioned, upgrading the plugins should be as easy as just dropping them into the rrplugins directory.

Enjoy, and as always, let me know if you find any bugs :)