Winpmem may appear to be a simple a memory acquisition tool, but it is really much more. In yesterday's diary I gave a brief introduction to the tool and showed how you can use it to create a raw memory image. If you didn't see that article check it out for the background needed for today's installment. You can read it here.
One of my favorite parts of Winpmem is that it has the ability to analyze live memory on a running computer. Rather than dumping the memory and analyzing it in two seperate steps you can search for memory on a running system. Of course this will affect other forensics artifacts so you only want to use this on backup copies of your evidence. But this is also useful outside of forensics. There are all kinds of useful ways to use this tool. Searching for memory is useful to security reasearchers. You can search memory for strings that are in common pieces of malware. Do software vendors tell you that they encrypt sensative data in memory? You can use this tool to see if that is really true. So how do you do it?
Winpmem allows you to install the memory access device driver and then use it in your own Python scripts. To install the device driver run winpmem with the -L option like so:
Once the driver is installed it will create a \\.\pmem device object that you can open with Python. You will notice that it also reports 3 memory ranges. These are the ranges of physical memory addreses where the operating system stores data. In this case the first memory range starts at 0x1000 and has a length of 0x9e000. So it ends at memory address 0x9f000. The second range starts at 0x100000 and has a length of 0x3fdf0000. This leaves a conspicuous gap between the ranges. These gaps are used by the processor and other chipsets on your computer and aren't directly addressible by the Windows memory manager. Memory acquisition tools will only dump those ranges of memory used by the OS. This could lead to some interesting research where malware hides in those memory blind spots. Winpmem also has the ability to read those reserved areas of memory but doing so may lock up your machine.
To read memory it will require a little bit of Python code, but winpmem does the hard part for you. You can read memory with only 4 lines of Python code. All we have to do is import winpmem, create a handle to a file with win32file.CreateFile (the "fd" variable in the program below). Then use win32file.SetFilePointer() to point to the address you want to read. Finally call win32file.ReadFile() to read the bytes at that memory location. Thats it! So I threw together a quick script to allow me to search memory. I called this script "memsearch.py" when I saved it to my computer.
from winpmem import *
After writing the program I run python with the "-i" option so that I am dropped into an interactive shell with the new modules and variables already defined. I'll get an interactive Python prompt that I can use to call the memsrch() and readmem() functions. Because it is in a shell I can run multiple searches with different options until I find what I am looking for. Here is a short example calling each function once, In this case I read 100 bytes of memory starting at 18352196. Then I search for 5 occurences of the word "password" beginning at the address 0x100000.
readmem() is used to read data from memory. The readmem() function takes 3 parameters. The first is fd. This is the file handle that points to the \\.\pmem device created by the winpmem device driver. The 2nd parameter is the address to start reading from and the 3rd parameter is how much data to read.
memsrch() can be used to search memory for the string you specify. The memsrch() function takes several options. The first is again fd. The 2nd parameter is the search tearm to find in memory. The 3rd parameter is the starting address to being searching and the 4th parameter is the ending address. The rest of the parameters are optional. The 5th parameter is the number of matches to find in memory. The 6th parameter is used to turn on Verbose searching. If verbose is true the matching strings are printed to the screen. The last argument is the "includepython" argument. If includepython is set to True then it will allow the Python script to find itself as it searches through memory for matches.
Keep in mind that you are searching Physical memory. This is much different that virtual OS memory. Things may move around and you may find things in places where you do not expect them. To get a better understanding of how memory is being used by the OS read this excellent paper that accompanies the tool.
Still not convinced of winpmem's awesomeness? There is more to it. I'll look at more tomorrow.
Do you want to learn how to do all sorts of cook stuff with Python? Check out SEC573 Python for Penetration testers! I am teaching it in Reston VA March 17th! Click HERE for more information.
Follow me on twitter? @MarkBaggett
Nov 20th 2013
6 years ago