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:\intrusion2005\physicalmemory.dd conv=noerror
--md5sum --verifymd5 --md5out=F:\intrusion2005\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...
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:\intrusion2005\physicalmemory.dd conv=noerror
--md5sum --verifymd5 --md5out=F:\intrusion2005\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...