mirror of
https://github.com/volatilityfoundation/volatility
synced 2026-06-08 18:04:46 +00:00
170 lines
6.6 KiB
Python
170 lines
6.6 KiB
Python
# Volatility
|
|
# Copyright (C) 2008 Volatile Systems
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 2 of the License, or (at
|
|
# your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful, but
|
|
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
# General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
#
|
|
|
|
"""
|
|
@author: AAron Walters and Brendan Dolan-Gavitt
|
|
@license: GNU General Public License 2.0 or later
|
|
@contact: awalters@volatilesystems.com,bdolangavitt@wesleyan.edu
|
|
@organization: Volatile Systems
|
|
"""
|
|
|
|
from operator import itemgetter
|
|
from bisect import bisect_right
|
|
|
|
import volatility.obj as obj
|
|
import volatility.win32.tasks as tasks
|
|
import volatility.win32.modules as modules
|
|
import volatility.commands as commands
|
|
import volatility.utils as utils
|
|
import volatility.debug as debug #pylint: disable-msg=W0611
|
|
from volatility.cache import CacheDecorator
|
|
|
|
#pylint: disable-msg=C0111
|
|
|
|
sdt_types = {
|
|
'_SERVICE_DESCRIPTOR_TABLE' : [ 0x40, {
|
|
'Descriptors' : [0x0, ['array', 4, ['_SERVICE_DESCRIPTOR_ENTRY']]],
|
|
} ],
|
|
}
|
|
|
|
sdt_types_2k3 = {
|
|
'_SERVICE_DESCRIPTOR_TABLE' : [ 0x40, {
|
|
'Descriptors' : [0x0, ['array', 2, ['_SERVICE_DESCRIPTOR_ENTRY']]],
|
|
} ],
|
|
}
|
|
|
|
sde_types = {
|
|
'_SERVICE_DESCRIPTOR_ENTRY' : [ 0x10, {
|
|
'KiServiceTable' : [0x0, ['pointer', ['void']]],
|
|
'CounterBaseTable' : [0x4, ['pointer', ['unsigned long']]],
|
|
'ServiceLimit' : [0x8, ['long']],
|
|
'ArgumentTable' : [0xc, ['pointer', ['unsigned char']]],
|
|
} ],
|
|
}
|
|
|
|
def find_module(modlist, mod_addrs, addr):
|
|
"""Uses binary search to find what module a given address resides in.
|
|
|
|
This is much faster than a series of linear checks if you have
|
|
to do it many times. Note that modlist and mod_addrs must be sorted
|
|
in order of the module base address."""
|
|
|
|
pos = bisect_right(mod_addrs, addr) - 1
|
|
if pos == -1:
|
|
return None
|
|
mod = modlist[mod_addrs[pos]]
|
|
|
|
if (addr >= mod.DllBase.v() and
|
|
addr < mod.DllBase.v() + mod.SizeOfImage.v()):
|
|
return mod
|
|
else:
|
|
return None
|
|
|
|
class SSDT(commands.command):
|
|
"Display SSDT entries"
|
|
# Declare meta information associated with this plugin
|
|
meta_info = {
|
|
'author': 'Brendan Dolan-Gavitt',
|
|
'copyright': 'Copyright (c) 2007,2008 Brendan Dolan-Gavitt',
|
|
'contact': 'bdolangavitt@wesleyan.edu',
|
|
'license': 'GNU General Public License 2.0 or later',
|
|
'url': 'http://moyix.blogspot.com/',
|
|
'os': 'WIN_32_XP_SP2',
|
|
'version': '1.0'}
|
|
|
|
@CacheDecorator("tests/ssdt")
|
|
def calculate(self):
|
|
addr_space = utils.load_as(self._config)
|
|
addr_space.profile.add_types(sde_types)
|
|
|
|
if addr_space.profile.metadata.get('major', 0) == 5 and addr_space.profile.metadata.get('minor',0) == 2:
|
|
addr_space.profile.add_types(sdt_types_2k3)
|
|
else:
|
|
addr_space.profile.add_types(sdt_types)
|
|
|
|
## Get a sorted list of module addresses
|
|
mods = dict((mod.DllBase.v(), mod) for mod in modules.lsmod(addr_space))
|
|
mod_addrs = sorted(mods.keys())
|
|
|
|
# Gather up all SSDTs referenced by threads
|
|
print "Gathering all referenced SSDTs from KTHREADs..."
|
|
ssdts = set()
|
|
for proc in tasks.pslist(addr_space):
|
|
for thread in proc.ThreadListHead.list_of_type("_ETHREAD", "ThreadListEntry"):
|
|
ssdt_obj = thread.Tcb.ServiceTable.dereference_as('_SERVICE_DESCRIPTOR_TABLE')
|
|
ssdts.add(ssdt_obj)
|
|
|
|
# Get a list of *unique* SSDT entries. Typically we see only two.
|
|
tables = set()
|
|
|
|
for ssdt_obj in ssdts:
|
|
for i, desc in enumerate(ssdt_obj.Descriptors):
|
|
# Apply some extra checks - KiServiceTable should reside in kernel memory and ServiceLimit
|
|
# should be greater than 0 but not unbelievably high
|
|
if desc.is_valid() and desc.ServiceLimit > 0 and desc.ServiceLimit < 0xFFFF and desc.KiServiceTable > 0x80000000:
|
|
tables.add((i, desc.KiServiceTable.v(), desc.ServiceLimit.v()))
|
|
|
|
print "Finding appropriate address space for tables..."
|
|
tables_with_vm = []
|
|
for idx, table, n in tables:
|
|
found = False
|
|
for p in tasks.pslist(addr_space):
|
|
## This is the process address space
|
|
ps_ad = p.get_process_address_space()
|
|
## Is the table accessible from the process AS?
|
|
if ps_ad.is_valid_address(table):
|
|
tables_with_vm.append((idx, table, n, ps_ad))
|
|
found = True
|
|
break
|
|
## If not we use the kernel address space
|
|
if not found:
|
|
# Any VM is equally bad...
|
|
tables_with_vm.append((idx, table, n, addr_space))
|
|
|
|
for idx, table, n, vm in sorted(tables_with_vm, key = itemgetter(0)):
|
|
yield idx, table, n, vm, mods, mod_addrs
|
|
|
|
def render_text(self, outfd, data):
|
|
|
|
addr_space = utils.load_as(self._config)
|
|
syscalls = addr_space.profile.syscalls
|
|
|
|
# Print out the entries for each table
|
|
for idx, table, n, vm, mods, mod_addrs in data:
|
|
outfd.write("SSDT[{0}] at {1:x} with {2} entries\n".format(idx, table, n))
|
|
if vm.is_valid_address(table):
|
|
for i in range(n):
|
|
syscall_addr = obj.Object('unsigned long', table + (i * 4), vm).v()
|
|
try:
|
|
syscall_name = syscalls[idx][i]
|
|
except IndexError:
|
|
syscall_name = "Unknown"
|
|
|
|
syscall_mod = find_module(mods, mod_addrs, syscall_addr)
|
|
if syscall_mod:
|
|
syscall_modname = syscall_mod.BaseDllName
|
|
else:
|
|
syscall_modname = "UNKNOWN"
|
|
|
|
outfd.write(" Entry {0:#06x}: {1:#x} ({2}) owned by {3}\n".format(idx * 0x1000 + i,
|
|
syscall_addr,
|
|
syscall_name,
|
|
syscall_modname))
|
|
else:
|
|
outfd.write(" [SSDT not resident at 0x{0:08X} ]\n".format(table))
|