From 93defa112c707b1155e53f18362c3afc77f3861c Mon Sep 17 00:00:00 2001 From: SolitudePy <47316655+SolitudePy@users.noreply.github.com> Date: Sat, 7 Jun 2025 16:29:30 +0300 Subject: [PATCH 1/4] Plugins: categorize windows.svcdiff as a malware plugin --- .../plugins/windows/malware/svcdiff.py | 102 ++++++++++++++++++ .../framework/plugins/windows/svcdiff.py | 101 ++--------------- 2 files changed, 112 insertions(+), 91 deletions(-) create mode 100644 volatility3/framework/plugins/windows/malware/svcdiff.py diff --git a/volatility3/framework/plugins/windows/malware/svcdiff.py b/volatility3/framework/plugins/windows/malware/svcdiff.py new file mode 100644 index 000000000..78b61eb67 --- /dev/null +++ b/volatility3/framework/plugins/windows/malware/svcdiff.py @@ -0,0 +1,102 @@ +# This file is Copyright 2024 Volatility Foundation and licensed under the Volatility Software License 1.0 +# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0 +# +# This module compares services found through list walking versus scanning, +# with the aim of finding hidden services. +# +# For background of hidden services and a real-world example of the use of this plugin, +# please see our blogpost: +# +# https://volatilityfoundation.org/memory-forensics-rd-illustrated-detecting-hidden-windows-services/ + +import logging + +from volatility3.framework import symbols, interfaces +from volatility3.framework.configuration import requirements +from volatility3.plugins.windows import svclist, svcscan +from volatility3.framework.symbols.windows import versions + +vollog = logging.getLogger(__name__) + + +class SvcDiff(svcscan.SvcScan): + """Compares services found through list walking versus scanning to find rootkits""" + + _required_framework_version = (2, 4, 0) + + _version = (2, 0, 0) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._enumeration_method = self.service_diff + + @classmethod + def get_requirements(cls): + # Since we're calling the plugin, make sure we have the plugin's requirements + return [ + requirements.ModuleRequirement( + name="kernel", + description="Windows kernel", + architectures=["Intel32", "Intel64"], + ), + requirements.VersionRequirement( + name="svclist", component=svclist.SvcList, version=(2, 0, 0) + ), + requirements.VersionRequirement( + name="svcscan", component=svcscan.SvcScan, version=(4, 0, 0) + ), + ] + + @classmethod + def service_diff( + cls, + context: interfaces.context.ContextInterface, + kernel_module_name: str, + service_table_name: str, + service_binary_dll_map, + filter_func, + ): + """ + On Windows 10 version 15063+ 64bit Windows memory samples, walk the services list + and scan for services then report differences + """ + kernel = context.modules[kernel_module_name] + + if not symbols.symbol_table_is_64bit( + context=context, symbol_table_name=kernel.symbol_table_name + ) or not versions.is_win10_15063_or_later( + context=context, symbol_table=kernel.symbol_table_name + ): + vollog.warning( + "This plugin only supports Windows 10 version 15063+ 64bit Windows memory samples" + ) + return + + from_scan = set() + from_list = set() + records = {} + + # collect unique service names from scanning + for service in svcscan.SvcScan.service_scan( + context, + kernel_module_name, + service_table_name, + service_binary_dll_map, + filter_func, + ): + from_scan.add(service[6]) + records[service[6]] = service + + # collect services from listing walking + for service in svclist.SvcList.service_list( + context, + kernel_module_name, + service_table_name, + service_binary_dll_map, + filter_func, + ): + from_list.add(service[6]) + + # report services found from scanning but not list walking + for hidden_service in from_scan - from_list: + yield records[hidden_service] diff --git a/volatility3/framework/plugins/windows/svcdiff.py b/volatility3/framework/plugins/windows/svcdiff.py index 78b61eb67..c95a9e62d 100644 --- a/volatility3/framework/plugins/windows/svcdiff.py +++ b/volatility3/framework/plugins/windows/svcdiff.py @@ -1,102 +1,21 @@ -# This file is Copyright 2024 Volatility Foundation and licensed under the Volatility Software License 1.0 +# This file is Copyright 2025 Volatility Foundation and licensed under the Volatility Software License 1.0 # which is available at https://www.volatilityfoundation.org/license/vsl-v1.0 # -# This module compares services found through list walking versus scanning, -# with the aim of finding hidden services. -# -# For background of hidden services and a real-world example of the use of this plugin, -# please see our blogpost: -# -# https://volatilityfoundation.org/memory-forensics-rd-illustrated-detecting-hidden-windows-services/ - import logging - -from volatility3.framework import symbols, interfaces -from volatility3.framework.configuration import requirements -from volatility3.plugins.windows import svclist, svcscan -from volatility3.framework.symbols.windows import versions +from volatility3.framework import interfaces, deprecation +from volatility3.plugins.windows.malware import svcdiff vollog = logging.getLogger(__name__) -class SvcDiff(svcscan.SvcScan): - """Compares services found through list walking versus scanning to find rootkits""" +class SvcDiff( + interfaces.plugins.PluginInterface, + deprecation.PluginRenameClass, + replacement_class=svcdiff.SvcDiff, + removal_date="2026-06-07", +): + """Compares services found through list walking versus scanning to find rootkits (deprecated).""" _required_framework_version = (2, 4, 0) _version = (2, 0, 0) - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self._enumeration_method = self.service_diff - - @classmethod - def get_requirements(cls): - # Since we're calling the plugin, make sure we have the plugin's requirements - return [ - requirements.ModuleRequirement( - name="kernel", - description="Windows kernel", - architectures=["Intel32", "Intel64"], - ), - requirements.VersionRequirement( - name="svclist", component=svclist.SvcList, version=(2, 0, 0) - ), - requirements.VersionRequirement( - name="svcscan", component=svcscan.SvcScan, version=(4, 0, 0) - ), - ] - - @classmethod - def service_diff( - cls, - context: interfaces.context.ContextInterface, - kernel_module_name: str, - service_table_name: str, - service_binary_dll_map, - filter_func, - ): - """ - On Windows 10 version 15063+ 64bit Windows memory samples, walk the services list - and scan for services then report differences - """ - kernel = context.modules[kernel_module_name] - - if not symbols.symbol_table_is_64bit( - context=context, symbol_table_name=kernel.symbol_table_name - ) or not versions.is_win10_15063_or_later( - context=context, symbol_table=kernel.symbol_table_name - ): - vollog.warning( - "This plugin only supports Windows 10 version 15063+ 64bit Windows memory samples" - ) - return - - from_scan = set() - from_list = set() - records = {} - - # collect unique service names from scanning - for service in svcscan.SvcScan.service_scan( - context, - kernel_module_name, - service_table_name, - service_binary_dll_map, - filter_func, - ): - from_scan.add(service[6]) - records[service[6]] = service - - # collect services from listing walking - for service in svclist.SvcList.service_list( - context, - kernel_module_name, - service_table_name, - service_binary_dll_map, - filter_func, - ): - from_list.add(service[6]) - - # report services found from scanning but not list walking - for hidden_service in from_scan - from_list: - yield records[hidden_service] From d4644208a972d8a10b4532c4b0a8a16e5e33e11c Mon Sep 17 00:00:00 2001 From: SolitudePy <47316655+SolitudePy@users.noreply.github.com> Date: Sat, 7 Jun 2025 17:32:54 +0300 Subject: [PATCH 2/4] Plugins: fix svcdiff deprecation wrapper --- volatility3/framework/plugins/windows/svcdiff.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/volatility3/framework/plugins/windows/svcdiff.py b/volatility3/framework/plugins/windows/svcdiff.py index c95a9e62d..bafdf34da 100644 --- a/volatility3/framework/plugins/windows/svcdiff.py +++ b/volatility3/framework/plugins/windows/svcdiff.py @@ -4,18 +4,21 @@ import logging from volatility3.framework import interfaces, deprecation from volatility3.plugins.windows.malware import svcdiff +from volatility3.plugins.windows import svcscan vollog = logging.getLogger(__name__) class SvcDiff( - interfaces.plugins.PluginInterface, + svcscan.SvcScan, deprecation.PluginRenameClass, replacement_class=svcdiff.SvcDiff, removal_date="2026-06-07", ): """Compares services found through list walking versus scanning to find rootkits (deprecated).""" - + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._enumeration_method = self.service_diff _required_framework_version = (2, 4, 0) _version = (2, 0, 0) From 6537086e62d65f85fcbc3359432237af7278706c Mon Sep 17 00:00:00 2001 From: SolitudePy <47316655+SolitudePy@users.noreply.github.com> Date: Sat, 7 Jun 2025 17:33:09 +0300 Subject: [PATCH 3/4] black --- volatility3/framework/plugins/windows/svcdiff.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/volatility3/framework/plugins/windows/svcdiff.py b/volatility3/framework/plugins/windows/svcdiff.py index bafdf34da..6e4bc30e0 100644 --- a/volatility3/framework/plugins/windows/svcdiff.py +++ b/volatility3/framework/plugins/windows/svcdiff.py @@ -16,9 +16,11 @@ class SvcDiff( removal_date="2026-06-07", ): """Compares services found through list walking versus scanning to find rootkits (deprecated).""" + def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._enumeration_method = self.service_diff + _required_framework_version = (2, 4, 0) _version = (2, 0, 0) From 45934ae0fd13a88ff03b2325e57424ac56b9eb1d Mon Sep 17 00:00:00 2001 From: SolitudePy <47316655+SolitudePy@users.noreply.github.com> Date: Sat, 7 Jun 2025 17:40:02 +0300 Subject: [PATCH 4/4] removed import for ruff --- volatility3/framework/plugins/windows/svcdiff.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/volatility3/framework/plugins/windows/svcdiff.py b/volatility3/framework/plugins/windows/svcdiff.py index 6e4bc30e0..24bc53e49 100644 --- a/volatility3/framework/plugins/windows/svcdiff.py +++ b/volatility3/framework/plugins/windows/svcdiff.py @@ -2,7 +2,7 @@ # which is available at https://www.volatilityfoundation.org/license/vsl-v1.0 # import logging -from volatility3.framework import interfaces, deprecation +from volatility3.framework import deprecation from volatility3.plugins.windows.malware import svcdiff from volatility3.plugins.windows import svcscan