Skip to content

Commit a1091c8

Browse files
committed
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, this also bumps the framework patch version number.
1 parent f66acd6 commit a1091c8

File tree

3 files changed

+136
-146
lines changed

3 files changed

+136
-146
lines changed

volatility3/framework/constants/_version.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# We use the SemVer 2.0.0 versioning scheme
22
VERSION_MAJOR = 2 # Number of releases of the library with a breaking change
33
VERSION_MINOR = 23 # Number of changes that only add to the interface
4-
VERSION_PATCH = 0 # Number of changes that do not change the interface
4+
VERSION_PATCH = 1 # Number of changes that do not change the interface
55
VERSION_SUFFIX = ""
66

77
PACKAGE_VERSION = (

volatility3/framework/plugins/windows/devicetree.py

+56-138
Original file line numberDiff line numberDiff line change
@@ -3,75 +3,14 @@
33
#
44

55
import logging
6-
from typing import Iterator, List, Set, Tuple
6+
from typing import Iterator, List, Set, Tuple, Union
77

88
from volatility3.framework import constants, exceptions, interfaces, renderers
99
from volatility3.framework.configuration import requirements
1010
from volatility3.framework.renderers import format_hints
11-
from volatility3.framework.symbols.windows.extensions import DEVICE_OBJECT
11+
from volatility3.framework.symbols.windows import extensions
1212
from volatility3.plugins.windows import driverscan
1313

14-
DEVICE_CODES = {
15-
0x00000027: "FILE_DEVICE_8042_PORT",
16-
0x00000032: "FILE_DEVICE_ACPI",
17-
0x00000029: "FILE_DEVICE_BATTERY",
18-
0x00000001: "FILE_DEVICE_BEEP",
19-
0x0000002A: "FILE_DEVICE_BUS_EXTENDER",
20-
0x00000002: "FILE_DEVICE_CD_ROM",
21-
0x00000003: "FILE_DEVICE_CD_ROM_FILE_SYSTEM",
22-
0x00000030: "FILE_DEVICE_CHANGER",
23-
0x00000004: "FILE_DEVICE_CONTROLLER",
24-
0x00000005: "FILE_DEVICE_DATALINK",
25-
0x00000006: "FILE_DEVICE_DFS",
26-
0x00000035: "FILE_DEVICE_DFS_FILE_SYSTEM",
27-
0x00000036: "FILE_DEVICE_DFS_VOLUME",
28-
0x00000007: "FILE_DEVICE_DISK",
29-
0x00000008: "FILE_DEVICE_DISK_FILE_SYSTEM",
30-
0x00000033: "FILE_DEVICE_DVD",
31-
0x00000009: "FILE_DEVICE_FILE_SYSTEM",
32-
0x0000003A: "FILE_DEVICE_FIPS",
33-
0x00000034: "FILE_DEVICE_FULLSCREEN_VIDEO",
34-
0x0000000A: "FILE_DEVICE_INPORT_PORT",
35-
0x0000000B: "FILE_DEVICE_KEYBOARD",
36-
0x0000002F: "FILE_DEVICE_KS",
37-
0x00000039: "FILE_DEVICE_KSEC",
38-
0x0000000C: "FILE_DEVICE_MAILSLOT",
39-
0x0000002D: "FILE_DEVICE_MASS_STORAGE",
40-
0x0000000D: "FILE_DEVICE_MIDI_IN",
41-
0x0000000E: "FILE_DEVICE_MIDI_OUT",
42-
0x0000002B: "FILE_DEVICE_MODEM",
43-
0x0000000F: "FILE_DEVICE_MOUSE",
44-
0x00000010: "FILE_DEVICE_MULTI_UNC_PROVIDER",
45-
0x00000011: "FILE_DEVICE_NAMED_PIPE",
46-
0x00000012: "FILE_DEVICE_NETWORK",
47-
0x00000013: "FILE_DEVICE_NETWORK_BROWSER",
48-
0x00000014: "FILE_DEVICE_NETWORK_FILE_SYSTEM",
49-
0x00000028: "FILE_DEVICE_NETWORK_REDIRECTOR",
50-
0x00000015: "FILE_DEVICE_NULL",
51-
0x00000016: "FILE_DEVICE_PARALLEL_PORT",
52-
0x00000017: "FILE_DEVICE_PHYSICAL_NETCARD",
53-
0x00000018: "FILE_DEVICE_PRINTER",
54-
0x00000019: "FILE_DEVICE_SCANNER",
55-
0x0000001C: "FILE_DEVICE_SCREEN",
56-
0x00000037: "FILE_DEVICE_SERENUM",
57-
0x0000001A: "FILE_DEVICE_SERIAL_MOUSE_PORT",
58-
0x0000001B: "FILE_DEVICE_SERIAL_PORT",
59-
0x00000031: "FILE_DEVICE_SMARTCARD",
60-
0x0000002E: "FILE_DEVICE_SMB",
61-
0x0000001D: "FILE_DEVICE_SOUND",
62-
0x0000001E: "FILE_DEVICE_STREAMS",
63-
0x0000001F: "FILE_DEVICE_TAPE",
64-
0x00000020: "FILE_DEVICE_TAPE_FILE_SYSTEM",
65-
0x00000038: "FILE_DEVICE_TERMSRV",
66-
0x00000021: "FILE_DEVICE_TRANSPORT",
67-
0x00000022: "FILE_DEVICE_UNKNOWN",
68-
0x0000002C: "FILE_DEVICE_VDM",
69-
0x00000023: "FILE_DEVICE_VIDEO",
70-
0x00000024: "FILE_DEVICE_VIRTUAL_DISK",
71-
0x00000025: "FILE_DEVICE_WAVE_IN",
72-
0x00000026: "FILE_DEVICE_WAVE_OUT",
73-
}
74-
7514
vollog = logging.getLogger(__name__)
7615

7716

@@ -101,97 +40,76 @@ def _generator(self) -> Iterator[Tuple]:
10140
self.config["kernel"],
10241
):
10342
try:
104-
try:
105-
driver_name = driver.DriverName.get_string()
106-
except (ValueError, exceptions.InvalidAddressException):
107-
vollog.log(
108-
constants.LOGLEVEL_VVVV,
109-
f"Failed to get Driver name : {driver.vol.offset:x}",
110-
)
111-
driver_name = renderers.UnparsableValue()
112-
113-
yield (
114-
0,
115-
(
116-
format_hints.Hex(driver.vol.offset),
117-
"DRV",
118-
driver_name,
119-
renderers.NotApplicableValue(),
120-
renderers.NotApplicableValue(),
121-
renderers.NotApplicableValue(),
122-
),
123-
)
124-
125-
# Scan to get the device information of driver.
126-
for device in driver.get_devices():
127-
for level, (
128-
offset,
129-
drv_name,
130-
dev_name,
131-
att_drv_name,
132-
dev_typ,
133-
) in self._traverse_device_stack(device, driver_name, 1):
134-
yield level, (
135-
offset,
136-
"DEV" if level == 1 else "ATT",
137-
drv_name,
138-
dev_name,
139-
att_drv_name,
140-
dev_typ,
141-
)
142-
143-
except exceptions.InvalidAddressException:
43+
driver_name = driver.DriverName.get_string()
44+
except (ValueError, exceptions.InvalidAddressException):
14445
vollog.log(
14546
constants.LOGLEVEL_VVVV,
146-
f"Invalid address identified in drivers and devices: {driver.vol.offset:x}",
47+
f"Failed to get Driver name : {driver.vol.offset:x}",
14748
)
148-
continue
49+
driver_name = renderers.UnparsableValue()
50+
51+
yield (
52+
0,
53+
(
54+
format_hints.Hex(driver.vol.offset),
55+
"DRV",
56+
driver_name,
57+
renderers.NotApplicableValue(),
58+
renderers.NotApplicableValue(),
59+
renderers.NotApplicableValue(),
60+
),
61+
)
62+
63+
# Scan to get the device information of driver.
64+
for device in driver.get_devices():
65+
for level, device_entry in self._traverse_device_stack(device, 1):
66+
try:
67+
device_name = device.get_device_name()
68+
except exceptions.InvalidAddressException:
69+
device_name = renderers.UnparsableValue()
70+
71+
try:
72+
attached_driver_name = device.get_attached_driver_name()
73+
except exceptions.InvalidAddressException:
74+
attached_driver_name = renderers.UnparsableValue()
75+
76+
try:
77+
device_type = device.get_device_type()
78+
except exceptions.InvalidAddressException:
79+
device_type = renderers.UnparsableValue()
80+
81+
yield level, (
82+
format_hints.Hex(device_entry.vol.offset),
83+
"DEV" if level == 1 else "ATT",
84+
driver_name,
85+
device_name,
86+
attached_driver_name,
87+
device_type,
88+
)
14989

