From 72ebf11fd36ff6d0d942181713529c25a02f55f5 Mon Sep 17 00:00:00 2001 From: Paul Kermann Date: Sun, 24 Apr 2022 15:13:55 +0300 Subject: [PATCH 01/10] 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 02/10] 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 03/10] 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 04/10] 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" From 6b7d5b63fe6d3fbef6fdcf339dc5c6b9426129e8 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Fri, 6 May 2022 00:49:03 +0900 Subject: [PATCH 05/10] Add: venv environments, memory dump for .gitignore --- .gitignore | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.gitignore b/.gitignore index c6da33754..5986612ea 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,16 @@ config*.json # Pyinstaller files build dist + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Memory dump files +*.dmp +*.vmem From 16313c593989a9d5c42afa430194bfe248766c80 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Fri, 6 May 2022 01:18:31 +0900 Subject: [PATCH 06/10] Fix: typo for dlllist --- volatility3/framework/plugins/windows/dlllist.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/volatility3/framework/plugins/windows/dlllist.py b/volatility3/framework/plugins/windows/dlllist.py index b24f2c0ca..2fd7deeaf 100644 --- a/volatility3/framework/plugins/windows/dlllist.py +++ b/volatility3/framework/plugins/windows/dlllist.py @@ -65,7 +65,7 @@ class DllList(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface): try: name = dll_entry.FullDllName.get_string() except exceptions.InvalidAddressException: - name = 'UnreadbleDLLName' + name = 'UnreadableDLLName' if layer_name is None: layer_name = dll_entry.vol.layer_name From 8b6194f8f4231ce8304366f2e985ca7e47f71e4e Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sat, 7 May 2022 18:16:43 +0900 Subject: [PATCH 07/10] Remove: environment .bak on .gitignore --- .gitignore | 2 -- 1 file changed, 2 deletions(-) diff --git a/.gitignore b/.gitignore index 5986612ea..d26e17d91 100644 --- a/.gitignore +++ b/.gitignore @@ -34,8 +34,6 @@ dist env/ venv/ ENV/ -env.bak/ -venv.bak/ # Memory dump files *.dmp From 8f369180e4c1dcb8fafcc618b78450bcf36b7bb2 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sun, 8 May 2022 18:33:38 +0900 Subject: [PATCH 08/10] Fix: typo for documents --- doc/source/symbol-tables.rst | 2 +- doc/source/volshell.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/source/symbol-tables.rst b/doc/source/symbol-tables.rst index 245dd9c67..4dea6077d 100644 --- a/doc/source/symbol-tables.rst +++ b/doc/source/symbol-tables.rst @@ -63,7 +63,7 @@ To determine the string for a particular memory image, use the `banners` plugin. try to locate that exact kernel debugging package for the operating system. Unfortunately each distribution provides its debugging packages under different package names and there are so many that the distribution may not keep all old versions of the debugging symbols, and therefore **it may not be possible to find the right symbols to analyze a linux -memory image with volatlity**. With Macs there are far fewer kernels and only one distribution, making it easier to +memory image with volatility**. With Macs there are far fewer kernels and only one distribution, making it easier to ensure that the right symbols can be found. Once a kernel with debugging symbols/appropriate DWARF file has been located, `dwarf2json `_ will convert it into an diff --git a/doc/source/volshell.rst b/doc/source/volshell.rst index de3c4398a..5a4b21ade 100644 --- a/doc/source/volshell.rst +++ b/doc/source/volshell.rst @@ -110,7 +110,7 @@ This means that pointers do not need to be explicitly dereferenced to access und Running plugins --------------- -It's possible to run any plugin by importing it appropriately and passing it to the `display_plugin_ouptut` or `dpo` +It's possible to run any plugin by importing it appropriately and passing it to the `display_plugin_output` or `dpo` method. In the following example we'll provide no additional parameters. Volatility will show us which parameters were required: From fde05cd1f2d7a35dd1949988f667d7f97d8e9459 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Mon, 9 May 2022 11:23:13 +0900 Subject: [PATCH 09/10] Fix: typo for cli exception message --- volatility3/cli/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/volatility3/cli/__init__.py b/volatility3/cli/__init__.py index 488892d37..e3fb726a1 100644 --- a/volatility3/cli/__init__.py +++ b/volatility3/cli/__init__.py @@ -423,7 +423,7 @@ class CommandLine: detail = f"{excp}" caused_by = ["A required python module is not installed (install the module and re-run)"] else: - general = "Volatilty encountered an unexpected situation." + general = "Volatility encountered an unexpected situation." detail = "" caused_by = [ "Please re-run using with -vvv and file a bug with the output", f"at {constants.BUG_URL}" From f54edee36203d8537bf6716a577799bd9184bb1c Mon Sep 17 00:00:00 2001 From: Paul Kermann Date: Mon, 9 May 2022 10:56:40 +0300 Subject: [PATCH 10/10] removed svcscan import --- volatility3/framework/plugins/windows/callbacks.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/volatility3/framework/plugins/windows/callbacks.py b/volatility3/framework/plugins/windows/callbacks.py index dca17aff7..2195671df 100644 --- a/volatility3/framework/plugins/windows/callbacks.py +++ b/volatility3/framework/plugins/windows/callbacks.py @@ -11,7 +11,6 @@ from volatility3.framework.renderers import format_hints from volatility3.framework.symbols import intermed from volatility3.framework.symbols.windows import versions from volatility3.plugins.windows import ssdt -from volatility3.plugins.windows import svcscan vollog = logging.getLogger(__name__) @@ -28,7 +27,6 @@ class Callbacks(interfaces.plugins.PluginInterface): requirements.ModuleRequirement(name = 'kernel', description = 'Windows kernel', architectures = ["Intel32", "Intel64"]), requirements.PluginRequirement(name = 'ssdt', plugin = ssdt.SSDT, version = (1, 0, 0)), - requirements.PluginRequirement(name = 'svcscan', plugin = svcscan.SvcScan, version = (1, 0, 0)) ] @staticmethod