Merge pull request #1399 from dgmcdona/dgmcdona/missing_session_space_def

Windows: Handle missing _MM_SESSION_SPACE
This commit is contained in:
ikelos
2024-12-17 23:14:44 +00:00
committed by GitHub
2 changed files with 53 additions and 22 deletions
@@ -2,14 +2,14 @@
# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0
#
import logging
from typing import List, Iterable, Generator
from typing import Generator, Iterable, List
from volatility3.framework import exceptions, interfaces, constants, renderers
from volatility3.framework import constants, exceptions, interfaces, renderers
from volatility3.framework.configuration import requirements
from volatility3.framework.renderers import format_hints
from volatility3.framework.symbols import intermed
from volatility3.framework.symbols.windows.extensions import pe
from volatility3.plugins.windows import pslist, pedump
from volatility3.plugins.windows import pedump, pslist
vollog = logging.getLogger(__name__)
@@ -164,13 +164,31 @@ class Modules(interfaces.plugins.PluginInterface):
# create the session space object in the process' own layer.
# not all processes have a valid session pointer.
session_space = context.object(
symbol_table + constants.BANG + "_MM_SESSION_SPACE",
layer_name=layer_name,
offset=proc.Session,
)
try:
session_space = context.object(
symbol_table + constants.BANG + "_MM_SESSION_SPACE",
layer_name=layer_name,
offset=proc.Session,
)
session_id = session_space.SessionId
if session_space.SessionId in seen_ids:
except exceptions.SymbolError:
# In Windows 11 24H2, the _MM_SESSION_SPACE type was
# replaced with _PSP_SESSION_SPACE, and the kernel PDB
# doesn't contain information about its members (otherwise,
# we would just fall back to the new type). However, it
# appears to be, for our purposes, functionally identical
# to the _MM_SESSION_SPACE. Because _MM_SESSION_SPACE
# stores its session ID at offset 8 as an unsigned long, we
# create an unsigned long at that offset and use that
# instead.
session_id = context.object(
layer_name=layer_name,
object_type=symbol_table + constants.BANG + "unsigned long",
offset=proc.Session + 8,
)
if session_id in seen_ids:
continue
except exceptions.InvalidAddressException:
@@ -181,7 +199,7 @@ class Modules(interfaces.plugins.PluginInterface):
continue
# save the layer if we haven't seen the session yet
seen_ids.append(session_space.SessionId)
seen_ids.append(session_id)
yield proc_layer_name
@classmethod
@@ -794,7 +794,7 @@ class EPROCESS(generic.GenericIntelProcess, pool.ExecutiveObject):
return renderers.UnreadableValue()
def get_session_id(self):
def get_session_id(self) -> Union[int, interfaces.renderers.BaseAbsentValue]:
try:
if self.has_member("Session"):
if self.Session == 0:
@@ -810,23 +810,36 @@ class EPROCESS(generic.GenericIntelProcess, pool.ExecutiveObject):
offset=kvo,
native_layer_name=self.vol.native_layer_name,
)
session = ntkrnlmp.object(
object_type="_MM_SESSION_SPACE", offset=self.Session, absolute=True
)
if session.has_member("SessionId"):
return session.SessionId
try:
session = ntkrnlmp.object(
object_type="_MM_SESSION_SPACE",
offset=self.Session,
absolute=True,
)
if session.has_member("SessionId"):
return session.SessionId
except exceptions.SymbolError:
# In Windows 11 24H2, the _MM_SESSION_SPACE type was
# replaced with _PSP_SESSION_SPACE, and the kernel PDB
# doesn't contain information about its members (otherwise,
# we would just fall back to the new type). However, it
# appears to be, for our purposes, functionally identical
# to the _MM_SESSION_SPACE. Because _MM_SESSION_SPACE
# stores its session ID at offset 8 as an unsigned long, we
# create an unsigned long at that offset and use that
# instead.
session_id = ntkrnlmp.object(
object_type="unsigned long",
offset=self.Session + 8,
absolute=True,
)
return session_id
except exceptions.InvalidAddressException:
vollog.log(
constants.LOGLEVEL_VVV,
f"Cannot access _EPROCESS.Session.SessionId at {self.vol.offset:#x}",
)
except exceptions.SymbolError:
vollog.log(
constants.LOGLEVEL_VVV,
"Could not lookup _MM_SESSION_SPACE in symbol table",
)
return renderers.UnreadableValue()