ralphymoto / volatility

Automatically exported from code.google.com/p/volatility
GNU General Public License v2.0
0 stars 0 forks source link

kdbgscan - sanity checks and more informational output #268

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
kdbgscan with the current signature-finding technique works great for small 
memory dumps, but once you get into the 1GB - 2GB or greater sizes, kdbgscan 
can yield hundreds of potential KDBG structures. At that point, its useless 
because no one's going to pass that many addresses to --kdbg in trial and 
error. 

So we need to consider some additional sanity checks that will not yield FPs 
but also not skip valid KDBGs. This issue is similar to Issue #224, however we 
found that the sanity check described in that issue (Header.List) does not 
always work. Gleeda and I have worked out a potential solution, patches 
forthcoming. 

Also while we're at it, I think we should beef up the output from kdgscan so 
its not just a (P) and (V) address. We could show some of the critical values 
(like address of PsActiveProcessHead) just to be informational, or to help the 
user decide which of the potential KDBG structures is most likely to be valid. 

Original issue reported on code.google.com by michael.hale@gmail.com on 1 Jun 2012 at 1:44

GoogleCodeExporter commented 8 years ago
The sanity checks can be extended to reduce the FP to an acceptable level, even 
if you find that you can not reflect through the Header.List member always. 
Certainly you can try to follow PsActiveProcessHead and reflect through that, 
or even PsLoadedModuleList. There is no reason why the scanner can not do these 
checks to reduce the FPs.

The point is that the scan is signature free so works on all windows versions, 
and extremely fast. Currently I can see about a 5x-10x speedup in the scudette 
branch over trunk (e.g. pslist in trunk takes around 5 sec and in scudette 
branch about 0.6 sec) and I think probably about 2 seconds of that is due to 
the trunk kdbg scan being sub optimal.

Original comment by scude...@gmail.com on 6 Jun 2012 at 1:04

GoogleCodeExporter commented 8 years ago
Hey Scudette, 

The speed improvement sounds impressive. Unfortunately every time I check out 
the branch to test something, I don't end up getting very far. Without a branch 
to test with, or a clear cut patch for trunk, its difficult to work with. I 
took some commands you posted in Issue #224 and got the following. Is there 
something I'm doing wrong? 

$ svn info
Path: .
URL: https://volatility.googlecode.com/svn/branches/scudette
Repository Root: https://volatility.googlecode.com/svn
Repository UUID: 8d5d6628-2090-11de-9909-f37ff7dbbc12
Revision: 1847
Node Kind: directory
Schedule: normal
Last Changed Author: scudette@gmail.com
Last Changed Rev: 1832
Last Changed Date: 2012-06-04 20:54:13 -0400 (Mon, 04 Jun 2012)

$ python vol.py 
Welcome to volshell! 
To get help, type 'help()'
>>> session.filename = 
"/Users/Michael/Desktop/memory/Win7SP0x86/win7_mcafee.vmem"
>>> session.profile = "Win7SP0x86"
>>> vol(plugins.pslist)
> /Users/Michael/volatility_scudette/volatility/obj.py(1338)Object()
-> logging.warning("Cant find object {0} in profile {1}?".format(theType, self))
(Pdb) Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/Users/Michael/volatility_scudette/volatility/session.py", line 351, in vol
    result = plugin_cls(**kwargs)
  File "/Users/Michael/volatility_scudette/volatility/plugins/windows/taskmods.py", line 61, in __init__
    super(WinPsList, self).__init__(**kwargs)
  File "/Users/Michael/volatility_scudette/volatility/plugins/windows/common.py", line 413, in __init__
    super(WinProcessFilter, self).__init__(**kwargs)
  File "/Users/Michael/volatility_scudette/volatility/plugins/windows/common.py", line 366, in __init__
    super(KDBGMixin, self).__init__(**kwargs)
  File "/Users/Michael/volatility_scudette/volatility/plugin.py", line 149, in __init__
    super(KernelASMixin, self).__init__(**kwargs)
  File "/Users/Michael/volatility_scudette/volatility/plugin.py", line 185, in __init__
    self.session.plugins.load_as(session=self.session)
  File "/Users/Michael/volatility_scudette/volatility/plugins/core.py", line 151, in __init__
    **kwargs)
  File "/Users/Michael/volatility_scudette/volatility/plugins/core.py", line 179, in GuessAddressSpace
    astype=astype, profile=self.profile, **kwargs)
  File "/Users/Michael/volatility_scudette/volatility/plugins/addrspaces/amd64.py", line 53, in __init__
    super(AMD64PagedMemory, self).__init__(**kwargs)
  File "/Users/Michael/volatility_scudette/volatility/plugins/addrspaces/intel.py", line 93, in __init__
    find_dtb = self.session.plugins.find_dtb(session=self.session)
  File "/Users/Michael/volatility_scudette/volatility/plugins/windows/common.py", line 98, in __init__
    "_EPROCESS", "ImageFileName")
  File "/Users/Michael/volatility_scudette/volatility/obj.py", line 1187, in get_obj_offset
    tmp = self._get_dummy_obj(name)
  File "/Users/Michael/volatility_scudette/volatility/obj.py", line 1182, in _get_dummy_obj
    tmp = self.Object(theType = name, offset = 0, vm = self._dummy)
  File "/Users/Michael/volatility_scudette/volatility/obj.py", line 1338, in Object
    logging.warning("Cant find object {0} in profile {1}?".format(theType, self))
  File "/Users/Michael/volatility_scudette/volatility/obj.py", line 1338, in Object
    logging.warning("Cant find object {0} in profile {1}?".format(theType, self))
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/bdb.py", line 48, in trace_dispatch
    return self.dispatch_line(frame)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/bdb.py", line 66, in dispatch_line
    self.user_line(frame)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pdb.py", line 158, in user_line
    self.interaction(frame, None)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pdb.py", line 210, in interaction
    self.cmdloop()
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/cmd.py", line 130, in cmdloop
    line = raw_input(self.prompt)
