Gakaza / volatility

Automatically exported from code.google.com/p/volatility
0 stars 0 forks source link

Bug in VadInfo plugin #236

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
This bug is probably the result of ambiguous validity checking. I did a vadinfo 
on the image xp-laptop-2005-06-25.img and I could see lines like:

FileObject @823c234c FileBuffer @ f000af7e          , Name: -

I was curious why the Name was not printed correctly, and set a break point to 
examine this result in trunk:

        FO = vad.get_file_object()
        if FO.obj_offset == 0x823c234c:
            import pdb; pdb.set_trace()

This what I could see:
> volatility/trunk/volatility/plugins/vadinfo.py(146)write_vad_control()
-> if FO:
(Pdb) l
141     
142             FO = vad.get_file_object()
143             if FO.obj_offset == 0x823c234c:
144                 import pdb; pdb.set_trace()
145     
146  ->         if FO:
147                 outfd.write("FileObject @{0:08x} FileBuffer @ {1:08x}         
 , Name: {2}\n".format(FO.obj_offset, FO.FileName.Buffer, FO.FileName))
148     
149         def write_vad_ext(self, outfd, vad):
150             """Renders a text version of a Long Vad"""
151             outfd.write("First prototype PTE: {0:08x} Last contiguous PTE: 
{1:08x}\n".format(vad.FirstPrototypePte, vad.LastContiguousPte))
(Pdb) print FO
0
(Pdb) print FO.obj_offset
2184979276
(Pdb) FO.FileName.Buffer
<NoneObject pointer to [0xF000AF7E]>
(Pdb) FO.FileName
[_UNICODE_STRING FileName] @ 0x00000030
(Pdb) FO
<_FILE_OBJECT pointer to [0x00000000]>
(Pdb) bool(FO)
True
(Pdb) FO.obj_vm.vtop(0)
229806080
(Pdb) FO.obj_vm.name
'Process 504'

You can see that FO (the file object) is actually a NULL pointer. But the check 
is for validity (if FO:) which is the same as calling bool(FO).

Since the Vads are traversed in the process address space, the zero page is 
actually mapped! So this means that user space NULL pointers do pass the 
_nonzero_ check and volatility thinks they are valid which is wrong.

For null pointers we should not be printing any names of file objects.

We should probably explicitly check for NULL pointers in the __nonzero__ method.

Original issue reported on code.google.com by scude...@gmail.com on 27 Mar 2012 at 1:10

GoogleCodeExporter commented 8 years ago
Another question for MHL: Why do we use the process AS for the Vad tree? If I 
use the kernel address space I can see way more Vad nodes which we are simply 
not showing normally. For example in that image above I have a process:

0x82000980 0x02000980 wmiprvse.exe           4080    740      7      0 
2005-06-25 16:57:53       

Which I can not get its Peb because:
In [9]: task.m('Peb')
Out[9]: <NoneObject pointer to [0x7FFD5000]>

So without a Peb there is no process address space and we can not traverse the 
VadTree for that process. I checked and in that image all Vad nodes have an 
address > 0x80000000 which mean they are in kernel mode anyway. Since the vad 
addresses are in kernel space anyway we certainly can traverse it if we use the 
kernel address space.

Original comment by scude...@gmail.com on 27 Mar 2012 at 1:42

GoogleCodeExporter commented 8 years ago
Hmm, Sorry MHL, I just noticed this file was written by Brendan Dolan-Gavitt 
and Mike Auty? I will CC them as well.

Original comment by scude...@gmail.com on 27 Mar 2012 at 1:45

GoogleCodeExporter commented 8 years ago
There is also another bug in the vadinfo module. Running in trunk I get a line 
such as:

 FileObject @823a4acc FileBuffer @ e100bf08          , Name: \WINDOWS\system32\ntdll.dll

Suggesting that the file object is at location 0x823a4acc. This is in fact not 
correct as it is in location 0x8221e458. The first location is the pointer to 
the _FILE_OBJECT.

This can be traced to this code:

   def get_file_object(self):
        """Returns the FilePointer of the ControlArea of the MMVAD"""
        return self.ControlArea.FilePointer

which returns the pointer to the file object - not the object itself. This is 
then used to print the offset of the pointer:

 outfd.write("FileObject @{0:08x} FileBuffer @ {1:08x}          , Name: {2}\n".format(FO.obj_offset, FO.FileName.Buffer, FO.FileName))

Original comment by scude...@gmail.com on 27 Mar 2012 at 8:03

GoogleCodeExporter commented 8 years ago
Hey Scudette, 

I agree, we should use kernel AS for the vad tree. I looked back and since 2.0 
we've been creating the root MMVAD in kernel AS (since its dereferenced from an 
EPROCESS in kernel AS) but all child nodes were in process AS. A few weeks ago, 
Ikelos and I wanted to make it consistent so it was changed to process AS for 
the whole tree, when really the switch should have been to kernel AS for the 
whole tree. So we'll work on a patch before 2.1 for that...thanks for spotting 
it!

> So without a Peb there is no process address space and we can not traverse 
the VadTree for that process.

Hmm, I don't think think EPROCESS.get_process_address_space() relies on the 
Peb. Did you see self.Pcb instead (Pcb is KPROCESS in this case not the PEB)?

So about adding a null pointer check in __nonzero__ would that be 
obj.Pointer.__nonzero__? Right I now I see:

def __nonzero__(self):
        return bool(self.is_valid())

We could add a self.v() == 0 check there, but what about cases when self.v() == 
1 or something. Its still invalid for the same reason as 0 but just our 
self.v() == 0 wouldn't cover it. Maybe we should do all of 0-0xfff? Are there 
other ranges we should exclude? Happy to help research if needed....

MHL

Original comment by michael.hale@gmail.com on 1 Apr 2012 at 7:09

GoogleCodeExporter commented 8 years ago

Original comment by michael.hale@gmail.com on 4 Apr 2012 at 7:26

GoogleCodeExporter commented 8 years ago
The last of these issues was fixed in r1608 (with exception of the __nonzero__ 
thing which can be opened in a separate issue and discussed if needed. 

Original comment by michael.hale@gmail.com on 8 Apr 2012 at 3:30