Monday, December 10, 2012

Automatically detecting profiles.

Volatility uses a profile to encapsulates information about a specific version of an operating systems. As internal kernel data structures change from release to release, so too must volatility adapt to these changes. The profile is usually automatically generated from debugging symbols taken from a specific version of the operating system. For analyzing windows systems, Volatility comes with a number of pre-generated profiles for the common windows releases out there. For Linux, a profile must almost always be generated for the system under examination, since the layout of Linux data structures change, even depending on local configuration changes. For that reason we wont be discussing Linux profiles in this post.
Previous versions of Volatility required the profile to always be explicitly specified. This is fine if you know in advance what version of windows you have, but sometimes you receive an image taken by a third party which has no context - you don’t exactly know the version or patch level of the image. In previous versions of volatility you would need to run the imageinfo plugin. This plugin uses difference in the KDBG structure between windows versions to guess the correct profile. You would then need to copy the profile detected and provide it to all future invocations with the --profile options:
~/volatility/trunk$ python vol.py -f image.raw imageinfo
Volatile Systems Volatility Framework 2.3_alpha
Determining profile based on KDBG search...

          Suggested Profile(s) : WinXPSP2x86, WinXPSP3x86 (Instantiated with WinXPSP2x86)
                     AS Layer1 : JKIA32PagedMemoryPae (Kernel AS)
                     AS Layer2 : FileAddressSpace (image.raw)
                      PAE type : PAE
                           DTB : 0xb94000L
                          KDBG : 0x8054d2e0
          Number of Processors : 2
     Image Type (Service Pack) : 3
                KPCR for CPU 0 : 0xffdff000
                KPCR for CPU 1 : 0xf7777000
             KUSER_SHARED_DATA : 0xffdf0000
           Image date and time : 2012-12-11 00:03:40 UTC+0000
     Image local date and time : 2012-12-10 18:03:40 -0600
The old imageinfo plugin takes a long time to run since it instantiates every profile in turn. It is OK to use this plugin to discover the profile name initially, but then we still need to provide it again.
NotePrevious versions of Volatility used incidental information in the kernel debugger block to guess the profile (for example, the size of the KdDebuggerDataBlock struct). This information needed to be hand maintained for each profile since it is not present in debug symbols. In the next Volatility version, this information is not used, and even the KDBG scanner does not use profile specific information (The kernel debugger block layout is mostly identical for all versions of Windows).
For the next version of Volatility, I wanted to have an automatic profile selection system, so users just do not need to think about it. It is not necessary to even provide the profile at all. To make this work we need to have a very quick but very reliable method of detecting the profile.

Finding the kernel DTB

One of the first things Volatility does when opening the image is to detect the kernel Directory Table Base. This is the physical address of the kernel’s base of the page tables. Without a valid DTB it is impossible to create the kernel’s virtual address space - and hence this is the first thing we need.
Volatility finds out the address of the DTB by scanning for a well known _EPROCESS signature corresponding to a kernel process. Volatility 2.x scans for theIdle process by searching to the string "Idle". Once the Idle process is found, we can deduce the kernel DTB by following the _EPROCESS.Pcb.DirectoryTableBase member. In order to follow this member we need to know about the memory layout of the _EPROCESS struct - which we get from the profile. Therefore in the old 2.x releases of Volatility, we needed to know the profile before determining the DTB.

Guessing the profile

With the next generation of Volatility, profile auto-selection is combined with the DTB scan in order to kill two birds at once. The guess_profile plugin is automatically run by the framework when the profile is not provided. This plugin scans for both the DTB and profile parameters at the same time. Deciding on the correct profile to choose comes down to the differences in the _EPROCESS struct layout alone (i.e. we no longer look at differences in the KDBG structure). In the new version, we search for the "System" process instead of the "Idle" process since it is more robust for verification (The Idle process does not always have valid threads, and is not always in the PsActiveProcessList list).
Since profiles are large and rather expensive to load and compile (There are now over 20 different Windows profiles), we pre-generate a concise and very small test profile containing important _EPROCESS member offsets for all the currently supported profiles. We then load this very small concise profile and overlay each version of the _EPROCESS struct over the System process signature, ensuring to sanity check the match:
  • Search for a string "System" - this should be the ImageFileName member.
  • For each test profile in the concise look-up map, perform the following:
    • Go back to the start of the _EPROCESS and get the DirectoryTableBase member. Validate the DTB to eliminate obviously wrong values.
    • Instantiate a virtual address space using the DTB value, and use this address space to reflect through both the ActiveProcessLinks and ThreadListHead linked lists. This gives a pretty strong signal that the _EPROCESS address is valid.
    • When we get here we are pretty certain to have found the correct profile and DTB.