KeyboardInterrupt
>>> help()
Welocome to Volatility.

You can get help on any module or object by typing:

help object

Some interesting topics to get you started, explaining some volatility specific
concepts:

help addrspace - The address space.
help obj       - The volatility objects.
help profile   - What are Profiles?

>>> help profile
  File "<console>", line 1
    help profile
               ^
SyntaxError: invalid syntax

Original comment by michael.hale@gmail.com on 6 Jun 2012 at 3:24

GoogleCodeExporter commented 8 years ago
Hi Michael,
   Only some of the profiles are currently enabled (the ones I use :-)
 Try Win7SP1x64 instead :-). I will check the rest of the profiles in
shortly.

Since there is a testing framework now you can see exactly the
difference in performance for each plugin between the two versions
(The testing framework runs each tool and records details about the
run in a baseline file - then we can retest the tool again in future
to detect regressions etc):

http://code.google.com/p/volatility/source/browse/branches/scudette/test_data/xp
-laptop-2005-06-25_trunk/pslist

and
http://code.google.com/p/volatility/source/browse/branches/scudette/test_data/xp
-laptop-2005-06-25_ng/pslist

In this instance 0.23 sec vs 2.3 sec for trunk (Of course these
numbers are machine dependent, but both tests were run several times
in succession with no other load on the box).

I did some more analysis and I think the reasons trunk is slow are
varied (I did new tests this time on a different box):

Trunk:
time python vol.py -f xp-laptop-2005-06-25.img --profile WinXPSP2x86 pslist
real 0m4.936s

Scudette branch (you can now use the command line as well as the
interactive shell):
time python vol.py -f xp-laptop-2005-06-25.img --profile WinXPSP2x86 pslist
real 0m0.895s

- The kdbg scan accounts for about 3 seconds of the time (which is
huge!). If I supply --kdbg on the command line the time falls
significant:
real 0m1.997s

- The dtb scan seems to have less impact. Supplying --dtb to trunk gives:
real 0m1.870s

- Start up time is significant - I made an empty plugin null.py:

class Null(common.AbstractWindowsCommand):
    def render_text(self, outfd, data):
        pass

and I get in trunk.
real 0m1.526s

Whereas the same plugin in the scudette branch shows:
real 0m0.709s

So it seems the registry and plugin code in trunk are also very slow.

Michael.

Original comment by scude...@gmail.com on 6 Jun 2012 at 8:06

GoogleCodeExporter commented 8 years ago
Hmm I still can't get it to work, even with an XPSP2x86 profile

$ svn info
Path: .
URL: https://volatility.googlecode.com/svn/branches/scudette
Repository Root: https://volatility.googlecode.com/svn
Repository UUID: 8d5d6628-2090-11de-9909-f37ff7dbbc12
Revision: 1848
Node Kind: directory
Schedule: normal
Last Changed Author: scudette@gmail.com
Last Changed Rev: 1848
Last Changed Date: 2012-06-06 08:21:19 -0400 (Wed, 06 Jun 2012)

$ python vol.py -f ~/Desktop/memory/WinXPSP2x86/silentbanker.vmem --profile 
WinXPSP2x86 pslist
Traceback (most recent call last):
  File "vol.py", line 32, in <module>
    from volatility import plugins
  File "/Users/Michael/volatility_scudette/volatility/plugins/__init__.py", line 4, in <module>
    from volatility.plugins import core
  File "/Users/Michael/volatility_scudette/volatility/plugins/core.py", line 258, in <module>
    class Null(WinMemDump):
NameError: name 'WinMemDump' is not defined

Original comment by michael.hale@gmail.com on 6 Jun 2012 at 12:57

GoogleCodeExporter commented 8 years ago
Ah I recently introduced a typo when committing the Null plugin we
discussed in this thread. Try again :-)

Original comment by scude...@gmail.com on 6 Jun 2012 at 1:12

