mirror of
https://github.com/volatilityfoundation/volatility3.git
synced 2026-09-28 12:34:53 +02:00
116 lines
3.8 KiB
Python
116 lines
3.8 KiB
Python
# This file is Copyright 2019 Volatility Foundation and licensed under the Volatility Software License 1.0
|
|
# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0
|
|
#
|
|
|
|
import logging
|
|
|
|
from typing import List, Optional, Tuple
|
|
|
|
from volatility3.framework import interfaces, exceptions, symbols
|
|
from volatility3.framework.configuration import requirements
|
|
from volatility3.framework.symbols.windows import versions
|
|
from volatility3.plugins.windows import svcscan, pslist
|
|
from volatility3.framework.layers import scanners
|
|
|
|
vollog = logging.getLogger(__name__)
|
|
|
|
|
|
class SvcList(svcscan.SvcScan):
|
|
"""Lists services contained with the services.exe doubly linked list of services"""
|
|
|
|
_version = (1, 0, 0)
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
self._enumeration_method = self.service_list
|
|
|
|
@classmethod
|
|
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
|
|
# Since we're calling the plugin, make sure we have the plugin's requirements
|
|
return [
|
|
requirements.PluginRequirement(
|
|
name="svcscan", plugin=svcscan.SvcScan, version=(3, 0, 0)
|
|
),
|
|
requirements.ModuleRequirement(
|
|
name="kernel",
|
|
description="Windows kernel",
|
|
architectures=["Intel32", "Intel64"],
|
|
),
|
|
]
|
|
|
|
@classmethod
|
|
def _get_exe_range(cls, proc) -> Optional[Tuple[int, int]]:
|
|
"""
|
|
Returns a tuple of starting,ending address for
|
|
the VAD containing services.exe
|
|
"""
|
|
|
|
vad_root = proc.get_vad_root()
|
|
for vad in vad_root.traverse():
|
|
filename = vad.get_file_name()
|
|
if isinstance(filename, str) and filename.lower().endswith(
|
|
"\\services.exe"
|
|
):
|
|
return [(vad.get_start(), vad.get_size())]
|
|
|
|
return None
|
|
|
|
@classmethod
|
|
def service_list(
|
|
cls,
|
|
context: interfaces.context.ContextInterface,
|
|
layer_name: str,
|
|
symbol_table: str,
|
|
service_table_name: str,
|
|
service_binary_dll_map,
|
|
filter_func,
|
|
):
|
|
if not symbols.symbol_table_is_64bit(
|
|
context, symbol_table
|
|
) or not versions.is_win10_15063_or_later(
|
|
context=context, symbol_table=symbol_table
|
|
):
|
|
vollog.warning(
|
|
"This plugin only supports Windows 10 version 15063+ 64bit Windows memory samples"
|
|
)
|
|
return
|
|
|
|
for proc in pslist.PsList.list_processes(
|
|
context=context,
|
|
layer_name=layer_name,
|
|
symbol_table=symbol_table,
|
|
filter_func=filter_func,
|
|
):
|
|
try:
|
|
layer_name = proc.add_process_layer()
|
|
except exceptions.InvalidAddressException:
|
|
vollog.warning(
|
|
"Unable to access memory of services.exe running with PID: {}".format(
|
|
proc.UniqueProcessId
|
|
)
|
|
)
|
|
continue
|
|
|
|
layer = context.layers[layer_name]
|
|
|
|
exe_range = cls._get_exe_range(proc)
|
|
if not exe_range:
|
|
vollog.warning(
|
|
"Could not find the application executable VAD for services.exe. Unable to proceed."
|
|
)
|
|
continue
|
|
|
|
for offset in layer.scan(
|
|
context=context,
|
|
scanner=scanners.BytesScanner(needle=b"Sc27"),
|
|
sections=exe_range,
|
|
):
|
|
for record in cls.enumerate_vista_or_later_header(
|
|
context,
|
|
service_table_name,
|
|
service_binary_dll_map,
|
|
layer_name,
|
|
offset,
|
|
):
|
|
yield record
|