From 6e816c2f20d00bc0d92b291fd762b9a3139dd571 Mon Sep 17 00:00:00 2001 From: Mike Auty Date: Sat, 22 Aug 2020 15:02:20 +0100 Subject: [PATCH] Windows: Convert os_distinguisher to callable class --- .../framework/plugins/windows/bigpools.py | 11 +--- .../framework/plugins/windows/poolscanner.py | 20 ++---- .../plugins/windows/registry/hivescan.py | 5 +- .../framework/plugins/windows/svcscan.py | 57 +++++------------ .../framework/symbols/windows/winver.py | 63 ++++++++++++++++--- 5 files changed, 76 insertions(+), 80 deletions(-) diff --git a/volatility/framework/plugins/windows/bigpools.py b/volatility/framework/plugins/windows/bigpools.py index 5e6a0162b..e7164f9e9 100644 --- a/volatility/framework/plugins/windows/bigpools.py +++ b/volatility/framework/plugins/windows/bigpools.py @@ -21,13 +21,6 @@ class BigPools(interfaces.plugins.PluginInterface): _version = (1, 0, 0) - is_vista_or_later = winver.os_distinguisher(version_check = lambda x: x >= (6, 0), - fallback_checks = [("KdCopyDataBlock", None, True)]) - - is_win10 = winver.os_distinguisher(version_check = lambda x: (10, 0) <= x, - fallback_checks = [("ObHeaderCookie", None, True), - ("_HANDLE_TABLE", "HandleCount", False)]) - @classmethod def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: # Since we're calling the plugin, make sure we have the plugin's requirements @@ -72,8 +65,8 @@ class BigPools(interfaces.plugins.PluginInterface): big_page_table_type = ntkrnlmp.get_type("_POOL_TRACKER_BIG_PAGES") except exceptions.SymbolError: # We have to manually load a symbol table - is_vista_or_later = cls.is_vista_or_later(context, symbol_table) - is_win10 = cls.is_win10(context, symbol_table) + is_vista_or_later = winver.is_vista_or_later(context, symbol_table) + is_win10 = winver.is_win10(context, symbol_table) if is_win10: big_pools_json_filename = "bigpools-win10" elif is_vista_or_later: diff --git a/volatility/framework/plugins/windows/poolscanner.py b/volatility/framework/plugins/windows/poolscanner.py index 66f8bc0e4..3981da857 100644 --- a/volatility/framework/plugins/windows/poolscanner.py +++ b/volatility/framework/plugins/windows/poolscanner.py @@ -127,18 +127,6 @@ class PoolScanner(plugins.PluginInterface): requirements.PluginRequirement(name = 'handles', plugin = handles.Handles, version = (1, 0, 0)), ] - is_windows_10 = winver.os_distinguisher(version_check = lambda x: x >= (10, 0), - fallback_checks = [("ObHeaderCookie", None, True)]) - is_windows_8_or_later = winver.os_distinguisher(version_check = lambda x: x >= (6, 2), - fallback_checks = [("_HANDLE_TABLE", "HandleCount", False)]) - # Technically, this is win7 or less - is_windows_7 = winver.os_distinguisher(version_check = lambda x: x == (6, 1), - fallback_checks = [("_OBJECT_HEADER", "TypeIndex", True), - ("_HANDLE_TABLE", "HandleCount", True)]) - - is_vista_or_later = winver.os_distinguisher(version_check = lambda x: x >= (6, 0), - fallback_checks = [("KdCopyDataBlock", None, True)]) - def _generator(self): symbol_table = self.config["nt_symbols"] @@ -288,8 +276,8 @@ class PoolScanner(plugins.PluginInterface): cookie = handles.Handles.find_cookie(context = context, layer_name = layer_name, symbol_table = symbol_table) - is_windows_10 = cls.is_windows_10(context, symbol_table) - is_windows_8_or_later = cls.is_windows_8_or_later(context, symbol_table) + is_windows_10 = winver.is_windows_10(context, symbol_table) + is_windows_8_or_later = winver.is_windows_8_or_later(context, symbol_table) # start off with the primary virtual layer scan_layer = layer_name @@ -383,7 +371,7 @@ class PoolScanner(plugins.PluginInterface): # We have to manually load a symbol table if symbols.symbol_table_is_64bit(context, symbol_table): - is_win_7 = cls.is_windows_7(context, symbol_table) + is_win_7 = winver.is_windows_7(context, symbol_table) if is_win_7: pool_header_json_filename = "poolheader-x64-win7" else: @@ -392,7 +380,7 @@ class PoolScanner(plugins.PluginInterface): pool_header_json_filename = "poolheader-x86" # set the class_type to match the normal WindowsKernelIntermedSymbols - is_vista_or_later = cls.is_vista_or_later(context, symbol_table) + is_vista_or_later = winver.is_vista_or_later(context, symbol_table) if is_vista_or_later: class_type = extensions.pool.POOL_HEADER_VISTA else: diff --git a/volatility/framework/plugins/windows/registry/hivescan.py b/volatility/framework/plugins/windows/registry/hivescan.py index 06f3706b4..94028c2e6 100644 --- a/volatility/framework/plugins/windows/registry/hivescan.py +++ b/volatility/framework/plugins/windows/registry/hivescan.py @@ -17,9 +17,6 @@ class HiveScan(interfaces.plugins.PluginInterface): _version = (1, 0, 0) - is_windows_8_1_or_later = winver.os_distinguisher(version_check = lambda x: x >= (6, 3), - fallback_checks = [("_KPRCB", "PendingTickFlags", True)]) - @classmethod def get_requirements(cls): return [ @@ -49,7 +46,7 @@ class HiveScan(interfaces.plugins.PluginInterface): """ is_64bit = symbols.symbol_table_is_64bit(context, symbol_table) - is_windows_8_1_or_later = HiveScan.is_windows_8_1_or_later(context = context, symbol_table = symbol_table) + is_windows_8_1_or_later = winver.is_windows_8_1_or_later(context = context, symbol_table = symbol_table) if is_windows_8_1_or_later and is_64bit: kvo = context.layers[layer_name].config['kernel_virtual_offset'] diff --git a/volatility/framework/plugins/windows/svcscan.py b/volatility/framework/plugins/windows/svcscan.py index 701e1bf76..a1bd2a57c 100644 --- a/volatility/framework/plugins/windows/svcscan.py +++ b/volatility/framework/plugins/windows/svcscan.py @@ -22,35 +22,6 @@ class SvcScan(interfaces.plugins.PluginInterface): _version = (1, 0, 0) - is_vista_or_later = winver.os_distinguisher(version_check = lambda x: x >= (6, 0), - fallback_checks = [("KdCopyDataBlock", None, True)]) - - is_windows_xp = winver.os_distinguisher(version_check = lambda x: (5, 1) <= x < (5, 2), - fallback_checks = [("KdCopyDataBlock", None, False), - ("_HANDLE_TABLE", "HandleCount", True)]) - - is_xp_or_2003 = winver.os_distinguisher(version_check = lambda x: (5, 1) <= x < (6, 0), - fallback_checks = [("KdCopyDataBlock", None, False), - ("_HANDLE_TABLE", "HandleCount", True)]) - - is_win10_up_to_15063 = winver.os_distinguisher(version_check = lambda x: (10, 0) <= x < (10, 0, 15063), - fallback_checks = [("ObHeaderCookie", None, True), - ("_HANDLE_TABLE", "HandleCount", False), - ("_EPROCESS", "KeepAliveCounter", True)]) - - is_win10_15063 = winver.os_distinguisher(version_check = lambda x: x == (10, 0, 15063), - fallback_checks = [("ObHeaderCookie", None, True), - ("_HANDLE_TABLE", "HandleCount", False), - ("_EPROCESS", "KeepAliveCounter", False), - ("_EPROCESS", "ControlFlowGuardEnabled", True)]) - - is_win10_16299_or_later = winver.os_distinguisher(version_check = lambda x: x >= (10, 0, 16299), - fallback_checks = [("ObHeaderCookie", None, True), - ("_HANDLE_TABLE", "HandleCount", False), - ("_EPROCESS", "KeepAliveCounter", False), - ("_EPROCESS", "ControlFlowGuardEnabled", - False)]) - @classmethod def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: # Since we're calling the plugin, make sure we have the plugin's requirements @@ -86,30 +57,30 @@ class SvcScan(interfaces.plugins.PluginInterface): native_types = context.symbol_space[symbol_table].natives is_64bit = symbols.symbol_table_is_64bit(context, symbol_table) - if SvcScan.is_windows_xp(context = context, symbol_table = symbol_table) and not is_64bit: + if winver.is_windows_xp(context = context, symbol_table = symbol_table) and not is_64bit: symbol_filename = "services-xp-x86" - elif SvcScan.is_xp_or_2003(context = context, symbol_table = symbol_table) and is_64bit: + elif winver.is_xp_or_2003(context = context, symbol_table = symbol_table) and is_64bit: symbol_filename = "services-xp-2003-x64" - elif SvcScan.is_win10_16299_or_later(context = context, symbol_table = symbol_table) and is_64bit: + elif winver.is_win10_16299_or_later(context = context, symbol_table = symbol_table) and is_64bit: symbol_filename = "services-win10-16299-x64" - elif SvcScan.is_win10_16299_or_later(context = context, symbol_table = symbol_table) and not is_64bit: + elif winver.is_win10_16299_or_later(context = context, symbol_table = symbol_table) and not is_64bit: symbol_filename = "services-win10-16299-x86" - elif SvcScan.is_win10_up_to_15063(context = context, symbol_table = symbol_table) and is_64bit: + elif winver.is_win10_up_to_15063(context = context, symbol_table = symbol_table) and is_64bit: symbol_filename = "services-win8-x64" - elif SvcScan.is_win10_up_to_15063(context = context, symbol_table = symbol_table) and not is_64bit: + elif winver.is_win10_up_to_15063(context = context, symbol_table = symbol_table) and not is_64bit: symbol_filename = "services-win8-x86" - elif SvcScan.is_win10_15063(context = context, symbol_table = symbol_table) and is_64bit: + elif winver.is_win10_15063(context = context, symbol_table = symbol_table) and is_64bit: symbol_filename = "services-win10-15063-x64" - elif SvcScan.is_win10_15063(context = context, symbol_table = symbol_table) and not is_64bit: + elif winver.is_win10_15063(context = context, symbol_table = symbol_table) and not is_64bit: symbol_filename = "services-win10-15063-x86" - elif poolscanner.PoolScanner.is_windows_8_or_later(context = context, symbol_table = symbol_table) and is_64bit: + elif winver.is_windows_8_or_later(context = context, symbol_table = symbol_table) and is_64bit: symbol_filename = "services-win8-x64" - elif poolscanner.PoolScanner.is_windows_8_or_later(context = context, - symbol_table = symbol_table) and not is_64bit: + elif winver.is_windows_8_or_later(context = context, + symbol_table = symbol_table) and not is_64bit: symbol_filename = "services-win8-x86" - elif SvcScan.is_vista_or_later(context = context, symbol_table = symbol_table) and is_64bit: + elif winver.is_vista_or_later(context = context, symbol_table = symbol_table) and is_64bit: symbol_filename = "services-vista-x64" - elif SvcScan.is_vista_or_later(context = context, symbol_table = symbol_table) and not is_64bit: + elif winver.is_vista_or_later(context = context, symbol_table = symbol_table) and not is_64bit: symbol_filename = "services-vista-x86" else: raise NotImplementedError("This version of Windows is not supported!") @@ -130,7 +101,7 @@ class SvcScan(interfaces.plugins.PluginInterface): filter_func = pslist.PsList.create_name_filter(["services.exe"]) - is_vista_or_later = SvcScan.is_vista_or_later(context = self.context, symbol_table = self.config["nt_symbols"]) + is_vista_or_later = winver.is_vista_or_later(context = self.context, symbol_table = self.config["nt_symbols"]) if is_vista_or_later: service_tag = b"serH" diff --git a/volatility/framework/symbols/windows/winver.py b/volatility/framework/symbols/windows/winver.py index c06763988..9a931ffb9 100644 --- a/volatility/framework/symbols/windows/winver.py +++ b/volatility/framework/symbols/windows/winver.py @@ -6,10 +6,7 @@ from volatility.framework import interfaces, constants, exceptions vollog = logging.getLogger(__name__) -def os_distinguisher( - version_check: Callable[[Tuple[int, ...]], bool], - fallback_checks: List[Tuple[str, Optional[str], - bool]]) -> Callable[[interfaces.context.ContextInterface, str], bool]: +class OsDistinguisher: """Distinguishes a symbol table as being above a particular version or point. @@ -34,8 +31,13 @@ def os_distinguisher( A function that takes a context and a symbol table name and determines whether that symbol table passes the distinguishing checks """ + def __init__(self, version_check: Callable[[Tuple[int, ...]], bool], + fallback_checks: List[Tuple[str, Optional[str], bool]]): + self._verison_check = version_check + self._fallback_checks = fallback_checks + # try the primary method based on the pe version in the ISF - def method(context: interfaces.context.ContextInterface, symbol_table: str) -> bool: + def __call__(self, context: interfaces.context.ContextInterface, symbol_table: str) -> bool: """ Args: @@ -49,12 +51,12 @@ def os_distinguisher( try: pe_version = context.symbol_space[symbol_table].metadata.pe_version major, minor, revision, build = pe_version - return version_check((major, minor, revision, build)) + return self._version_check((major, minor, revision, build)) except (AttributeError, ValueError, TypeError): vollog.log(constants.LOGLEVEL_VVV, "Windows PE version data is not available") # fall back to the backup method, if necessary - for name, member, response in fallback_checks: + for name, member, response in self._fallback_checks: if member is None: if (context.symbol_space.has_symbol(symbol_table + constants.BANG + name) or context.symbol_space.has_type(symbol_table + constants.BANG + name)) != response: @@ -70,4 +72,49 @@ def os_distinguisher( return True - return method + +is_windows_8_1_or_later = OsDistinguisher(version_check = lambda x: x >= (6, 3), + fallback_checks = [("_KPRCB", "PendingTickFlags", True)]) + +is_vista_or_later = OsDistinguisher(version_check = lambda x: x >= (6, 0), + fallback_checks = [("KdCopyDataBlock", None, True)]) + +is_win10 = OsDistinguisher(version_check = lambda x: (10, 0) <= x, + fallback_checks = [("ObHeaderCookie", None, True), + ("_HANDLE_TABLE", "HandleCount", False)]) + +is_windows_xp = OsDistinguisher(version_check = lambda x: (5, 1) <= x < (5, 2), + fallback_checks = [("KdCopyDataBlock", None, False), + ("_HANDLE_TABLE", "HandleCount", True)]) + +is_xp_or_2003 = OsDistinguisher(version_check = lambda x: (5, 1) <= x < (6, 0), + fallback_checks = [("KdCopyDataBlock", None, False), + ("_HANDLE_TABLE", "HandleCount", True)]) + +is_win10_up_to_15063 = OsDistinguisher(version_check = lambda x: (10, 0) <= x < (10, 0, 15063), + fallback_checks = [("ObHeaderCookie", None, True), + ("_HANDLE_TABLE", "HandleCount", False), + ("_EPROCESS", "KeepAliveCounter", True)]) + +is_win10_15063 = OsDistinguisher(version_check = lambda x: x == (10, 0, 15063), + fallback_checks = [("ObHeaderCookie", None, True), + ("_HANDLE_TABLE", "HandleCount", False), + ("_EPROCESS", "KeepAliveCounter", False), + ("_EPROCESS", "ControlFlowGuardEnabled", True)]) + +is_win10_16299_or_later = OsDistinguisher(version_check = lambda x: x >= (10, 0, 16299), + fallback_checks = [("ObHeaderCookie", None, True), + ("_HANDLE_TABLE", "HandleCount", False), + ("_EPROCESS", "KeepAliveCounter", False), + ("_EPROCESS", "ControlFlowGuardEnabled", + False)]) + +is_windows_10 = OsDistinguisher(version_check = lambda x: x >= (10, 0), + fallback_checks = [("ObHeaderCookie", None, True)]) + +is_windows_8_or_later = OsDistinguisher(version_check = lambda x: x >= (6, 2), + fallback_checks = [("_HANDLE_TABLE", "HandleCount", False)]) +# Technically, this is win7 or less +is_windows_7 = OsDistinguisher(version_check = lambda x: x == (6, 1), + fallback_checks = [("_OBJECT_HEADER", "TypeIndex", True), + ("_HANDLE_TABLE", "HandleCount", True)])