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

6 comments:

neofito said...

Great work!

I tried in Windows Vista Home Premium SP2 (x86) and the result is the same that for Windows 2008 SP0 x86 (\x00\x00\x00\x00\x00\x00\x00\x00KDBG\x30\x03).

Jamie Levy said...

Thanks for testing it out, neofito :-)

hrmmmm... that's interesting that it chose that profile. Vista and W2K8 are very close. I hadn't tested against Vista Home though.

Do any of the other commands work if you pass the --profile ? like:

python volatility pslist -f [image] profile=VistaSP0x86 ?

Reason why I'm asking is because imageinfo attempts to match against every profile address space if the suggested profile does not exist or match.

neofito said...

Microsoft (R) Windows Debugger Version 6.12.0002.633 X86
Copyright (c) Microsoft Corporation. All rights reserved.


Loading Dump File [test.dmp]
Kernel Complete Dump File: Full address space is available

Symbol search path is: SRV*C:\websymbols*http://msdl.microsoft.com/download/symbols;srv*c:\websymbols
*http://msdl.microsoft.com/download/symbols
Executable search path is:
Windows Server 2008/Windows Vista Kernel Version 6002 (Service Pack 2) MP (2 procs) Free x86 compatible
Product: WinNt, suite: TerminalServer SingleUserTS Personal
Built by: 6002.18267.x86fre.vistasp2_gdr.100608-0458
Machine Name:
Kernel base = 0x81e48000 PsLoadedModuleList = 0x81f5fc70
Debug session time: Thu Nov 4 21:32:32.357 2010 (UTC + 1:00)
System Uptime: 0 days 0:23:40.328


C:\Volatility-1.4_rc1>volatility.py -f test.dmp imageinfo
Volatile Systems Volatility Framework 1.4_rc1
Determining profile based on KDBG search...
Suggested Profile : Win2008SP0x86 (Instantiated as WinXPSP2x86)
AS Layer1 : JKIA32PagedMemoryPae (Kernel AS)
AS Layer2 : WindowsCrashDumpSpace32 (C:\Volatility-1.4_rc1\test.dmp)
AS Layer3 : FileAddressSpace (C:\Volatility-1.4_rc1\test.dmp)
PAE type : No PAE
DTB : 0x122000
KPCR : 0xffdff000L
KUSER_SHARED_DATA : 0xffdf0000L
Image date and time : 2010-11-04 20:32:32 UTC+0000
Image local date and time : 2010-11-04 21:32:32 +0100

C:\Volatility-1.4_rc1>volatility.py -f test.dmp pslist --profile=VistaSP0x86
Volatile Systems Volatility Framework 1.4_rc1
Name Pid PPid Thds Hnds Time
Could not list tasks, please verify the --profile option and whether this image is valid

Jamie Levy said...

So some background: the last service packs for Vista and W2k8 were released as one. Vista SP2 does have the same signature as W2k8.

The imageinfo plugin of Volatility will attempt to use the suggested profile, but if it does not match up, it will attempt to use every other available profile until it either finds a match or does not. You will see the preferred match if this happens like (Instantiated as X), where X is the preferred match. For some reason your sample seems closer to WinXPSP2x86 in your output...

So what this means, is that the Vista profile currently in Volatility is not compatible with your memory image. It seems to be more an issue of Home vs. Professional (or some other build). Therefore another profile for Vista Home will need to be generated.

If the VistaSP0x86 profile had been matched, you would see something like this:

$ ./volatility.py imageinfo -f vistaSP2x86.vmem
Volatile Systems Volatility Framework 1.4_rc1
Determining profile based on KDBG search...
Suggested Profile : Win2008SP0x86 (Instantiated as VistaSP0x86)
AS Layer1 : JKIA32PagedMemoryPae (Kernel AS)
AS Layer2 : FileAddressSpace (vistaSP2x86.vmem)
PAE type : No PAE
DTB : 0x122000
KPCR : 0x818fe800
KUSER_SHARED_DATA : 0xffdf0000
[snip]
Image Type : Service Pack 2

ForensicZone said...

Jamie
I use the following GREP that is basically looking for the metadata in NTOSKRNL.exe image in the memory dump. Immediately following a hit is the Windows Operating System Version by version number. So far this expression has worked on versions Win2000 to Win7.

\x4E\x00\x54\x00\x20\x00\x4B\x00\x65\x00\x72\x00\x6E\x00\x65\x00\x6C\x00\x20\x00\x26\x00\x20\x00\x53\x00\x79\x00\x73\x00\x74\x00\x65\x00\x6D\x00\x00\x00\x00\x00[\x00-\xFF]\x00[\x00-\xFF]\x00\x01\x00\x46\x00\x69\x00\x6C\x00\x65\x00\x56\x00\x65\x00\x72\x00\x73\x00\x69\x00\x6F\x00\x6E\x00\x00\x00\x00\x00

I use this GREP in my OS identifying Enscript


“Thank You” for the addition information.

Richard McQuown
ForensicZone.com

ForensicZone said...

Jamie
I use the following GREP that is basically looking for the metadata in NTOSKRNL.exe image in the memory dump. Immediately following a hit is the Windows Operating System Version by version number. So far this expression has worked on versions Win2000 to Win7.

\x4E\x00\x54\x00\x20\x00\x4B\x00\x65\x00\x72\x00\x6E\x00\x65\x00\x6C\x00\x20\x00\x26\x00\x20\x00\x53\x00\x79\x00\x73\x00\x74\x00\x65\x00\x6D\x00\x00\x00\x00\x00[\x00-\xFF]\x00[\x00-\xFF]\x00\x01\x00\x46\x00\x69\x00\x6C\x00\x65\x00\x56\x00\x65\x00\x72\x00\x73\x00\x69\x00\x6F\x00\x6E\x00\x00\x00\x00\x00

I use this GREP in my OS identifying Enscript


“Thank You” for the addition information.

Richard McQuown
ForensicZone.com