From 72ebf11fd36ff6d0d942181713529c25a02f55f5 Mon Sep 17 00:00:00 2001 From: Paul Kermann Date: Sun, 24 Apr 2022 15:13:55 +0300 Subject: [PATCH 1/4] support CallbackListHead when CmpCallBackVector not present --- .../framework/plugins/windows/callbacks.py | 75 ++++++++++++++----- .../symbols/windows/callbacks-x64.json | 43 +++++++++++ .../symbols/windows/callbacks-x86.json | 43 +++++++++++ 3 files changed, 143 insertions(+), 18 deletions(-) diff --git a/volatility3/framework/plugins/windows/callbacks.py b/volatility3/framework/plugins/windows/callbacks.py index 352dba448..d8e5aea86 100644 --- a/volatility3/framework/plugins/windows/callbacks.py +++ b/volatility3/framework/plugins/windows/callbacks.py @@ -111,30 +111,19 @@ class Callbacks(interfaces.plugins.PluginInterface): yield symbol_name, callback.Callback, None @classmethod - def list_registry_callbacks(cls, context: interfaces.context.ContextInterface, layer_name: str, symbol_table: str, - callback_table_name: str) -> Iterable[Tuple[str, int, None]]: - """Lists all registry callbacks. - - Args: - context: The context to retrieve required elements (layers, symbol tables) from - layer_name: The name of the layer on which to operate - symbol_table: The name of the table containing the kernel symbols - callback_table_name: The nae of the table containing the callback symbols - - Yields: - A name, location and optional detail string + def _list_registry_callbacks_legacy(cls, context: interfaces.context.ContextInterface, layer_name: str, symbol_table: str, + callback_table_name: str) -> Iterable[Tuple[str, int, None]]: + """ + Lists all registry callbacks from the old format via the CmpCallBackVector. """ kvo = context.layers[layer_name].config['kernel_virtual_offset'] ntkrnlmp = context.module(symbol_table, layer_name = layer_name, offset = kvo) full_type_name = callback_table_name + constants.BANG + "_EX_CALLBACK_ROUTINE_BLOCK" - try: - symbol_offset = ntkrnlmp.get_symbol("CmpCallBackVector").address - symbol_count_offset = ntkrnlmp.get_symbol("CmpCallBackCount").address - except exceptions.SymbolError: - vollog.debug("Cannot find CmpCallBackVector or CmpCallBackCount") - return + symbol_offset = ntkrnlmp.get_symbol("CmpCallBackVector").address + symbol_count_offset = ntkrnlmp.get_symbol("CmpCallBackCount").address + callback_count = ntkrnlmp.object(object_type = "unsigned int", offset = symbol_count_offset) @@ -155,6 +144,56 @@ class Callbacks(interfaces.plugins.PluginInterface): if callback.Function != 0: yield "CmRegisterCallback", callback.Function, None + @classmethod + def _list_registry_callbacks_new(cls, context: interfaces.context.ContextInterface, layer_name: str, symbol_table: str, + callback_table_name: str) -> Iterable[Tuple[str, int, None]]: + """ + Lists all registry callbacks via the CallbackListHead. + """ + + kvo = context.layers[layer_name].config['kernel_virtual_offset'] + ntkrnlmp = context.module(symbol_table, layer_name = layer_name, offset = kvo) + full_type_name = callback_table_name + constants.BANG + "_CM_CALLBACK_ENTRY" + + symbol_offset = ntkrnlmp.get_symbol("CallbackListHead").address + symbol_count_offset = ntkrnlmp.get_symbol("CmpCallBackCount").address + + callback_count = ntkrnlmp.object(object_type = "unsigned int", offset = symbol_count_offset) + + if callback_count == 0: + return + + callback_list = ntkrnlmp.object(object_type = "_LIST_ENTRY", offset = symbol_offset) + for callback in callback_list.to_list(full_type_name, "Link"): + yield "CmRegisterCallbackEx", callback.Function, f"Alltitude: {callback.Alltitude.String}" + + @classmethod + def list_registry_callbacks(cls, context: interfaces.context.ContextInterface, layer_name: str, symbol_table: str, + callback_table_name: str) -> Iterable[Tuple[str, int, None]]: + """Lists all registry callbacks. + + Args: + context: The context to retrieve required elements (layers, symbol tables) from + layer_name: The name of the layer on which to operate + symbol_table: The name of the table containing the kernel symbols + callback_table_name: The nae of the table containing the callback symbols + + Yields: + A name, location and optional detail string + """ + + kvo = context.layers[layer_name].config['kernel_virtual_offset'] + ntkrnlmp = context.module(symbol_table, layer_name = layer_name, offset = kvo) + full_type_name = callback_table_name + constants.BANG + "_EX_CALLBACK_ROUTINE_BLOCK" + + if ntkrnlmp.has_symbol("CmpCallBackVector") and ntkrnlmp.has_symbol("CmpCallBackCount"): + yield from cls._list_registry_callbacks_legacy(context, layer_name, symbol_table, callback_table_name) + elif ntkrnlmp.has_symbol("CallbackListHead") and ntkrnlmp.has_symbol("CmpCallBackCount"): + yield from cls._list_registry_callbacks_new(context, layer_name, symbol_table, callback_table_name) + else: + vollog.debug("Cannot find CmpCallBackVector or CmpCallBackCount or CallbackListHead") + return + @classmethod def list_bugcheck_reason_callbacks(cls, context: interfaces.context.ContextInterface, layer_name: str, symbol_table: str, callback_table_name: str) -> Iterable[Tuple[str, int, str]]: diff --git a/volatility3/framework/symbols/windows/callbacks-x64.json b/volatility3/framework/symbols/windows/callbacks-x64.json index dbb6086df..5300d28f9 100644 --- a/volatility3/framework/symbols/windows/callbacks-x64.json +++ b/volatility3/framework/symbols/windows/callbacks-x64.json @@ -8,6 +8,12 @@ "signed": false, "endian": "little" }, + "unsigned long long": { + "kind": "int", + "size": 8, + "signed": false, + "endian": "little" + }, "unsigned char": { "kind": "char", "size": 1, @@ -137,6 +143,43 @@ }, "kind": "struct", "size": 64 + }, + "_CM_CALLBACK_ENTRY": { + "fields": { + "Link": { + "type": { + "kind": "struct", + "name": "nt_symbols!_LIST_ENTRY" + }, + "offset": 0 + }, + "Cookie": { + "type": { + "kind": "base", + "name": "unsigned long long" + }, + "offset": 24 + }, + "Function": { + "type": { + "kind": "pointer", + "subtype": { + "kind": "base", + "name": "void" + } + }, + "offset": 40 + }, + "Alltitude": { + "type": { + "kind": "struct", + "name": "nt_symbols!_UNICODE_STRING" + }, + "offset": 48 + } + }, + "kind": "struct", + "size": 64 } }, "metadata": { diff --git a/volatility3/framework/symbols/windows/callbacks-x86.json b/volatility3/framework/symbols/windows/callbacks-x86.json index cf0cb8b65..52baeb18f 100644 --- a/volatility3/framework/symbols/windows/callbacks-x86.json +++ b/volatility3/framework/symbols/windows/callbacks-x86.json @@ -8,6 +8,12 @@ "signed": false, "endian": "little" }, + "unsigned long long": { + "kind": "int", + "size": 8, + "signed": false, + "endian": "little" + }, "unsigned char": { "kind": "char", "size": 1, @@ -137,6 +143,43 @@ }, "kind": "struct", "size": 28 + }, + "_CM_CALLBACK_ENTRY": { + "fields": { + "Link": { + "type": { + "kind": "struct", + "name": "nt_symbols!_LIST_ENTRY" + }, + "offset": 0 + }, + "Cookie": { + "type": { + "kind": "base", + "name": "unsigned long long" + }, + "offset": 16 + }, + "Function": { + "type": { + "kind": "pointer", + "subtype": { + "kind": "base", + "name": "void" + } + }, + "offset": 28 + }, + "Alltitude": { + "type": { + "kind": "struct", + "name": "nt_symbols!_UNICODE_STRING" + }, + "offset": 32 + } + }, + "kind": "struct", + "size": 40 } }, "metadata": { From bc04d22a1b7e2969f1ddd5ec6598439724c17bc7 Mon Sep 17 00:00:00 2001 From: Paul Kermann Date: Sun, 24 Apr 2022 16:42:25 +0300 Subject: [PATCH 2/4] remove unused line --- volatility3/framework/plugins/windows/callbacks.py | 1 - 1 file changed, 1 deletion(-) diff --git a/volatility3/framework/plugins/windows/callbacks.py b/volatility3/framework/plugins/windows/callbacks.py index d8e5aea86..c10d97405 100644 --- a/volatility3/framework/plugins/windows/callbacks.py +++ b/volatility3/framework/plugins/windows/callbacks.py @@ -184,7 +184,6 @@ class Callbacks(interfaces.plugins.PluginInterface): kvo = context.layers[layer_name].config['kernel_virtual_offset'] ntkrnlmp = context.module(symbol_table, layer_name = layer_name, offset = kvo) - full_type_name = callback_table_name + constants.BANG + "_EX_CALLBACK_ROUTINE_BLOCK" if ntkrnlmp.has_symbol("CmpCallBackVector") and ntkrnlmp.has_symbol("CmpCallBackCount"): yield from cls._list_registry_callbacks_legacy(context, layer_name, symbol_table, callback_table_name) From 0057f81269b382fdaa9f15922ec41f0cd1f31faa Mon Sep 17 00:00:00 2001 From: Paul Kermann Date: Mon, 25 Apr 2022 09:27:54 +0300 Subject: [PATCH 3/4] log which symbol does not exist --- volatility3/framework/plugins/windows/callbacks.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/volatility3/framework/plugins/windows/callbacks.py b/volatility3/framework/plugins/windows/callbacks.py index c10d97405..5ee11f164 100644 --- a/volatility3/framework/plugins/windows/callbacks.py +++ b/volatility3/framework/plugins/windows/callbacks.py @@ -190,7 +190,14 @@ class Callbacks(interfaces.plugins.PluginInterface): elif ntkrnlmp.has_symbol("CallbackListHead") and ntkrnlmp.has_symbol("CmpCallBackCount"): yield from cls._list_registry_callbacks_new(context, layer_name, symbol_table, callback_table_name) else: - vollog.debug("Cannot find CmpCallBackVector or CmpCallBackCount or CallbackListHead") + symbols_to_check = ["CmpCallBackVector", "CmpCallBackCount", "CallbackListHead"] + vollog.debug("Failed to get registry callbacks!") + for symbol_name in symbols_to_check: + symbol_status = "does not exist" + if ntkrnlmp.has_symbol(symbol_name): + symbol_status = "exists" + vollog.debug(f"symbol {symbol_name} {symbol_status}.") + return @classmethod From a8d70c065738b3c3691da3ec2a82a6d4a7ca24a6 Mon Sep 17 00:00:00 2001 From: Paul Kermann Date: Tue, 26 Apr 2022 10:11:12 +0300 Subject: [PATCH 4/4] fix typo --- volatility3/framework/plugins/windows/callbacks.py | 2 +- volatility3/framework/symbols/windows/callbacks-x64.json | 2 +- volatility3/framework/symbols/windows/callbacks-x86.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/volatility3/framework/plugins/windows/callbacks.py b/volatility3/framework/plugins/windows/callbacks.py index 5ee11f164..dca17aff7 100644 --- a/volatility3/framework/plugins/windows/callbacks.py +++ b/volatility3/framework/plugins/windows/callbacks.py @@ -165,7 +165,7 @@ class Callbacks(interfaces.plugins.PluginInterface): callback_list = ntkrnlmp.object(object_type = "_LIST_ENTRY", offset = symbol_offset) for callback in callback_list.to_list(full_type_name, "Link"): - yield "CmRegisterCallbackEx", callback.Function, f"Alltitude: {callback.Alltitude.String}" + yield "CmRegisterCallbackEx", callback.Function, f"Altitude: {callback.Altitude.String}" @classmethod def list_registry_callbacks(cls, context: interfaces.context.ContextInterface, layer_name: str, symbol_table: str, diff --git a/volatility3/framework/symbols/windows/callbacks-x64.json b/volatility3/framework/symbols/windows/callbacks-x64.json index 5300d28f9..87682cb92 100644 --- a/volatility3/framework/symbols/windows/callbacks-x64.json +++ b/volatility3/framework/symbols/windows/callbacks-x64.json @@ -170,7 +170,7 @@ }, "offset": 40 }, - "Alltitude": { + "Altitude": { "type": { "kind": "struct", "name": "nt_symbols!_UNICODE_STRING" diff --git a/volatility3/framework/symbols/windows/callbacks-x86.json b/volatility3/framework/symbols/windows/callbacks-x86.json index 52baeb18f..702b68a65 100644 --- a/volatility3/framework/symbols/windows/callbacks-x86.json +++ b/volatility3/framework/symbols/windows/callbacks-x86.json @@ -170,7 +170,7 @@ }, "offset": 28 }, - "Alltitude": { + "Altitude": { "type": { "kind": "struct", "name": "nt_symbols!_UNICODE_STRING"