Hi everybody,
Another one, hot off the press. This time I went for the files module.
I thought this one was going to be really tricky, but luckily most of
the work had already been done in the xp_sp2.py for _EPROCESS objects.
I spotted that the Array didn't seem to be generated properly, and I
changed the function to return all objects (since I figured whatever was
using them could narrow down the objects based on their type, rather
than only ever returning file objects). Otherwise, it was just the
plugin file that needed changing... 5:)
I've also tried to ensure I don't do repeated checks and/or "is None"
checks... 5;P
Mike 5:)
diff --git a/Volatility/memory_objects/Windows/xp_sp2.py
b/Volatility/memory_objects/Windows/xp_sp2.py
index 4cc4956..215a181 100644
--- a/Volatility/memory_objects/Windows/xp_sp2.py
+++ b/Volatility/memory_objects/Windows/xp_sp2.py
@@ -25,11 +25,11 @@
#pylint: disable-msg=C0111
-from forensics.object2 import CType, NewObject, NoneObject, NativeType, Curry
-from forensics.win32.datetime import windows_to_unix_time
+import forensics.object2 as object2
+import forensics.win32 as win32
import vmodules
-class _UNICODE_STRING(CType):
+class _UNICODE_STRING(object2.CType):
"""Class representing a _UNICODE_STRING
Adds the following behavior:
@@ -50,7 +50,7 @@ class _UNICODE_STRING(CType):
def __str__(self):
return self.v()
-class _LIST_ENTRY(CType):
+class _LIST_ENTRY(object2.CType):
""" Adds iterators for _LIST_ENTRY types """
def list_of_type(self, type, member, forward=True):
if not self.is_valid():
@@ -69,10 +69,10 @@ class _LIST_ENTRY(CType):
while 1:
## Instantiate the object
- obj = NewObject(type, offset = lst.offset - offset,
- vm=self.vm,
- parent=self.parent,
- profile=self.profile, name=type)
+ obj = object2.NewObject(type, offset = lst.offset - offset,
+ vm=self.vm,
+ parent=self.parent,
+ profile=self.profile, name=type)
if forward:
@@ -89,7 +89,7 @@ class _LIST_ENTRY(CType):
def __iter__(self):
return self.list_of_type(self.parent.name, self.name)
-class String(NativeType):
+class String(object2.NativeType):
def __init__(self, type, offset, vm=None,
length=1, parent=None, profile=None, name=None, **args):
## Allow length to be a callable:
@@ -99,7 +99,7 @@ class String(NativeType):
pass
## length must be an integer
- NativeType.__init__(self, type, offset, vm, parent=parent, profile=profile,
+ object2.NativeType.__init__(self, type, offset, vm, parent=parent,
profile=profile,
name=name, format_string="%ds" % length)
def upper(self):
@@ -113,7 +113,7 @@ class String(NativeType):
## Make sure its null terminated:
return data.split("\x00")[0]
-class WinTimeStamp(NativeType):
+class WinTimeStamp(object2.NativeType):
def __init__(self, type=None, offset=None, vm=None, value=None,
parent=None, profile=None, name=None, **args):
## This allows us to have a WinTimeStamp object with a
@@ -122,17 +122,17 @@ class WinTimeStamp(NativeType):
if value:
self.data = value
else:
- NativeType.__init__(self, type, offset, vm, parent=parent, profile=profile,
- name=name, format_string="q")
+ object2.NativeType.__init__(self, type, offset, vm, parent=parent,
profile=profile,
+ name=name, format_string="q")
def value(self):
"""Override the value return, depending on whether we have a data
field"""
if self.data is not None:
return self.data
- return NativeType.value(self)
+ return object2.NativeType.value(self)
def v(self):
- return windows_to_unix_time(self.value())
+ return win32.datetime.windows_to_unix_time(self.value())
def __sub__(self, x):
return WinTimeStamp(value = self.value() - x.value())
@@ -143,7 +143,7 @@ class WinTimeStamp(NativeType):
LEVEL_MASK = 0xfffffff8
-class _EPROCESS(CType):
+class _EPROCESS(object2.CType):
""" An extensive _EPROCESS with bells and whistles """
def _Peb(self, _attr):
""" Returns a _PEB object which is using the process address
space.
@@ -155,13 +155,13 @@ class _EPROCESS(CType):
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)
+ peb = object2.NewObject("_PEB", offset, vm=process_ad,
profile=self.profile,
+ name = "Peb", parent=self)
if peb.is_valid():
return peb
- return NoneObject("Peb not found")
+ return object2.NoneObject("Peb not found")
def get_process_address_space(self):
""" Gets a process address space for a task given in _EPROCESS
"""
@@ -177,9 +177,8 @@ class _EPROCESS(CType):
and iterates over them.
"""
- table = NewObject("Array", offset, self.vm,
- count=0x200, parent=self, profile=self.profile,
- target = Curry(NewObject, "_HANDLE_TABLE_ENTRY"))
+ table = object2.Array("_HANDLE_TABLE_ENTRY", offset=offset,
vm=self.vm,
+ count=0x200, parent=self, profile=self.profile)
for t in table:
offset = t.dereference_as('unsigned int')
if not offset.is_valid():
@@ -193,13 +192,11 @@ class _EPROCESS(CType):
## OK We got to the bottom table, we just resolve
## objects here:
offset = int(offset) & ~0x00000007
- obj = NewObject("_OBJECT_HEADER", offset, self.vm,
- parent=self, profile=self.profile)
+ obj = object2.NewObject("_OBJECT_HEADER", offset, self.vm,
+ parent=self, profile=self.profile)
try:
- if obj.Type.Name.__str__()=='File':
- filevar = NewObject("_FILE_OBJECT", obj.Body.offset,
self.vm,
- parent=self, profile=self.profile)
- yield filevar
+ if obj.Type.Name:
+ yield obj
except Exception, _e:
pass
@@ -227,7 +224,7 @@ class _EPROCESS(CType):
import socket, struct
-class _TCPT_OBJECT(CType):
+class _TCPT_OBJECT(object2.CType):
def _RemoteIpAddress(self, attr):
return socket.inet_ntoa(struct.pack("<I", self.m(attr).v()))
diff --git a/Volatility/memory_plugins/internal/files.py
b/Volatility/memory_plugins/internal/files.py
new file mode 100644
index 0000000..7bce080
--- /dev/null
+++ b/Volatility/memory_plugins/internal/files.py
@@ -0,0 +1,78 @@
+'''
+Created on 26 Sep 2009
+
+@author: Mike Auty
+'''
+
+#pylint: disable-msg=C0111
+
+import forensics.commands
+import forensics.win32 as win32
+import forensics.object2 as object2
+import forensics.utils as utils
+
+class files(forensics.commands.command):
+ """Print list of open files for each process"""
+
+ def __init__(self, args=None):
+ forensics.commands.command.__init__(self, args)
+ self.profile = None
+
+ def parser(self):
+ """Sets up the parser before execution"""
+ forensics.commands.command.parser(self)
+
+ self.op.add_option('-o', '--offset',
+ help='EPROCESS Offset (in hex) in physical address space',
+ action='store', type='string', dest='offset')
+
+ self.op.add_option('-p', '--pid',
+ help='Get info for this Pid', default=None,
+ action='store', type='int', dest='pid')
+
+ def render_text(self, outfd, data):
+ first = True
+ for pid in data:
+ if not first:
+ outfd.write("*" * 72 + "\n")
+ outfd.write("Pid: %-6d\n" % pid)
+ first = False
+
+ handles = data[pid]
+ for h in handles:
+ if h.FileName:
+ outfd.write("%-6s %-40s\n" % ("File",
h.FileName))
+
+ def calculate(self):
+ result = {}
+ self.profile = object2.Profile()
+
+ addr_space = utils.load_as(self.opts)
+
+ if self.opts.offset:
+ try:
+ offset = int(self.opts.offset, 16)
+ except ValueError:
+ self.op.error("EPROCESS offset must be a hexadecimal number.")
+
+ tasks = [object2.NewObject("_EPROCESS", offset, addr_space,
profile=self.profile)]
+
+ else:
+ tasks = win32.tasks.pslist(addr_space, self.profile)
+
+ for task in tasks:
+ if task.ObjectTable.HandleTableList:
+ pid = int(task.ObjectTable.UniqueProcessId)
+ if self.opts.pid and pid != self.opts.pid:
+ continue
+ handles = task.handles()
+
+ # Weed out just the file handles:
+ for h in handles:
+ if str(h.Type.Name) == 'File':
+ filevar = object2.NewObject("_FILE_OBJECT",
h.Body.offset, task.vm, parent=task, profile=task.profile)
+ hlist = result.get(pid, [])
+ hlist.append(filevar)
+ result[pid] = hlist
+
+ return result
\ No newline at end of file
diff --git a/Volatility/vmodules.py b/Volatility/vmodules.py
index a910b03..2082b73 100644
--- a/Volatility/vmodules.py
+++ b/Volatility/vmodules.py
@@ -40,7 +40,7 @@ from forensics.object import read_unicode_string, read_obj
from forensics.win32.tasks import module_base, module_path, module_size,
create_addr_space, process_addr_space, process_command_line, process_dtb,
process_find_pid
from forensics.win32.tasks import process_imagename, process_ldrs, process_list,
process_peb, process_pid, process_handle_table, process_create_time, process_handle_count
from forensics.win32.tasks import process_inherited_from, process_num_active_threads,
process_vadroot
-from forensics.win32.handles import handle_entries, handle_process_id, handle_tables,
handle_entry_object, is_object_file, object_data, file_name
+from forensics.win32.handles import handle_entries, handle_process_id, handle_tables
from forensics.win32.vad import vad_dump, vad_info, print_vad_dot_infix,
print_vad_dot_prefix, print_vad_table, print_vad_tree, traverse_vad
from forensics.win32.scan import module_scan, conn_scan, ps_scan_dot, ps_scan,
socket_scan, thrd_scan
from forensics.win32.crashdump import crash_to_dd, dd_to_crash
@@ -295,87 +295,6 @@ def get_dlllist(cmdname, argv):
print
###################################
-# files - List open files
-###################################
-def print_entry_file(addr_space, types, entry):
-
- if not addr_space.is_valid_address(entry):
- return
-
- obj = handle_entry_object(addr_space, types, entry)
- if obj is None:
- return
-
- if addr_space.is_valid_address(obj):
- if is_object_file(addr_space, types, obj):
- f = object_data(addr_space, types, obj)
- fname = file_name(addr_space, types, f)
- if fname != "":
- print "%-6s %-40s" % ("File", fname)
-
-def get_open_files(cmdname, argv):
- """
- Function prints a list of open files for each process.
- """
- htables = []
-
- op = get_standard_parser(cmdname)
-
- op.add_option('-o', '--offset',
- help='EPROCESS Offset (in hex) in physical address space',
- action='store', type='string', dest='offset')
-
- op.add_option('-p', '--pid',
- help='Get info for this Pid',
- action='store', type='int', dest='pid')
-
- opts, _args = op.parse_args(argv)
-
- filename = opts.filename
- pid = opts.pid
-
- (addr_space, symtab, types) = load_and_identify_image(op, opts)
-
- if not opts.offset is None:
-
- try:
- offset = int(opts.offset, 16)
- except:
- op.error("EPROCESS offset must be a hexadecimal number.")
-
- try:
- flat_address_space = FileAddressSpace(filename)
- except:
- op.error("Unable to open image file %s" % (filename))
-
- ObjectTable = process_handle_table(flat_address_space, types, offset)
-
- if addr_space.is_valid_address(ObjectTable):
- htables.append(ObjectTable)
-
- else:
-
- htables = handle_tables(addr_space, types, symtab, pid)
-
-
- star_line = '*' * 72
-
- for table in htables:
- if len(htables) > 1:
- print "%s" % star_line
-
- process_id = handle_process_id(addr_space, types, table)
- if process_id == None:
- continue
-
- print "Pid: %-6d" % (process_id)
-
- entries = handle_entries(addr_space, types, table)
- for hentry in entries:
- print_entry_file(addr_space, types, hentry)
-
-
-###################################
# strings - identify pid(s) associated with a string
###################################
def print_string(offset, pidlist, string):
diff --git a/Volatility/volatility.py b/Volatility/volatility.py
index a765579..baee253 100644
--- a/Volatility/volatility.py
+++ b/Volatility/volatility.py
@@ -48,10 +48,6 @@ modules = {
VolatoolsModule('dlllist',
'Print list of loaded dlls for each process',
get_dlllist),
- 'files':
- VolatoolsModule('files',
- 'Print list of open files for each process',
- get_open_files),
'strings':
VolatoolsModule('strings',
'Match physical offsets to virtual addresses (may take a while,
VERY verbose)',