Thursday, March 16, 2006

Windows Physical Memory Analysis, pt II

I've been taking a look at what's out there with regards to analyzing physical memory (RAM) dumps from Windows systems, and correlating what's available. Most of this is in my previous post on the subject, so what I'd like to do now it present some of what I've got so far. I've taken the work that Andreas Schuster (ie, ptfinder.pl) and Joe Stewart (ie, pmodump.pl from the TRUMAN project) have done, done some research on structures such as the PEB, PEB_LDR_DATA, and RTL_USER_PROCESS_PARAMETERS, and taken it a step further, albiet a small one.

Here's what I've got...the Perl code I've got right now parses through the memory dump (I'm using the dump from the DFRWS 2005 Memory Challenge as my initial test case) looking for EPROCESS blocks. Note that this is specific to Windows 2000, as we already know that's what the platform is/was, and so far, I haven't gotten around to working out how to determine the base OS from nothing more than a memory dump file. From there, the code retrieves data from the dump file, parsing structures and handling translations between virtual addresses (and pointers) to physical offsets within the dump file itself. Some of the information that gets pulled for each process includes the FLINK/BLINK values (pointers to previous/next EPROCESS block in the doubly-linked list), creation time (exit time, if applicable), whether exit has been called or not, and the location of the Process Environment Block.

Here's an example:

Possible EPROCESS block located at offset 0x6601460
Process Name : metasploit.exe
PID : 600
Parent PID : 240
FLINK : 0x0
BLINK : 0x0
SubSystem : 4.0
Exit Status : 0
Create Time : Sun Jun 5 00:55:08 2005
Exit Time : Sun Jun 5 00:55:08 2005
Exit Called : 1
PEB : 0x7ffdf000
DTB : 0x01a6d000
PEB Offset : 0x00000000

Notice that for this process named "metasploit.exe", the FLINK/BLINK values are zero'd out, and exit has been called. The offset to the PEB (ie, the physical offset within the dump file) has been calculated to be 0, based on the PEB and DirectoryPageTable values retrieved from the EPROCESS block.

