mirror of
https://github.com/volatilityfoundation/volatility3.git
synced 2026-09-09 11:17:38 +02:00
Merge pull request #1680 from volatilityfoundation/fix_timers_kpcr
Fix timers and kpcrs bugs, missing smear checks, and API. Closes #1642
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
|
||||
import logging
|
||||
|
||||
from typing import Iterator, List, Tuple
|
||||
from typing import Iterator, Generator, List, Tuple
|
||||
|
||||
from volatility3.framework import (
|
||||
renderers,
|
||||
@@ -22,7 +22,7 @@ class KPCRs(interfaces.plugins.PluginInterface):
|
||||
"""Print KPCR structure for each processor"""
|
||||
|
||||
_required_framework_version = (2, 0, 0)
|
||||
_version = (1, 0, 0)
|
||||
_version = (2, 0, 0)
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
|
||||
@@ -39,60 +39,70 @@ class KPCRs(interfaces.plugins.PluginInterface):
|
||||
cls,
|
||||
context: interfaces.context.ContextInterface,
|
||||
kernel_module_name: str,
|
||||
layer_name: str,
|
||||
symbol_table: str,
|
||||
) -> interfaces.objects.ObjectInterface:
|
||||
) -> Generator[Tuple[interfaces.objects.ObjectInterface, int], None, None]:
|
||||
"""Returns the KPCR structure for each processor
|
||||
|
||||
Args:
|
||||
context: The context to retrieve required elements (layers, symbol tables) from
|
||||
kernel_module_name: The name of the kernel module on which to operate
|
||||
layer_name: The name of the layer on which to operate
|
||||
symbol_table: The name of the table containing the kernel symbols
|
||||
|
||||
Returns:
|
||||
The _KPCR structure for each processor
|
||||
"""
|
||||
|
||||
kernel = context.modules[kernel_module_name]
|
||||
kernel_layer = context.layers[kernel.layer_name]
|
||||
|
||||
kpcr_type = kernel.get_type("_KPCR")
|
||||
|
||||
reloff = kpcr_type.relative_child_offset("Prcb")
|
||||
|
||||
if kpcr_type.has_member("CurrentPrcb"):
|
||||
kpcr_member = "CurrentPrcb"
|
||||
else:
|
||||
kpcr_member = "Prcb"
|
||||
|
||||
cpu_count_offset = kernel.get_symbol("KeNumberProcessors").address
|
||||
|
||||
cpu_count = kernel.object(
|
||||
object_type="unsigned int", layer_name=layer_name, offset=cpu_count_offset
|
||||
object_type="unsigned int",
|
||||
layer_name=kernel_layer.name,
|
||||
offset=cpu_count_offset,
|
||||
)
|
||||
|
||||
processor_block = kernel.object(
|
||||
object_type="pointer",
|
||||
layer_name=layer_name,
|
||||
layer_name=kernel_layer.name,
|
||||
offset=kernel.get_symbol("KiProcessorBlock").address,
|
||||
)
|
||||
|
||||
processor_pointers = utility.array_of_pointers(
|
||||
context=context,
|
||||
array=processor_block,
|
||||
count=cpu_count,
|
||||
subtype=symbol_table + constants.BANG + "_KPRCB",
|
||||
subtype=kernel.symbol_table_name + constants.BANG + "_KPRCB",
|
||||
)
|
||||
|
||||
for pointer in processor_pointers:
|
||||
kprcb = pointer.dereference()
|
||||
reloff = kernel.get_type("_KPCR").relative_child_offset("Prcb")
|
||||
kpcr = context.object(
|
||||
symbol_table + constants.BANG + "_KPCR",
|
||||
offset=kprcb.vol.offset - reloff,
|
||||
layer_name=layer_name,
|
||||
)
|
||||
yield kpcr
|
||||
|
||||
object_address = kprcb.vol.offset - reloff
|
||||
|
||||
if not kernel_layer.is_valid(kprcb.vol.offset):
|
||||
continue
|
||||
|
||||
kpcr = kernel.object("_KPCR", offset=object_address, absolute=True)
|
||||
|
||||
yield kpcr, kpcr.member(kpcr_member)
|
||||
|
||||
def _generator(self) -> Iterator[Tuple]:
|
||||
kernel = self.context.modules[self.config["kernel"]]
|
||||
layer_name = kernel.layer_name
|
||||
symbol_table = kernel.symbol_table_name
|
||||
|
||||
for kpcr in self.list_kpcrs(
|
||||
self.context, self.config["kernel"], layer_name, symbol_table
|
||||
):
|
||||
for kpcr, current_prcb in self.list_kpcrs(self.context, self.config["kernel"]):
|
||||
yield (
|
||||
0,
|
||||
(
|
||||
format_hints.Hex(kpcr.vol.offset),
|
||||
format_hints.Hex(kpcr.CurrentPrcb),
|
||||
format_hints.Hex(current_prcb),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ class Timers(interfaces.plugins.PluginInterface):
|
||||
name="ssdt", plugin=ssdt.SSDT, version=(2, 0, 0)
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="kpcrs", plugin=kpcrs.KPCRs, version=(1, 0, 0)
|
||||
name="kpcrs", plugin=kpcrs.KPCRs, version=(2, 0, 0)
|
||||
),
|
||||
]
|
||||
|
||||
@@ -47,16 +47,12 @@ class Timers(interfaces.plugins.PluginInterface):
|
||||
cls,
|
||||
context: interfaces.context.ContextInterface,
|
||||
kernel_module_name: str,
|
||||
layer_name: str,
|
||||
symbol_table: str,
|
||||
) -> Iterable[extensions.KTIMER]:
|
||||
"""Lists all kernel timers.
|
||||
|
||||
Args:
|
||||
context: The context to retrieve required elements (layers, symbol tables) from
|
||||
kernel_module_name: The name of the kernel module on which to operate
|
||||
layer_name: The name of the layer on which to operate
|
||||
symbol_table: The name of the table containing the kernel symbols
|
||||
|
||||
Yields:
|
||||
A _KTIMER entry
|
||||
@@ -64,19 +60,19 @@ class Timers(interfaces.plugins.PluginInterface):
|
||||
|
||||
kernel = context.modules[kernel_module_name]
|
||||
if versions.is_windows_7(
|
||||
context=context, symbol_table=symbol_table
|
||||
) or versions.is_windows_8_or_later(context=context, symbol_table=symbol_table):
|
||||
context=context, symbol_table=kernel.symbol_table_name
|
||||
) or versions.is_windows_8_or_later(
|
||||
context=context, symbol_table=kernel.symbol_table_name
|
||||
):
|
||||
# Starting with Windows 7, there is no more KiTimerTableListHead. The list is
|
||||
# at _KPCR.PrcbData.TimerTable.TimerEntries
|
||||
# See http://pastebin.com/FiRsGW3f
|
||||
for kpcr in kpcrs.KPCRs.list_kpcrs(
|
||||
context, kernel_module_name, layer_name, symbol_table
|
||||
):
|
||||
for kpcr, _ in kpcrs.KPCRs.list_kpcrs(context, kernel_module_name):
|
||||
if hasattr(kpcr.Prcb.TimerTable, "TableState"):
|
||||
for timer_entries in kpcr.Prcb.TimerTable.TimerEntries:
|
||||
for timer_entry in timer_entries:
|
||||
for timer in timer_entry.Entry.to_list(
|
||||
symbol_table + constants.BANG + "_KTIMER",
|
||||
kernel.symbol_table_name + constants.BANG + "_KTIMER",
|
||||
"TimerListEntry",
|
||||
):
|
||||
yield timer
|
||||
@@ -84,17 +80,19 @@ class Timers(interfaces.plugins.PluginInterface):
|
||||
else:
|
||||
for timer_entries in kpcr.Prcb.TimerTable.TimerEntries:
|
||||
for timer in timer_entries.Entry.to_list(
|
||||
symbol_table + constants.BANG + "_KTIMER",
|
||||
kernel.symbol_table_name + constants.BANG + "_KTIMER",
|
||||
"TimerListEntry",
|
||||
):
|
||||
yield timer
|
||||
|
||||
elif versions.is_xp_or_2003(
|
||||
context=context, symbol_table=symbol_table
|
||||
) or versions.is_vista_or_later(context=context, symbol_table=symbol_table):
|
||||
is_64bit = symbols.symbol_table_is_64bit(context, symbol_table)
|
||||
context=context, symbol_table=kernel.symbol_table_name
|
||||
) or versions.is_vista_or_later(
|
||||
context=context, symbol_table=kernel.symbol_table_name
|
||||
):
|
||||
is_64bit = symbols.symbol_table_is_64bit(context, kernel.symbol_table_name)
|
||||
if is_64bit or versions.is_vista_or_later(
|
||||
context=context, symbol_table=symbol_table
|
||||
context=context, symbol_table=kernel.symbol_table_name
|
||||
):
|
||||
# On XP x64, Windows 2003 SP1-SP2, and Vista SP0-SP2, KiTimerTableListHead
|
||||
# is an array of 512 _KTIMER_TABLE_ENTRY structs.
|
||||
@@ -112,7 +110,7 @@ class Timers(interfaces.plugins.PluginInterface):
|
||||
)
|
||||
for table in timer_table_list_head:
|
||||
for timer in table.to_list(
|
||||
symbol_table + constants.BANG + "_KTIMER",
|
||||
kernel.symbol_table_name + constants.BANG + "_KTIMER",
|
||||
"TimerListEntry",
|
||||
):
|
||||
yield timer
|
||||
@@ -121,8 +119,6 @@ class Timers(interfaces.plugins.PluginInterface):
|
||||
raise NotImplementedError("This version of Windows is not supported!")
|
||||
|
||||
def _generator(self) -> Iterator[Tuple]:
|
||||
kernel = self.context.modules[self.config["kernel"]]
|
||||
|
||||
collection = ssdt.SSDT.build_module_collection(
|
||||
context=self.context,
|
||||
kernel_module_name=self.config["kernel"],
|
||||
@@ -132,8 +128,6 @@ class Timers(interfaces.plugins.PluginInterface):
|
||||
for timer in self.list_timers(
|
||||
self.context,
|
||||
self.config["kernel"],
|
||||
kernel.layer_name,
|
||||
kernel.symbol_table_name,
|
||||
):
|
||||
if not timer.valid_type():
|
||||
continue
|
||||
|
||||
Reference in New Issue
Block a user