Skip to content

Commit 0e236fd

Browse files
authored
Merge pull request #1680 from volatilityfoundation/fix_timers_kpcr
Fix timers and kpcrs bugs, missing smear checks, and API. Closes #1642
2 parents 21bcdf9 + 9e01666 commit 0e236fd

File tree

2 files changed

+49
-45
lines changed

2 files changed

+49
-45
lines changed

volatility3/framework/plugins/windows/kpcrs.py

Lines changed: 34 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
import logging
66

7-
from typing import Iterator, List, Tuple
7+
from typing import Iterator, Generator, List, Tuple
88

99
from volatility3.framework import (
1010
renderers,
@@ -22,7 +22,7 @@ class KPCRs(interfaces.plugins.PluginInterface):
2222
"""Print KPCR structure for each processor"""
2323

2424
_required_framework_version = (2, 0, 0)
25-
_version = (1, 0, 0)
25+
_version = (2, 0, 0)
2626

2727
@classmethod
2828
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
@@ -39,60 +39,70 @@ def list_kpcrs(
3939
cls,
4040
context: interfaces.context.ContextInterface,
4141
kernel_module_name: str,
42-
layer_name: str,
43-
symbol_table: str,
44-
) -> interfaces.objects.ObjectInterface:
42+
) -> Generator[Tuple[interfaces.objects.ObjectInterface, int], None, None]:
4543
"""Returns the KPCR structure for each processor
4644
4745
Args:
4846
context: The context to retrieve required elements (layers, symbol tables) from
4947
kernel_module_name: The name of the kernel module on which to operate
50-
layer_name: The name of the layer on which to operate
51-
symbol_table: The name of the table containing the kernel symbols
5248
5349
Returns:
5450
The _KPCR structure for each processor
5551
"""
5652

5753
kernel = context.modules[kernel_module_name]
54+
kernel_layer = context.layers[kernel.layer_name]
55+
56+
kpcr_type = kernel.get_type("_KPCR")
57+
58+
reloff = kpcr_type.relative_child_offset("Prcb")
59+
60+
if kpcr_type.has_member("CurrentPrcb"):
61+
kpcr_member = "CurrentPrcb"
62+
else:
63+
kpcr_member = "Prcb"
64+
5865
cpu_count_offset = kernel.get_symbol("KeNumberProcessors").address
66+
5967
cpu_count = kernel.object(
60-
object_type="unsigned int", layer_name=layer_name, offset=cpu_count_offset
68+
object_type="unsigned int",
69+
layer_name=kernel_layer.name,
70+
offset=cpu_count_offset,
6171
)
72+
6273
processor_block = kernel.object(
6374
object_type="pointer",
64-
layer_name=layer_name,
75+
layer_name=kernel_layer.name,
6576
offset=kernel.get_symbol("KiProcessorBlock").address,
6677
)
78+
6779
processor_pointers = utility.array_of_pointers(
6880
context=context,
6981
array=processor_block,
7082
count=cpu_count,
71-
subtype=symbol_table + constants.BANG + "_KPRCB",
83+
subtype=kernel.symbol_table_name + constants.BANG + "_KPRCB",
7284
)
85+
7386
for pointer in processor_pointers:
7487
kprcb = pointer.dereference()
75-
reloff = kernel.get_type("_KPCR").relative_child_offset("Prcb")
76-
kpcr = context.object(
77-
symbol_table + constants.BANG + "_KPCR",
78-
offset=kprcb.vol.offset - reloff,
79-
layer_name=layer_name,
80-
)
81-
yield kpcr
88+
89+
object_address = kprcb.vol.offset - reloff
90+
91+
if not kernel_layer.is_valid(kprcb.vol.offset):
92+
continue
93+
94+
kpcr = kernel.object("_KPCR", offset=object_address, absolute=True)
95+
96+
yield kpcr, kpcr.member(kpcr_member)
8297

8398
def _generator(self) -> Iterator[Tuple]:
84-
kernel = self.context.modules[self.config["kernel"]]
85-
layer_name = kernel.layer_name
86-
symbol_table = kernel.symbol_table_name
8799

88-
for kpcr in self.list_kpcrs(
89-
self.context, self.config["kernel"], layer_name, symbol_table
90-
):
100+
for kpcr, current_prcb in self.list_kpcrs(self.context, self.config["kernel"]):
91101
yield (
92102
0,
93103
(
94104
format_hints.Hex(kpcr.vol.offset),
95-
format_hints.Hex(kpcr.CurrentPrcb),
105+
format_hints.Hex(current_prcb),
96106
),
97107
)
98108

