You are on page 1of 130

Memory Forensics With Volatility

Michael Cohen
Software Engineer - Google Inc.

Acknowledgements
Many great researchers in the memory forensics field (and Volatility Contributors): Aaron Walters. Brendan Dolan-Gavitt. Andreas Schuster. Michael Hale Ligh. Andrew Case. Jamie Levy. Mike Auty. ... and many others!

References
Malware Analyst's Cookbook Michael Hale Ligh, Steven Adair, Blake Hartstein, Matthew Richard
http://code.google.com/p/malwarecookbook/

Module 1 - Introduction
Why memory forensics? What can Volatility do for me? Symbols and debugging information.
How does Volatility support multiple operating systems and versions.

Memory imaging
Linux. Windows.

Memory Forensics - Why?


Live response.
Can quickly triage a system.

Capture of memory freezes system state.


As memory is volatile we can minimize interference with memory. Analysis does not use the system APIs.

Memory analysis technology evolves with time.


We used to only have grep :-) NIST reference image: xp-laptop-2005-06-25.img: Registry dump Passwords Screenshots

The Volatility Memory Forensics Framework.


Current release on google code: http://code.google.com/p/volatility/
Supports 64 bit windows up to windows 7.

Volatility technology preview (TP):


Major refactoring/code rewriting - lots of new features. Ease of use as a library. Interface uses IPython - interactive console. Memory acquisition drivers included.

We will be using both but mainly Volatility TP.


Check with the volatility site for an upcoming release.

A short Volatility Demo

Types and debugging Information.


Operating systems are generally written in C
typedef unsigned char uchar; enum { It is generally not possible to predict the memory layout of a C struct without knowing OPT1, external factors: Alignment OPT2 Endianess Bit size } options; Compiler
Optimizations etc

struct foobar { enum options flags; short int bar; uchar *foo; }

Unless packed structs.

Types and debugging Information DWARF.


$ readelf --debug-dump=info module.ko
<1><10fe>: Abbrev Number: 28 (DW_TAG_structure_type) <10ff> <1103> <1105> <1106> <1107> <110c> <1110> <1111> <1113> <1117> <111b> <111f> <1120> <1122> <1126> DW_AT_name DW_AT_byte_size DW_AT_decl_file DW_AT_decl_line DW_AT_sibling DW_AT_name DW_AT_decl_file DW_AT_decl_line DW_AT_type : (indirect string, offset: 0x7d7e): task_struct : 5864 : 17 : 7 : <0x19c8> : (indirect string, offset: 0x254): state : 18 : 1221 : <0x3cf> (DW_OP_plus_uconst: 0)

<2><110b>: Abbrev Number: 32 (DW_TAG_member)

DW_AT_data_member_location: 2 byte block: 23 0 DW_AT_name DW_AT_decl_file DW_AT_decl_line DW_AT_type

<2><111a>: Abbrev Number: 32 (DW_TAG_member) : (indirect string, offset: 0xb200): stack : 18 : 1222 : <0x615> (DW_OP_plus_uconst: 8)

DW_AT_data_member_location: 2 byte block: 23 8

Types and debugging Information PDB.

Types and debugging Information The Volatility Type system - Profiles.


A compilation unit is a self consistent unit of compiled
code which uses the same memory layout for structs. For example, a .obj file or a dll. It is important to note that the same struct may have different layout in different dlls. For example: 32 bit processes running on a 64bit operating system have different definitions for integers. Microsoft exports _EPROCESS in the kernel and in userspace but these are different. VTypes is a special language for specifying memory layout of structs and other objects using python data structures.

User Space/Kernel Space

Types and debugging Information The Volatility Type system - Profiles.


Struct Name
'_EPROCESS' : [ 0x4d0, {

Struct Size Member Offset Member Type

'Pcb' : [ 0x0, ['_KPROCESS']], 'ProcessLock' : [ 0x160, ['_EX_PUSH_LOCK']], 'CreateTime' : [ 0x168, ['_LARGE_INTEGER']], 'ExitTime' : [ 0x170, ['_LARGE_INTEGER']], 'RundownProtect' : [ 0x178, ['_EX_RUNDOWN_REF']],

'UniqueProcessId' : [ 0x180, ['pointer64', ['void']]], 'ActiveProcessLinks' : [ 0x188, ['_LIST_ENTRY']], 'ProcessQuotaUsage' : [ 0x198, ['array', 2, ['unsigned 'CommitCharge' : [ 0x1b8, ['unsigned long long']],

'ProcessQuotaPeak' : [ 0x1a8, ['array', 2, ['unsigned long long']]], 'QuotaBlock' : [ 0x1c0, ['pointer64', ['_EPROCESS_QUOTA_BLOCK']]], 'CpuQuotaBlock' : [ 0x1c8, ['pointer64', ['_PS_CPU_QUOTA_BLOCK']]], 'PeakVirtualSize' : [ 0x1d0, ['unsigned long long']], 'VirtualSize' : [ 0x1d8, ['unsigned long long']], 'SessionProcessLinks' : [ 0x1e0, ['_LIST_ENTRY']], 'DebugPort' : [ 0x1f0, ['pointer64', ['void']]], .....

Special support for array and pointers long long']]], (legacy).

Types and debugging Information The Volatility Type system - Profiles.


VTypes are autogenerated from debugging symbols:
Linux: a special module is compiled with debugging symbols and the DWARF information is extracted. Uses pyelftools or dwarfdump. Windows: the pdb files are downloaded from the microsoft symbol server and parsed. Uses pdbdump by Brendan Dolan-Gavit.

VTypes are not enough though!


Debug information fails to convey semantic meaning. PDB files may be incomplete or not exist - then we need to reverse engineer the struct members.

Types and debugging Information The Volatility Type system - Profiles.


The volatility object system is built on the vtypes
definition language to present an object oriented, automatic parsing system. Everything is an object extending obj.BaseObject() Definitions are layered: Object classes Overlays VType definition.

Types and debugging Information The Volatility Type system - Profiles.


An Overlay is a partial vtype structure with "holes"
signified by None which overlays on top of the original VType definition. This is used to "correct" the original vtype, while allowing some aspect of the previous definitions to come through.
'_EPROCESS' : [ 0x4d0, { 'Pcb' : [ 0x0, ['_KPROCESS']], 'ProcessLock' : [ 0x160, ['_EX_PUSH_LOCK']], 'CreateTime' : [ 0x168, '_LARGE_INTEGER']], 'ExitTime' : [ 0x170, ['_LARGE_INTEGER']], ..... }], '_EPROCESS' : [ None, { 'CreateTime' : [ None, ['WinTimeStamp', {}]]], 'ExitTime' : [ None, ['WinTimeStamp', {}]], ..... }],

VType

Overlay

Types and debugging Information The Volatility Type system - Profiles.


The overlay can apply to wide range of operating
system versions The exact offsets are controlled by the debugging symbols, but the semantic meaning is given by the overlay.
'_EPROCESS' : [ 0x4d0, { 'Pcb' : [ 0x0, ['_KPROCESS']], 'ProcessLock' : [ 0x160, ['_EX_PUSH_LOCK']], 'CreateTime' : [ 0x168, '_LARGE_INTEGER']], 'ExitTime' : [ 0x170, ['_LARGE_INTEGER']], ..... }], '_EPROCESS' : [ None, { 'CreateTime' : [ None, ['WinTimeStamp', {}]]], 'ExitTime' : [ None, ['WinTimeStamp', {}]], ..... }],

VType

Overlay

Types and debugging Information The Volatility Type system - Profiles.


Behaviors can be attached to objects via defining
specialized classes. The VType system instantiates a named class with the given arguments when a struct member is dereferenced. The class instance can provide extra methods.
'_EPROCESS' : [ 0x4d0, { 'Pcb' : [ 0x0, ['_KPROCESS']], 'ProcessLock' : [ 0x160, ['_EX_PUSH_LOCK']], 'CreateTime' : [ 0x168, '_LARGE_INTEGER']], 'ExitTime' : [ 0x170, ['_LARGE_INTEGER']], ..... }], '_EPROCESS' : [ None, { 'CreateTime' : [ None, ['WinTimeStamp', {}]]], 'ExitTime' : [ None, ['WinTimeStamp', {}]], ..... }],

VType

Overlay

Types and debugging Information The Volatility Type system - Profiles.


This is an object representing the _EPROCESS struct. In [1]: task = session.profile._EPROCESS(0xFA8000ACAB30) Out[1]: [_EPROCESS _EPROCESS] @ 0xFA8000ACAB30 There is a CreateTime member which is an instance of the WinTimeStamp class. In [2]: type(task.CreateTime) Out[2]: volatility.plugins.overlays.basic.WinTimeStamp The WinTimeStamp class knows how to print itself nicely. In [3]: print task.CreateTime 2012-02-22 11:28:59 The WinTimeStamp class offers more functionality related to timestamp conversions. In [4]: print task.CreateTime.as_windows_timestamp() 129743837397084000

