mirror of
https://github.com/volatilityfoundation/volatility3.git
synced 2026-09-13 21:27:39 +02:00
Merge pull request #1389 from dgmcdona/dgmcdona/24H2_handles_pointer_decoding
fix(Windows: Handles): Unreliable SAR value on 24H2
This commit is contained in:
@@ -48,7 +48,7 @@ class Callbacks(interfaces.plugins.PluginInterface):
|
||||
name="driverirp", plugin=driverirp.DriverIrp, version=(1, 0, 0)
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="handles", plugin=handles.Handles, version=(1, 0, 0)
|
||||
name="handles", plugin=handles.Handles, version=(2, 0, 0)
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ class DumpFiles(interfaces.plugins.PluginInterface):
|
||||
name="pslist", component=pslist.PsList, version=(2, 0, 0)
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="handles", component=handles.Handles, version=(1, 0, 0)
|
||||
name="handles", component=handles.Handles, version=(2, 0, 0)
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
#
|
||||
|
||||
import logging
|
||||
from typing import List, Optional, Dict
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
from volatility3.framework import constants, exceptions, renderers, interfaces, symbols
|
||||
from volatility3.framework import constants, exceptions, interfaces, renderers, symbols
|
||||
from volatility3.framework.configuration import requirements
|
||||
from volatility3.framework.objects import utility
|
||||
from volatility3.framework.renderers import format_hints
|
||||
@@ -13,23 +13,15 @@ from volatility3.plugins.windows import pslist, psscan
|
||||
|
||||
vollog = logging.getLogger(__name__)
|
||||
|
||||
try:
|
||||
import capstone
|
||||
|
||||
has_capstone = True
|
||||
except ImportError:
|
||||
has_capstone = False
|
||||
|
||||
|
||||
class Handles(interfaces.plugins.PluginInterface):
|
||||
"""Lists process open handles."""
|
||||
|
||||
_required_framework_version = (2, 0, 0)
|
||||
_version = (1, 0, 2)
|
||||
_version = (2, 0, 0)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self._sar_value = None
|
||||
self._type_map = None
|
||||
self._cookie = None
|
||||
self._level_mask = 7
|
||||
@@ -62,21 +54,6 @@ class Handles(interfaces.plugins.PluginInterface):
|
||||
),
|
||||
]
|
||||
|
||||
def _decode_pointer(self, value, magic):
|
||||
"""Windows encodes pointers to objects and decodes them on the fly
|
||||
before using them.
|
||||
|
||||
This function mimics the decoding routine so we can generate the
|
||||
proper pointer values as well.
|
||||
"""
|
||||
|
||||
value = value & 0xFFFFFFFFFFFFFFF8
|
||||
value = value >> magic
|
||||
# if (value & (1 << 47)):
|
||||
# value = value | 0xFFFF000000000000
|
||||
|
||||
return value
|
||||
|
||||
def _get_item(self, handle_table_entry, handle_value):
|
||||
"""Given a handle table entry (_HANDLE_TABLE_ENTRY) structure from a
|
||||
process' handle table, determine where the corresponding object's
|
||||
@@ -100,24 +77,11 @@ class Handles(interfaces.plugins.PluginInterface):
|
||||
)
|
||||
|
||||
if is_64bit:
|
||||
if handle_table_entry.LowValue == 0:
|
||||
if handle_table_entry.ObjectPointerBits == 0:
|
||||
return None
|
||||
|
||||
magic = self.find_sar_value()
|
||||
offset = handle_table_entry.ObjectPointerBits << 4
|
||||
|
||||
# is this the right thing to raise here?
|
||||
if magic is None:
|
||||
if has_capstone:
|
||||
raise AttributeError(
|
||||
"Unable to find the SAR value for decoding handle table pointers"
|
||||
)
|
||||
else:
|
||||
raise exceptions.MissingModuleException(
|
||||
"capstone",
|
||||
"Requires capstone to find the SAR value for decoding handle table pointers",
|
||||
)
|
||||
|
||||
offset = self._decode_pointer(handle_table_entry.LowValue, magic)
|
||||
else:
|
||||
if handle_table_entry.InfoTable == 0:
|
||||
return None
|
||||
@@ -135,78 +99,6 @@ class Handles(interfaces.plugins.PluginInterface):
|
||||
object_header.HandleValue = handle_value
|
||||
return object_header
|
||||
|
||||
def find_sar_value(self):
|
||||
"""Locate ObpCaptureHandleInformationEx if it exists in the sample.
|
||||
|
||||
Once found, parse it for the SAR value that we need to decode
|
||||
pointers in the _HANDLE_TABLE_ENTRY which allows us to find the
|
||||
associated _OBJECT_HEADER.
|
||||
"""
|
||||
DEFAULT_SAR_VALUE = 0x10 # to be used only when decoding fails
|
||||
|
||||
if self._sar_value is None:
|
||||
if not has_capstone:
|
||||
vollog.debug(
|
||||
"capstone module is missing, unable to create disassembly of ObpCaptureHandleInformationEx"
|
||||
)
|
||||
return None
|
||||
kernel = self.context.modules[self.config["kernel"]]
|
||||
|
||||
virtual_layer_name = kernel.layer_name
|
||||
kvo = self.context.layers[virtual_layer_name].config[
|
||||
"kernel_virtual_offset"
|
||||
]
|
||||
ntkrnlmp = self.context.module(
|
||||
kernel.symbol_table_name, layer_name=virtual_layer_name, offset=kvo
|
||||
)
|
||||
|
||||
try:
|
||||
func_addr = ntkrnlmp.get_symbol("ObpCaptureHandleInformationEx").address
|
||||
except exceptions.SymbolError:
|
||||
vollog.debug("Unable to locate ObpCaptureHandleInformationEx symbol")
|
||||
return None
|
||||
|
||||
try:
|
||||
func_addr_to_read = kvo + func_addr
|
||||
num_bytes_to_read = 0x200
|
||||
vollog.debug(
|
||||
f"ObpCaptureHandleInformationEx symbol located at {hex(func_addr_to_read)}"
|
||||
)
|
||||
data = self.context.layers.read(
|
||||
virtual_layer_name, func_addr_to_read, num_bytes_to_read
|
||||
)
|
||||
except exceptions.InvalidAddressException:
|
||||
vollog.warning(
|
||||
f"Failed to read {hex(num_bytes_to_read)} bytes at symbol {hex(func_addr_to_read)}. Unable to decode SAR value. Failing back to a common value of {hex(DEFAULT_SAR_VALUE)}"
|
||||
)
|
||||
self._sar_value = DEFAULT_SAR_VALUE
|
||||
return self._sar_value
|
||||
|
||||
md = capstone.Cs(capstone.CS_ARCH_X86, capstone.CS_MODE_64)
|
||||
|
||||
instruction_count = 0
|
||||
for address, size, mnemonic, op_str in md.disasm_lite(
|
||||
data, kvo + func_addr
|
||||
):
|
||||
# print("{} {} {} {}".format(address, size, mnemonic, op_str))
|
||||
instruction_count += 1
|
||||
if mnemonic.startswith("sar"):
|
||||
# if we don't want to parse op strings, we can disasm the
|
||||
# single sar instruction again, but we use disasm_lite for speed
|
||||
self._sar_value = int(op_str.split(",")[1].strip(), 16)
|
||||
vollog.debug(
|
||||
f"SAR located at {hex(address)} with value of {hex(self._sar_value)}"
|
||||
)
|
||||
break
|
||||
|
||||
if self._sar_value is None:
|
||||
vollog.warning(
|
||||
f"Failed to to locate SAR value having parsed {instruction_count} instructions, failing back to a common value of {hex(DEFAULT_SAR_VALUE)}"
|
||||
)
|
||||
self._sar_value = DEFAULT_SAR_VALUE
|
||||
|
||||
return self._sar_value
|
||||
|
||||
@classmethod
|
||||
def get_type_map(
|
||||
cls,
|
||||
|
||||
@@ -139,7 +139,7 @@ class PoolScanner(plugins.PluginInterface):
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="handles", plugin=handles.Handles, version=(1, 0, 0)
|
||||
name="handles", plugin=handles.Handles, version=(2, 0, 0)
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ class PsXView(plugins.PluginInterface):
|
||||
name="thrdscan", component=thrdscan.ThrdScan, version=(1, 0, 0)
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="handles", component=handles.Handles, version=(1, 0, 0)
|
||||
name="handles", component=handles.Handles, version=(2, 0, 0)
|
||||
),
|
||||
requirements.BooleanRequirement(
|
||||
name="physical-offsets",
|
||||
|
||||
Reference in New Issue
Block a user