150-
@staticmethod
90+
@classmethod
15191
def _traverse_device_stack(
152-
device: DEVICE_OBJECT, driver_name: str, level: int, seen: Set[int] = set()
153-
) -> Iterator[Tuple]:
92+
cls, device: extensions.DEVICE_OBJECT, level: int, seen: Set[int] = set()
93+
) -> Iterator[Tuple[int, extensions.DEVICE_OBJECT]]:
15494
while device and device.vol.offset not in seen:
15595
seen.add(device.vol.offset)
156-
try:
157-
device_name = device.get_device_name()
158-
except (ValueError, exceptions.InvalidAddressException):
159-
vollog.log(
160-
constants.LOGLEVEL_VVVV,
161-
f"Failed to get Device name : {device.vol.offset:x}",
162-
)
163-
device_name = renderers.UnparsableValue()
164-
165-
device_type = DEVICE_CODES.get(device.DeviceType, "UNKNOWN")
166-
167-
att_drv_name = device.DriverObject.DriverName.get_string()
16896

97+
# Yield the first device and its level
16998
yield (
17099
level,
171-
(
172-
format_hints.Hex(device.vol.offset),
173-
driver_name,
174-
device_name,
175-
att_drv_name,
176-
device_type,
177-
),
100+
device,
178101
)
179-
try:
180-
attached = device.AttachedDevice.dereference()
181-
yield from DeviceTree._traverse_device_stack(
182-
attached, driver_name, level + 1, seen
183-
)
184-
except exceptions.InvalidAddressException:
185-
vollog.debug(
186-
f"Failed to dereference attached device for device at {device.vol.offset:#x}, "
187-
"devnode may not have drivers associated with it"
188-
)
102+
103+
for attached in device.get_attached_devices():
104+
# Go depth-first through all of this device's child devices
105+
yield from cls._traverse_device_stack(attached, level + 1, seen)
189106

