Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion volatility3/framework/constants/_version.py
Original file line number Diff line number Diff line change
@@ -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 = ""

Expand Down
202 changes: 65 additions & 137 deletions volatility3/framework/plugins/windows/devicetree.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,75 +3,14 @@
#

import logging
from typing import Iterator, List, Set, Tuple

from typing import Iterator, List, Tuple

from volatility3.framework import constants, renderers, exceptions, interfaces
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 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__)


Expand Down Expand Up @@ -101,90 +40,79 @@ def _generator(self) -> Iterator[Tuple]:
self.config["kernel"],
):
try:
try:
driver_name = driver.get_driver_name()
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(),
),
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}",
)

# Scan to get the device information of driver.
for device in driver.get_devices():
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, device_entry in self._traverse_device_tree(device, 1):
try:
device_name = device.get_device_name()
except (ValueError, exceptions.InvalidAddressException):
vollog.log(
constants.LOGLEVEL_VVVV,
f"Failed to get Device name : {device.vol.offset:x}",
)
device_name = renderers.UnparsableValue()

device_type = DEVICE_CODES.get(device.DeviceType, "UNKNOWN")

yield (
1,
(
format_hints.Hex(driver.vol.offset),
"DEV",
driver_name,
device_name,
renderers.NotApplicableValue(),
device_type,
),
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,
)

# Scan to get the attached devices information of device.
for level, attached_device in enumerate(
device.get_attached_devices(), start=2
):
try:
device_name = attached_device.get_device_name()
except (ValueError, exceptions.InvalidAddressException):
vollog.log(
constants.LOGLEVEL_VVVV,
f"Failed to get Attached Device Name: {attached_device.vol.offset:x}",
)
device_name = renderers.UnparsableValue()

attached_device_driver_name = (
attached_device.DriverObject.DriverName.get_string()
)
attached_device_type = DEVICE_CODES.get(
attached_device.DeviceType, "UNKNOWN"
)

yield (
level,
(
format_hints.Hex(driver.vol.offset),
"ATT",
driver_name,
device_name,
attached_device_driver_name,
attached_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.log(
constants.LOGLEVEL_VVVV,
f"Invalid address identified in drivers and devices: {driver.vol.offset:x}",
vollog.debug(
"Failed to dereference next driver in linked list, "
"may have reached end of list"
)
continue

def run(self) -> renderers.TreeGrid:
return renderers.TreeGrid(
Expand Down
113 changes: 104 additions & 9 deletions volatility3/framework/symbols/windows/extensions/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,8 @@
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__)

Expand Down Expand Up @@ -406,33 +405,129 @@ def dereference(self) -> interfaces.objects.ObjectInterface:
)


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


Expand Down
Loading