Now, if the process was active at the time that the memory dump was made, the Perl code I wrote will parse the RTL_USER_PROCESS_PARAMETERS structure and retrieve information such as the current directory path, DLL path, command line, window title, and desktop name (I'll add parsing of additional information, such as flag values, once I locate information on the format of these structures). Here's an example:

Possible EPROCESS block located at offset 0x6352d60
Process Name : cmd2k.exe
PID : 1132
Parent PID : 324
FLINK : 0xff1190c0
BLINK : 0xff1440c0
SubSystem : 4.0
Exit Status : 259
Create Time : Sun Jun 5 14:10:52 2005
Exit Called : 0
PEB : 0x7ffdf000
DTB : 0x058dd000
PEB Offset : 0x01862000
Mutant = 0xffffffff
Base Addr = 0x00000000
PEB_LDR_DATA = 0x00131e90 (0x03293e90)
Params = 0x00020000 (0x04126000)
Current Directory Path = E:\Shells\
DllPath = E:\Shells;.;C:\WINNT\System32;C:\WINNT\system;C:\WINNT;
C:\WINNT\system32;C:\WINNT;C:\WINNT\System32\Wbem
ImagePathName = E:\Shells\cmd2k.exe
Command Line = "E:\Shells\cmd2k.exe" /D /T:80 /F:ON /K cmdenv.bat
Window Title = E:\Shells\cmd2k.exe
Desktop Name = WinSta0\Default

From this information, we can see where the process was initiated from, as well as the command line used to launch the process. I'd sure like to see what's in cmdenv.bat!

Oh, and there's more! I was running through the output of the script and found that nc.exe was running when the dump was made...here's the image path and command line for the nc.exe process (PID = 1096):

ImagePathName = c:\winnt\system32\nc.exe
Command Line = "c:\winnt\system32\nc.exe" -L -p 3000 -t -e cmd.exe

Not only did I find a process called dd.exe that had exited, but I also found one that was still running (yeah, I know...it's the one that created the memory dump!). The image path and command line for that process are (note: I cleaned it up a little to make it easier to read):

ImagePathName = E:\Acquisition\FAU\dd.exe
Command Line = ..\Acquisition\FAU\dd.exe if=\\.\PhysicalMemory
of=F:\i
ntrusion2005\physicalmemory.dd conv=noerror
--md5sum --verifymd5 --md5out=F:\in
trusion2005\physicalmemory.dd.md5 --log=F:\intrusion2005\audit.log

So...so far, so good. The Perl code for this is a little too messy to release right now, but I will post it once I clean it up a bit and document it a bit better. I need to add dumping of the module list, and a couple of other functions to the script, as well as parsing for other structures.

Addendum 26 Mar: I've continued working on the code, and moved to a little side project. I've copied the subroutines from the original code and targetted individual EPROCESS blocks...searching the RAM dump for each EPROCESS block was just too slow for some simple testing and coding.

So, anyway...I'm pulling more from the EPROCESS block and PEB. For example, I've been able to pull the Environment variables (if they exist) from the process...the stuff you see when you type "Set" into the command prompt, as well as dumping the loading modules. From the first DFRWS 2005 Memory Challenge memory dump, the cmd2k.exe process uses the following modules:

E:\Shells\cmd2k.exe
C:\WINNT\System32\ntdll.dll
C:\WINNT\system32\KERNEL32.dll
C:\WINNT\system32\USER32.dll
C:\WINNT\system32\GDI32.DLL
C:\WINNT\system32\ADVAPI32.dll
C:\WINNT\system32\RPCRT4.DLL
C:\WINNT\system32\MSVCRT.dll

The Environment contains such things as LOGONSERVER and COMPUTERNAME. Cool stuff.

What I'm up to now is parsing through the handle table, starting with the ObjectTable value from within the EPROCESS block. If anyone wants to throw some pointers my way, I'd appreciate it! ;-)

Addendum 31 Mar: I wanted to get this one in late...if I wait until tomorrow, everyone will think it's a prank! With some help from Andreas, I've been able to extract the handle tables from a process, using the ObjectTable value. Andreas was kind enough to point to me, among other things, that I wasn't translating one of the virtual addresses I was receiving to a physical address.

So, what I've been getting for the cmd2k.exe process looks like this:

Object Header at 0xfcd79010 (0x01396010)
Type Name : File
Type = 5
Size = 112
Name = \Shells

Object Header at 0xfca255c0 (0x010425c0)
Type Name : WindowStation

Object Header at 0xfca255c0 (0x010425c0)
Type Name : WindowStation

Object Header at 0xff29e9e0 (0x052099e0)
Type Name : Desktop

This is what I've been able to extract from the dump. I have to keep reminding myself that the system that the physical memory was dumped from had 128MB of RAM, so some of the virtual addresses will be to pages that have been swapped out of physical memory to the pagefile. I'll be sure to add this to the documentation of the code, and show where that aspect of an address is calculated.

Here's some more eye-candy...the UMGR32.exe process has these two handles:

Object Header at 0xff1bc010 (0x01a8d010)
Type Name : File
Type = 5
Size = 112
Name = \Endpoint

Object Header at 0xff1cf7b0 (0x006827b0)
Type Name : File
Type = 5
Size = 112
Name = \WINNT\system32\Perflib_Perfdata_29c.dat

The nc.exe process also points to a file handle named "\Endpoint".

Now, to get the pages of the memory used by each process...

Saturday, March 04, 2006

Windows Physical Memory Analysis

I'll be writing more on this particular subject as time goes on, but I wanted to post something right away. I've noticed over the past couple of weeks that Andreas Schuster has been doing some work with debuggers, etc., to document some of the structures found in physical memory for various versions of Windows, from Win2000 SP4 through Vista (he's noted that most of the structures change between versions and even between Service Packs). Well, I took a look the other day and noticed that he'd posted something called PTFinder, which as it just so happens is a Perl script that parses a dump of physical memory (this version works for dumps of physical memory from Win2000 SP4 systems).

So, I took a look at what he was doing, and exchanged some emails, and expressed my desire to assist with what he's doing. As it turns out, the DFRWS 2005 Memory Challenge provides a great set of test files (2, actually) for testing any tools you're writing to parse a memory dump generated using dd.exe.

I started working on something of my own, using the exercise as a learning process so that I can not only be smarter on this stuff, but to also assist Andreas with what he's doing. I've got the output of the Memory Challenge submissions to check my work against, and so far, things are working pretty well. Here's an excerpt of the output from my version of the script:

Possible EPROCESS block located at offset 0x3e35ae0
Process Name : Explorer.Exe
PID : 820
Parent PID : 800
Exit Status : 259
Create Time : Sun Jun 5 00:33:53 2005
Exit Called : 0

Possible EPROCESS block located at offset 0x40b4660
Process Name : PcfMgr.exe
PID : 1048
Parent PID : 820
Exit Status : 259
Create Time : Sun Jun 5 00:34:01 2005
Exit Called : 0

Possible EPROCESS block located at offset 0x414dd60
Process Name : dd.exe
PID : 284
Parent PID : 1112
Exit Status : 259
Create Time : Sun Jun 5 14:53:42 2005
Exit Called : 0

Pretty cool, eh? One thing to point out is that processes (specifically, EPROCESS blocks) are maintained in a doubly-linked list. One way to walk through the process blocks is to find one and follow the links...but you can miss things this way. Andreas' approach, and the one I've chosen to follow, is to start at the beginning of the dump file and start looking for process blocks.

There's a lot of work that still needs to be done. Last week, a LEO I know attending the Southeast CyberCrime Summit sent me a message from his Blackberry, asking me if I'd come up with a way to run a tool to dump the contents of physical memory to a thumb drive or some other removable storage platform. In the past, I've talked to folks (particularly LEOs) about why they collect the contents of physical memory, and most have told me that they do so in order to run 'strings' against it to see if they can find leads (not evidence) such as passwords, IP or email addresses, IM screennames, etc. The DFRWS 2005 Memory Challenge didn't result in any publicly available tools but research has continued (like I said, I'll be posting more on this later, and recognizing others who've done research along these lines, particularly Mariusz Burdach and his presentation at BlackHat Federal 2006).

Addendum 7 Mar 2006: Like I said, I wanted to post some more information on this subject, describing what has already gone on, and then hopefully where we need to go with this research.

Last year, I became aware of a paper by Mariusz Burdach that described how to analyze the contents of physical memory that was collected using dd/dd.exe. Being interested primarily in how to do this on Windows, I was a little disappointed that the paper focused on Linux. This sort of thing has been discussed in other areas, the most formal being the DFRWS 2005 Memory Challenge. There has been discussion of this subject in other forums, such as Rootkit.com and Windows Forensic Analysis (Yahoo! Group).

The results of the DFRWS Memory Challenge included two winning responses, one by Chris Betz, and the other by George M. Garner, Jr. and Robert-Jan Mora. Both of these approaches are very involved, and produced some interesting results. The down-side of this work is that neither of the tools mentioned in both winning submissions is publicly available. Andreas Schuster released ptfinder.pl, a Perl script that parses through a dump of Windows physical memory searching for the different structures. Andreas recently posted on the difference between tools like ptfinder.pl and the "list-walkers" produced by Betz and Garner/Mora.

Addendum 9 Mar: Yesterday I became aware of some work by Joe Stewart over at LURHQ.com...specifically, the TRUMAN Project, described as the "reusable unknown malware analysis net". Part of the project is a Perl script called pmodump.pl
, "a Perl-based tool to reconstruct the virtual memory space of a process from a PhysicalMemory dump". The description goes on to say that "with this tool it is possible to circumvent most packers to perform strings analysis on the dumped malware". Very cool, and a great idea.

Pmodump.pl operates a bit differently from the other methods presented so far. The script locates potential Page Directory blocks and then does a translation between "logical" or virtual addresses and physical offsets within the dump file, using the default value for the pointer to the Process Environment Block (PEB) for pre-WinXP systems. The output of the script is very comprehensive, including such things as PE headers for executables loaded into memory (check out the File::ReadPE module to see how to parse this info), module lists, etc.

What this shows is that there have been several different, disparate approaches to this issue, different authors taking different approaches, as their needs and skill sets have been different. This looks like a great opportunity to bring all of these efforts together into a single project.

Another thing I'd like to see is information regarding other kernel structures that can be found within memory. I've got the MS Debugging Tools installed on my system, so all I'm really missing at this point is the correct names of the structures. Does anyone have any pointers?

Addendum 11 Mar: More great reading posted...Andreas has posted a blog entry on translating virtual addresses located in memory dumps to physical offsets within the dump file. Great stuff!

Addendum 14 Mar: I got a call late last night, just before CSI:Miami started (note to self: unplug phone when any version of CSI starts...)...evidently this blog entry had been mentioned in the 11 Mar Cyberspeak podcast! If you look at the main page, you'll see that many a famous name in the community has been interviewed by these guys...I haven't made it a habit of listening to these podcasts, but that's about to change. For the record, though, guys, it's "windowsir", not "windows", "s", "i", "r".

Friday, March 03, 2006

ProScript posted

I've posted another ProScript to the Techpathways forum...this one consolidates the other two that I previously posted. It dumps user information by parsing the F and V structures from the user's Registry key in the SAM hive, and gets group information by parsing the C structure from the group's key in the SAM hive. Note: The version of the ProScript that I posted to the forum doesn't try to translate any of the FILETIME objects found in the F structure.

Here's an excerpt from output from the script (one of the ones that does attempt to translate FILETIME objects), with user information displayed. I have an image that I downloaded from the Internet (one of those online challenges) open:

Username : Mr. Evil
Acct Creation Date : Thu Aug 19 23:03:54 2004
RID : 1003
Logins : 15
Flags :
Password does not expire
Normal user account

I have to go back and take a look at that script again...I wonder why my translation subroutine thinks that if Mr. Evil logged in 15 times, that he doesn't have a last login date. Hhhmmm...that's easy enough to check, though...I'll just have ProDiscover dump the appropriate key value to a file, and I'll open that in a hex editor. Either way, it's really cool stuff, being able to pull this sort of thing from the Registry. Now, correlate that with (a) the contents of the ProfileList Registry key, and (b) the "Documents and Settings" directory contents, and you've got a pretty comprehensive look at who's been logging into the system.

Here's an excerpt of that the group information looks like:

Group : Administrators
Comment : Administrators have complete and unrestricted access to the computer/domain
--> Administrator
--> Mr. Evil

I had a good deal of help from two sources in particular, Andreas Schuster and Peter Nordahl. Andreas provided information about the C structure, and Peter's NT bootdisk source code laid out what the F and V structures "look like". Very helpful...thanks to you both.