190107
try:
108+
# Then move sideways to the next device in the current linked list
191109
device = device.NextDevice.dereference()
192110
except exceptions.InvalidAddressException:
193111
vollog.debug(
194-
f"Failed to dereference next driver in linked list at {int(device.NextDevice)}, "
112+
f"Failed to dereference next driver in linked list, "
195113
"may have reached end of list"
196114
)
197115

volatility3/framework/symbols/windows/extensions/__init__.py

+79-7
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,8 @@
2222
from volatility3.framework.layers import intel
2323
from volatility3.framework.objects import utility
2424
from volatility3.framework.renderers import conversion
25-
from volatility3.framework.symbols import generic
25+
from volatility3.framework.symbols import generic, windows
2626
from volatility3.framework.symbols.windows.extensions import pool
27-
from volatility3.framework.symbols import windows
2827

2928
vollog = logging.getLogger(__name__)
3029

@@ -406,6 +405,68 @@ def dereference(self) -> interfaces.objects.ObjectInterface:
406405
)
407406

408407

408+
DEVICE_CODES = {
409+
0x00000027: "FILE_DEVICE_8042_PORT",
410+
0x00000032: "FILE_DEVICE_ACPI",
411+
0x00000029: "FILE_DEVICE_BATTERY",
412+
0x00000001: "FILE_DEVICE_BEEP",
413+
0x0000002A: "FILE_DEVICE_BUS_EXTENDER",
414+
0x00000002: "FILE_DEVICE_CD_ROM",
415+
0x00000003: "FILE_DEVICE_CD_ROM_FILE_SYSTEM",
416+
0x00000030: "FILE_DEVICE_CHANGER",
417+
0x00000004: "FILE_DEVICE_CONTROLLER",
418+
0x00000005: "FILE_DEVICE_DATALINK",
419+
0x00000006: "FILE_DEVICE_DFS",
420+
0x00000035: "FILE_DEVICE_DFS_FILE_SYSTEM",
421+
0x00000036: "FILE_DEVICE_DFS_VOLUME",
422+
0x00000007: "FILE_DEVICE_DISK",
423+
0x00000008: "FILE_DEVICE_DISK_FILE_SYSTEM",
424+
0x00000033: "FILE_DEVICE_DVD",
425+
0x00000009: "FILE_DEVICE_FILE_SYSTEM",
426+
0x0000003A: "FILE_DEVICE_FIPS",
427+
0x00000034: "FILE_DEVICE_FULLSCREEN_VIDEO",
428+
0x0000000A: "FILE_DEVICE_INPORT_PORT",
429+
0x0000000B: "FILE_DEVICE_KEYBOARD",
430+
0x0000002F: "FILE_DEVICE_KS",
431+
0x00000039: "FILE_DEVICE_KSEC",
432+
0x0000000C: "FILE_DEVICE_MAILSLOT",
433+
0x0000002D: "FILE_DEVICE_MASS_STORAGE",
434+
0x0000000D: "FILE_DEVICE_MIDI_IN",
435+
0x0000000E: "FILE_DEVICE_MIDI_OUT",
436+
0x0000002B: "FILE_DEVICE_MODEM",
437+
0x0000000F: "FILE_DEVICE_MOUSE",
438+
0x00000010: "FILE_DEVICE_MULTI_UNC_PROVIDER",
439+
0x00000011: "FILE_DEVICE_NAMED_PIPE",
440+
0x00000012: "FILE_DEVICE_NETWORK",
441+
0x00000013: "FILE_DEVICE_NETWORK_BROWSER",
442+
0x00000014: "FILE_DEVICE_NETWORK_FILE_SYSTEM",
443+
0x00000028: "FILE_DEVICE_NETWORK_REDIRECTOR",
444+
0x00000015: "FILE_DEVICE_NULL",
445+
0x00000016: "FILE_DEVICE_PARALLEL_PORT",
446+
0x00000017: "FILE_DEVICE_PHYSICAL_NETCARD",
447+
0x00000018: "FILE_DEVICE_PRINTER",
448+
0x00000019: "FILE_DEVICE_SCANNER",
449+
0x0000001C: "FILE_DEVICE_SCREEN",
450+
0x00000037: "FILE_DEVICE_SERENUM",
451+
0x0000001A: "FILE_DEVICE_SERIAL_MOUSE_PORT",
452+
0x0000001B: "FILE_DEVICE_SERIAL_PORT",
453+
0x00000031: "FILE_DEVICE_SMARTCARD",
454+
0x0000002E: "FILE_DEVICE_SMB",
455+
0x0000001D: "FILE_DEVICE_SOUND",
456+
0x0000001E: "FILE_DEVICE_STREAMS",
457+
0x0000001F: "FILE_DEVICE_TAPE",
458+
0x00000020: "FILE_DEVICE_TAPE_FILE_SYSTEM",
459+
0x00000038: "FILE_DEVICE_TERMSRV",
460+
0x00000021: "FILE_DEVICE_TRANSPORT",
461+
0x00000022: "FILE_DEVICE_UNKNOWN",
462+
0x0000002C: "FILE_DEVICE_VDM",
463+
0x00000023: "FILE_DEVICE_VIDEO",
464+
0x00000024: "FILE_DEVICE_VIRTUAL_DISK",
465+
0x00000025: "FILE_DEVICE_WAVE_IN",
466+
0x00000026: "FILE_DEVICE_WAVE_OUT",
467+
}
468+
469+
409470
class DEVICE_OBJECT(objects.StructType, pool.ExecutiveObject):
410471
"""A class for kernel device objects."""
411472

