Sunday, December 12, 2010

Identifying Memory Images

Have you ever been given a memory image to examine and not known what OS it was? Or maybe you were told it was X when it was really Y? Or perhaps you have a collection of images that may not be labeled correctly?

So how do you figure out the OS of an unknown Windows image?

Strings

You could use strings to look for clues of the OS type. For example looking for the version numbers [1]. You can often find this in close proximity to a DLL name. Two examples (XP and Windows 7) are below:

Windows XP: 5.1.2600


2546060:5.1.2600.0 (xpclient.010817-1148)
2546134:InternalName
2546160:HCAppRes.dll
2546194:LegalCopyright
2546226: Microsoft Corporation. All rights reserved.
2546322:OriginalFilename
2546356:HCAppRes.dll


Windows 7: 6.1.7600.16385 (win7_rtm.090713-1255)


1335896:6.1.7600.16385 (win7_rtm.090713-1255)
1335978:InternalName
1336004:BlbEvents.dll
1336038:LegalCopyright
1336070: Microsoft Corporation. All rights reserved.


How do you determine if the memory image is from a x86 or x64 machine? Well, here you can look for environmental variables like PROCESSOR_ARCHITECTURE and PROCESSOR_ARCHITEW6432 (used for WOW64) [2]. An example from x86 and x64 machines:


PROCESSOR_ARCHITECTURE=x86
PROCESSOR_IDENTIFIER=x86 Family 6 Model 37 Stepping 5, GenuineIntel

PROCESSOR_ARCHITECTURE=AMD64
PROCESSOR_IDENTIFIER=Intel64

PROCESSOR_ARCHITECTURE=x86
PROCESSOR_ARCHITEW6432=AMD64



More details about these variables can be found here.

Still, this is more labor intensive than it need be.

Using _DBGKD_DEBUG_DATA_HEADER64

Remembering a blogpost Moyix wrote about finding kernel global variables in Windows I figured each OS would have a different size after the OwnerTag defined in wdbgext.h:


typedef struct _DBGKD_DEBUG_DATA_HEADER64 {
LIST_ENTRY64 List;
ULONG OwnerTag; //"KDBG"
ULONG Size; //Different for each OS
} DBGKD_DEBUG_DATA_HEADER64, *PDBGKD_DEBUG_DATA_HEADER64;


Moyix gives us the pattern to search for regarding x86 OSes since the end of LIST_ENTRY64 will be 0 for x86 machines [3]:


\x00\x00\x00\x00\x00\x00\x00\x00KDBG


First let's try to find the sizes for each OS:


$ xxd xpsp3x86.dd |less
[skip]
0000b70: 6780 0000 0000 0000 0000 4b44 4247 9002 g.........KDBG..
[skip]

$ xxd win7x86.dd |less
[skip]
0000bf0: ffff ffec 6fbb 83ec 6fbb 8300 0000 0000 ....o...o.......
0000c00: 0000 004b 4442 4740 0300 0000 8084 8300 ...KDBG@........
[skip]


After examining XP, W2K3, Vista, W2K8 and Windows 7 machines (and different service packs), this is what we get (Windows 2000 value not done personally, but taken from Moyix's blog [3]):


OS Size
Windows 2000 \x08\x02
XP \x90\x02
W2K3 \x18\x03
Vista \x28\x03
W2K8 \x30\x03
Windows 7 \x40\x03


Now we need to find the pattern for x64 systems as well. We could do this with a hexdump of memory images to find the KDBG pattern:


$ xxd win7x64.dd |less
[skip]
0000080: f8ff ff10 44a1 0200 f8ff ff4b 4442 4740 ....D......KDBG@
0000090: 0300 0000 f080 0200 f8ff ff60 8f87 0200 ...........`....
[skip]

$ xxd w2k8x64.dd |less
[skip]
0000f10: f8ff ff40 f878 0100 f8ff ff4b 4442 4730 ...@.x.....KDBG0
0000f20: 0300 0000 c060 0100 f8ff ff60 b865 0100 .....`.....`.e..
[skip]


After examining several x64 dumps, the pattern that seemed universal to them was:


'\x00\xf8\xff\xffKDBG'


The header sizes also appear to remain the same for x64 and x86 machines. So there it is. You can search for a unique pattern in the memory image in order to figure out what OS it is. Some examples:

Windows 7x86: '\x00\x00\x00\x00\x00\x00\x00\x00KDBG\x40\x03'
W2K3 x86: '\x00\x00\x00\x00\x00\x00\x00\x00KDBG\x18\x03'
W2K8 x64: '\x00\xf8\xff\xffKDBG\x30\x03'

You could very easily write a Python script to identify Windows memory images using this technique, but you don't have to: This has already been incorporated into the Volatility 1.4 framework in the imageinfo.py plugin. Thanks to Mike Auty (ikelos) for doing the honors :-)

References

[1] List of Windows Versions
http://en.wikipedia.org/wiki/List_of_Microsoft_Windows_versions

[2] HOWTO: Detect Process Bitness
http://blogs.msdn.com/b/david.wang/archive/2006/03/26/howto-detect-process-bitness.aspx

[3] Finding Kernel Global Variables in Windows
http://moyix.blogspot.com/2008/04/finding-kernel-global-variables-in.html

Monday, December 06, 2010

Volatility 1.3 get_plugins Script Update

I've finally gotten around to updating the get_plugins script I wrote a while back for Volatility 1.3 (and finally gotten around to blogging about it). This is due to a few changes in plugins, dependencies and to address difficulties mentioned in lorgor's blog.

MHL has also updated malfind2 to work with Yara 1.4a, so this script is compatible with those changes.

I have only tested this on Ubuntu and Mac OSX (with MacPorts installed).

  1. You must run this script as root

  2. This script also installs Volatility using SVN. If you are running Ubuntu or Mac it will check that SVN is installed, and if not, will install it and pull down Volatility in the current directory.

  3. If you are running Ubuntu or Mac OSX, this script will install other dependencies you will need like pcregrep libpcre++-dev python-dev for Ubuntu or pcre pcre++ for Mac.

  4. This script installs dependencies: pefile, libdasm, pycrypto, yara-python 1.4a, as well as all known Volatility plugins, including the newer VAP ones from MHL


You still have to install Inline::Python on your own.

You can find the script in my GitHub repository or as raw text here