Skip to content

Commit

Permalink
Update pstree to use the new volatility object model.
Browse files Browse the repository at this point in the history
darcs-hash:20090126180341-f1522-7cb0b013b08310ab1af9acdd684365fa70c6f0f8.gz
  • Loading branch information
scudette committed Jan 26, 2009
1 parent 2e9422e commit 1057c2c
Show file tree
Hide file tree
Showing 7 changed files with 194 additions and 119 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ def NewObject(theType, offset, vm, parent=None, profile=None, name=None, **kwarg
a string) from the type in profile passing optional args of
kwargs.
"""
if name==None: name=theType

if theType in profile.types:
result = profile.types[theType](offset=offset, vm=vm, name=name,
parent=parent, profile=profile)
Expand All @@ -97,8 +99,8 @@ def NewObject(theType, offset, vm, parent=None, profile=None, name=None, **kwarg
if theType:
if MemoryRegistry.OBJECT_CLASSES.objects.has_key(theType):
return MemoryRegistry.OBJECT_CLASSES[theType](
theType=theType,
offset = offset,
theType,
offset,
vm = vm, parent=parent, profile=profile, name=name,
**kwargs)
except AttributeError:
Expand Down Expand Up @@ -265,11 +267,17 @@ def __init__(self, theType, offset, vm, parent=None, profile=None, target=None,
self.target = target
self.format_string = "=L"

def is_valid(self):
""" Returns if what we are pointing to is valid """
return self.vm.is_valid_address(self.v())

def dereference(self):
offset = self.v()

return self.target(offset=offset, vm=self.vm, parent=self,
profile=self.profile, name=self.name)
result = self.target(offset=offset, vm=self.vm, parent=self,
profile=self.profile, name=self.name)

return result

def dereference_as(self, derefType):
return NewObject(derefType, self.v(), \
Expand All @@ -284,12 +292,20 @@ def __repr__(self):
def __str__(self):
return "<%s pointer to [0x%08X]>" % (self.dereference().__class__.__name__, self.v())

def __int__(self):
return self.v()

def __getattribute__(self, attr):
try:
return super(Pointer,self).__getattribute__(attr)
except AttributeError:
## We just dereference ourself
return self.dereference()
result = self.dereference()

#if isinstance(result, CType):
# return result.m(attr)

return result

class CTypeMember:
""" A placeholder for a type in a struct.
Expand Down Expand Up @@ -374,7 +390,7 @@ def next(self):
return self.target(offset = offset, vm=self.vm,
profile=self.profile, parent=self,
name="%s %s" % (self.name, self.position))

def __str__(self):
return "Array (len=%s of %s)\n" % (self.count, self.current.name)

Expand Down Expand Up @@ -442,9 +458,15 @@ def m(self, attr):
return result

def __getattribute__(self,attr):
try:
return Object.__getattribute__(self, "_"+attr)(attr)
except AttributeError,e:
pass

try:
return Object.__getattribute__(self, attr)
except AttributeError: pass
except AttributeError,e:
pass

## Special code to follow flink,blink lists
if attr=='next':
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,41 @@
from forensics.object2 import NewObject
from forensics.win32.datetime import *
#from forensics.win32.info import *
from forensics.win32.info import find_psactiveprocesshead
from forensics.win32.info import find_psactiveprocesshead, kpcr_addr
import os
from struct import unpack

from forensics.addrspace import *

def pslist(addr_space, profile):
""" A Generator for _EPROCESS objects (uses _KPCR symbols) """

## Locate the kpcr struct - this is hard coded right now
kpcr = NewObject("_KPCR", kpcr_addr, addr_space, profile=profile)

## Try to dereference the KdVersionBlock as a 64 bit struct
DebuggerDataList = kpcr.KdVersionBlock.dereference_as("_DBGKD_GET_VERSION64").DebuggerDataList

if DebuggerDataList.is_valid():
offset = DebuggerDataList.dereference()

## This is a pointer to a _KDDEBUGGER_DATA64 struct. We only
## care about the PsActiveProcessHead entry:
PsActiveProcessHead = NewObject("_KDDEBUGGER_DATA64", offset,
addr_space, profile=profile).PsActiveProcessHead


if not PsActiveProcessHead.is_valid():
## Ok maybe its a 32 bit struct
PsActiveProcessHead = NewObject("_KDDEBUGGER_DATA32", offset,
addr_space, profile=profile).PsActiveProcessHead

## Try to iterate over the process list in PsActiveProcessHead
## (its really a pointer to a _LIST_ENTRY)
for l in PsActiveProcessHead.dereference_as("_LIST_ENTRY").list_of_type(
"_EPROCESS", "ActiveProcessLinks"):
yield l

def process_list(addr_space, types, symbol_table=None):
"""
Get the virtual addresses of all Windows processes
Expand All @@ -44,6 +73,8 @@ def process_list(addr_space, types, symbol_table=None):

PsActiveProcessHead = find_psactiveprocesshead(addr_space,types)

print "head is %s" % PsActiveProcessHead

if not PsActiveProcessHead is None:
(offset, tmp) = get_obj_offset(types, ['_EPROCESS', 'ActiveProcessLinks'])

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@
@contact: [email protected]
"""

