mirror of
https://github.com/volatilityfoundation/volatility3.git
synced 2026-09-11 20:27:38 +02:00
Windows: Cleanup devicetree + extension class
Moves a lot of the code that was parsing information about device objects out of the `DeviceTree` plugin logic and into the `DEVICE_OBJECT` extension class. Also moved the dict mapping integer values to device types into the extension module. Fixes a bug within the extension class' `get_attached_devices` method - now, immediate children of the device in the tree are yielded, instead of the faulty deep traversal that was occuring before. Because of this bugfix in an extension class as well as the addition of new methods in the extension class, this also bumps the framework minor version number.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# We use the SemVer 2.0.0 versioning scheme
|
||||
VERSION_MAJOR = 2 # Number of releases of the library with a breaking change
|
||||
VERSION_MINOR = 23 # Number of changes that only add to the interface
|
||||
VERSION_MINOR = 24 # Number of changes that only add to the interface
|
||||
VERSION_PATCH = 0 # Number of changes that do not change the interface
|
||||
VERSION_SUFFIX = ""
|
||||
|
||||
|
||||
@@ -8,70 +8,9 @@ from typing import Iterator, List, Set, Tuple
|
||||
from volatility3.framework import constants, exceptions, interfaces, renderers
|
||||
from volatility3.framework.configuration import requirements
|
||||
from volatility3.framework.renderers import format_hints
|
||||
from volatility3.framework.symbols.windows.extensions import DEVICE_OBJECT
|
||||
from volatility3.framework.symbols.windows import extensions
|
||||
from volatility3.plugins.windows import driverscan
|
||||
|
||||
DEVICE_CODES = {
|
||||
0x00000027: "FILE_DEVICE_8042_PORT",
|
||||
0x00000032: "FILE_DEVICE_ACPI",
|
||||
0x00000029: "FILE_DEVICE_BATTERY",
|
||||
0x00000001: "FILE_DEVICE_BEEP",
|
||||
0x0000002A: "FILE_DEVICE_BUS_EXTENDER",
|
||||
0x00000002: "FILE_DEVICE_CD_ROM",
|
||||
0x00000003: "FILE_DEVICE_CD_ROM_FILE_SYSTEM",
|
||||
0x00000030: "FILE_DEVICE_CHANGER",
|
||||
0x00000004: "FILE_DEVICE_CONTROLLER",
|
||||
0x00000005: "FILE_DEVICE_DATALINK",
|
||||
0x00000006: "FILE_DEVICE_DFS",
|
||||
0x00000035: "FILE_DEVICE_DFS_FILE_SYSTEM",
|
||||
0x00000036: "FILE_DEVICE_DFS_VOLUME",
|
||||
0x00000007: "FILE_DEVICE_DISK",
|
||||
0x00000008: "FILE_DEVICE_DISK_FILE_SYSTEM",
|
||||
0x00000033: "FILE_DEVICE_DVD",
|
||||
0x00000009: "FILE_DEVICE_FILE_SYSTEM",
|
||||
0x0000003A: "FILE_DEVICE_FIPS",
|
||||
0x00000034: "FILE_DEVICE_FULLSCREEN_VIDEO",
|
||||
0x0000000A: "FILE_DEVICE_INPORT_PORT",
|
||||
0x0000000B: "FILE_DEVICE_KEYBOARD",
|
||||
0x0000002F: "FILE_DEVICE_KS",
|
||||
0x00000039: "FILE_DEVICE_KSEC",
|
||||
0x0000000C: "FILE_DEVICE_MAILSLOT",
|
||||
0x0000002D: "FILE_DEVICE_MASS_STORAGE",
|
||||
0x0000000D: "FILE_DEVICE_MIDI_IN",
|
||||
0x0000000E: "FILE_DEVICE_MIDI_OUT",
|
||||
0x0000002B: "FILE_DEVICE_MODEM",
|
||||
0x0000000F: "FILE_DEVICE_MOUSE",
|
||||
0x00000010: "FILE_DEVICE_MULTI_UNC_PROVIDER",
|
||||
0x00000011: "FILE_DEVICE_NAMED_PIPE",
|
||||
0x00000012: "FILE_DEVICE_NETWORK",
|
||||
0x00000013: "FILE_DEVICE_NETWORK_BROWSER",
|
||||
0x00000014: "FILE_DEVICE_NETWORK_FILE_SYSTEM",
|
||||
0x00000028: "FILE_DEVICE_NETWORK_REDIRECTOR",
|
||||
0x00000015: "FILE_DEVICE_NULL",
|
||||
0x00000016: "FILE_DEVICE_PARALLEL_PORT",
|
||||
0x00000017: "FILE_DEVICE_PHYSICAL_NETCARD",
|
||||
0x00000018: "FILE_DEVICE_PRINTER",
|
||||
0x00000019: "FILE_DEVICE_SCANNER",
|
||||
0x0000001C: "FILE_DEVICE_SCREEN",
|
||||
0x00000037: "FILE_DEVICE_SERENUM",
|
||||
0x0000001A: "FILE_DEVICE_SERIAL_MOUSE_PORT",
|
||||
0x0000001B: "FILE_DEVICE_SERIAL_PORT",
|
||||
0x00000031: "FILE_DEVICE_SMARTCARD",
|
||||
0x0000002E: "FILE_DEVICE_SMB",
|
||||
0x0000001D: "FILE_DEVICE_SOUND",
|
||||
0x0000001E: "FILE_DEVICE_STREAMS",
|
||||
0x0000001F: "FILE_DEVICE_TAPE",
|
||||
0x00000020: "FILE_DEVICE_TAPE_FILE_SYSTEM",
|
||||
0x00000038: "FILE_DEVICE_TERMSRV",
|
||||
0x00000021: "FILE_DEVICE_TRANSPORT",
|
||||
0x00000022: "FILE_DEVICE_UNKNOWN",
|
||||
0x0000002C: "FILE_DEVICE_VDM",
|
||||
0x00000023: "FILE_DEVICE_VIDEO",
|
||||
0x00000024: "FILE_DEVICE_VIRTUAL_DISK",
|
||||
0x00000025: "FILE_DEVICE_WAVE_IN",
|
||||
0x00000026: "FILE_DEVICE_WAVE_OUT",
|
||||
}
|
||||
|
||||
vollog = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -101,97 +40,77 @@ class DeviceTree(interfaces.plugins.PluginInterface):
|
||||
self.config["kernel"],
|
||||
):
|
||||
try:
|
||||
try:
|
||||
driver_name = driver.DriverName.get_string()
|
||||
except (ValueError, exceptions.InvalidAddressException):
|
||||
vollog.log(
|
||||
constants.LOGLEVEL_VVVV,
|
||||
f"Failed to get Driver name : {driver.vol.offset:x}",
|
||||
)
|
||||
driver_name = renderers.UnparsableValue()
|
||||
|
||||
yield (
|
||||
0,
|
||||
(
|
||||
format_hints.Hex(driver.vol.offset),
|
||||
"DRV",
|
||||
driver_name,
|
||||
renderers.NotApplicableValue(),
|
||||
renderers.NotApplicableValue(),
|
||||
renderers.NotApplicableValue(),
|
||||
),
|
||||
)
|
||||
|
||||
# Scan to get the device information of driver.
|
||||
for device in driver.get_devices():
|
||||
for level, (
|
||||
offset,
|
||||
drv_name,
|
||||
dev_name,
|
||||
att_drv_name,
|
||||
dev_typ,
|
||||
) in self._traverse_device_stack(device, driver_name, 1):
|
||||
yield level, (
|
||||
offset,
|
||||
"DEV" if level == 1 else "ATT",
|
||||
drv_name,
|
||||
dev_name,
|
||||
att_drv_name,
|
||||
dev_typ,
|
||||
)
|
||||
|
||||
except exceptions.InvalidAddressException:
|
||||
vollog.log(
|
||||
constants.LOGLEVEL_VVVV,
|
||||
f"Invalid address identified in drivers and devices: {driver.vol.offset:x}",
|
||||
)
|
||||
continue
|
||||
|
||||
@staticmethod
|
||||
def _traverse_device_stack(
|
||||
device: DEVICE_OBJECT, driver_name: str, level: int, seen: Set[int] = set()
|
||||
) -> Iterator[Tuple]:
|
||||
while device and device.vol.offset not in seen:
|
||||
seen.add(device.vol.offset)
|
||||
try:
|
||||
device_name = device.get_device_name()
|
||||
driver_name = driver.DriverName.get_string()
|
||||
except (ValueError, exceptions.InvalidAddressException):
|
||||
vollog.log(
|
||||
constants.LOGLEVEL_VVVV,
|
||||
f"Failed to get Device name : {device.vol.offset:x}",
|
||||
f"Failed to get Driver name : {driver.vol.offset:x}",
|
||||
)
|
||||
device_name = renderers.UnparsableValue()
|
||||
|
||||
device_type = DEVICE_CODES.get(device.DeviceType, "UNKNOWN")
|
||||
|
||||
att_drv_name = device.DriverObject.DriverName.get_string()
|
||||
driver_name = renderers.UnparsableValue()
|
||||
|
||||
yield (
|
||||
level,
|
||||
0,
|
||||
(
|
||||
format_hints.Hex(device.vol.offset),
|
||||
format_hints.Hex(driver.vol.offset),
|
||||
"DRV",
|
||||
driver_name,
|
||||
device_name,
|
||||
att_drv_name,
|
||||
device_type,
|
||||
renderers.NotApplicableValue(),
|
||||
renderers.NotApplicableValue(),
|
||||
renderers.NotApplicableValue(),
|
||||
),
|
||||
)
|
||||
try:
|
||||
attached = device.AttachedDevice.dereference()
|
||||
yield from DeviceTree._traverse_device_stack(
|
||||
attached, driver_name, level + 1, seen
|
||||
)
|
||||
except exceptions.InvalidAddressException:
|
||||
vollog.debug(
|
||||
f"Failed to dereference attached device for device at {device.vol.offset:#x}, "
|
||||
"devnode may not have drivers associated with it"
|
||||
)
|
||||
|
||||
# Scan to get the device information of driver.
|
||||
for device in driver.get_devices():
|
||||
for level, device_entry in self._traverse_device_tree(device, 1):
|
||||
try:
|
||||
device_name = device.get_device_name()
|
||||
except (ValueError, exceptions.InvalidAddressException):
|
||||
device_name = renderers.UnparsableValue()
|
||||
|
||||
try:
|
||||
attached_driver_name = device.get_attached_driver_name()
|
||||
except exceptions.InvalidAddressException:
|
||||
attached_driver_name = renderers.UnparsableValue()
|
||||
|
||||
try:
|
||||
device_type = device.get_device_type()
|
||||
except exceptions.InvalidAddressException:
|
||||
device_type = renderers.UnparsableValue()
|
||||
|
||||
yield level, (
|
||||
format_hints.Hex(device_entry.vol.offset),
|
||||
"DEV" if level == 1 else "ATT",
|
||||
driver_name,
|
||||
device_name,
|
||||
attached_driver_name,
|
||||
device_type,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def _traverse_device_tree(
|
||||
cls, device: extensions.DEVICE_OBJECT, level: int, seen: Set[int] = set()
|
||||
) -> Iterator[Tuple[int, extensions.DEVICE_OBJECT]]:
|
||||
vollog.debug(f"Traversing device tree for device at {device.vol.offset:#x}")
|
||||
while device and device.vol.offset not in seen:
|
||||
seen.add(device.vol.offset)
|
||||
|
||||
# Yield the first device and its level
|
||||
yield (
|
||||
level,
|
||||
device,
|
||||
)
|
||||
|
||||
for attached in device.get_attached_devices():
|
||||
# Go depth-first through all of this device's child devices
|
||||
yield from cls._traverse_device_tree(attached, level + 1, seen)
|
||||
|
||||
try:
|
||||
# Then move sideways to the next device in the current linked list
|
||||
device = device.NextDevice.dereference()
|
||||
except exceptions.InvalidAddressException:
|
||||
vollog.debug(
|
||||
f"Failed to dereference next driver in linked list at {int(device.NextDevice)}, "
|
||||
"Failed to dereference next driver in linked list, "
|
||||
"may have reached end of list"
|
||||
)
|
||||
|
||||
|
||||
@@ -22,9 +22,8 @@ from volatility3.framework.interfaces.objects import ObjectInterface
|
||||
from volatility3.framework.layers import intel
|
||||
from volatility3.framework.objects import utility
|
||||
from volatility3.framework.renderers import conversion
|
||||
from volatility3.framework.symbols import generic
|
||||
from volatility3.framework.symbols import generic, windows
|
||||
from volatility3.framework.symbols.windows.extensions import pool
|
||||
from volatility3.framework.symbols import windows
|
||||
|
||||
vollog = logging.getLogger(__name__)
|
||||
|
||||
@@ -406,33 +405,129 @@ class EX_FAST_REF(objects.StructType):
|
||||
)
|
||||
|
||||
|
||||
DEVICE_CODES = {
|
||||
0x00000027: "FILE_DEVICE_8042_PORT",
|
||||
0x00000032: "FILE_DEVICE_ACPI",
|
||||
0x00000029: "FILE_DEVICE_BATTERY",
|
||||
0x00000001: "FILE_DEVICE_BEEP",
|
||||
0x0000002A: "FILE_DEVICE_BUS_EXTENDER",
|
||||
0x00000002: "FILE_DEVICE_CD_ROM",
|
||||
0x00000003: "FILE_DEVICE_CD_ROM_FILE_SYSTEM",
|
||||
0x00000030: "FILE_DEVICE_CHANGER",
|
||||
0x00000004: "FILE_DEVICE_CONTROLLER",
|
||||
0x00000005: "FILE_DEVICE_DATALINK",
|
||||
0x00000006: "FILE_DEVICE_DFS",
|
||||
0x00000035: "FILE_DEVICE_DFS_FILE_SYSTEM",
|
||||
0x00000036: "FILE_DEVICE_DFS_VOLUME",
|
||||
0x00000007: "FILE_DEVICE_DISK",
|
||||
0x00000008: "FILE_DEVICE_DISK_FILE_SYSTEM",
|
||||
0x00000033: "FILE_DEVICE_DVD",
|
||||
0x00000009: "FILE_DEVICE_FILE_SYSTEM",
|
||||
0x0000003A: "FILE_DEVICE_FIPS",
|
||||
0x00000034: "FILE_DEVICE_FULLSCREEN_VIDEO",
|
||||
0x0000000A: "FILE_DEVICE_INPORT_PORT",
|
||||
0x0000000B: "FILE_DEVICE_KEYBOARD",
|
||||
0x0000002F: "FILE_DEVICE_KS",
|
||||
0x00000039: "FILE_DEVICE_KSEC",
|
||||
0x0000000C: "FILE_DEVICE_MAILSLOT",
|
||||
0x0000002D: "FILE_DEVICE_MASS_STORAGE",
|
||||
0x0000000D: "FILE_DEVICE_MIDI_IN",
|
||||
0x0000000E: "FILE_DEVICE_MIDI_OUT",
|
||||
0x0000002B: "FILE_DEVICE_MODEM",
|
||||
0x0000000F: "FILE_DEVICE_MOUSE",
|
||||
0x00000010: "FILE_DEVICE_MULTI_UNC_PROVIDER",
|
||||
0x00000011: "FILE_DEVICE_NAMED_PIPE",
|
||||
0x00000012: "FILE_DEVICE_NETWORK",
|
||||
0x00000013: "FILE_DEVICE_NETWORK_BROWSER",
|
||||
0x00000014: "FILE_DEVICE_NETWORK_FILE_SYSTEM",
|
||||
0x00000028: "FILE_DEVICE_NETWORK_REDIRECTOR",
|
||||
0x00000015: "FILE_DEVICE_NULL",
|
||||
0x00000016: "FILE_DEVICE_PARALLEL_PORT",
|
||||
0x00000017: "FILE_DEVICE_PHYSICAL_NETCARD",
|
||||
0x00000018: "FILE_DEVICE_PRINTER",
|
||||
0x00000019: "FILE_DEVICE_SCANNER",
|
||||
0x0000001C: "FILE_DEVICE_SCREEN",
|
||||
0x00000037: "FILE_DEVICE_SERENUM",
|
||||
0x0000001A: "FILE_DEVICE_SERIAL_MOUSE_PORT",
|
||||
0x0000001B: "FILE_DEVICE_SERIAL_PORT",
|
||||
0x00000031: "FILE_DEVICE_SMARTCARD",
|
||||
0x0000002E: "FILE_DEVICE_SMB",
|
||||
0x0000001D: "FILE_DEVICE_SOUND",
|
||||
0x0000001E: "FILE_DEVICE_STREAMS",
|
||||
0x0000001F: "FILE_DEVICE_TAPE",
|
||||
0x00000020: "FILE_DEVICE_TAPE_FILE_SYSTEM",
|
||||
0x00000038: "FILE_DEVICE_TERMSRV",
|
||||
0x00000021: "FILE_DEVICE_TRANSPORT",
|
||||
0x00000022: "FILE_DEVICE_UNKNOWN",
|
||||
0x0000002C: "FILE_DEVICE_VDM",
|
||||
0x00000023: "FILE_DEVICE_VIDEO",
|
||||
0x00000024: "FILE_DEVICE_VIRTUAL_DISK",
|
||||
0x00000025: "FILE_DEVICE_WAVE_IN",
|
||||
0x00000026: "FILE_DEVICE_WAVE_OUT",
|
||||
}
|
||||
|
||||
|
||||
class DEVICE_OBJECT(objects.StructType, pool.ExecutiveObject):
|
||||
"""A class for kernel device objects."""
|
||||
|
||||
def get_device_name(self) -> str:
|
||||
"""Get device's name from the object header."""
|
||||
"""Get device's name from the object header.
|
||||
|
||||
Raises:
|
||||
ValueError if the device has no _OBJECT_HEADER_NAME_INFO member
|
||||
InvalidAddressException if the name cannot be dereferenced due to smear/swapped pages
|
||||
|
||||
"""
|
||||
header = self.get_object_header()
|
||||
return header.NameInfo.Name.String # type: ignore
|
||||
|
||||
def get_attached_devices(self) -> Generator[ObjectInterface, None, None]:
|
||||
"""Enumerate the attached device's objects"""
|
||||
def get_attached_driver_name(self) -> str:
|
||||
"""Gets the name of the driver that is attached to this device.
|
||||
|
||||
Raises:
|
||||
InvalidAddressException if the name cannot be dereferenced due to smear/swapped pages
|
||||
"""
|
||||
return self.DriverObject.DriverName.get_string()
|
||||
|
||||
def get_device_type(self) -> str:
|
||||
"""Gets the device type as a readable string.
|
||||
|
||||
Raises:
|
||||
InvalidAddressException if the DeviceType member cannot be read.
|
||||
"""
|
||||
return DEVICE_CODES.get(self.DeviceType, "UNKNOWN")
|
||||
|
||||
def get_attached_devices(self) -> Iterator["DEVICE_OBJECT"]:
|
||||
"""Enumerate the attached device's objects.
|
||||
|
||||
This only yields devices that are direct children of this devnode. In order to visit
|
||||
nodes farther down the tree, this method must be called on each of those children
|
||||
(and their children, and so on) to fully enumerate the device subtree. Child enumeration
|
||||
will stop if a device is seen twice or at the first InvalidAddressException, but the
|
||||
InvalidAddressException is not raised to the calling function.
|
||||
"""
|
||||
seen = set()
|
||||
|
||||
try:
|
||||
device = self.AttachedDevice.dereference()
|
||||
except exceptions.InvalidAddressException:
|
||||
vollog.debug(
|
||||
f"No attached device dereferenced for DEVICE_OBJECT at {self.vol.offset:#x}"
|
||||
)
|
||||
return
|
||||
|
||||
while device:
|
||||
if device.vol.offset in seen:
|
||||
break
|
||||
while device and device.vol.offset not in seen:
|
||||
seen.add(device.vol.offset)
|
||||
|
||||
yield device
|
||||
|
||||
try:
|
||||
device = device.AttachedDevice.dereference()
|
||||
device = device.NextDevice.dereference()
|
||||
except exceptions.InvalidAddressException:
|
||||
vollog.debug(
|
||||
f"Failed to dereference next device "
|
||||
f"for device at {device.vol.offset:#x}, may have reached list end"
|
||||
)
|
||||
return
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user