@@ -414,25 +475,36 @@ def get_device_name(self) -> str:
414475
header = self.get_object_header()
415476
return header.NameInfo.Name.String # type: ignore
416477

417-
def get_attached_devices(self) -> Generator[ObjectInterface, None, None]:
478+
def get_attached_driver_name(self) -> Optional[str]:
479+
return self.DriverObject.DriverName.get_string()
480+
481+
def get_device_type(self) -> str:
482+
return DEVICE_CODES.get(self.DeviceType, "UNKNOWN")
483+
484+
def get_attached_devices(self) -> Iterator["DEVICE_OBJECT"]:
418485
"""Enumerate the attached device's objects"""
419486
seen = set()
420487

421488
try:
422489
device = self.AttachedDevice.dereference()
423490
except exceptions.InvalidAddressException:
491+
vollog.debug(
492+
f"No attached device dereferenced for DEVICE_OBJECT at {self.vol.offset:#x}"
493+
)
424494
return
425495

426-
while device:
427-
if device.vol.offset in seen:
428-
break
496+
while device and device.vol.offset not in seen:
429497
seen.add(device.vol.offset)
430498

431499
yield device
432500

433501
try:
434-
device = device.AttachedDevice.dereference()
502+
device = device.NextDevice.dereference()
435503
except exceptions.InvalidAddressException:
504+
vollog.debug(
505+
f"Failed to dereference next device "
506+
f"for device at {device.vol.offset:#x}, may have reached list end"
507+
)
436508
return
437509

438510

0 commit comments

Comments
 (0)