GDI Utilities: Taking Screenshots of Memory Dumps
I've posted about this before (twice!), but somehow never gotten around to releasing functioning code. Here (click), for your downloading pleasure, is a set of plugins designed to extract information about on-screen (graphical) windows from Windows XP SP2/3 memory images. This includes:
- window_list - give a text listing of the window hierarchy, with each window's on-screen coordinates, current style, and its class (Button, Window, etc.). Here's some example output to whet your appetite.
- screenshot - save a wireframe "screenshot" of the on-screen windows in a memory image. See later in this post for some examples. Requires PIL.
- wndmon - continuously monitor a memory image and provide an updating view of the on-screen windows. Works best in a live environment, e.g. with XenAccess and PyXa. Requires PyGame. (This is what I used for the video demo).
- Get distorm3 from its Google Code site.
- Go into build/linux and type "make".
- Copy the resulting libdistorm3.so into the Python directory.
- Rename the Python directory to "distorm" and move it somewhere in your Python path (I use Debian, and found that /usr/local/lib/python2.6/dist-packages/ worked well).
Have fun with the code. If you go exploring in the source, you may find some interesting things -- there's more functionality there than is exposed through the plugins, including some functions and data structures that can extract HTML content from IE in memory... ;)
Anyway, to wrap things up, here's an example of the output from the screenshot plugin, running on the two NIST memory images:
From the 6/25 image:
From the 7/4 image:
And that, my friends, is the power of memory analysis.
Comments
$ python volatility window_list -f ram.dd
Traceback (most recent call last):
File "volatility", line 219, in
main()
File "volatility", line 215, in main
command.execute()
File "memory_plugins/windowlist.py", line 142, in execute
UserAtomTableHandle = read_value(addr_space, 'pointer', atom_table_off)
File "/cygdrive/d/Downloads/Volatility-1.3_Beta/forensics/object.py", line 71, in read_value
AttributeError: 'NoneType' object has no attribute 'read'
Traceback (most recent call last):
File "./volatility", line 219, in
main()
File "./volatility", line 215, in main
command.execute()
File "memory_plugins/screenshot.py", line 113, in execute
atom_table_off = find_atomtable(addr_space, types, symtab, theProfile)
File "/pentest/forensics/volatility/forensics/win32/findatomtable.py", line 94, in find_atomtable
uaa_addr = find_UserAddAtom(thrd.vm, reg_addr)
File "/pentest/forensics/volatility/forensics/win32/findatomtable.py", line 55, in find_UserAddAtom
asm = Decode(reg_addr, fn_data, Decode32Bits)
File "/usr/lib/python2.5/distorm/__init__.py", line 440, in Decode
return list( DecodeGenerator(offset, code, type) )
File "/usr/lib/python2.5/distorm/__init__.py", line 408, in DecodeGenerator
p_code = byref(code_buf, instruction_off)
TypeError: byref() takes exactly one argument (2 given)
=======================
Steps taken - linux "BackTrack4R2"
1- downloaded http://distorm.googlecode.com/files/distorm3.zip
2- unzip && cd include && cp * ../
I did that because of error complaining about missing files
3- cd ../make/linux && make
the result was libdistorm3.so
4- put libdistorm3.so & __init__.py in one directory called "distorm" && cp /usr/lib/python2.5/
thanks in advance for the help, and thanks for your excellent tools that have proven to be life-savers...
It works! :)
thanks again, and again, your tool made me look good...
I use a Win7 system and the solution for getting distorm imported was copying
c:\Python27\Lib\site-packages\distorm3\ to
c:\Python27\Lib\site-packages\distorm\
Sadly screenshot as the most impressive feature caused an error:
c:\Micha\Forensics\Volatility-1.4>python volatility screenshot -f D:\X-Ways-Images\RAMHans_RipperFRES.001
Saving screenshot to 624.81d64980.png
Traceback (most recent call last):
File "volatility", line 219, in
main()
File "volatility", line 215, in main
command.execute()
File "c:\Micha\Forensics\Volatility-1.4\memory_plugins/screenshot.py", line 152, in execute
gdi.traverse_windows(win, fun=draw_win, do_node=gdi.is_visible)
File "c:\Micha\Forensics\Volatility-1.4\forensics\win32\gdi.py", line 306, in traverse_windows
traverse_windows(cur.pChildWindow,fun=fun,do_node=do_node,level=level+1)
File "c:\Micha\Forensics\Volatility-1.4\forensics\win32\gdi.py", line 306, in traverse_windows
traverse_windows(cur.pChildWindow,fun=fun,do_node=do_node,level=level+1)
File "c:\Micha\Forensics\Volatility-1.4\forensics\win32\gdi.py", line 303, in traverse_windows
fun(cur, level)
File "c:\Micha\Forensics\Volatility-1.4\memory_plugins/screenshot.py", line 138, in draw_win
text = gdi.get_editbox_text(win)
File "c:\Micha\Forensics\Volatility-1.4\forensics\win32\gdi.py", line 427, in get_editbox_text
return ed.hBuf
File "c:\Micha\Forensics\Volatility-1.4\forensics\object2.py", line 96, in __getattribute__
return object.__getattribute__(self, attr)
File "c:\Micha\Forensics\Volatility-1.4\memory_objects\Windows/gdi.py", line 163, in getBuf
s = RtlRunDecodeUnicodeString(self.encKey, s)
File "c:\Micha\Forensics\Volatility-1.4\forensics\object2.py", line 109, in __getattribute__
off = self.get_member_offset(attr, relative=True)
File "c:\Micha\Forensics\Volatility-1.4\forensics\object2.py", line 200, in get_member_offset
thisMemberType = self.type.get_member(memname)
File "c:\Micha\Forensics\Volatility-1.4\forensics\object2.py", line 413, in get_member
return self.members[memname]
KeyError: 'encKey'
Any help appreciated...
@Brendan: The Vol2.0-version will be launched this week, right? ;-)