When the System _EPROCESS is identified, we set both the DTB and the profile. The above process is pretty fast and actually does not add any more processing than in previous versions. We are still scanning the image once, looking for the System process signature. This algorithm is also very robust.
Due to the low cost of this plugin in comparison to the previous imageinfo plugin, we can afford to run this by default at every run. This improves usability since the user doesn’t even need to think about a profile - they just run Volatility as normal:
~/volatility/svn$ ./vol.py -f image.raw pslist
Updating session profile and address spaces.
Offset (V) Name                    PID   PPID   Thds     Hnds   Sess  Wow64 Start                Exit
---------- -------------------- ------ ------ ------ -------- ------ ------ -------------------- --------------------
0x8a6d3490 System                    4      0     83      944 ------  False -                    -
0x89c66990 smss.exe                868      4      2       21 ------  False 2012-12-03 18:33:03  -
0x89cce6c8 csrss.exe               928    868     12      492      0  False 2012-12-03 18:33:05  -
0x89474788 winlogon.exe            952    868     16      520      0  False 2012-12-03 18:33:08  -
0x89465da0 services.exe            996    952     16      299      0  False 2012-12-03 18:33:11  -
0x89458020 lsass.exe              1008    952     25      507      0  False 2012-12-03 18:33:12  -
.....
When no plugin is provided, Volatility drops into the interactive shell. In this case the user can see the chosen profile as part of the Volatility prompt:
~/volatility/svn$ python vol.py -f image.raw
Updating session profile and address spaces.
Python 2.7.3 (default, Aug  1 2012, 05:14:39)
Type "copyright", "credits" or "license" for more information.

This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License.
WinXPSP3x86PAE:image.raw 07:16:09> pslist
---------------------------------> pslist()
Offset (V) Name                    PID   PPID   Thds     Hnds   Sess  Wow64 Start                Exit
---------- -------------------- ------ ------ ------ -------- ------ ------ -------------------- --------------------
0x8a6d3490 System                    4      0     83      944 ------  False -                    -
0x89c66990 smss.exe                868      4      2       21 ------  False 2012-12-03 18:33:03  -
0x89cce6c8 csrss.exe               928    868     12      492      0  False 2012-12-03 18:33:05  -

Guessing a profile from KDBG

Sometimes we already know a lot of information about the image before we start. For example, when analyzing a crash dump, we already have the DirectoryTableBase member, as well as the KdDebuggerDataBlock address provided for us in the crash dump _DMP_HEADER64 header.
Similarly when using the WinPmem driver for analyzing live systems, we can obtain these structures directly from the driver which collects the kernel’s CR3 and the KdDebuggerDataBlock address.
In these cases, profile auto-selection does add a significant amount of work to startup, since we would not normally need to perform a DTB scan at all, but without a profile we still need to scan for the System process as described above.
To avoid this we need to implement a slightly different algorithm for profile selection when the KDBG and DTB are already known:
  • Locate the _KDDEBUGGER_DATA64.PsActiveProcessHead member for the head of the process list. We also instantiate a virtual kernel address space using the provided DTB.
  • For each _EPROCESS in the test profile, attempt to get the next process in the list from the PsActiveProcessHead. We can then verify this process in the same way as above (i.e. check that we can properly reflect through its lists etc). The profile which works is the correct profile to select.
This method is extremely fast and does not actually add any time to startup time.
So now we can avoid having to specify the profile altogether, making the user experience much smoother. As a result the imageinfo plugin is now deprecated (in its current form) in the Tech Preview branch since it is no longer useful.