GoogleCodeExporter commented 8 years ago
We're not going to hold 2.1.x back on this, given it's how it's always worked 
(so people aren't getting *worse* performance).

Original comment by mike.auty@gmail.com on 6 Jun 2012 at 8:30

GoogleCodeExporter commented 8 years ago
Hey guys, 

OK I've added the verbose output in r1866. The technique and order of 
operatings when KDBG scanning has not changed yet since we agreed to keep that 
the same through the next release. So currently you'll see something like this 
now:

**************************************************
Instantiating KDBG using: Kernel AS VistaSP2x64 (6.0.6002 64bit)
Offset (V)                    : 0xf800019c1f20
Offset (P)                    : 0x19c1f20
KDBG owner tag check          : True
Profile suggestion (KDBGHeader): Win2008SP2x64
Version64                     : 0xf800019c1ed8 (Major: 15, Minor: 6002)
Service Pack (CmNtCSDVersion) : 2
Build string (NtBuildLab)     : 6002.18005.amd64fre.lh_sp2rtm.09
PsActiveProcessHead           : 0xfffff800019f4440 (52 processes)
PsLoadedModuleList            : 0xfffff80001a14dd0 (153 modules)
KernelBase                    : 0xfffff80001850000 (Matches MZ: True)
Major (OptionalHeader)        : 6
Minor (OptionalHeader)        : 0
KPCR                          : 0xfffff800019c3500 (CPU 0)

If no one has objections to this format, then I'll close the issue and we can 
open separate one(s) for speed related enhancements and of course for 
auto-selecting the profile. 

Scudette, if you want to add your reflect check to the output, that'd be cool 
and would give us yet another factor to distinguish between FPs (and then it'll 
be ready to use if we need it as an additional sanity check for 
auto-selection). Also, 2003 and Vista images are the ones (in my experience) 
that have multiple KDBGs with some being valid and some not, so I'll be glad to 
test your branch more, but you'll have to enable support for those missing 
profiles first. 

Original comment by michael.hale@gmail.com on 12 Jun 2012 at 10:58

GoogleCodeExporter commented 8 years ago
Hi Michael,
   This looks very nice. I especially like the Major and Minor versions from the OptionalHeader because I think this is very predictive of the operating system version. Accroding to:

https://media.blackhat.com/bh-eu-12/Haruyama/bh-eu-12-Haruyama-Memory_Forensic-S
lides.pdf slide 34

Some other tools use this value for detecting os version. Of course these 
values are super easy to change by malware (So is KDBG), but they are a good 
indication usually. It is actually possible to load these values completely 
without an OS dependent profile since the KDBG structure itself is always the 
same between all windows versions.

I looked at the scanner code again to try to understand where the difference in 
speed comes from. The trunk version still looks for the KDBG tag first, and 
then narrows the selection down by employing the other tests. If you count the 
number of hits that actually get past the PoolTagCheck checker it is actually 
only one. In the scudette branch this is 2 so not much different (because there 
are no other checkers). OTOH the time it takes to set up all the profiles is 
extremely significant - I count nearly 4 seconds out of a total time of 7 
seconds in the calculate function until the scanner is actually instantiated.

I think you have implemented so many additional checks now that relying on 
profile specific signatures is kind of pointless. A suggestion is maybe extract 
the signatures all into a single data structure so you dont need to load all 
profiles in their entirety before each run.

Original comment by scude...@gmail.com on 14 Jun 2012 at 6:51

GoogleCodeExporter commented 8 years ago
Yeah, I agree. The speed enhancements and auto-profile selection are at the top 
of the list of things to do next. They're both related so we should be able to 
knock them both out at the same time with some revisions to the KDBG and DTB 
scanner (and possibly the profile/AS load order). 

At a very high level, to choose the right profile in the fastest way possible I 
was thinking something like:

1) Find the DTB so we can get a kernel space 
2) Scan kernel AS for KDBGHeader or drop the signature and just look for "KDBG" 
per your suggestion
3) Use the checks that kdbgscan currently prints to distinguish the Major, 
Minor, and Service Pack
4) Update to the chosen profile
5) Run the plugin code 

Preferably like you said, we would have some type of static setting and none of 
the steps would require updating to all profiles before even starting the work. 
The first hurdle I think would be finding the DTB before/without applying a 
profile, since currently the DTB scanner needs the offsets to 
EPROCESS.ImageFileName and KPROCESS.DirectoryTableBase. If we could do that, I 
think the rest would be pretty easy. 

Also I just wanted to mention that the "other tools" ;-) sometimes fail to 
identify an image even if its a version they claim to support. So allowing 
users to override with --profile and --kdbg is still a valuable feature I 
think. That's part of the motivation behind the verbose kdbgscan output...while 
we're planning the next steps we'll be gathering details on the reliability of 
the different checks (through our own usage of the plugin and community bug 
reports if any). 

I'm not sure if anyone has ever tried loading an image in Redline (wouldn't be 
surprised if you haven't) but it can take several hours before it shows the 
initial GUI for investigation. Compared to that, our trunk speed for kdbgscan 
is pretty darn fast. 

So yeah, I look forward to us putting our heads together and developing a fast 
and reliable auto-profile selection ;-)

Original comment by michael.hale@gmail.com on 15 Jun 2012 at 5:26

GoogleCodeExporter commented 8 years ago
Alright, I'll close this out since the sanity checks and more informational 
output patches have been completed. We can reference this issue when discussing 
kdbg stuff for 2.2. 

Original comment by michael.hale@gmail.com on 24 Jun 2012 at 8:00