volatility3/framework/plugins/windows/timers.py

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]
3838
name="ssdt", plugin=ssdt.SSDT, version=(2, 0, 0)
3939
),
4040
requirements.PluginRequirement(
41-
name="kpcrs", plugin=kpcrs.KPCRs, version=(1, 0, 0)
41+
name="kpcrs", plugin=kpcrs.KPCRs, version=(2, 0, 0)
4242
),
4343
]
4444

@@ -47,54 +47,52 @@ def list_timers(
4747
cls,
4848
context: interfaces.context.ContextInterface,
4949
kernel_module_name: str,
50-
layer_name: str,
51-
symbol_table: str,
5250
) -> Iterable[extensions.KTIMER]:
5351
"""Lists all kernel timers.
5452
5553
Args:
5654
context: The context to retrieve required elements (layers, symbol tables) from
5755
kernel_module_name: The name of the kernel module on which to operate
58-
layer_name: The name of the layer on which to operate
59-
symbol_table: The name of the table containing the kernel symbols
6056
6157
Yields:
6258
A _KTIMER entry
6359
"""
6460

6561
kernel = context.modules[kernel_module_name]
6662
if versions.is_windows_7(
67-
context=context, symbol_table=symbol_table
68-
) or versions.is_windows_8_or_later(context=context, symbol_table=symbol_table):
63+
context=context, symbol_table=kernel.symbol_table_name
64+
) or versions.is_windows_8_or_later(
65+
context=context, symbol_table=kernel.symbol_table_name
66+
):
6967
# Starting with Windows 7, there is no more KiTimerTableListHead. The list is
7068
# at _KPCR.PrcbData.TimerTable.TimerEntries
7169
# See http://pastebin.com/FiRsGW3f
72-
for kpcr in kpcrs.KPCRs.list_kpcrs(
73-
context, kernel_module_name, layer_name, symbol_table
74-
):
70+
for kpcr, _ in kpcrs.KPCRs.list_kpcrs(context, kernel_module_name):
7571
if hasattr(kpcr.Prcb.TimerTable, "TableState"):
7672
for timer_entries in kpcr.Prcb.TimerTable.TimerEntries:
7773
for timer_entry in timer_entries:
7874
for timer in timer_entry.Entry.to_list(
79-
symbol_table + constants.BANG + "_KTIMER",
75+
kernel.symbol_table_name + constants.BANG + "_KTIMER",
8076
"TimerListEntry",
8177
):
8278
yield timer
8379

8480
else:
8581
for timer_entries in kpcr.Prcb.TimerTable.TimerEntries:
8682
for timer in timer_entries.Entry.to_list(
87-
symbol_table + constants.BANG + "_KTIMER",
83+
kernel.symbol_table_name + constants.BANG + "_KTIMER",
8884
"TimerListEntry",
8985
):
9086
yield timer
9187

9288
elif versions.is_xp_or_2003(
93-
context=context, symbol_table=symbol_table
94-
) or versions.is_vista_or_later(context=context, symbol_table=symbol_table):
95-
is_64bit = symbols.symbol_table_is_64bit(context, symbol_table)
89+
context=context, symbol_table=kernel.symbol_table_name
90+
) or versions.is_vista_or_later(
91+
context=context, symbol_table=kernel.symbol_table_name
92+
):
93+
is_64bit = symbols.symbol_table_is_64bit(context, kernel.symbol_table_name)
9694
if is_64bit or versions.is_vista_or_later(
97-
context=context, symbol_table=symbol_table
95+
context=context, symbol_table=kernel.symbol_table_name
9896
):
9997
# On XP x64, Windows 2003 SP1-SP2, and Vista SP0-SP2, KiTimerTableListHead
10098
# is an array of 512 _KTIMER_TABLE_ENTRY structs.
@@ -112,7 +110,7 @@ def list_timers(
112110
)
113111
for table in timer_table_list_head:
114112
for timer in table.to_list(
115-
symbol_table + constants.BANG + "_KTIMER",
113+
kernel.symbol_table_name + constants.BANG + "_KTIMER",
116114
"TimerListEntry",
117115
):
118116
yield timer
@@ -121,8 +119,6 @@ def list_timers(
121119
raise NotImplementedError("This version of Windows is not supported!")
122120

123121
def _generator(self) -> Iterator[Tuple]:
124-
kernel = self.context.modules[self.config["kernel"]]
125-
126122
collection = ssdt.SSDT.build_module_collection(
127123
context=self.context,
128124
kernel_module_name=self.config["kernel"],
@@ -132,8 +128,6 @@ def _generator(self) -> Iterator[Tuple]:
132128
for timer in self.list_timers(
133129
self.context,
134130
self.config["kernel"],
135-
kernel.layer_name,
136-
kernel.symbol_table_name,
137131
):
138132
if not timer.valid_type():
139133
continue

0 commit comments

Comments
 (0)