Types and debugging Information The Volatility Type system - Profiles.


A Profile is an internally consistent collection of vtypes
and definitions. Strictly a profile represents a single compilation unit. Volatility 2.0 has one global profile Can not represent multiple, contradictory compilation units (e.g. 32bit process on 64bit OS).

Volatility TP has domain specific profiles.


A profile therefore represents an internal implementation of a specialized parser. For example the registry parser consists of vtypes, overlays and classes together forming an API for handling the windows registry.

Supporting multiple operating system versions.


For windows we have pre-computed profiles from different versions of ntoskrnl.exe.
Must specify the correct profile to use using the session.profile variable. (or --profile command line).

For linux we must generate vtypes to specific kernel version we are analysing.
This is because the struct layouts vary depending on kernel configuration. (There are #ifdefs in the middle of the structs). We generate a profile_file which is a zip containing: System.map-2.6.32-40-generic A special module.ko built with symbols.

Memory Imaging.
Take a permanent copy of physical memory: Lots of techniques to do this:
Hardware based Firewire. Cold Boot attack. Tribble Software base Hibernation Crash dumps Inserting a special driver. Debugger APIs.

Hibernation
When a system hibernates it copies its memory state to disk.
Volatility can analyse this image. Pros Easy to obtain image. No prior preparation needed. Cons Prior to hibernation, an ACPI pnp event is transmitted to all drivers:
Network sockets are removed. Malware may cleanup.

Windows only copies in use pages to the hibernation file.

Crashdump - Windows BSOD.


A crashdump is a standard mechanism for windows debugging. Pros: The system stops most running threads during the dump - atomicity is best. Can attach the windows debugger (windbg) to the crash dump. Raw image can be converted to crash dump too. Cons: Usually must be pre-configured. Only dumps memory used by the kernel (e.g. not bios areas - page 0). System can not resume - so we can not do differential analysis.

Memory Acquisition tools.


Volatility TP comes with the winpmem acquisition driver (Experimental):
For 64 bit windows these must be signed. The winpmem driver makes physical memory accessible via the \\.\pmem device. This means you can run Volatility TP directly on the raw memory device. Can produce a crash dump via raw2dmp plugin.

Other popular options:


windd by moonsols http://www.moonsols.com/windows-memory-toolkit/ Can produce crashdumps etc. Only writes image from kernel space and therefore not suitable for live memory analysis.

Windows acquisition - Example


Driver reports CR3 and valid memory ranges

Imager pads gaps with zeros for raw image.

Memory Acquisition tools - Linux.


Volatility TP comes with a Linux driver pmem.ko
Must be compiled for the exact kernel version that should be imaged (this is a Linux requirement). Provides a new device in /dev/pmem. Can use Volatility TP to analyse the running system.

Kernel driver normally has to be compiled to the kernel version.


The linux kernel has symbol versioning. When loading a module with insmod the kernel ensures the module is compiled for the same version. Not very convenient from an incident response point of view.

Memory acquisition - Linux


scudette@scudette:~/volatility/svn/tools/linux$ sudo apt-get install linux-image-3.0.022-generic linux-headers-3.0.0-22-generic Reading package lists... Done Building dependency tree Reading state information... Done linux-image-3.0.0-22-generic is already the newest version. linux-headers-3.0.0-22-generic is already the newest version. 0 upgraded, 0 newly installed, 0 to remove and 12 not upgraded. scudette@scudette:~/volatility/svn/tools/linux$ make KVER=3.0.0-22-generic make -C //lib/modules/3.0.0-22-generic/build CONFIG_DEBUG_INFO=y M=/home/scudette/volatility/svn/tools/linux modules make[1]: Entering directory `/usr/src/linux-headers-3.0.0-22-generic' CC [M] CC [M] .... /home/scudette/volatility/svn/tools/linux/module.o /home/scudette/volatility/svn/tools/linux/pmem.o

This is the target kernel image version.

Driver creates a new device Copy to the target machine and then:
# insmod pmem.ko # dd if=/dev/pmem of=myimage.dd # rmmod pmem

Patching linux kernel modules


Ideally we want to have a binary kernel module we can insert to any kernel version.
This can only work if the structs used are stable across versions. The pmem driver is very simple - all real work is done in userspace so kernel space code is minimized and remains stable across versions. Must bypass the linux kernel's module versioning checks. Andreas Moser has implemented a live module patcher. Search the system for other kernel modules. Copy the symbol versions to pmem.ko

Patching kernel module - Example


scudette@scudette:~/volatility/svn/tools/linux$ sudo insmod ./module.ko insmod: error inserting './module.ko': -1 Invalid module format scudette@scudette:~/volatility/svn/tools/linux$ python ko_patcher.py module.ko patched_module.ko INFO:root:Module version is 2.6.32-21-generic, kernel version is 2.6.32-40-generic. INFO:root:All imports found, gathered data from 1 modules. INFO:root:Checksum mismatch for module_layout. INFO:root:Kernel Object patched. scudette@scudette:~/volatility/svn/tools/linux$ sudo insmod ./patched_module.ko scudette@scudette:~/volatility/svn/tools/linux$

Virtual Machine Imaging


Taking a memory image from a virtual machine is most reliable: e.g. Virtual Box:
VBoxManage debugvm <vmname> dumpguestcore --filename <name>

Summary for Module 1


Introduction to memory forensics and Volatility
Symbols types and memory layout. The Volatility type system. What are Profiles. Generating profiles for Linux. Different types of images. How to image Windows systems. How to image Linux systems. Live memory analysis with volatility.

Memory Imaging

Module 2 - Virtual Memory and Paging


How does virtual memory work? We can see a string in the image - where does it come from? Why do I get a 2gb file when I dump out a single process address space?

Virtual Memory and Paging.


Pages Virtual Address Frames Shared Memory Backed Mem Physical Address Paged out

Overcommited

Backed Mem

Physical Memory

Page File Process A Virtual Memory Process B Virtual Memory

Virtual Memory and Paging.


Paging allows different processes to have their own unique view of physical memory:
Physical memory can be shared between processes at different virtual addresses. Physical memory can be assigned to a specific process's use without being accessible from other processes. Processes can request memory to be mapped into their virtual address space which is not yet backed by physical memory (overcommitted). A process's memory can be paged out to disk. A process may map a file into its address space the kernel will automatically read from the file when a page fault occurs.

Paging in 32 bit model.


Virtual Address Page Directory Index CR3 Page Table Index Byte Index

Directory Table Base (DTB)

PTN

Page Frame

PTE

Page Directory

Page Tables

Physical Memory

The CR3 register.


Paging is done automatically by the MMU in hardware.
All the CPU has to do is store the address of the current Page directory table in the CR3 register. When the kernel switches task context (to another process), a new value of CR3 is loaded to point at new page tables. The value of CR3 is key to make sense of a physical memory image. Some imaging tools also capture CR3.

Page Table Entry.


Prototype

Large Page

Valid Page Frame number U P Cw Gl L D A Cd Wt O W V

Page Faults
When bit 1 in the PTE is set to 0 (invalid), any access to
this page will generate a page fault. Note that all other bits of PTE are ignored in this case. So the PTE can be technically used for OS private data. Page fault handler is a kernel routine which handles the page fault: Page may be fetched from page file. Page is in transition if Prototype bit is also set.
A page is transition is waiting to be paged out, but is actually valid still. A page fault here can return it into the working set immediately.

Page may be overcommitted and kernel will allocate physical memory for it.

Volatility Address Spaces


An address space is an object which satisfies read requests.
Many address spaces satisfy their reads from another address space - Address Spaces stack.
An address space can be sparse - i.e. read() to some regions will fail. The address space should implement get_available_addresses() to assist in scanning. read() zread() can be used to pad invalid regions with 0.

MmapFileAddressSpace IA32PagedMemory

Volatility Address Spaces


By default, most plugins will invoke the load_as() plugin. This uses an automated voting algorithm to figure out the correct layering of address spaces (it will call the find_dtb() scanner). loas_as() will populate the session with the physical and kernel address spaces. A profile is applied onto an address space in order to instantiate a vtype object:
task = session.profile._EPROCESS(vm=self.kernel_address_space, offset=0x12345) print task.ImageFileName

How to find the Kernel DTB Windows


Many imaging tools already capture the DTB. Can deduce DTB from any process:
When the kernel schedules a process, it must restore CR3 to the process DTB - hence the process DTB is stored in the process struct (task.Pcb. DirectoryTableBase): Every process maps the kernel! '_EPROCESS' : [ 0x260, {
Typically scan for 'Pcb' : [ 0x0, ['_KPROCESS']], "Idle" 'ImageFileName' : [ 0x174, ['array', 16, ['unsigned char']]], }] '_KPROCESS' : [ 0x6c, { 'Header' : [ 0x0, ['_DISPATCHER_HEADER']], 'ProfileListHead' : [ 0x10, ['_LIST_ENTRY']], 'DirectoryTableBase' : [ 0x18, ['array', 2, ['unsigned long']]],

In [15]: find_dtb? find_dtb: A plugin to search for the Directory Table Base for windows systems. Scans the image for the Idle process. ... In [16]: find_dtb -------> find_dtb() _EPROCESS (P) DTB 0x02813140 0x00187000 0x1179b7dc 0x00490050

How does imaging work? Linux


In Linux it is more efficient to implement devices through mmap:
static int pmem_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { loff_t offset = vmf->pgoff << PAGE_SHIFT; /* Offset of faulting page */ unsigned long pfn = (unsigned long)(vmf->pgoff); /* Faulting page */ struct page *page; /* Map the real page here. */ page = pfn_to_page(pfn); get_page(page); vmf->page = page; return 0; } static struct vm_operations_struct pmem_vm_ops = { .fault = pmem_vma_fault, };

Listing processes - Linux.


In linux processes are represented by task_struct structures:
'task_struct': [5864, 'tasks': [576, ['list_head']], }] 'list_head': [16, { 'next': [0, ['pointer', ['list_head']]], 'prev': [8, ['pointer', ['list_head']]]}]

All tasks are connected in a list. The init task is always alive and its address is hard coded into the kernel symbols.

Listing processes - Linux.

Init Task

next prev

next prev

next prev

The Kernel Debugger Block Windows KDBG.


KDBG Block

PsActiveProcessHead

Flink Blink

Flink Blink

Flink Blink

Flink Blink

The Kernel Debugger Block Windows KDBG.


The kernel debugger uses the KDBG to store information important for debugging.
The PsActiveProcessHead is a pointer to the list head of the active processes.

The KDBG is not critical to the operation of the system, so malware can easily corrupt it. You can always list the processes by finding a single _EPROCESS object and following the list around.
The PsActiveProcessHead is not a real process, so will need to discard that.

Scanning for the KDBG


$ python vol.py -f ~/images/xp-laptop-2005-06-25.img --profile WinXPSP3x86 kdbgscan Volatile Systems Volatility Framework 2.1_alpha ************************************************** Instantiating KDBG using: Kernel AS WinXPSP2x86 (5.1.0 32bit) Offset (V) Offset (P) KDBG owner tag check Version64 Build string (NtBuildLab) PsActiveProcessHead PsLoadedModuleList KernelBase Major (OptionalHeader) Minor (OptionalHeader) KPCR : 0x8054c060 : 0x54c060 : True : 0x8054c038 (Major: 15, Minor: 2600) : 2600.xpsp_sp2_gdr.050301-1519 : 0x805604d8 (47 processes) : 0x8055a420 (127 modules) : 0x804d7000 (Matches MZ: True) : 5 : 1 : 0xffdff000 (CPU 0)

Profile suggestion (KDBGHeader): WinXPSP3x86 Service Pack (CmNtCSDVersion) : 2

Listing processes - Windows.


$ ./vol.py -f ~/images/win7_trial_64bit.raw --profile=Win7SP0x64 --logging info In [1]: pslist ------> pslist() INFO:root:Autodetected physical address space WindowsCrashDumpSpace64 INFO:root:Autodetected virtual address space AMD64PagedMemory@0x00187000 (Kernel AS@0x187000) INFO:root:KDBG not provided - Volatility will try to automatically scan for it now using plugin.kdbgscan. INFO:root:Found a KDBG hit [_KDDEBUGGER_DATA64 _KDDEBUGGER_DATA64] @ 0xF80002803070. Hope it works. If not try setting it manually. Offset (V) Name PID PPID Thds Hnds Sess Wow64 Start Exit -------------- -------------------- ------ ------ ------ -------- ------ ------ --------------------------------------0xfa80004b09e0 System 0xfa8000ce97f0 smss.exe 0xfa8000c006c0 csrss.exe 0xfa8000c92300 wininit.exe 4 208 296 332 0 4 288 288 78 2 9 3 489 -----29 -----385 74 0 0 False 2012-02-22 19:58:20 False 2012-02-22 19:58:20 False 2012-02-22 19:58:24 False 2012-02-22 19:58:30 -

Finding hidden processes - psxview


Combines the output from several plugins
_EPROCESS list traversal Pool tag scanning. CSRSS handles Thread scanning. Kernel debugger PspCidTable

Results are always inconsistent


Some processes just do not show up on some sources.

In [5]: psxview ------> psxview() Offset(P) Name PID pslist 1952 True 4080 True 2040 True 448 False 1424 False 528 True 2624 True 944 True 2740 True 1400 True 1076 True 580 True 1960 False 876 True psscan True True True True True True True True True True True True True True thrdproc pspcdid csrss True True True False False True True True True True True True False True True False True False False True True True True True True True False True True False True False False True True True True True True True False True ---------- -------------------- ------ ------- ------- -------- ------- ------0x01f67500 TaskSwitch.exe 0x02000980 wmiprvse.exe 0x02025608 atiptaxx.exe 0x12cd3020 smss.exe 0x0fe5f8e0 snmp.exe 0x01f8eb10 winlogon.exe 0x02079c18 cmd.exe 0x02218020 PluckSvr.exe 0x01ed76b0 PluckTray.exe 0x01f48da0 tcpsvcs.exe 0x01f6db28 msdtc.exe 0x020e0da0 services.exe 0x1a192a90 Fast.exe 0x01fa8240 Smc.exe

Volatility TP as a library
#!/usr/bin/python from volatility import session s = session.Session() s.filename = "MyImage.raw" s.profile = "Win7SP1x64"

A session is an object which holds all analysis results for the current session.

pslist = s.plugins.pslist() The module is available from the session object. A module exports methods which we can call. for task in pslist.list_eprocess(): print task.UniqueProcessId, task.ImageFileName

Normally the vol() helper calls the render() method of the module, but many modules export many other methods.

What could go wrong?


BH Europe 2012: One-byte Modification for Breaking Memory Forensic Analysis specifically attacks these processes: 1. Virtual address translation in kernel space. a. Corrupt the header of Idle process. 2. Guessing OS version and Architecture. a. Change the PE header of kernel. 3. Getting kernel objects a. traversing linked lists or binary trees b. object carving i. Corrupts the pool tags. The overall effect is that it does not work out of the box!

DKOM
Very old technique for unlinking _EPROCESS objects: Works because
KDBG Block the scheduler uses threads

PsActiveProcessHe ad

Flink Blink

Flink Blink

Flink Blink

Flink Blink

http://i159.photobucket.com/albums/t141/sovietweasel/hideproc-vmware.jpg

Summary of module 2
Virtual paging
Volatility Address spaces

Analysis techniques
List following

Some antiforensic techniques


DKOM Signature subversion.

Module 3
Windows internals: The PE File format.
Finding PE files in memory.

Scanning for kernel objects in memory.


psscan, filescan, driverscan

PE Executables
The PE file format is specifically designed to allow fast and efficient loading of executables into memory.
The structure of executables on disk is similar to their structure in memory. Imports and Exports are resolved at load time.

PE Overview

http://code.google.com/p/corkami/downloads/detail?name=pe-20110117.pdf

Example of PE Parsing from memory


In [5]: from volatility.plugins.overlays.windows import pe_vtypes In [6]: pe = pe_vtypes.PE(address_space=session.kernel_address_space, image_base= session.kdbg.KernBase) In [7]: p pe.nt_header [_IMAGE_NT_HEADERS _IMAGE_NT_HEADERS] @ 0x804D70E8 0x00 Signature 0x04 FileHeader 0xF8 Sections [unsigned long:Signature]: 0x00004550 [_IMAGE_FILE_HEADER FileHeader] @ 0x804D70EC <Array 21 x _IMAGE_SECTION_HEADER @ 0x804D71E0>

This is the address of ntoskrnl.exe

0x18 OptionalHeader [_IMAGE_OPTIONAL_HEADER OptionalHeader] @ 0x804D7100

In [8]: p pe.nt_header.OptionalHeader [_IMAGE_OPTIONAL_HEADER OptionalHeader] @ 0x804D7100 0x1C ImageBase 0x20 SectionAlignment 0x24 FileAlignment 0x28 MajorOperatingSystemVersion 0x00000005 0x2A MinorOperatingSystemVersion 0x00000001 [unsigned long:ImageBase]: 0x00400000 [unsigned long:SectionAlignment]: 0x00000080 [unsigned long:FileAlignment]: 0x00000080 [unsigned short:MajorOperatingSystemVersion]: [unsigned short:MinorOperatingSystemVersion]:

Version 5.1= Windows XP SP 2

Listing Sections of PE Files


In [42]: for section in pe.Sections(): print section ('xr-', ('xr-', ('xr-', ('xr-', ('xrw', ('-r-', ('-rw', ('-r-', ..... [String:Name]: '.text\x00\x00\x00', [String:Name]: 'INITKDBG', [String:Name]: 'POOLCODE', [String:Name]: 'POOLMI\x00\x00', [String:Name]: 'RWEXEC\x00\x00', [String:Name]: '.rdata\x00\x00', [String:Name]: '.pdata\x00\x00', [unsigned long:VirtualAddress]: 0x00001000, 1689600) [unsigned long:VirtualAddress]: 0x0019D000, 1706496) [unsigned long:VirtualAddress]: 0x001A1000, 1715200) [unsigned long:VirtualAddress]: 0x001A6000, 1728512) [unsigned long:VirtualAddress]: 0x001A7000, 1980928) [unsigned long:VirtualAddress]: 0x001E4000, 2046976) [unsigned long:VirtualAddress]: 0x00278000, 2783744) [unsigned long:VirtualAddress]: 0x001A3000, 1728512)

[String:Name]: '.data\x00\x00\x00',

The peinfo plugin


In [11]: peinfo? peinfo: Print information about a PE binary. Dump a PE binary from memory. Status is shown for each exported function: - M: The function is mapped into memory. Parameter address_space image_base Documentation The address space which contains the PE image. The address of the image base (dos header).

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

The peinfo plugin


In [3]: peinfo session.kernel_address_space, session.kdbg.KernBase Machine Machine TimeDateStamp Characteristics .... Sections (Relative to 0xFFFFF8000261A000): Perm Name xrxrxr.... Data Directories: IMAGE_DIRECTORY_ENTRY_EXPORT IMAGE_DIRECTORY_ENTRY_IMPORT IMAGE_DIRECTORY_ENTRY_RESOURCE ... VMA Size ---------------------------------------- -------------- -------------0xfffff80002b43000 0x000000010962 0xfffff80002bbccec 0x000000000078 0xfffff80002bbe000 0x000000035d34 .text POOLMI VMA Size ---- -------- -------------- -------------0x000000001000 0x00000019b800 0x0000001a1000 0x000000001c00 INITKDBG 0x00000019d000 0x000000003a00 TimeDateStamp IMAGE_FILE_MACHINE_AMD64 2009-07-13 23:40:48 UTC+0000 IMAGE_FILE_EXECUTABLE_IMAGE, IMAGE_FILE_LARGE_ADDRESS_AWARE -------------------- -------------

Other PE Files - Processes


In [12]: eprocess = session.profile._EPROCESS(vm=session.kernel_address_space, offset=0x0000fa8000aa0b30) In [5]: eprocess.Peb.ImageBaseAddress Out[5]: <Void Pointer to [0xFF120000] (ImageBaseAddress)>

This is the address of a process that comes from pslist

The process Environment Block

In [14]: pe = pe_vtypes.PE(address_space=eprocess.get_process_address_space(), image_base=eproc ImageBaseAddress) In [16]: for section in pe.Sections(): print section ('xr-', ('-r-', ('-rw', ('-r-', ('-r-', ('-r-', [String:Name]: '.text\x00\x00\x00', [String:Name]: '.rdata\x00\x00', [String:Name]: '.pdata\x00\x00', [String:Name]: '.reloc\x00\x00', [String:Name]: '.data\x00\x00\x00', [String:Name]: '.rsrc\x00\x00\x00',

[unsigned long:VirtualAddress]: 0x00001000, 33228 The PE file is mapped

into the process address [unsigned long:VirtualAddress]: 0x00052000, 455168)


[unsigned long:VirtualAddress]: 0x00073000, 499712) [unsigned long:VirtualAddress]: 0x00093000, 606208)

space [unsigned long:VirtualAddress]: 0x00070000, 46848

[unsigned long:VirtualAddress]: 0x0007A000, 60211

DLLs
The _EPROCESS object has 3 lists of dlls loaded:
eprocess.Peb.Ldr.InInitializationOrderModuleList eprocess.Peb.Ldr.InLoadOrderModuleList eprocess.Peb.Ldr.InMemoryOrderModuleList

Unfortunately these are located in the process address space.


A malicious process can easily unlink their dlls from these lists.

Process Loaded DLL lists.


In [10]: for x in eprocess.get_load_modules(): print x.FullDllName, hex(x.DllBase) C:\Windows\system32\SearchIndexer.exe 0xff120000 C:\Windows\SYSTEM32\ntdll.dll 0x76d40000 C:\Windows\system32\kernel32.dll 0x76b20000 C:\Windows\system32\KERNELBASE.dll 0x7fefcd50000 C:\Windows\system32\ADVAPI32.dll 0x7fefd110000 In [11]: for x in eprocess.get_init_modules(): print x.FullDllName, hex(x.DllBase) C:\Windows\SYSTEM32\ntdll.dll 0x76d40000 C:\Windows\system32\KERNELBASE.dll 0x7fefcd50000 C:\Windows\system32\kernel32.dll 0x76b20000 In [12]: for x in eprocess.get_mem_modules(): print x.FullDllName, hex(x.DllBase) C:\Windows\system32\SearchIndexer.exe 0xff120000 C:\Windows\SYSTEM32\ntdll.dll 0x76d40000 C:\Windows\system32\kernel32.dll 0x76b20000 C:\Windows\system32\KERNELBASE.dll 0x7fefcd50000

DLLs are PE files too.


In [16]: for version in pe.VersionInformation(): print version ( [UnicodeString:Key]: u'CompanyName\x00', Corporation\x00') [UnicodeString:Value]: u'Microsoft

( [UnicodeString:Key]: u'FileDescription\x00', Natural Language Server Data and Code\x00') ( [UnicodeString:Key]: u'FileVersion\x00', (win7_rtm.090713-1255)\x00') ( [UnicodeString:Key]: u'InternalName\x00',

[UnicodeString:Value]: u'Microsoft English

[UnicodeString:Value]: u'6.1.7600.16385

[UnicodeString:Value]: u'NlsData0009\x00')

Dumping a PE file from memory


def WritePEFile(self, fd, address_space, image_base): dos_header = self.pe_profile._IMAGE_DOS_HEADER(offset=image_base, vm=address_space) image_base = dos_header.obj_offset nt_header = dos_header.NTHeader

The PE Image is located in memory.

# First copy the PE file header, then copy the sections. data = dos_header.obj_vm.zread(image_base, nt_header.OptionalHeader.SizeOfHeaders) fd.seek(0) fd.write(data)

Copy the headers.

for section in nt_header.Sections: data = section.obj_vm.zread(section.VirtualAddress + image_base, section.SizeOfRawData) fd.seek(section.PointerToRawData, 0) fd.write(data)

Copy each section.

PE Dumping from memory


Can be done using a bunch of plugins:
procdump - Dumps _EPROCESS images using PID. dlldump - Dumps DLLs. pedump - Generic PE dumper that is used by the other modules.

Potential problems:
Rootkits can easily change the in-memory PE headers. (e.g. Section description etc). It is possible to corrupt the headers so the tool blows up - too much data, huge executables. Import Address Table is not patched. Not all sections are fully mapped into memory (e.g. . rsrc not always mapped in).

Dumping packed binaries.


Normal binaries contain two import thunks:

Packed binaries
Packed binaries have a very small IAT on disk (just enough for the unpacker).
The real import table is built in memory but does not contain any function names - only dll 1 function pointers. dll 1
IAT on disk IAT in memory Binary Code Section export table code

dll 1 export table

dll 1 code

dll 1 export table

dll 1 code

impscan - Reconstruct IATs


1. Scan all the dlls in the process address space, and enumerate their exports. 2. We disassemble the code segment of the binary, looking for indirect calls through the IAT. 3. Match up these calls with the known dll exports. 4. Create a report or IDAC code to inform IDA about the exports.

Example
In [2]: impscan pid=2236 ------> impscan(pid=2236) ************************************************** Process conhost.exe PID 2236 IAT Call Module Function CreateRectRgn DeleteObject SelectObject SelectPalette DeleteDC GetStockObject PolyPatBlt -------------- -------------- -------------------- -------0x0000ffddf000 0x07fefd7c2520 GDI32.dll 0x0000ffddf018 0x07fefd7c1090 GDI32.dll 0x0000ffddf030 0x07fefd7c1860 GDI32.dll 0x0000ffddf038 0x07fefd7c6274 GDI32.dll 0x0000ffddf048 0x07fefd7c222c GDI32.dll 0x0000ffddf070 0x07fefd7c103c GDI32.dll 0x0000ffddf078 0x07fefd7c14a0 GDI32.dll

Module 3 Summary
The PE executable format.
Relation between PE in memory and PE on disk. Dumping out PE from memory. Different types of PE files: Processes. DLLs. Kernel Drivers.

Module 4: Memory Management


The windows kernel Object Manager.
Allocation strategy - Pool tags Scanning for objects. Back references to _EPROCESS objects. Scanning vs. List following.

Process memory management:


Page File Number database. VAD tree. Some Malware hiding techniques.

Window Kernel Memory Allocation


The windows kernel uses Pools to manage allocation:
Paged pool - can be paged to disk. Non paged - For use by critical components which must not be paged (e.g. Interrupt level).

Allocations come from the pool, and are tagged using a special identifier "Tag":
ExAllocatePoolWithTag Tags are used to track memory owners and detect leaks.

Poolmon

Windows Kernel Objects


The windows Object Manager is responsible for managing allocation/deallocation of objects.
An object is a managed data structure in the kernel. There are many types of objects - basically anything we require the kernel to manage is an object. Allocation functions end up delegating to ObCreateObject()

Object Allocation Scheme


http://www.codemachine.com/article_objectheader.html

Number of optional headers is encoded in the Object Header

Pool Header

Optional Header

Optional Header

Object Header ObCreateObject() Object

The Volatility Scanning framework


Specify a set of conditions which all have to match.
Conditions are tested in order, exit early. Conditions can specify a "skipper" - i.e. can return a number of bytes to skip which can never match.

The user of the scanner calls the scan() iterator to receive possible matches. Some useful scanners:
Discontiguous Scanner - can efficiently scan Virtual Address Space. VAD Scanner - used to scan memory accessible to a process.

Discontiguous Scanners.
Discontiguous Scanners

Physical Address Space Virtual Address Space

Scanning for Objects


class PoolScanDriver(PoolScanFile): """ Scanner for _DRIVER_OBJECT """ '_DRIVER_EXTENSION'] checks = [ ('PoolTagCheck', dict(tag = "Dri\xf6")),

Declare header allocation order.

allocation = ['_POOL_HEADER', '_OBJECT_HEADER', '_DRIVER_OBJECT',

Pool Tag

('CheckPoolSize', dict(condition = lambda x: x >= 0xf8)), ('CheckPoolType', dict(paged = True, non_paged = True, free = True)), ('CheckPoolIndex', dict(value = 0)), ]

We can scan in the physical address space or kernel address space: Physical AS can be fooled by process allocations but is slightly faster. Scanning for kernel objects in kernel address space is sufficient.

Scanning for Objects


Because the size of the object header is variable we can not just calculate the size directly:
Use a bottom up approach:
Pool Header Optional Header Optional Header Object Header Object Size of Object Header Size of Object (e.g. _FILE_OBJECT) Allocation Size

Total Size of Object Optional Headers

Windows 8
The bottom up method does not work on Windows 8:
Windows 8 uses a binned memory allocator: Each allocation is rounded up to the next bin size. Can not calculate object size from allocation size. Need to iterate through all possible header configurations. In addition pool tags are not unique enough e.g. for EPROCESS it is "Proc"

Pool scanning on windows 8 is slower

Object Owners
When the object manager allocates a kernel object on behalf of a process, sometimes, there is a reference to the _EPROCESS embedded into the _OBJECT_HEADER: object_obj.HandleInfo.SingleEntry.Process
http://computer.forensikblog.de/en/2009/04/linking-file-objects-to-processes.html
In [4]: vol plugins.filescan, address_space=session.kernel_address_space Offset #Ptr #Hnd Access Owner OwnerPid OwnerName Name

------------------ ---- ---- ------ ------------------ --------- ---------------- ---0x0000f6fd40004530 15 0 RW-rw- ------------------ --------- ---------------\Users\testing\AppData\Roaming\Microsoft\Windows\Cookies\Low\index.dat 0x0000f6fd40006050 1 1 RW-r-d 0x0000fa80004b09e0 \Windows\System32\wdi\LogFiles\WdiContextLog.etl.001 4 System

0x0000fa8000514dd0 19 1 RW-r-- 0x0000fa80007d09e0 916 svchost.exe \Windows\System32\winevt\Logs\Microsoft-Windows-BranchCacheSMB%4Operational.evtx

Example: psscan vs. pslist


$ vol.py --profile WinXPSP2x86 -f malwarecookbook/15/6/prolaco.vmem psscan Offset Offset(V) Name PID 1260 468 1028 1336 PPID PDB Time created Time exited 2010-08-11 16:50:42 ---------- ---------- ---------------- ------ ------ ---------- -------------------- -------------------0x005f23a0 0xff0dd3a0 rundll32.exe 0x010f7588 0x80f94588 wuauclt.exe 0x01122910 0x80fbf910 svchost.exe 0x0113f648 0x80fdc648 1_doc_RCData_61 1724 0x06cc0360 2010-08-11 16:50:29 1028 0x06cc0180 2010-08-11 06:09:37 676 0x06cc0120 2010-08-11 06:06:24 1136 0x06cc0340 2010-08-11 16:50:20

$ vol.py --profile WinXPSP2x86 -f malwarecookbook/15/6/prolaco.vmem pslist Offset (V) Name 0x810b1660 System .... (Not found) 1136 1724 2 73 0 False 2010-08-11 16:50:19 PID 4 PPID 0 Thds 56 Hnds Sess Wow64 Start False Exit -

---------- -------------------- ------ ------ ------ -------- ------ ------ -------------------- ---------------253 ------

0xff37a4b0 ImmunityDebugge

The Page Frame Number (PFN) database (Windows).


The operating system maintains a database about the allocation status of every physical page in the system.
Since the page tables exist in the physical address space, but the OS can only reference the Virtual Address space, there must be a way to quickly access the PTEs that control a particular physical page. The hardware can only do the forward mapping (Virtual to Physical). Hence the operating system needs to keep track of the reverse mapping (Physical Page to PTE).

Paging in 32 bit model.


Virtual Address Page Directory Index CR3 Page Table Index Byte Index

Directory Table Base (DTB)

PTN

Page Frame

PTE

PFN DB Maps PFN to PTE

Page Directory

Page Tables

Physical Memory

The PFN Database


An array of _MMPFN structs, one for every page of physical memory.
The PFN database start is referenced by kdbg. MmPfnDatabase. To get the PFN of a physical address we just divide by 0x1000 (i.e. its the page number). Index the array of _MMPFN structs (aka the PFN database) to read the PFN record.

The PFN record contains important information about the physical page.
In use/Valid/Paged Virtual Address of the PTE which controls this page.

Page Frame Number


[_MMPFN MmPfnDatabase[200264] ] @ 0xFA800092AD80 0x00 Type 0x00 u1 0x08 u2 0x10 Lock 0x10 PteAddress 0x10 PteLong 0x10 VolatilePteAddress 0x18 u3 0x1C 0x1E 0x1F [ValueEnumeration:Type]: 0x00000006 (ActiveAndValid) [__unnamed_152d u1] @ 0xFA800092AD80 [__unnamed_152f u2] @ 0xFA800092AD88 [long:Lock]: 0x40018718 <CType Pointer to [0xF6FC40018718] (PteAddress)> [unsigned long long:PteLong]: 0xFFFFF6FC40018718 <Void Pointer to [0xF6FC40018718] (VolatilePteAddress)> 0x00000000

Page is valid.

The [__unnamed_1534 u3] @ 0xFA800092AD98 PTE UsedPageTableEntries [unsigned short:UsedPageTableEntries]: address in VaType [unsigned char:VaType]: 0x00000000 Kernel Address ViewCount [unsigned char:ViewCount]: 0x00000000 Space
[long:AweReferenceCount]: 0x00000080 [_MMPTE OriginalPte] @ 0xFA800092ADA0 [__unnamed_153c u4] @ 0xFA800092ADA8

0x20 AweReferenceCount 0x20 OriginalPte 0x28 u4

[__unnamed_153c u4] @ 0xFA800092ADA8 0x00 PrototypePte 0x00 PteFrame 0x00 Unused [BitField:PrototypePte]: 0x00000000 [BitField:PteFrame]: 0x00019A18 [BitField:Unused]: 0x00000000

The physical page containing the PTE.

Physical to Virtual mapping


Can use the PFN database to map from physical address to virtual address.
Find the Virtual PTE address for the physical address. (e.g. 0xF6FC40018718) Find the PteFrame (This is the physical address for the PTE). (e.g. 0x00019A18) PTE Physical address is then 0x00019A18718. Because there is a virtual mapping to the PTE itself, we can repeat the process to find the PTE controlling this PTE (i.e. the PDE). Use the PFN database to locate the PDE, PDPDTE, PML4E and DTB, in turn.

Example
In [36]: vtop 0xf880030e3000 -------> vtop(0xf880030e3000) Virtual 0xF880030E3000, Page Directory 0x00187000 pml4e@ 0x00187F88 = 0x2E004863 pdpte@ 0x2E004000 = 0x2E003863 pde@ 0x2E0030C0 = 0x19A18863 pte@ 0x19A18718 = 0x30E48963 PTE mapped@ 0x19A18718 = 0x30E48000

Physical Address
In [37]: ptov 0x30E48000 -------> ptov(0x30E48000) Physical Address 0x0000000030E48000 => Virtual Address 0x0000F880030E3000 DTB @ 0x0000000000187000 PML4E @ 0x0000000000187F88 PDPDE @ 0x000000002E004000 PDE @ 0x000000002E0030C0 PTE @ 0x0000000019A18718

DTB for this page is found.

PFN DB is used to connect all the levels.

In [35]: pfn 0x30E48 -------> pfn(0x30E48) PFN 0x00030E48 at kernel address 0x0000FA800092AD80 flink 00000000 blink / share count 0000000000000001 (Phys AS) 0x0000000019A18718 ActiveAndValid M color 0 0x00019A18 pteaddress (VAS) 0x0000F6FC40018718 reference count 0001 containing page Modified

Finding hidden processes using PFN


Every process has its own address space.
Hence every process has its own DTB. Perform the physical to virtual mapping of all the physical pages, and find all the DTBs. Compare to the DTBs of known processes.

This is actually very hard for a rootkit to hide.

Finding hidden processes using PFN


$ python vol.py -f ~/images/win7_trial_64bit.dmp --profile=Win7SP0x64 dtbscan DTB _EPROCESS Image Name -------------- -------------- ---------0x000000187000 0xfa800096a9e0 System 0x00001f915000 0xfa8001d4b630 svchost.exe 0x0000209de000 0xfa8000bbdb30 &.exe

0x00001b2c8000 0xfa8001ea5b30 spoolsv.exe 0x0000211a4000 0xfa8001dbfb30 svchost.exe 0x00002ceb9000 0xfa8000a2d060 svchost.exe 0x00002178b000 0xfa8001db5b30 svchost.exe 0x000022e75000 0xfa8000bbd060 conhost.exe 0x000022192000 0xfa8001d03ac0 lsm.exe 0x000019295000 0xfa80020bfb30 sppsvc.exe 0x00001d3a2000 0xfa8001fd9890 svchost.exe 0x00002573b000 0xfa8001974630 winlogon.exe -0x00000001000 -------------- Process not Found! 0x000021533000 0xfa8001e905b0 svchost.exe 0x00001d5c7000 0xfa8001dd7800 explorer.exe .....

Process Memory management - The Vad Tree.


Windows manages process memory through 2 mechanisms:
Ultimately pages are assigned through the page tables and the PFN database. The Virtual Memory Address Descriptors (VAD) maintain a high level overview of the pages assigned to a process. A binary tree in memory of virtual memory assigned to a process. The kernel uses the VAD tree to manage the page tables for this process.

The VAD tree: A process-eye view of physical memory - Brendan Dolan-Gavitt digitalinvestigation 4S (2007) S62S64

Inspecting the VAD


In [2]: vad pid=4012 ------> vad(pid=4012) Pid: 4012 dd.exe VAD 0x81edc7e0 0x8220fad0 0x81ff0398 0x820ee328 0x82068e78 0x81f1b548 0x81f338b0 0x81ffa408 0x81eef6d8 0xff94a1d0 0x8220e848 0x8136f140 0x82216830 0x820c9308 0x81f16390 lev 0 1 2 1 2 3 3 4 6 6 7 10 2 3 4 start 0x30 0x10 0x20 0x400 0x140 0x130 0x250 0x240 0x2c0 0x330 0x320 0x37f 0x7c900 0x7c800 0x10000 end 0x12f 0x10 0x20 0x40d 0x23f 0x132 0x25f 0x24f 0x300 0x332 0x32f 0x37f 0x7c9af 0x7c8f3 0x10005 com 3 Private 1 Private 1 Private 2 Mapped 12 Private 0 Mapped 0 Mapped 6 Private 0 Mapped 0 Mapped 8 Private 0 Mapped 5 Mapped 5 Mapped 2 Mapped Exe Exe Exe Exe Protect READWRITE READWRITE READWRITE EXECUTE_WRITECOPY READWRITE READONLY READWRITE READWRITE READONLY READONLY READWRITE READONLY EXECUTE_WRITECOPY EXECUTE_WRITECOPY EXECUTE_WRITECOPY \WINDOWS\system32\ntdll.dll \WINDOWS\system32\kernel32.dll \dd\UnicodeRelease\getopt.dll \dd\UnicodeRelease\dd.exe Filename ---------- --- ---------- ---------- ---- ------- ------ -------------------- --------

Mapped DLLs are shared between \WINDOWS\system32\sortkey.nls \WINDOWS\system32\ctype.nls processes.

vadinfo
$ vol.py -f xp-laptop-2005-06-25.img --profile WinXPSP2x86 --pid 4012 vadinfo .... VAD node @ 0x820c9308 Start 0x7c800000 End 0x7c8f3fff Tag Vad Flags: CommitCharge: 5, ImageMap: 1, Protection: 7 Protection: PAGE_EXECUTE_WRITECOPY ControlArea @820e24b8 Segment e165b3d8 Dereference list: Flink 00000000, Blink 00000000 NumberOfSectionReferences: NumberOfMappedViews: WaitingForDeletion Event: 00000000 , Name: \WINDOWS\system32\kernel32.dll 1 NumberOfPfnReferences: 41 NumberOfUserReferences: 119 42

Control Flags: Accessed: 1, File: 1, HadUserReference: 1, Image: 1 FileObject @821745e0 FileBuffer @ e17c2460 Flags2: Inherit: 1 First prototype PTE: e165b410 Last contiguous PTE: fffffffc

Using the VAD to find hidden files.


$ vol.py --profile WinXPSP2x86 -f malwarecookbook/15/6/prolaco.vmem Welcome to the volatility interactive shell! In [1]: psscan Offset Offset(V) Name PID 1260 468 1028 1336 PPID PDB Time created Time exited 2010-08-11 16:50:42 ---------- ---------- ---------------- ------ ------ ---------- -------------------- -------------------0x005f23a0 0xff0dd3a0 rundll32.exe This is the hidden 0x010f7588 0x80f94588 wuauclt.exe process. 0x01122910 0x80fbf910 svchost.exe 0x0113f648 0x80fdc648 1_doc_RCData_61 ... In [2]: vad eprocess=0x80fdc648 Pid: 1336 1_doc_RCData_61 VAD lev start end com Protect Filename \Documents and ---------- --- ---------- ---------- ---- ------- ------ -------------------- -------0xff1418a8 0 0x400 0x454 48 Mapped Exe EXECUTE_WRITECOPY Executable location. Settings\Administrator\Desktop\1_doc_RCData_612.exe 0x80fddab0 0xff277bc8 0xff083310 0xff149fa8 1 2 3 4 0x10 0x20 0x30 0x230 0x10 0x20 0x22f 0x232 1 Private 1 Private 4 Private 0 Mapped READWRITE READWRITE READWRITE READONLY 1724 0x06cc0360 2010-08-11 16:50:29 1028 0x06cc0180 2010-08-11 06:09:37 676 0x06cc0120 2010-08-11 06:06:24 1136 0x06cc0340 2010-08-11 16:50:20

The original

Using the vad to double check loaded dlls.


As we mentioned previously there are 3 lists of loaded dlls in the Peb:
In loaded order. In Init order. In Memory order.

Malware can easily unlink a module from these lists, but its harder to manipulate the VAD.

The ldrmodules plugin.


Pid 1928 1928 1928 1928 1928 1928 1928 1928 1928 1928 1928 1928 1928 1928 Process lsass.exe lsass.exe lsass.exe lsass.exe lsass.exe lsass.exe lsass.exe lsass.exe lsass.exe lsass.exe lsass.exe lsass.exe lsass.exe lsass.exe Base 0x00080000 0x7c900000 0x77c00000 0x01000000 0x5b860000 0x76bf0000 0x77c10000 0x77dd0000 0x7c9c0000 0x00870000 0x76f20000 0x5d090000 0x71aa0000 0x77b20000

How can we get an executable area without being in the module lists and not having file mapping?

$ vol.py --profile WinXPSP2x86 -f malwarecookbook/stuxnet.vmem --pid 680 --verbose ldrmodules InLoad InInit InMem MappedPath False True True True True True True True True True True True True True False False True True True True True True True True True True True True True True True True True True True True True True True True \WINDOWS\system32\ntdll.dll \WINDOWS\system32\version.dll \WINDOWS\system32\netapi32.dll \WINDOWS\system32\psapi.dll \WINDOWS\system32\msvcrt.dll \WINDOWS\system32\advapi32.dll \WINDOWS\system32\shell32.dll \WINDOWS\system32\dnsapi.dll \WINDOWS\system32\comctl32.dll \WINDOWS\system32\ws2help.dll \WINDOWS\system32\msasn1.dll

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

False True

Process Hollowing
Malware can attempt to hide by using process hollowing: 1. Create a new process using a legitimate executable, but do not start it. 2. Free the memory section that contains the ImageBase from the executable. 3. Allocate a new memory region in the new process, and copy malicious code into it.
a. VirtualAllocEx, WriteProcessMemory

4. Resume the start thread from the new executable.

Malware Analyst's Cookbook - Michael Hale Ligh, Steven Adair, Blake Hartstein, Matthew Richard

How does that look in memory?


$ vol.py --profile WinXPSP2x86 -f malwarecookbook/stuxnet.vmem In [1]: pslist pid=868 Offset (V) Name 0x81c498c8 lsass.exe In [3]: vad eprocess=0x81c498c8 Pid: 868 lsass.exe VAD 0x81f459d0 0x822e7e70 0x81fc8520 ... 0x8209b818 0x8209c3d0 0x81f1ef08 0x81fa64b0 0x81c970a8 3 1 2 3 4 0x200 0x7c900 0x1000 0x240 0x220 0x20f 0x7c9ae 0x1005 0x280 0x235 lev 0 1 2 start 0x210 0x80 0x10 end 0x21f 0xf9 0x10 com 0 Mapped 0 Mapped 1 Private Exe Protect READWRITE EXECUTE_READWRITE READWRITE Filename ---------- --- ---------- ---------- ---- ------- ------ -------------------- -------PID 868 PPID 668 Thds 2 Hnds 23 Sess 0 Wow64 Start False 2011-06-03 04:26:55 Exit -

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

Executable memory 6 Private READWRITE which is notExe backed 5 Mapped EXECUTE_WRITECOPY by Mapped Exe a file???? 2 EXECUTE_READWRITE
0 Mapped 0 Mapped READONLY READONLY

\WINDOWS\system32\ntdll.d

\WINDOWS\system32\locale. \WINDOWS\system32\unicod

In [7]: task = session.profile._EPROCESS(vm=session.kernel_address_space, offset=0x81c498c8) In [8]: dump task.get_process_address_space(), 0x80000 ------> dump(task.get_process_address_space(), 0x80000) 0x00080000 0x00080010 0x00080020 0x00080030 0x00080040 0x00080050 0x00080060 0x00080070 0x00080080 0x00080090 4d 5a 90 00 03 00 00 00 04 00 00 00 ff ff 00 00 b8 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 01 00 00 0e 1f ba 0e 00 b4 09 cd 21 b8 01 4c cd 21 54 68 69 73 20 70 72 6f 67 72 61 6d 20 63 61 6e 6e 6f 74 20 62 65 20 72 75 6e 20 69 6e 20 44 4f 53 20 6d 6f 64 65 2e 0d 0d 0a 24 00 00 00 00 00 00 00 c7 1c 48 b9 83 7d 26 ea 83 7d 26 ea 83 7d 26 ea a4 bb 4b ea 81 7d 26 ea 9d 2f a2 ea 88 7d 26 ea MZ.............. ........@....... ................ ................ ........!..L.!Th is.program.canno t.be.run.in.DOS. mode....$....... ..H..}&..}&..}&. ..K..}&../...}&.

Module 4: Summary
Scanning for objects in kernel memory.
Discontiguous scanners.

Examining the PFN database


dtbscan physical to virtual mapping.

The VAD tree


Finding evidence of VirtualAllocEx and WritePrecessMemory. Dll injections, process hollowing.

Module 5: Hooking
Hooking means to change the flow control of execution to take control of certain code paths.
Malware uses hooking to monitor and filter various operations. e.g. File operations can be subverted to prevent security software from seeing malware specific files. HTTP traffic can be intercepted even prior to encryption - used for credential stealing etc.

Security software has similar goals - hence many security applications also hook.

Kernel hooking - ssdt


The system dispatcher table is used to control what driver can service requests from userspace.
Not really useful on new versions of windows due to patchguard.

ssdt plugin:
Entry 0x0073: 0x8060bc6c (NtOpenEventPair) owned by ntoskrnl.exe Entry 0x0074: 0x8056e26a (NtOpenFile) owned by ntoskrnl.exe Entry 0x0075: 0x8056bab6 (NtOpenIoCompletion) owned by ntoskrnl.exe Entry 0x0076: 0x805ca2ac (NtOpenJobObject) owned by ntoskrnl.exe Entry 0x0077: 0x80619f68 (NtOpenKey) owned by ntoskrnl.exe Entry 0x0078: 0x8060c064 (NtOpenMutant) owned by ntoskrnl.exe Entry 0x0079: 0x805e8fcc (NtOpenObjectAuditAlarm) owned by ntoskrnl.exe Entry 0x007a: 0xfca2953e (NtOpenProcess) owned by lanmandrv.sys Entry 0x007b: 0x805e229e (NtOpenProcessToken) owned by ntoskrnl.exe Entry 0x007c: 0x805e1ea4 (NtOpenProcessTokenEx) owned by ntoskrnl.exe

Kernel hooking - Drivers.


In windows IO operations on a device are sent to a driver in an IO Request Packet (IRP):
The IRP contains the data for the IO operation as well as a completion routine. The user space program is free to continue with other tasks while waiting for the IO. The IRP is sent to the driver, and is services asyncronously.

There are several types of IRPs - each type is handled by a different dispatch routing in the driver.

Kernel hooking - Drivers.


In [10]: driverscan address_space=session.kernel_address_space Offset(P) 0x81e97b28 0x81e97f38 0x81f7dda0 #Ptr #Hnd 3 7 3 Start Size Service Key Name Gpc PSched Msfs

The windows _DRIVER_OBJECT:


Instantiate 0 0xf8711000
0 0 0xf88f9000

Scan for drivers in the kernel address space.

Driver Name \Driver\Gpc \Driver\PSched \FileSystem\Msfs

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

a 0x8900 Gpc _DRIVER_OBJECT at this address. 0xf819f000 0x10e00 PSched


0x4a80 Msfs

In [11]: d = session.profile._DRIVER_OBJECT(0x81f7dda0) In [12]: p d [_DRIVER_OBJECT _DRIVER_OBJECT] @ 0x81F7DDA0 0x1C DriverName 0x38 MajorFunction [_UNICODE_STRING DriverName] @ 0x81F7DDBC <IndexedArray 28 x Pointer @ 0x81F7DDD8>

In [13]: p d.MajorFunction <IndexedArray 28 x Pointer @ 0x81F7DDD8> 0x0000 <Function Pointer to [0xF88FA2B0] (IRP_MJ_CREATE)> 0x0002 <Function Pointer to [0xF88FAD74] (IRP_MJ_CLOSE)> 0x0003 <Function Pointer to [0xF88F9E62] (IRP_MJ_READ)> 0x0004 <Function Pointer to [0xF88FA0B4] (IRP_MJ_WRITE)>

Each element of this array points to a different function.

Kernel hooking - Drivers.


When an IO Request Packet (IRP) is created by the kernel for this device, the kernel uses the MajorFunction table to pass the IRP to the driver for processing. A couple of ways for subversion
Malware can install their own handler for this device so it legitimately receives the IRP for processing (layered model). A malicious driver can insert a detour in another driver to intercept IRPs intended for the legitimate driver.

IRP IRP IRP

Malicious Driver Driver 1 Driver 1 Driver 2 Driver 2 Driver 2 Malicious Driver Driver 1

Driver 3 Driver 3

Driver 3

Normal handling of IRP

Attaching to device as a filter driver.

Detour hooking through the Major Function Table

Kernel hooking - driverirp


driverirp scans for drivers and enumerates their major
functions. These functions are then located in their respective driver.
In [15]: driverirp .... ************************************************** DriverName: Teefer DriverStart: 0xf837d000 DriverSize: 0x1d000 DriverStartIo: 0x0 Func Name 0 IRP_MJ_CREATE 1 IRP_MJ_CREATE_NAMED_PIPE 2 IRP_MJ_CLOSE 3 IRP_MJ_READ 4 IRP_MJ_WRITE 5 IRP_MJ_QUERY_INFORMATION 6 IRP_MJ_SET_INFORMATION Func Addr Module ---- ------------------------------------ ---------- -----------------------------0xf83852c0 Teefer.sys 0x805031be \WINDOWS\system32\ntoskrnl.exe 0xf8385380 Teefer.sys 0xf8386e40 Teefer.sys 0xf8386e10 Teefer.sys 0x805031be \WINDOWS\system32\ntoskrnl.exe 0x805031be \WINDOWS\system32\ntoskrnl.exe

This driver only handles some IRPs

Usermode hooks
Malware can intercept functions used by user mode programs.
Malware Code dll 1 code Legitimate process IAT in memory Binary Code Section dll 1 code Detour/ Trampoline Malware Code

FinFisher - A commercial rootkit. https://citizenlab. org/2012/07/from-bahrainwith-love-finfishers-spy-kitexposed/

Hijack code is located in an injected memory region

Trampoline hook installed

https://citizenlab.org/wp-content/uploads/2012/07/image29-500.png

Registry Dumping
The windows registry is a central location for configuration data.
A rich source of evidence in a digital investigation. There are many tools that can analyse registry files.

The registry is cached in memory


Registry data is stored in hives. Hives are divided into HBins. HBins are cached in memory.

Volatility has a full registry parser and a bunch of modules to deal with registry.
Forensic Analysis of the Windows Registry in Memory. - Brendan Dolan-Gavitt. DFRWS 2008

Registry in Memory
_CMHIVE: System _CMHIVE: Software Linked list

Hive.Storage.Map[].Directory[].Table[].BlockAddress Structure is very similar to a page table which refers to HBINS. If a HBIN is not frequently used it will be paged out (i.e. not memory resident). When a program attempts to read a key which is contained in this HBIN - the HBIN will be paged into memory.

HBIN

HBIN

Not resident

HBIN

Registry in Memory
In [5]: hivescan ------> hivescan() Offset(V) Offset(P) Name 0xe102e008 0x02837008 [no name] @ 0xe102e008 0xe1035b60 0x0283db60 \Device\HarddiskVolume1\WINDOWS\system32\config\system @ 0xe1035b60 0xe1558578 0x02d63578 [no name] @ 0xe1558578 ..... In [9]: printkey key="Software" Legend: (S) = Stable (V) = Volatile ---------------------------Registry: \Device\HarddiskVolume1\Documents and Settings\NetworkService\Local Settings\Application Data\Microsoft\Windows\UsrClass.dat @ 0xe1bf1b60 Key name: Software (S) Last updated: 2005-03-18 21:42:02 Subkeys: (S) Microsoft ....

Registry analysis from memory.


There are some excellent forensic tools for registry analysis:
Regripper Registry Decoder Encase/FTK and other commercial tools

But these tools typically only work with registry files...


So we need to dump out the registry into files.

Dumping out the registry


In [11]: regdump? regdump: Dump all registry hives into a dump directory. Parameter hive_offset Documentation A list of hive offsets as found by hivelist (virtual address). If not provided we call hivescan ourselves and dump all hives found. dump_dir Directory in which to dump hive files. In [12]: regdump dump_dir="/tmp/" ************************************************** Dumping \Device\HarddiskVolume1\WINDOWS\system32\config\system @ 0xe1035b60 into "/tmp/system @ 0xe1035b60" Dumped 5312512 bytes ************************************************** Dumping \Device\HarddiskVolume1\Documents and Settings\Sarah\Local Settings\Application Data\Microsoft\Windows\UsrClass.dat @ 0xe1ecd008 into "/tmp/UsrClass_dat @ 0xe1ecd008" Dumped 8192 bytes

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

Domain Specific Profiles


Memory analysis of modules other than the kernel.
Usually we do not have symbols for applications. We often need different profiles for applications than the kernel.

Still a lot of research to do in this area.

Example: svcscan
Windows drivers are loaded through the service control manager (SCM).
The SCM is a process (services.exe) which keeps additional accounting on which services are currently registered. The process memory can be analysed. We can carve the process memory for tag signatures of _SERVICE_RECORD objects. Use the VadScanner to only look at the process memory. A malicious kernel driver may remove itself from the module list but will remain in the SCM internal lists.

svcscan
In [14]: svcscan Offset: 0x6e1e90 Order: 1 Process ID: Service Name: Abiosdsk Display Name: Abiosdsk Service Type: SERVICE_KERNEL_DRIVER Service State: SERVICE_STOPPED Binary Path: Offset: 0x6e1f20 Order: 2 Process ID: Service Name: abp480n5 Display Name: abp480n5 Service Type: SERVICE_KERNEL_DRIVER Service State: SERVICE_STOPPED Binary Path: -

Netscan - tcpip.sys
The windows TCP/IP stack is implemented by tcpip.sys
No public symbols available. However... Reverse engineering shows basic structures: _TCP_ENDPOINT _UDP_ENDPOINT _TCP_LISTENER These have well recognized pool tags. We can scan for these but structs must be reversed for each version of windows. Information is mostly private to the tcpip.sys module.

Windows 7: netscan
In [7]: netscan Offset(P) Proto Local Address 0.0.0.0:135 :::135 0.0.0.0:49153 :::49153 0.0.0.0:49155 0.0.0.0:49155 :::49155 :49359 10.0.2.15:49363 :49341 10.0.2.15:49254 10.0.2.15:49171 10.0.2.15:49347 :49369 :49368 10.0.2.15:49296 :49358 :49373 Remote Address 0.0.0.0:0 :::0 0.0.0.0:0 :::0 0.0.0.0:0 0.0.0.0:0 :::0 93.184.220.20:80 173.194.35.38:80 82.165.218.111:80 74.125.31.157:80 204.245.34.130:80 173.194.35.36:80 82.165.218.111:80 82.165.218.111:80 74.125.127.148:80 93.184.220.20:80 82.165.218.111:80 State LISTENING LISTENING LISTENING LISTENING LISTENING LISTENING LISTENING CLOSED ESTABLISHED CLOSED CLOSE_WAIT ESTABLISHED CLOSE_WAIT CLOSED CLOSED CLOSE_WAIT CLOSED CLOSED Pid Owner 628 svchost.exe 628 svchost.exe 444 lsass.exe 444 lsass.exe 880 svchost.exe 880 svchost.exe 880 svchost.exe 2820 iexplore.exe 2820 iexplore.exe 2820 iexplore.exe 2820 iexplore.exe 2820 iexplore.exe 2820 iexplore.exe 1892 iexplore.exe 2820 iexplore.exe 2820 iexplore.exe 2820 iexplore.exe 2820 iexplore.exe Created -------------- -------- -------------------- -------------------- ---------------- ----- -------------- ------0x00000f882a30 TCPv4 0x00001121b7b0 TCPv6 0x000017de8980 TCPv4 0x000017de8980 TCPv6 0x000017f35240 TCPv4 0x000017f362b0 TCPv4 0x000017f362b0 TCPv6 0x00001725d010 TCPv4 0x000017270530 TCPv4 0x000017285010 TCPv4 0x000017288a90 TCPv4 0x00001728f6b0 TCPv4 0x000017291ba0 TCPv4 0x000017292cf0 TCPv4 0x0000174e2cf0 TCPv4 0x0000174f9440 TCPv4 0x000017527cf0 TCPv4 0x0000175288b0 TCPv4

Windows XP: connections and sockets


In [3]: connections Offset (V) Local Address 0x820869b0 127.0.0.1:1055 0xffa2baf0 127.0.0.1:1056 0x8220c008 192.168.2.7:1077 0x81f11e70 192.168.2.7:1082 0x8220d6b8 192.168.2.7:1066 In [4]: sockets Offset (V) 0x82004e98 0x82052e98 0x821cad08 0x81341308 0x82036008 0x81fdf968 PID 984 4 1400 4 1948 592 Port 1027 138 19 0 1030 500 Proto Protocol 17 UDP 17 UDP 17 UDP 47 GRE 6 TCP 17 UDP Address 0.0.0.0 192.168.2.7 0.0.0.0 0.0.0.0 0.0.0.0 0.0.0.0 Create Time 2005-06-25 16:48:02 2005-06-25 16:47:48 2005-06-25 16:48:00 2005-06-25 16:48:13 2005-06-25 16:48:05 2005-06-25 16:47:59 ---------- ------ ------ ------ --------------- --------------- ----------Remote Address 127.0.0.1:1056 127.0.0.1:1055 64.62.243.144:80 205.161.7.134:80 199.239.137.200:80 Pid 2160 2160 2392 2392 2392 ---------- ------------------------- ------------------------- ------

Summary for Module 5 - Detecting malware.


Kernel Hooking Userspace Hooking Domain specific profiles:
Registry Dumping Service Control Manager Network connections.

You might also like