From 04517ca79768c16cb8afc323a5625567fe87d225 Mon Sep 17 00:00:00 2001 From: David McDonald Date: Thu, 12 Dec 2024 23:24:40 -0600 Subject: [PATCH] Windows: Handle missing _MM_SESSION_SPACE As of Windows 11 24H2, the `_MM_SESSION_SPACE` type no longer appears in the kernel PDB. Instead, the `_EPROCESS.Session` member refers to a new type, `_PSP_SESSION_SPACE`, which does not have a type definition. However, experimentation has shown that this new structure is functionally identical to the old structure - the `ProcessList` and `SessionId` members still appear to be at their old offsets. In order to account for this when analyzing these newer Windows versions, this catches the `SymbolError` and instantiates an `unsigned long` at the offset (8) where the `SessionId` member would normally be defined within an `_MM_SESSION_SPACE` structure. --- .../framework/plugins/windows/modules.py | 34 ++++++++++++++---- .../symbols/windows/extensions/__init__.py | 35 +++++++++++++------ 2 files changed, 51 insertions(+), 18 deletions(-) diff --git a/volatility3/framework/plugins/windows/modules.py b/volatility3/framework/plugins/windows/modules.py index ba45834d5..5ff252074 100644 --- a/volatility3/framework/plugins/windows/modules.py +++ b/volatility3/framework/plugins/windows/modules.py @@ -165,13 +165,33 @@ 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 = int( + 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: @@ -184,7 +204,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 diff --git a/volatility3/framework/symbols/windows/extensions/__init__.py b/volatility3/framework/symbols/windows/extensions/__init__.py index 793e506c3..78f59fc0c 100755 --- a/volatility3/framework/symbols/windows/extensions/__init__.py +++ b/volatility3/framework/symbols/windows/extensions/__init__.py @@ -813,23 +813,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 int(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()