Sunday, November 18, 2012

Finding the Kernel Debugger Block

The kernel debugger block (named KdDebuggerDataBlock of the type _KDDEBUGGER_DATA64) is important for many things that Volatility and debuggers do. For example, it has a reference to the PsActiveProcessHead which is the list head of all processes required for process listing.
Because it is so useful the location of the kernel debugger block is also stored in the crash dump header. This assists the kernel debugger to find the _KDDEBUGGER_DATA64 quickly.
I wanted to add the ability to write crash dump files to the WinPmem memory acquisition tool. Many commercial acquisition tools also offer this useful feature. Storing the image in a crash dump format is convenient since it is possible to open the image using a variety of tools such as volatility and Microsoft’s own kernel debugger Windbg. (Of course its possible to convert a raw image to a crash dump using volatility’s raw2dmp plugins but its more convenient to take the image using a crash dump in the first place).
So I needed a way locate the kernel debugger block (KdDebuggerDataBlock) from the running system. Previously there have been two methods published for doing this Finding Kernel Global Variables in Windows:
  1. The first method involves finding the KPCR (Which I talked about previously) and following its KdVersionBlock member. This method is ideal for performing on the running system since the KPCR is simply stored in the fs/gs register of the running thread.
  2. The second method which is used by Volatility itself is to scan for KdDebuggerDataBlock using a specific signature for a valid _KDDEBUGGER_DATA64.
Both of these methods are not ideal. The first method was used by win32dd for a time and Matthew Suiche wrote about it here. Unfortunately this method stopped working in recent versions of Windows. Recently the KdVersionBlock member is always 0 and does not link to the kernel debugger block.
The second method would work but would be quite slow as it scans the entire kernel address space for the KDBG signature. It is also less reliable since there could be a number of hits for the KDBG signature and we might get the wrong hit.
There has to be an easier way :).
The first thing I asked myself was "What exactly is the kernel debugger block?". I used google to locate a definition for it in the sources for ReactOS (an open source reimplementation of windows). The relevant snippet shows:
00392 KDDEBUGGER_DATA64 KdDebuggerDataBlock =
00393 {
00394     {{0}},
00395     0,
00396     {(ULONG_PTR)RtlpBreakWithStatusInstruction},
00397     0,
00398     FIELD_OFFSET(KTHREAD, CallbackStack),
00399     FIELD_OFFSET(KCALLOUT_FRAME, CallbackStack),
00400     FIELD_OFFSET(KCALLOUT_FRAME, CBSTACK_FRAME_POINTER),
00401     FALSE,
00402     {(ULONG_PTR)KiCallUserMode},
00403     0,
00404     {(ULONG_PTR)&PsLoadedModuleList},
00405     {(ULONG_PTR)&PsActiveProcessHead},
00406     {(ULONG_PTR)&PspCidTable},
00407     {(ULONG_PTR)&ExpSystemResourcesList},
00408     {(ULONG_PTR)ExpPagedPoolDescriptor},
00409     {(ULONG_PTR)&ExpNumberOfPagedPools},
00410     {(ULONG_PTR)&KeTimeIncrement},
...
00555     {(ULONG_PTR)&IopNumTriageDumpDataBlocks},
00556     {(ULONG_PTR)IopTriageDumpDataBlocks},
00557 };
So according to the ReactOS sources the debugger block is a statically allocated structure which seems to be filled in by KdInitSystem.
This is quite interesting since static structs are always located in the same position relative to the PE executable’s base address. The compiler usually places static variables in the .data section of the PE binary. This means that in practice, the KdDebuggerDataBlock can only exist within the .data section of the kernel binary.
The problem boils down to finding the kernel base address. Once we know that, we can easily find the valid ranges for the data section. In most kernel’s the .data section is very small (less than 100kb) and is super fast to scan. Also since there is only deterministic data there, there will never be another struct with the same signature in such a small region.
So how can the WinPmem driver locate the kernel base address? The base address itself is not actually exported, but many other symbols are exported from the kernel’s Export Address Tables (pretty much any kernel API). We know that the kernel export address table is usually located at a higher address than the kernel base, and that the kernel base address is page aligned. We now can scan for it:
KDBG
Figure 1. KDBG Scan algorithm
We choose to use NtBuildNumber as the exported symbol to look for (just in case a real API function is hooked). We then round down to page align and step backwards looking for the PE header. In Windows 7, there are unmapped guard pages between the mapped kernel sections - trying to read from these will blue screen the system. We therefore check first that the pages are mapped using the MmIsAddressValid() API.
Once the PE header is found, we calculate the region for the .data section. Since this region is very small and we do not need to worry about false positives, we can relax the search criteria and just search for the OwnerTag "KDBG".
The result is an extremely fast and reliable way for locating the kernel debugger block in a live system. This allows the WinPmem kernel driver to report this address so that the user space component can write the crash dump files correctly.
The added benefit of the kernel driver locating the debugger block itself is that Volatility does not need to scan for it while it is analysing the live system. This saves a rather expensive call for the kdbgscan plugin, which would otherwise need to be made before running most plugins.

Saturday, November 17, 2012

The PMEM Memory acquisition suite