from forensics.object2 import CType, NewObject
from forensics.object2 import CType, NewObject, NativeType
from forensics.object import *
from vtypes import xpsp2types as types
from forensics.win32.datetime import *
import vmodules

class _UNICODE_STRING(CType):
"""Class representing a _UNICODE_STRING
Expand All @@ -35,16 +37,16 @@ class _UNICODE_STRING(CType):
than a pointer to an unsigned short.
* The __str__ method returns the value of the Buffer.
"""
def v(self):
try:
data = self.vm.read(self.Buffer.v(), self.Length.v())
return data.decode("utf16","ignore")
except Exception,e:
return ''

def __str__(self):
return self.Buffer
return self.v()

# Custom Attributes
def getBuffer(self):
return read_unicode_string(self.vm, types, [], self.offset)

Buffer = property(fget=getBuffer)

class _LIST_ENTRY(CType):
""" Adds iterators for _LIST_ENTRY types """
def list_of_type(self, type, member, forward=True):
Expand Down Expand Up @@ -80,4 +82,56 @@ def list_of_type(self, type, member, forward=True):
yield obj

def __iter__(self):
print self.parent, self.name
return self.list_of_type(self.parent, self.name)

class String(NativeType):
def __init__(self, type, offset, vm=None,
length=1, parent=None, profile=None, name=None, **args):
NativeType.__init__(self, type, offset, vm, parent=parent, profile=profile,
name=name, format_string="%ss" % length)

def __str__(self):
data = self.v()
## Make sure its null terminated:
return data.strip("\x00")

class WinTimeStamp(NativeType):
def __init__(self, type, offset, vm=None,
parent=None, profile=None, name=None, **args):
NativeType.__init__(self, type, offset, vm, parent=parent, profile=profile,
name=name, format_string="q")

def v(self):
return windows_to_unix_time(NativeType.v(self))

def __str__(self):
return vmodules.format_time(self.v())

class _EPROCESS(CType):
""" An extensive _EPROCESS with bells and whistles """
def _Peb(self,attr):
""" Returns a _PEB object which is using the process address space.
The PEB structure is referencing back into the process address
space so we need to switch address spaces when we look at
it. This method ensure this happens automatically.
"""
process_ad = self.get_process_address_space()
if process_ad:
offset = self.m("Peb").v()

peb = NewObject("_PEB",offset, vm=process_ad, profile=self.profile,
name = "Peb", parent=self)

if peb.is_valid():
return peb

def get_process_address_space(self):
""" Gets a process address space for a task given in _EPROCESS """
directory_table_base = self.Pcb.DirectoryTableBase[0].v()

process_as= self.vm.__class__(self.vm.base, directory_table_base)
process_as.name = "Process"
return process_as

Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
""" These are basic modules which demonstrate how basic functionality
is now built using object2.py. These functions are basically the same
as the built in ones.
"""
Original file line number Diff line number Diff line change
Expand Up @@ -105,29 +105,29 @@ def execute(self):
handle_count,
create_time),defaults)

class _EPROCESS(CType):
"""Class representing an _EPROCESS.
Adds the following special behavior:
* Uses self.Pcb.DirectoryTableBase to re-calculate its
address space.
* Presents ImageFileName as a Python string rather than
an array of unsigned chars.
"""
hasMembers = True
name = "EPROCESS"

def __init__(self, *args, **kwargs):
CType.__init__(self, *args, **kwargs)
new_dtb = self.Pcb.DirectoryTableBase[0]
self.vm = create_addr_space(self.vm, new_dtb)
##class _EPROCESS(CType):
## """Class representing an _EPROCESS.

## Adds the following special behavior:
## * Uses self.Pcb.DirectoryTableBase to re-calculate its
## address space.
## * Presents ImageFileName as a Python string rather than
## an array of unsigned chars.
## """
## hasMembers = True
## name = "EPROCESS"

## def __init__(self, *args, **kwargs):
## CType.__init__(self, *args, **kwargs)
## new_dtb = self.Pcb.DirectoryTableBase[0]
## self.vm = create_addr_space(self.vm, new_dtb)

# Custom attributes
def getImageFileName(self):
return read_null_string(self.vm, types,
['_EPROCESS', 'ImageFileName'], self.offset)
ImageFileName = property(fget=getImageFileName)

def getCreateTime(self):
return process_create_time(self.vm, types, self.offset)
CreateTime = property(fget=getCreateTime)
## # Custom attributes
## def getImageFileName(self):
## return read_null_string(self.vm, types,
## ['_EPROCESS', 'ImageFileName'], self.offset)
## ImageFileName = property(fget=getImageFileName)

## def getCreateTime(self):
## return process_create_time(self.vm, types, self.offset)
## CreateTime = property(fget=getCreateTime)
Loading

0 comments on commit 1057c2c

Please sign in to comment.