diff --git a/volatility3/framework/plugins/windows/svcdiff.py b/volatility3/framework/plugins/windows/svcdiff.py index 4325771db..84d06a695 100644 --- a/volatility3/framework/plugins/windows/svcdiff.py +++ b/volatility3/framework/plugins/windows/svcdiff.py @@ -13,7 +13,7 @@ import logging -from volatility3.framework import symbols +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 @@ -26,6 +26,10 @@ class SvcDiff(svcscan.SvcScan): _required_framework_version = (2, 4, 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 @@ -43,19 +47,24 @@ class SvcDiff(svcscan.SvcScan): ), ] - def _generator(self): + @classmethod + def service_diff( + cls, + context: interfaces.context.ContextInterface, + layer_name: str, + symbol_table: 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, service_table_name, service_binary_dll_map, filter_func = ( - self.get_prereq_info() - ) - if not symbols.symbol_table_is_64bit( - self.context, kernel.symbol_table_name + context, symbol_table ) or not versions.is_win10_15063_or_later( - context=self.context, symbol_table=kernel.symbol_table_name + context=context, symbol_table=symbol_table ): vollog.warning( "This plugin only supports Windows 10 version 15063+ 64bit Windows memory samples" @@ -68,8 +77,9 @@ class SvcDiff(svcscan.SvcScan): # collect unique service names from scanning for service in svcscan.SvcScan.service_scan( - self.context, - kernel, + context, + layer_name, + symbol_table, service_table_name, service_binary_dll_map, filter_func, @@ -79,8 +89,9 @@ class SvcDiff(svcscan.SvcScan): # collect services from listing walking for service in svclist.SvcList.service_list( - self.context, - kernel, + context, + layer_name, + symbol_table, service_table_name, service_binary_dll_map, filter_func, @@ -89,4 +100,4 @@ class SvcDiff(svcscan.SvcScan): # report services found from scanning but not list walking for hidden_service in from_scan - from_list: - yield (0, records[hidden_service]) + yield records[hidden_service] diff --git a/volatility3/framework/plugins/windows/svclist.py b/volatility3/framework/plugins/windows/svclist.py index 832b3d129..a59581063 100644 --- a/volatility3/framework/plugins/windows/svclist.py +++ b/volatility3/framework/plugins/windows/svclist.py @@ -59,15 +59,16 @@ class SvcList(svcscan.SvcScan): def service_list( cls, context: interfaces.context.ContextInterface, - kernel, + layer_name: str, + symbol_table: str, service_table_name: str, service_binary_dll_map, filter_func, ): if not symbols.symbol_table_is_64bit( - context, kernel.symbol_table_name + context, symbol_table ) or not versions.is_win10_15063_or_later( - context=context, symbol_table=kernel.symbol_table_name + context=context, symbol_table=symbol_table ): vollog.warning( "This plugin only supports Windows 10 version 15063+ 64bit Windows memory samples" @@ -76,8 +77,8 @@ class SvcList(svcscan.SvcScan): for proc in pslist.PsList.list_processes( context=context, - layer_name=kernel.layer_name, - symbol_table=kernel.symbol_table_name, + layer_name=layer_name, + symbol_table=symbol_table, filter_func=filter_func, ): try: diff --git a/volatility3/framework/plugins/windows/svcscan.py b/volatility3/framework/plugins/windows/svcscan.py index 8b9706625..bf676acb7 100644 --- a/volatility3/framework/plugins/windows/svcscan.py +++ b/volatility3/framework/plugins/windows/svcscan.py @@ -148,14 +148,17 @@ class SvcScan(interfaces.plugins.PluginInterface): native_types=native_types, ) - def _get_service_key(self, kernel) -> Optional[objects.StructType]: + @classmethod + def _get_service_key( + cls, context, config_path: str, layer_name: str, symbol_table: str + ) -> Optional[objects.StructType]: for hive in hivelist.HiveList.list_hives( - context=self.context, + context=context, base_config_path=interfaces.configuration.path_join( - self.config_path, "hivelist" + config_path, "hivelist" ), - layer_name=kernel.layer_name, - symbol_table=kernel.symbol_table_name, + layer_name=layer_name, + symbol_table=symbol_table, filter_string="machine\\system", ): # Get ControlSet\Services. @@ -273,7 +276,8 @@ class SvcScan(interfaces.plugins.PluginInterface): def service_scan( cls, context: interfaces.context.ContextInterface, - kernel, + layer_name: str, + symbol_table: str, service_table_name: str, service_binary_dll_map, filter_func, @@ -283,7 +287,7 @@ class SvcScan(interfaces.plugins.PluginInterface): ).relative_child_offset("Tag") is_vista_or_later = versions.is_vista_or_later( - context=context, symbol_table=kernel.symbol_table_name + context=context, symbol_table=symbol_table ) if is_vista_or_later: @@ -295,8 +299,8 @@ class SvcScan(interfaces.plugins.PluginInterface): for task in pslist.PsList.list_processes( context=context, - layer_name=kernel.layer_name, - symbol_table=kernel.symbol_table_name, + layer_name=layer_name, + symbol_table=symbol_table, filter_func=filter_func, ): proc_id = "Unknown" @@ -348,36 +352,41 @@ class SvcScan(interfaces.plugins.PluginInterface): seen.append(service_record) yield service_record - def get_prereq_info(self): + @classmethod + def get_prereq_info(cls, context, config_path, layer_name: str, symbol_table: str): """ Data structures and information needed to analyze service information """ - kernel = self.context.modules[self.config["kernel"]] - service_table_name = self.create_service_table( - self.context, kernel.symbol_table_name, self.config_path + service_table_name = cls.create_service_table( + context, symbol_table, config_path ) - services_key = self._get_service_key(kernel) + services_key = cls._get_service_key( + context, config_path, layer_name, symbol_table + ) service_binary_dll_map = ( - self._get_service_binary_map(services_key) + cls._get_service_binary_map(services_key) if services_key is not None else {} ) filter_func = pslist.PsList.create_name_filter(["services.exe"]) - return kernel, service_table_name, service_binary_dll_map, filter_func + return service_table_name, service_binary_dll_map, filter_func def _generator(self): - kernel, service_table_name, service_binary_dll_map, filter_func = ( - self.get_prereq_info() + kernel = self.context.modules[self.config["kernel"]] + + service_table_name, service_binary_dll_map, filter_func = self.get_prereq_info( + self.context, self.config_path, kernel.layer_name, kernel.symbol_table_name ) for record in self._enumeration_method( self.context, - kernel, + kernel.layer_name, + kernel.symbol_table_name, service_table_name, service_binary_dll_map, filter_func,