A common way that people start their analysis is to look at differences in output of plugins that represent what the OS knows about (pslist/modules/connections/sockets etc) vs scanning for possible hidden/unlinked items. Examples of this can be seen in Jesse Kornblum's pstotal, Command Line Kung Fu's Making a Difference and MHL's psxview (which actually is very useful).
If you look at some of these examples, you might think to yourself that it's difficult to write a plugin to get a process difference, but it's really not! You can use inheritance to make your life easier.
PSList vs. PSScan2
Below is a complete plugin for printing out the difference between pslist and psscan2, which we will go over in detail.
1 import volatility.plugins.taskmods as taskmods
2 import volatility.plugins.filescan as filescan
3
4 class PSDiff(filescan.PSScan2):
5 """Print processes found in psscan2, but not in pslist"""
6
7 def __init__(self, config, *args):
8 filescan.PSScan2.__init__(self, config, *args)
9
10 def calculate(self):
11 pslist = taskmods.PSList(self._config).calculate()
12 pids = []
13 for task in pslist:
14 pids.append(task.UniqueProcessId.v())
15
16 psscan = filescan.PSScan2.calculate(self)
17 for task in psscan:
18 if task.UniqueProcessId.v() not in pids:
19 yield task
First you need to import the plugin files that contain the classes you want to inherit into your plugin file. In this case PSList is defined in volatility/plugins/taskmods.py and PSScan2 is defined in volatility/plugins/filescan.py. You can see the import in lines (1-2). Now you have to define the class for your plugin (line 4). Try to give it a meaningful name for what it does, here we will name it PSDiff. Classes should be named in CamelCase. In the parentheses after the class name we will specify which classes we want to inherit. Since we want processes that are only found in psscan2 output, we will use the render_text output function of psscan2 without having to redefine it. Therefore, since we want for our new class to be more like psscan2, we choose this class to inherit. We specify it as filescan.PSScan2 because we had imported the plugin file as "filescan" and the class for pssscan2 is named "PSScan2".
Next on line 5, we add a description of what this plugin does as a multiline comment. Whatever you type here will appear in the help function when you run python vol.py [plugin] -h, or just python vol.py -h.
Lines 7-8 are the initialization and options section of the plugin. We are not adding any command line options to this plugin and are just initializing the PSScan2 class that we inherited.
Lines 10-19 define the calculate part of our plugin, or what we want the plugin to do. In this case we only want to print out processes that are found by psscan2 and not pslist, so should decide how to do that... Since processes should have unique process IDs (PIDs) to specify unique processes. So PIDs that are found in psscan2, but not in pslist will be printed.
Let's walk through the calculate function. First we gather all processes that pslist knows about (line 11). We call the taskmods.PSList class, give it our configuration (self._config) so that it can know what profile to use and call its calculate function, which returns eprocess objects (and really is just DllList's calculate function, but we'll ignore that for now). In line 12, we define an empty list to store PIDs from pslist in order to compare to psscan2's PIDs. Lines 13-14 collect all the PIDs pslist knows about.
Now lines 16-19 repeat the process for psscan2 except that instead of collecting PIDs into a list, we check to see if the PID we've encountered is already in the list of PIDs from pslist. If it isn't, then we yield the task that contains that PID so that it will be caught by psscan2's render_text function and output onto the screen.
The output? Here you can see what it looks like on a Windows 7 image:
$ python vol.py -f win7.dd --profile=Win7SP0x86 psdiff
Volatile Systems Volatility Framework 1.4_rc1
Offset Name PID PPID PDB Time created Time exited
---------- ---------------- ------ ------ ---------- ------------------------ ------------------------
0x3eac6030 SearchProtocol 2448 1168 0x3ecf15c0 2010-06-16 23:30:52 2010-06-16 23:33:14
0x3eb10030 SearchFilterHo 1812 1168 0x3ecf1480 2010-06-16 23:31:02 2010-06-16 23:33:14
0x3f0576a0 svchost.exe 2836 508 0x3ecf15c0 2010-06-16 17:02:34 2010-06-16 17:08:43
0x3faa66e8 dllhost.exe 948 628 0x3ecf1540 2010-06-16 23:32:15 2010-06-16 23:32:21
0x3fbcf920 dllhost.exe 3776 628 0x3ecf11e0 2010-06-16 23:32:09 2010-06-16 23:32:15
The only difference in this case seems to be exited processes.
Here you can see a run on Moyix's ds_fuzz image:
$ python vol.py -f ds_fuzz_hidden_proc.img psdiff
Volatile Systems Volatility Framework 1.4_rc1
Offset Name PID PPID PDB Time created Time exited
---------- ---------------- ------ ------ ---------- ------------------------ ------------------------
0x0181b748 alg.exe 992 660 0x08140260 2008-11-15 23:43:25
0x0185dda0 cmd.exe 940 1516 0x081401a0 2008-11-26 07:43:39 2008-11-26 07:45:49
0x018af020 taskmgr.exe 808 620 0x08140280 2008-11-26 07:45:22 2008-11-26 07:45:40
0x019456e8 csrss.exe 592 360 0x08140040 2008-11-15 23:42:56
0x01946020 svchost.exe 828 660 0x081400c0 2008-11-15 23:42:57
0x019467e0 services.exe 660 616 0x08140080 2008-11-15 23:42:56
0x0194f658 svchost.exe 1016 660 0x08140100 2008-11-15 23:42:57
0x019533c8 svchost.exe 924 660 0x081400e0 2008-11-15 23:42:57
Suppose you are concerned that a PID could have been overwritten somehow (DKOM). You could rewrite the plugin to use _EPROCESS offsets instead of PIDs for a check:
1 import volatility.plugins.taskmods as taskmods
2 import volatility.plugins.filescan as filescan
3
4 class PSDiff(filescan.PSScan2):
5 """Print processes found in psscan2, but not in pslist"""
6
7 def __init__(self, config, *args):
8 filescan.PSScan2.__init__(self, config, *args)
9
10 def calculate(self):
11 pslist = taskmods.PSList(self._config).calculate()
12 offsets = []
13 for task in pslist:
14 offsets.append(task.obj_vm.vtop(task.obj_offset))
15
16 psscan = filescan.PSScan2.calculate(self)
17 for task in psscan:
18 if task.obj_offset not in offsets:
19 yield task
The changes are in lines 12, 14 and 18. The idea is the same as our PID plugin above, only with offsets. So we rename our list to offsets to make it clearer (line 12). We append the physical address of where our _EPROCESS object is found (line 14), this is because scanners like psscan2 only output physical addresses so we want to make sure that the addresses from pslist are the same. In line 18 we check to see if our _EPROCESS object offset found by psscan2 is already found by pslist and if not we yield it so that its information will be printed. Output is the same as what we saw above for our two test images.
Conclusion
So there you have it. You can use the same idea for comparing output from modules and modscan, connections and connscan2, sockets and sockscan or files and filescan etc... (I'm leaving this as an exercise for the reader ;-)).
You can check also out the references below for further reading on Python and Volatility. Make sure to read the Volatility Plugin Writers Guide that Mike Auty and Scudette put together.
Update: I just noticed that MHL also gave the Command Line Kung Fu crew a psdiff example. You can check out another way of doing things over there.
Update 2: I just updated the code to work with the current changes in the svn (we moved psscan2 to filescan).
References
Google Python Class http://code.google.com/edu/languages/google-python-class/
Python 2.7 Tutorial http://docs.python.org/tutorial/
Volatility Plugin Writers Guide http://code.google.com/p/volatility/wiki/PluginWritersGuide
2 comments:
Thank YOU!!
Very good stuff. Thanks for the tutorial. I also enjoyed your Timeliner tutorial in the release's PDF.
Post a Comment