Memory acquisition is the first step in memory analysis. Before any analysis can be done, we need to acquire the memory in the first place. There are a number of commercial solutions to acquire memory, but sadly open source solutions have been abandoned or not maintained (For example win32dd has been a popular solution many years ago but has now been commercialized and is no longer open source).
We believe in open source forensic tools to make testing and transparency easier. We also believe that the availability of open source solutions spurs further development in the field and enables choices.
That is the reason we feel an open source, well tested and capable forensic memory acquisition tool is essential - we call it the Pmem suite of tools. The pmem acquisition tool aims to provide a complete imaging solution for Windows, Linux and OSX.
The following is a quick overview of how to use the pmem tools. For detailed information consult the source.

1. WinPmem

The windows memory acquisition tool is called WinPmem.
These are the features it supports:
  1. Supports all windows versions from WinXP SP2 to Windows 8 in both i386 and amd64 flavours.
  2. Output formats include:
    1. Raw memory images.
    2. Microsoft Crashdump files for use in windbg and volatility.
    3. Output to stdout (in both the above formats) for piping through other tools (e.g. ssh, ewfacquirestream etc).
  3. Memory acquisition using
    1. MmMapIoSpace method.
    2. \Device\PhysicalMemory and ZwMapViewOfSection method.
  4. Direct analysis of the running kernel using Volatility (Live memory analysis).
  5. Optional Write support for manipulating kernel data structures from Volatility.

1.1. Download

The latest version can be found here or on the Volatility download page. You will find the tool released in two versions:
  • winpmem-1.3.1.exe: is the recommended binary for general use. This binary contains signed drivers so it can load on any windows system (even 64 bit ones). This binary does not include write support for memory.
  • winpmem-1.3.1-write.exe: is the binary with write support enabled. It is not signed so it will only work on 32 bit windows or 64 bit windows with special preparation (see below).
ImportantThe recommended version for regular use is the one without write support. The version with write support can not be used on a regular system.
c:\..> winpmem_1.3.exe -h
Winpmem - A memory imager for windows.
Copyright Michael Cohen (scudette@gmail.com) 2012.

Version 1.3. Built Nov 12 2012
Usage:
  winpmem_1.3.exe [option] [output path]

Option:
  -l    Load the driver and exit.
  -u    Unload the driver and exit.
  -h    Display this help.
  -w    Turn on/off write mode.
  -1    Use MmMapIoSpace method.
  -2    Use \\Device\PhysicalMemory method (Default).
  -d    Produce a crashdump file.


NOTE: an output filename of - will write the image to STDOUT.

1.2. Examples

Writes a raw image to physmem.raw
winpmem_1.3.exe physmem.raw
Writes a crashdump file to netcat for network transport. Output is supressed here because STDOUT is redirected.
winpmem_1.3.exe -d - | nc 192.168.1.1 80
Normally the driver will be automatically unloaded after the image is acquired. To allow volatility to attach to the raw device for live analysis, we need to load the driver and exit:
c:\..> winpmem.exe -l
Loaded Driver.
c:\..> vol.py -f \\.\pmem
NoteOnly the tech preview volatility version is able to open the raw device. In the tech preview version there is no need to specify a profile, since it is autodetected.
To unload the driver and exit:
c:\..> winpmem.exe -u
Driver Unloaded.
To acquire a raw image using the MmMapIoSpace method:
c:\..> winpmem_1.3.exe -1 myimage.raw
To acquire an image in crashdump format:
c:\..>winpmem_1.3.exe -d c:\temp\test.dmp
Driver Unloaded.
Loaded Driver C:\Users\mic\AppData\Local\Temp\win6C6.tmp.
Will write a crash dump file
CR3: 0x0000187000
 2 memory ranges:
Start 0x00001000 - Length 0x0009E000
Start 0x00100000 - Length 0x6F6FB000


00% 0x00001000 .

00% 0x00100000 ..................................................
02% 0x03300000 ..................................................
05% 0x06500000 ..................................................
...
92% 0x67300000 ..................................................
95% 0x6A500000 ..................................................
98% 0x6D700000 .................................
Driver Unloaded.

1.3. Experimental write support

As from Version 1.1, the winpmem drivers support writing to memory as well as reading. This capability is a great learning tool since many rootkit hiding techniques can be emulated by writing to memory directly. For example the following Volatility session illustrates changing the name of the binary:
c:..> vol.py -f \\.\pmem

WinXPSP2x86:pmem 03:10:40> task = session.profile._EPROCESS(0x82079c18)
WinXPSP2x86:pmem 03:10:57> task.ImageFileName
                    Out    [String:ImageFileName]: 'cmd.exe\x00'
WinXPSP2x86:pmem 03:11:15> task.ImageFileName = "foo.exe\x00"
WinXPSP2x86:pmem 03:11:21> task.ImageFileName
                    Out    [String:ImageFileName]: 'foo.exe\x00'
Since this is a rather dangerous capability, the signed binary drivers have write support disabled. The unsigned binaries (really self signed with a test certificate) can not load on a regular system due to them being test self signed. You can allow the unsigned drivers to be loaded on a test system by issuing (seehttp://msdn.microsoft.com/en-us/library/windows/hardware/ff553484(v=vs.85).aspx):
Bcdedit.exe -set TESTSIGNING ON
and reboot. You will see a small "Test Mode" text on the desktop to remind you that this machine is configured for test signed drivers.
Alternatively you can test this on XP or Vista32 which have no driver signing restrictions.
Once the correct driver is loaded, Write support must also be enabled at load time using the -w switch:
winpmem_1.3-write.exe -w -l
This will load the drivers and turn on write support. Then we can run volatility interactively, as usual on the raw device:
vol.exe --profile Win7SP1x64 --file \\.\pmem