mirror of
https://github.com/volatilityfoundation/volatility
synced 2026-06-08 18:04:46 +00:00
520 lines
22 KiB
Python
520 lines
22 KiB
Python
# Volatility
|
|
# Copyright (C) 2007-2013 Volatility Foundation
|
|
# Copyright (c) 2010, 2011, 2012 Michael Ligh <michael.ligh@mnin.org>
|
|
#
|
|
# This file is part of Volatility.
|
|
#
|
|
# Volatility 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.
|
|
#
|
|
# Volatility 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 Volatility. If not, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
|
|
import volatility.utils as utils
|
|
import volatility.obj as obj
|
|
import volatility.plugins.common as common
|
|
import volatility.win32.tasks as tasks
|
|
import volatility.debug as debug
|
|
import volatility.plugins.registry.registryapi as registryapi
|
|
from volatility.renderers import TreeGrid
|
|
from volatility.renderers.basic import Address
|
|
|
|
#--------------------------------------------------------------------------------
|
|
# vtypes
|
|
#--------------------------------------------------------------------------------
|
|
|
|
SERVICE_TYPE_FLAGS = {
|
|
'SERVICE_KERNEL_DRIVER': 0,
|
|
'SERVICE_FILE_SYSTEM_DRIVER': 1,
|
|
'SERVICE_WIN32_OWN_PROCESS': 4,
|
|
'SERVICE_WIN32_SHARE_PROCESS': 5,
|
|
'SERVICE_INTERACTIVE_PROCESS': 8}
|
|
SERVICE_STATE_ENUM = {
|
|
1: 'SERVICE_STOPPED',
|
|
2: 'SERVICE_START_PENDING',
|
|
3: 'SERVICE_STOP_PENDING',
|
|
4: 'SERVICE_RUNNING',
|
|
5: 'SERVICE_CONTINUE_PENDING',
|
|
6: 'SERVICE_PAUSE_PENDING',
|
|
7: 'SERVICE_PAUSED'}
|
|
SERVICE_START_ENUM = {
|
|
0: 'SERVICE_BOOT_START',
|
|
1: 'SERVICE_SYSTEM_START',
|
|
2: 'SERVICE_AUTO_START',
|
|
3: 'SERVICE_DEMAND_START',
|
|
4: 'SERVICE_DISABLED'}
|
|
|
|
svcscan_base_x86 = {
|
|
'_SERVICE_HEADER': [ None, {
|
|
'Tag': [ 0x0, ['array', 4, ['unsigned char']]],
|
|
'ServiceRecord': [ 0xC, ['pointer', ['_SERVICE_RECORD']]],
|
|
} ],
|
|
'_SERVICE_LIST_ENTRY' : [ 0x8, {
|
|
'Blink' : [ 0x0, ['pointer', ['_SERVICE_RECORD']]],
|
|
'Flink' : [ 0x4, ['pointer', ['_SERVICE_RECORD']]],
|
|
} ],
|
|
'_SERVICE_RECORD' : [ None, {
|
|
'ServiceList' : [ 0x0, ['_SERVICE_LIST_ENTRY']],
|
|
'ServiceName' : [ 0x8, ['pointer', ['String', dict(encoding = 'utf16', length = 512)]]],
|
|
'DisplayName' : [ 0xc, ['pointer', ['String', dict(encoding = 'utf16', length = 512)]]],
|
|
'Order' : [ 0x10, ['unsigned int']],
|
|
'Tag' : [ 0x18, ['array', 4, ['unsigned char']]],
|
|
'DriverName' : [ 0x24, ['pointer', ['String', dict(encoding = 'utf16', length = 256)]]],
|
|
'ServiceProcess' : [ 0x24, ['pointer', ['_SERVICE_PROCESS']]],
|
|
'Type' : [ 0x28, ['Flags', {'bitmap': SERVICE_TYPE_FLAGS}]],
|
|
'State' : [ 0x2c, ['Enumeration', dict(target = 'long', choices = SERVICE_STATE_ENUM)]],
|
|
'Start' : [ 0x44, ['Enumeration', dict(target = 'long', choices = SERVICE_START_ENUM)]],
|
|
} ],
|
|
'_SERVICE_PROCESS' : [ None, {
|
|
'BinaryPath' : [ 0x8, ['pointer', ['String', dict(encoding = 'utf16', length = 256)]]],
|
|
'ProcessId' : [ 0xc, ['unsigned int']],
|
|
} ],
|
|
}
|
|
|
|
svcscan_base_x64 = {
|
|
'_SERVICE_HEADER': [ None, {
|
|
'Tag': [ 0x0, ['array', 4, ['unsigned char']]],
|
|
'ServiceRecord': [ 0x10, ['pointer', ['_SERVICE_RECORD']]],
|
|
} ],
|
|
'_SERVICE_LIST_ENTRY' : [ 0x8, {
|
|
'Blink' : [ 0x0, ['pointer', ['_SERVICE_RECORD']]],
|
|
'Flink' : [ 0x10, ['pointer', ['_SERVICE_RECORD']]],
|
|
} ],
|
|
'_SERVICE_RECORD' : [ None, {
|
|
'ServiceList' : [ 0x0, ['_SERVICE_LIST_ENTRY']],
|
|
'ServiceName' : [ 0x8, ['pointer', ['String', dict(encoding = 'utf16', length = 512)]]],
|
|
'DisplayName' : [ 0x10, ['pointer', ['String', dict(encoding = 'utf16', length = 512)]]],
|
|
'Order' : [ 0x18, ['unsigned int']],
|
|
'Tag' : [ 0x20, ['array', 4, ['unsigned char']]],
|
|
'DriverName' : [ 0x30, ['pointer', ['String', dict(encoding = 'utf16', length = 256)]]],
|
|
'ServiceProcess' : [ 0x30, ['pointer', ['_SERVICE_PROCESS']]],
|
|
'Type' : [ 0x38, ['Flags', {'bitmap': SERVICE_TYPE_FLAGS}]],
|
|
'State' : [ 0x3C, ['Enumeration', dict(target = 'long', choices = SERVICE_STATE_ENUM)]],
|
|
'Start' : [ 0x54, ['Enumeration', dict(target = 'long', choices = SERVICE_START_ENUM)]],
|
|
} ],
|
|
'_SERVICE_PROCESS': [ None, {
|
|
'BinaryPath': [ 0x10, ['pointer', ['String', dict(encoding = 'utf16', length = 256)]]],
|
|
'ProcessId': [ 0x18, ['unsigned int']],
|
|
} ],
|
|
}
|
|
|
|
#--------------------------------------------------------------------------------
|
|
# object Classes
|
|
#--------------------------------------------------------------------------------
|
|
|
|
class _SERVICE_RECORD_LEGACY(obj.CType):
|
|
"Service records for XP/2003 x86 and x64"
|
|
|
|
@property
|
|
def Binary(self):
|
|
"Return the binary path for a service"
|
|
|
|
# No path in memory for services that aren't running
|
|
# (if needed, query the registry key)
|
|
if str(self.State) != 'SERVICE_RUNNING':
|
|
return obj.NoneObject("No path, service isn't running")
|
|
|
|
# Depending on whether the service is for a process
|
|
# or kernel driver, the binary path is stored differently
|
|
if 'PROCESS' in str(self.Type):
|
|
return self.ServiceProcess.BinaryPath.dereference()
|
|
else:
|
|
return self.DriverName.dereference()
|
|
|
|
@property
|
|
def Pid(self):
|
|
"Return the process ID for a service"
|
|
|
|
if str(self.State) == 'SERVICE_RUNNING':
|
|
if 'PROCESS' in str(self.Type):
|
|
return self.ServiceProcess.ProcessId
|
|
|
|
return obj.NoneObject("Cannot get process ID")
|
|
|
|
def is_valid(self):
|
|
"Check some fields for validity"
|
|
return obj.CType.is_valid(self) and self.Order > 0 and self.Order < 0xFFFF
|
|
|
|
def traverse(self):
|
|
|
|
rec = self # Include this object in the list
|
|
while rec and rec.is_valid():
|
|
yield rec
|
|
rec = rec.ServiceList.Blink.dereference()
|
|
|
|
class _SERVICE_RECORD_RECENT(_SERVICE_RECORD_LEGACY):
|
|
"Service records for 2008, Vista, 7 x86 and x64"
|
|
|
|
def traverse(self):
|
|
"""Generator that walks the singly-linked list"""
|
|
|
|
yield self # Include this object in the list
|
|
|
|
# Make sure we dereference these pointers, or the
|
|
# is_valid() checks will apply to the pointer and
|
|
# not the _SERVICE_RECORD object as intended.
|
|
rec = self.PrevEntry.dereference()
|
|
while rec and rec.is_valid():
|
|
yield rec
|
|
rec = rec.PrevEntry.dereference()
|
|
|
|
class _SERVICE_HEADER(obj.CType):
|
|
"Service headers for 2008, Vista, 7 x86 and x64"
|
|
|
|
def is_valid(self):
|
|
"Check some fields for validity"
|
|
return (obj.CType.is_valid(self) and
|
|
self.ServiceRecord.is_valid() and
|
|
self.ServiceRecord.Order < 0xFFFF)
|
|
|
|
#--------------------------------------------------------------------------------
|
|
# profile modifications
|
|
#--------------------------------------------------------------------------------
|
|
|
|
class ServiceBase(obj.ProfileModification):
|
|
"""The base applies to XP and 2003 SP0-SP1"""
|
|
|
|
before = ['WindowsOverlay', 'WindowsObjectClasses']
|
|
conditions = {'os': lambda x: x == 'windows'}
|
|
|
|
def modification(self, profile):
|
|
profile.object_classes.update({
|
|
'_SERVICE_RECORD': _SERVICE_RECORD_LEGACY,
|
|
'_SERVICE_HEADER': _SERVICE_HEADER,
|
|
})
|
|
profile.merge_overlay({'VOLATILITY_MAGIC': [ None, {
|
|
'ServiceTag': [ 0x0, ['VolatilityMagic', dict(value = "sErv")]]
|
|
}]})
|
|
profile.vtypes.update(svcscan_base_x86)
|
|
|
|
class ServiceBasex64(obj.ProfileModification):
|
|
"""This overrides the base x86 vtypes with x64 vtypes"""
|
|
|
|
before = ['WindowsOverlay', 'WindowsObjectClasses', 'ServiceBase']
|
|
conditions = {'os': lambda x: x == 'windows',
|
|
'memory_model': lambda x: x == '64bit'}
|
|
|
|
def modification(self, profile):
|
|
profile.vtypes.update(svcscan_base_x64)
|
|
|
|
class ServiceVista(obj.ProfileModification):
|
|
"""Override the base with OC's for Vista, 2008, and 7"""
|
|
|
|
before = ['WindowsOverlay', 'WindowsObjectClasses', 'ServiceBase']
|
|
conditions = {'os': lambda x: x == 'windows',
|
|
'major': lambda x: x >= 6}
|
|
|
|
def modification(self, profile):
|
|
profile.object_classes.update({
|
|
'_SERVICE_RECORD': _SERVICE_RECORD_RECENT,
|
|
})
|
|
profile.merge_overlay({'VOLATILITY_MAGIC': [ None, {
|
|
'ServiceTag': [ 0x0, ['VolatilityMagic', dict(value = "serH")]]
|
|
}]})
|
|
|
|
class ServiceVistax86(obj.ProfileModification):
|
|
"""Override the base with vtypes for x86 Vista, 2008, and 7"""
|
|
|
|
before = ['WindowsOverlay', 'WindowsObjectClasses', 'ServiceBase']
|
|
conditions = {'os': lambda x: x == 'windows',
|
|
'major': lambda x: x == 6,
|
|
'minor': lambda x: x < 2,
|
|
'memory_model': lambda x: x == '32bit'}
|
|
|
|
def modification(self, profile):
|
|
profile.merge_overlay({'_SERVICE_RECORD': [ None, {
|
|
'PrevEntry': [ 0x0, ['pointer', ['_SERVICE_RECORD']]],
|
|
'ServiceName': [ 0x4, ['pointer', ['String', dict(encoding = 'utf16', length = 512)]]],
|
|
'DisplayName': [ 0x8, ['pointer', ['String', dict(encoding = 'utf16', length = 512)]]],
|
|
'Order': [ 0xC, ['unsigned int']],
|
|
'ServiceProcess': [ 0x1C, ['pointer', ['_SERVICE_PROCESS']]],
|
|
'DriverName': [ 0x1C, ['pointer', ['String', dict(encoding = 'utf16', length = 256)]]],
|
|
'Type' : [ 0x20, ['Flags', {'bitmap': SERVICE_TYPE_FLAGS}]],
|
|
'State': [ 0x24, ['Enumeration', dict(target = 'long', choices = SERVICE_STATE_ENUM)]],
|
|
'Start' : [ 0x3C, ['Enumeration', dict(target = 'long', choices = SERVICE_START_ENUM)]],
|
|
}]})
|
|
|
|
class ServiceVistax64(obj.ProfileModification):
|
|
"""Override the base with vtypes for x64 Vista, 2008, and 7"""
|
|
|
|
before = ['WindowsOverlay', 'WindowsObjectClasses', 'ServiceBase']
|
|
conditions = {'os': lambda x: x == 'windows',
|
|
'major': lambda x: x == 6,
|
|
'minor': lambda x: x < 2,
|
|
'memory_model': lambda x: x == '64bit'}
|
|
|
|
def modification(self, profile):
|
|
profile.merge_overlay({'_SERVICE_RECORD': [ None, {
|
|
'PrevEntry': [ 0x0, ['pointer', ['_SERVICE_RECORD']]],
|
|
'ServiceName': [ 0x8, ['pointer', ['String', dict(encoding = 'utf16', length = 512)]]],
|
|
'DisplayName': [ 0x10, ['pointer', ['String', dict(encoding = 'utf16', length = 512)]]],
|
|
'Order': [ 0x18, ['unsigned int']],
|
|
'ServiceProcess': [ 0x28, ['pointer', ['_SERVICE_PROCESS']]],
|
|
'DriverName': [ 0x28, ['pointer', ['String', dict(encoding = 'utf16', length = 256)]]],
|
|
'Type' : [ 0x30, ['Flags', {'bitmap': SERVICE_TYPE_FLAGS}]],
|
|
'State': [ 0x34, ['Enumeration', dict(target = 'long', choices = SERVICE_STATE_ENUM)]],
|
|
'Start' : [ 0x4C, ['Enumeration', dict(target = 'long', choices = SERVICE_START_ENUM)]],
|
|
}]})
|
|
|
|
class Service8x64(obj.ProfileModification):
|
|
"""Service structures for Win8/8.1 and Server2012/R2 64-bit"""
|
|
|
|
before = ['WindowsOverlay', 'WindowsObjectClasses', 'ServiceBase', 'ServiceVista']
|
|
conditions = {'os': lambda x: x == 'windows',
|
|
'major': lambda x: x == 6,
|
|
'minor': lambda x: x >= 2,
|
|
'memory_model': lambda x: x == '64bit'}
|
|
|
|
def modification(self, profile):
|
|
profile.merge_overlay({
|
|
'_SERVICE_RECORD' : [ None, {
|
|
'Tag' : [ 0x0, ['String', dict(length = 4)]],
|
|
'PrevEntry': [ 0x8, ['pointer', ['_SERVICE_RECORD']]],
|
|
'ServiceName' : [ 0x10, ['pointer', ['String', dict(encoding = 'utf16', length = 512)]]],
|
|
'DisplayName' : [ 0x18, ['pointer', ['String', dict(encoding = 'utf16', length = 512)]]],
|
|
'Order' : [ 0x20, ['unsigned int']],
|
|
'DriverName' : [ 0x38, ['pointer', ['String', dict(encoding = 'utf16', length = 256)]]],
|
|
'ServiceProcess' : [ 0x38, ['pointer', ['_SERVICE_PROCESS']]],
|
|
'Type' : [ 0x40, ['Flags', {'bitmap': SERVICE_TYPE_FLAGS}]],
|
|
'State' : [ 0x44, ['Enumeration', dict(target = 'long', choices = SERVICE_STATE_ENUM)]],
|
|
'Start' : [ 0x5C, ['Enumeration', dict(target = 'long', choices = SERVICE_START_ENUM)]],
|
|
} ],
|
|
'_SERVICE_PROCESS': [ None, {
|
|
'BinaryPath': [ 0x18, ['pointer', ['String', dict(encoding = 'utf16', length = 256)]]],
|
|
'ProcessId': [ 0x20, ['unsigned int']],
|
|
} ],
|
|
})
|
|
|
|
class Service8x86(obj.ProfileModification):
|
|
"""Service structures for Win8/8.1 32-bit"""
|
|
|
|
before = ['WindowsOverlay', 'WindowsObjectClasses', 'ServiceBase', 'ServiceVista']
|
|
conditions = {'os': lambda x: x == 'windows',
|
|
'major': lambda x: x == 6,
|
|
'minor': lambda x: x >= 2,
|
|
'memory_model': lambda x: x == '32bit'}
|
|
|
|
def modification(self, profile):
|
|
profile.vtypes.update({
|
|
'_SERVICE_RECORD' : [ None, {
|
|
'Tag' : [ 0x0, ['String', dict(length = 4)]],
|
|
'PrevEntry': [ 0x4, ['pointer', ['_SERVICE_RECORD']]],
|
|
'ServiceName' : [ 0x8, ['pointer', ['String', dict(encoding = 'utf16', length = 512)]]],
|
|
'DisplayName' : [ 0xc, ['pointer', ['String', dict(encoding = 'utf16', length = 512)]]],
|
|
'Order' : [ 0x10, ['unsigned int']],
|
|
'DriverName' : [ 0x24, ['pointer', ['String', dict(encoding = 'utf16', length = 256)]]],
|
|
'ServiceProcess' : [ 0x24, ['pointer', ['_SERVICE_PROCESS']]],
|
|
'Type' : [ 0x28, ['Flags', {'bitmap': SERVICE_TYPE_FLAGS}]],
|
|
'State' : [ 0x2c, ['Enumeration', dict(target = 'long', choices = SERVICE_STATE_ENUM)]],
|
|
'Start' : [ 0x44, ['Enumeration', dict(target = 'long', choices = SERVICE_START_ENUM)]],
|
|
} ],
|
|
'_SERVICE_PROCESS': [ None, {
|
|
'BinaryPath': [ 0xc, ['pointer', ['String', dict(encoding = 'utf16', length = 256)]]],
|
|
'ProcessId': [ 0x10, ['unsigned int']],
|
|
} ],
|
|
})
|
|
|
|
#--------------------------------------------------------------------------------
|
|
# svcscan plugin
|
|
#--------------------------------------------------------------------------------
|
|
|
|
class SvcScan(common.AbstractWindowsCommand):
|
|
"Scan for Windows services"
|
|
|
|
def calculate(self):
|
|
addr_space = utils.load_as(self._config)
|
|
|
|
# Get the version we're analyzing
|
|
version = (addr_space.profile.metadata.get('major', 0),
|
|
addr_space.profile.metadata.get('minor', 0))
|
|
|
|
tag = obj.VolMagic(addr_space).ServiceTag.v()
|
|
|
|
# On systems more recent than XP/2003, the serH marker doesn't
|
|
# find *all* services, but the ones it does find have linked
|
|
# lists to the others. We use this variable to track which
|
|
# ones we've seen so as to not yield duplicates.
|
|
records = []
|
|
|
|
for task in tasks.pslist(addr_space):
|
|
# We only want the Service Control Manager process
|
|
if str(task.ImageFileName).lower() != "services.exe":
|
|
continue
|
|
# Process AS must be valid
|
|
process_space = task.get_process_address_space()
|
|
if process_space == None:
|
|
continue
|
|
# Find all instances of the record tag
|
|
for address in task.search_process_memory([tag]):
|
|
if version <= (5, 2):
|
|
# Windows XP/2003
|
|
rec = obj.Object("_SERVICE_RECORD", offset = address -
|
|
addr_space.profile.get_obj_offset('_SERVICE_RECORD', 'Tag'),
|
|
vm = process_space
|
|
)
|
|
# Apply our sanity checks
|
|
if rec.is_valid():
|
|
yield rec
|
|
else:
|
|
# Windows Vista, 2008, and 7
|
|
svc_hdr = obj.Object('_SERVICE_HEADER', offset = address,
|
|
vm = process_space)
|
|
# Apply our sanity checks
|
|
if svc_hdr.is_valid():
|
|
# Since we walk the s-list backwards, if we've seen
|
|
# an object, then we've also seen all objects that
|
|
# exist before it, thus we can break at that time.
|
|
for rec in svc_hdr.ServiceRecord.traverse():
|
|
if rec in records:
|
|
break
|
|
records.append(rec)
|
|
yield rec
|
|
|
|
def render_dot(self, outfd, data):
|
|
"""Generate a dot graph of service relationships.
|
|
|
|
This currently only works for XP/2003 profiles,
|
|
because the linked list was removed after that.
|
|
"""
|
|
|
|
## Collect all the service records from calculate()
|
|
all_services = [d for d in data]
|
|
|
|
## Abort if we're not using the supported profiles
|
|
if all_services[0].obj_vm.profile.metadata.get('major', 0) != 5:
|
|
debug.error("This profile does not support --output=dot format")
|
|
|
|
objects = set()
|
|
links = set()
|
|
|
|
for svc in all_services:
|
|
label = "{{ {0:#x} \\n {1} \\n {2} \\n F:{3:#x} B:{4:#x} }}".format(
|
|
svc.obj_offset,
|
|
svc.ServiceName.dereference(),
|
|
str(svc.State),
|
|
svc.ServiceList.Flink.v(),
|
|
svc.ServiceList.Blink.v())
|
|
objects.add('"{0:#x}" [label="{1}" shape="record"];\n'.format(
|
|
svc.obj_offset, label))
|
|
|
|
## Check the linked list pointers
|
|
flink = svc.ServiceList.Flink.dereference()
|
|
blink = svc.ServiceList.Blink.dereference()
|
|
|
|
if flink.is_valid():
|
|
links.add('"{0:#x}" -> "{1:#x}" [];\n'.format(
|
|
svc.obj_offset, flink.obj_offset))
|
|
if blink.is_valid():
|
|
links.add('"{0:#x}" -> "{1:#x}" [];\n'.format(
|
|
svc.obj_offset, blink.obj_offset))
|
|
|
|
## Now write the graph nodes
|
|
outfd.write("digraph svctree { \ngraph [rankdir = \"TB\"];\n")
|
|
for item in objects:
|
|
outfd.write(item)
|
|
for link in links:
|
|
outfd.write(link)
|
|
outfd.write("}\n")
|
|
|
|
@staticmethod
|
|
def get_service_dlls(regapi):
|
|
ccs = regapi.reg_get_currentcontrolset()
|
|
key_name = "{0}\\services".format(ccs)
|
|
dlls = {}
|
|
for subkey in regapi.reg_get_all_subkeys(hive_name = "system", key = key_name):
|
|
for rootkey in regapi.reg_get_all_subkeys(hive_name = "system", key = "", given_root = subkey):
|
|
if rootkey.Name == "Parameters":
|
|
service_dll = regapi.reg_get_value(hive_name = "system", key = "", value = "ServiceDll", given_root = rootkey)
|
|
if service_dll != None:
|
|
dlls[utils.remove_unprintable(str(subkey.Name))] = "{0}".format(utils.remove_unprintable(service_dll))
|
|
return dlls
|
|
|
|
def unified_output(self, data):
|
|
if self._config.VERBOSE:
|
|
return TreeGrid([("Offset", Address),
|
|
("Order", int),
|
|
("Start", str),
|
|
("PID", int),
|
|
("ServiceName", str),
|
|
("DisplayName", str),
|
|
("ServiceType", str),
|
|
("State", str),
|
|
("BinaryPath", str),
|
|
("ServiceDll", str)],
|
|
self.generator(data))
|
|
|
|
return TreeGrid([("Offset", Address),
|
|
("Order", int),
|
|
("Start", str),
|
|
("PID", int),
|
|
("ServiceName", str),
|
|
("DisplayName", str),
|
|
("ServiceType", str),
|
|
("State", str),
|
|
("BinaryPath", str)],
|
|
self.generator(data))
|
|
|
|
def generator(self, data):
|
|
if self._config.VERBOSE:
|
|
regapi = registryapi.RegistryApi(self._config)
|
|
dlls = self.get_service_dlls(regapi)
|
|
|
|
for rec in data:
|
|
if self._config.VERBOSE:
|
|
val = dlls.get("{0}".format(rec.ServiceName.dereference()), None)
|
|
if val == None:
|
|
val = ""
|
|
yield (0, [Address(rec.obj_offset),
|
|
int(rec.Order),
|
|
str(rec.Start),
|
|
int(rec.Pid),
|
|
str(rec.ServiceName.dereference() or ""),
|
|
str(rec.DisplayName.dereference() or ""),
|
|
str(rec.Type),
|
|
str(rec.State),
|
|
str(rec.Binary or ""),
|
|
str(val)])
|
|
else:
|
|
yield (0, [Address(rec.obj_offset),
|
|
int(rec.Order),
|
|
str(rec.Start),
|
|
int(rec.Pid),
|
|
str(rec.ServiceName.dereference() or ""),
|
|
str(rec.DisplayName.dereference() or ""),
|
|
str(rec.Type),
|
|
str(rec.State),
|
|
str(rec.Binary or "")])
|
|
|
|
def render_text(self, outfd, data):
|
|
|
|
if self._config.VERBOSE:
|
|
regapi = registryapi.RegistryApi(self._config)
|
|
dlls = self.get_service_dlls(regapi)
|
|
|
|
for rec in data:
|
|
# This can't possibly look neat in a table with columns...
|
|
outfd.write("Offset: {0:#x}\n".format(rec.obj_offset))
|
|
outfd.write("Order: {0}\n".format(rec.Order))
|
|
outfd.write("Start: {0}\n".format(rec.Start))
|
|
outfd.write("Process ID: {0}\n".format(rec.Pid))
|
|
outfd.write("Service Name: {0}\n".format(rec.ServiceName.dereference()))
|
|
outfd.write("Display Name: {0}\n".format(rec.DisplayName.dereference()))
|
|
outfd.write("Service Type: {0}\n".format(rec.Type))
|
|
outfd.write("Service State: {0}\n".format(rec.State))
|
|
outfd.write("Binary Path: {0}\n".format(rec.Binary))
|
|
|
|
if self._config.VERBOSE:
|
|
val = dlls.get("{0}".format(rec.ServiceName.dereference()), None)
|
|
if val is not None:
|
|
outfd.write("ServiceDll: {0}\n".format(val))
|
|
|
|
outfd.write("\n")
|