Skip to content
Closed
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
50 changes: 41 additions & 9 deletions volatility3/framework/plugins/windows/driverscan.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0
#

from typing import Iterable
from typing import Iterable, Optional, Tuple

from volatility3.framework import renderers, interfaces, exceptions
from volatility3.framework.configuration import requirements
Expand Down Expand Up @@ -51,14 +51,37 @@ def scan_drivers(
symbol_table, [b"Dri\xf6", b"Driv"]
)

layer = context.layers[layer_name]
module = context.module(symbol_table, layer_name, 0)
driver_start_offset = module.get_type("_DRIVER_OBJECT").relative_child_offset(
"DriverStart"
)

for result in poolscanner.PoolScanner.generate_pool_scan(
context, layer_name, symbol_table, constraints
):
_constraint, mem_object, _header = result
yield mem_object

# *Many* _DRIVER_OBJECT instances were found at the end of a page
# leading to member access causing backtraces across several plugins
# when members were accessed as the next page was paged out.
# `DriverStart` is the first member from the beginning of the structure
# of interest to plugins, so if it is not accessible then this instance
# is not useful or usable during analysis
# 8 covers this value 32 and 64 bit systems
if layer.is_valid(mem_object.vol.offset + driver_start_offset, 8):

# Many/most rootkits zero out their DriverStart member for anti-forensics
# so we accept a driver start that is either 0 or is mapped in kernel memory (the current layer)
if mem_object.DriverStart == 0 or layer.is_valid(
mem_object.DriverStart, 8
):
yield mem_object

@classmethod
def get_names_for_driver(cls, driver):
def get_names_for_driver(
cls, driver
) -> Tuple[Optional[str], Optional[str], Optional[str]]:
"""
Convenience method for getting the commonly used
names associated with a driver
Expand All @@ -72,17 +95,17 @@ def get_names_for_driver(cls, driver):
try:
driver_name = driver.get_driver_name()
except (ValueError, exceptions.InvalidAddressException):
driver_name = renderers.NotApplicableValue()
driver_name = None

try:
service_key = driver.DriverExtension.ServiceKeyName.String
except exceptions.InvalidAddressException:
service_key = renderers.NotApplicableValue()
service_key = None

try:
name = driver.DriverName.String
except exceptions.InvalidAddressException:
name = renderers.NotApplicableValue()
name = None

return driver_name, service_key, name

Expand All @@ -94,15 +117,24 @@ def _generator(self):
):
driver_name, service_key, name = self.get_names_for_driver(driver)

# Prior to #1481, this plugin reported dozens to hundreds of junk drivers per sample
if (
driver.DriverStart == 0
and not driver_name
and not service_key
and not name
):
continue

yield (
0,
(
format_hints.Hex(driver.vol.offset),
format_hints.Hex(driver.DriverStart),
format_hints.Hex(driver.DriverSize),
service_key,
driver_name,
name,
service_key or renderers.NotAvailableValue(),
driver_name or renderers.NotAvailableValue(),
name or renderers.NotAvailableValue(),
),
)

Expand Down
Loading