From 1aad1c8b1a933f46ae2753bb209dd986e49ce99e Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Mon, 21 Mar 2022 00:32:24 +0900 Subject: [PATCH 1/9] Initialize devicetree plugin --- volatility3/framework/plugins/windows/devicetree.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 volatility3/framework/plugins/windows/devicetree.py diff --git a/volatility3/framework/plugins/windows/devicetree.py b/volatility3/framework/plugins/windows/devicetree.py new file mode 100644 index 000000000..e69de29bb From fb081ec233c08548b40b5bc96d182464f68e9795 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Mon, 28 Mar 2022 00:36:03 +0900 Subject: [PATCH 2/9] Add Windows DRIVER_OBJECT, DEVICE_OBJECT method --- .../symbols/windows/extensions/__init__.py | 33 +++++++++++++++---- 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/volatility3/framework/symbols/windows/extensions/__init__.py b/volatility3/framework/symbols/windows/extensions/__init__.py index dc0de1dda..c1972cb7f 100755 --- a/volatility3/framework/symbols/windows/extensions/__init__.py +++ b/volatility3/framework/symbols/windows/extensions/__init__.py @@ -351,17 +351,38 @@ class EX_FAST_REF(objects.StructType): class DEVICE_OBJECT(objects.StructType, pool.ExecutiveObject): """A class for kernel device objects.""" - def get_device_name(self) -> str: - header = self.get_object_header() - return header.NameInfo.Name.String # type: ignore + def get_device_name(self) -> Union[str, interfaces.renderers.BaseAbsentValue]: + """Get device's name from the object header.""" + try: + header = self.get_object_header() + return header.NameInfo.Name.String # type: ignore + except(ValueError): + return renderers.UnparsableValue() + def get_attached_devices(self) -> interfaces.objects.ObjectInterface: + """Enumerate the device's attaches""" + device = self.AttachedDevice.dereference() + while device: + yield device + device = device.AttachedDevice.dereference() class DRIVER_OBJECT(objects.StructType, pool.ExecutiveObject): """A class for kernel driver objects.""" - def get_driver_name(self) -> str: - header = self.get_object_header() - return header.NameInfo.Name.String # type: ignore + def get_driver_name(self) -> Union[str, interfaces.renderers.BaseAbsentValue]: + """Get driver's name from the object header.""" + try: + header = self.get_object_header() + return header.NameInfo.Name.String # type: ignore + except(ValueError): + return renderers.UnparsableValue() + + def get_devices(self) -> interfaces.objects.ObjectInterface: + """Enumerate the driver's device objects""" + device = self.DeviceObject.dereference() + while device: + yield device + device = device.NextDevice.dereference() def is_valid(self) -> bool: """Determine if the object is valid.""" From 6b91927bb4f389cde1eb6f9bf339706e42cc1e3b Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Mon, 28 Mar 2022 00:51:35 +0900 Subject: [PATCH 3/9] Initialize DeviceTree plugin --- .../framework/plugins/windows/devicetree.py | 145 ++++++++++++++++++ 1 file changed, 145 insertions(+) diff --git a/volatility3/framework/plugins/windows/devicetree.py b/volatility3/framework/plugins/windows/devicetree.py index e69de29bb..67bfcfbbf 100644 --- a/volatility3/framework/plugins/windows/devicetree.py +++ b/volatility3/framework/plugins/windows/devicetree.py @@ -0,0 +1,145 @@ +# This file is Copyright 2022 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 Iterator, List, Tuple + +from volatility3.framework import constants, renderers, exceptions, interfaces +from volatility3.framework.configuration import requirements +from volatility3.framework.renderers import format_hints +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__) + +class DeviceTree(interfaces.plugins.PluginInterface): + """Listing tree based on drivers and attached devices in a particular windows memory image.""" + + _required_framework_version = (2, 0, 1) + _version = (1, 0, 0) + + @classmethod + def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: + return [ + requirements.ModuleRequirement(name = "kernel", description = "Windows kernel", + architectures = ["Intel32", "Intel64"]), + requirements.PluginRequirement(name = "driverscan", plugin = driverscan.DriverScan, version = (1, 0, 0)), + ] + + def _generator(self) -> Iterator[Tuple]: + kernel = self.context.modules[self.config["kernel"]] + + # Scan the Layer for drivers + for driver in driverscan.DriverScan.scan_drivers(self.context, kernel.layer_name, kernel.symbol_table_name): + try: + driver_name = driver.get_driver_name() + + yield (0, ( + format_hints.Hex(driver.vol.offset), + "DRV", + driver_name, + renderers.NotApplicableValue(), + renderers.NotApplicableValue() + )) + + # Scan to get the device information of driver. + for device in driver.get_devices(): + device_name = device.get_device_name() + device_type = DEVICE_CODES.get(device.DeviceType, "UNKNOWN") + + yield (1, ( + format_hints.Hex(driver.vol.offset), + "DEV", + driver_name, + device_name, + device_type + )) + + # Scan to get the attached devices information of device. + for level, attached_device in enumerate(device.get_attached_devices(), start=2): + device_name = attached_device.get_device_name() + + attached_device_name = "Unparsable Value" if isinstance(device_name, renderers.UnparsableValue) else device_name + name = "{} - {}".format(attached_device_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, + name, + attached_device_type + )) + + except(exceptions.PagedInvalidAddressException): + vollog.log(constants.LOGLEVEL_VVVV, f"Invalid address identified in drivers and devices: {format_hints.Hex(driver.vol.offset)}") + continue + + + def run(self) -> renderers.TreeGrid: + return renderers.TreeGrid([ + ("Offset", format_hints.Hex), ("Type", str), ("DriverName", str), ("DeviceName", str), ("DeviceType", str), + ], self._generator()) From 95a11c366965b03c4f69b6b75687e600d2dd231f Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Mon, 28 Mar 2022 03:25:16 +0900 Subject: [PATCH 4/9] Core: Bump the development version to 2.0.3 --- volatility3/framework/constants/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/volatility3/framework/constants/__init__.py b/volatility3/framework/constants/__init__.py index badec946b..46d5be577 100644 --- a/volatility3/framework/constants/__init__.py +++ b/volatility3/framework/constants/__init__.py @@ -40,7 +40,7 @@ BANG = "!" # We use the SemVer 2.0.0 versioning scheme VERSION_MAJOR = 2 # Number of releases of the library with a breaking change VERSION_MINOR = 0 # Number of changes that only add to the interface -VERSION_PATCH = 2 # Number of changes that do not change the interface +VERSION_PATCH = 3 # Number of changes that do not change the interface VERSION_SUFFIX = "" # TODO: At version 2.0.0, remove the symbol_shift feature From ff9c5cea4f021485bee51c8ae7fd5b5f3b5b93d8 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Mon, 28 Mar 2022 03:31:29 +0900 Subject: [PATCH 5/9] Modify return type hint of method for get driver's and device's --- .../framework/symbols/windows/extensions/__init__.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/volatility3/framework/symbols/windows/extensions/__init__.py b/volatility3/framework/symbols/windows/extensions/__init__.py index c1972cb7f..2266305fa 100755 --- a/volatility3/framework/symbols/windows/extensions/__init__.py +++ b/volatility3/framework/symbols/windows/extensions/__init__.py @@ -7,9 +7,10 @@ import datetime import functools import logging import math -from typing import Iterable, Iterator, List, Optional, Tuple, Union +from typing import Generator, Iterable, Iterator, List, Optional, Tuple, Union from volatility3.framework import constants, exceptions, interfaces, objects, renderers, symbols +from volatility3.framework.interfaces.objects import ObjectInterface from volatility3.framework.layers import intel from volatility3.framework.renderers import conversion from volatility3.framework.symbols import generic @@ -359,7 +360,7 @@ class DEVICE_OBJECT(objects.StructType, pool.ExecutiveObject): except(ValueError): return renderers.UnparsableValue() - def get_attached_devices(self) -> interfaces.objects.ObjectInterface: + def get_attached_devices(self) -> Generator[ObjectInterface, None, None]: """Enumerate the device's attaches""" device = self.AttachedDevice.dereference() while device: @@ -377,7 +378,7 @@ class DRIVER_OBJECT(objects.StructType, pool.ExecutiveObject): except(ValueError): return renderers.UnparsableValue() - def get_devices(self) -> interfaces.objects.ObjectInterface: + def get_devices(self) -> Generator[ObjectInterface, None, None]: """Enumerate the driver's device objects""" device = self.DeviceObject.dereference() while device: From 2f3bc8cf0d58263c64357ca06ffe0d494648f668 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Mon, 28 Mar 2022 03:34:24 +0900 Subject: [PATCH 6/9] Revert method for get driver's and device's name --- .../framework/plugins/windows/devicetree.py | 5 ++--- .../symbols/windows/extensions/__init__.py | 18 ++++++------------ 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/volatility3/framework/plugins/windows/devicetree.py b/volatility3/framework/plugins/windows/devicetree.py index 67bfcfbbf..add654795 100644 --- a/volatility3/framework/plugins/windows/devicetree.py +++ b/volatility3/framework/plugins/windows/devicetree.py @@ -77,7 +77,7 @@ vollog = logging.getLogger(__name__) class DeviceTree(interfaces.plugins.PluginInterface): """Listing tree based on drivers and attached devices in a particular windows memory image.""" - _required_framework_version = (2, 0, 1) + _required_framework_version = (2, 0, 3) _version = (1, 0, 0) @classmethod @@ -121,8 +121,7 @@ class DeviceTree(interfaces.plugins.PluginInterface): for level, attached_device in enumerate(device.get_attached_devices(), start=2): device_name = attached_device.get_device_name() - attached_device_name = "Unparsable Value" if isinstance(device_name, renderers.UnparsableValue) else device_name - name = "{} - {}".format(attached_device_name, attached_device.DriverObject.DriverName.get_string()) + name = "{} - {}".format(device_name, attached_device.DriverObject.DriverName.get_string()) attached_device_type = DEVICE_CODES.get(attached_device.DeviceType, "UNKNOWN") diff --git a/volatility3/framework/symbols/windows/extensions/__init__.py b/volatility3/framework/symbols/windows/extensions/__init__.py index 2266305fa..b7b53f6e9 100755 --- a/volatility3/framework/symbols/windows/extensions/__init__.py +++ b/volatility3/framework/symbols/windows/extensions/__init__.py @@ -352,13 +352,10 @@ class EX_FAST_REF(objects.StructType): class DEVICE_OBJECT(objects.StructType, pool.ExecutiveObject): """A class for kernel device objects.""" - def get_device_name(self) -> Union[str, interfaces.renderers.BaseAbsentValue]: + def get_device_name(self) -> str: """Get device's name from the object header.""" - try: - header = self.get_object_header() - return header.NameInfo.Name.String # type: ignore - except(ValueError): - return renderers.UnparsableValue() + header = self.get_object_header() + return header.NameInfo.Name.String # type: ignore def get_attached_devices(self) -> Generator[ObjectInterface, None, None]: """Enumerate the device's attaches""" @@ -370,13 +367,10 @@ class DEVICE_OBJECT(objects.StructType, pool.ExecutiveObject): class DRIVER_OBJECT(objects.StructType, pool.ExecutiveObject): """A class for kernel driver objects.""" - def get_driver_name(self) -> Union[str, interfaces.renderers.BaseAbsentValue]: + def get_driver_name(self) -> str: """Get driver's name from the object header.""" - try: - header = self.get_object_header() - return header.NameInfo.Name.String # type: ignore - except(ValueError): - return renderers.UnparsableValue() + header = self.get_object_header() + return header.NameInfo.Name.String # type: ignore def get_devices(self) -> Generator[ObjectInterface, None, None]: """Enumerate the driver's device objects""" From 8c29ba9fa5ccb733780378c28ba9c3d5fa856b6c Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Mon, 28 Mar 2022 03:36:41 +0900 Subject: [PATCH 7/9] Modify code comment of get_attached_devices method --- volatility3/framework/symbols/windows/extensions/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/volatility3/framework/symbols/windows/extensions/__init__.py b/volatility3/framework/symbols/windows/extensions/__init__.py index b7b53f6e9..7d083fbba 100755 --- a/volatility3/framework/symbols/windows/extensions/__init__.py +++ b/volatility3/framework/symbols/windows/extensions/__init__.py @@ -358,7 +358,7 @@ class DEVICE_OBJECT(objects.StructType, pool.ExecutiveObject): return header.NameInfo.Name.String # type: ignore def get_attached_devices(self) -> Generator[ObjectInterface, None, None]: - """Enumerate the device's attaches""" + """Enumerate the attached device's objects""" device = self.AttachedDevice.dereference() while device: yield device From 8104ee5fcb6393f6fdfc663a44d164dada15f77d Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Mon, 28 Mar 2022 03:43:36 +0900 Subject: [PATCH 8/9] Prettier of TreeGrid column --- volatility3/framework/plugins/windows/devicetree.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/volatility3/framework/plugins/windows/devicetree.py b/volatility3/framework/plugins/windows/devicetree.py index add654795..bd1a1ce36 100644 --- a/volatility3/framework/plugins/windows/devicetree.py +++ b/volatility3/framework/plugins/windows/devicetree.py @@ -140,5 +140,9 @@ class DeviceTree(interfaces.plugins.PluginInterface): def run(self) -> renderers.TreeGrid: return renderers.TreeGrid([ - ("Offset", format_hints.Hex), ("Type", str), ("DriverName", str), ("DeviceName", str), ("DeviceType", str), + ("Offset", format_hints.Hex), + ("Type", str), + ("DriverName", str), + ("DeviceName", str), + ("DeviceType", str), ], self._generator()) From 7b3fa278e058f296940bd1713b908beab8177664 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Mon, 28 Mar 2022 16:03:25 +0900 Subject: [PATCH 9/9] Move handling of ValueError, PagedInvalidAddressException to _generator --- .../framework/plugins/windows/devicetree.py | 35 ++++++++++++++----- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/volatility3/framework/plugins/windows/devicetree.py b/volatility3/framework/plugins/windows/devicetree.py index bd1a1ce36..8e92de0cc 100644 --- a/volatility3/framework/plugins/windows/devicetree.py +++ b/volatility3/framework/plugins/windows/devicetree.py @@ -94,19 +94,31 @@ class DeviceTree(interfaces.plugins.PluginInterface): # Scan the Layer for drivers for driver in driverscan.DriverScan.scan_drivers(self.context, kernel.layer_name, kernel.symbol_table_name): try: - driver_name = driver.get_driver_name() + try: + driver_name = driver.get_driver_name() + except (ValueError, exceptions.PagedInvalidAddressException): + 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(): - device_name = device.get_device_name() + try: + device_name = device.get_device_name() + except (ValueError, exceptions.PagedInvalidAddressException): + 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, ( @@ -114,35 +126,42 @@ class DeviceTree(interfaces.plugins.PluginInterface): "DEV", driver_name, device_name, + renderers.NotApplicableValue(), device_type )) # Scan to get the attached devices information of device. for level, attached_device in enumerate(device.get_attached_devices(), start=2): - device_name = attached_device.get_device_name() - - name = "{} - {}".format(device_name, attached_device.DriverObject.DriverName.get_string()) + try: + device_name = attached_device.get_device_name() + except (ValueError, exceptions.PagedInvalidAddressException): + 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, - name, + device_name, + attached_device_driver_name, attached_device_type )) except(exceptions.PagedInvalidAddressException): - vollog.log(constants.LOGLEVEL_VVVV, f"Invalid address identified in drivers and devices: {format_hints.Hex(driver.vol.offset)}") + vollog.log(constants.LOGLEVEL_VVVV, + f"Invalid address identified in drivers and devices: {driver.vol.offset:x}") continue - def run(self) -> renderers.TreeGrid: return renderers.TreeGrid([ ("Offset", format_hints.Hex), ("Type", str), ("DriverName", str), ("DeviceName", str), + ("DriverNameOfAttDevice", str), ("DeviceType", str), ], self._generator())