diff --git a/volatility/framework/automagic/mac.py b/volatility/framework/automagic/mac.py index 75c8f2cff..5bc26d4cb 100644 --- a/volatility/framework/automagic/mac.py +++ b/volatility/framework/automagic/mac.py @@ -4,7 +4,7 @@ import logging import struct -from typing import Optional, Iterable, Set +from typing import Optional, Iterable, Set, Iterator, Any from volatility.framework import interfaces, constants, layers, exceptions, objects from volatility.framework import symbols @@ -118,6 +118,66 @@ class MacintelStacker(interfaces.automagic.StackerLayerInterface): class MacUtilities(object): """Class with multiple useful mac functions.""" + @classmethod + def mask_mods_list(cls, + context: interfaces.context.ContextInterface, + layer_name: str, + mods: Iterator[Any]) -> Iterator[Any]: + + """ + A helper function to mask the starting and end address of kernel modules + """ + mask = context.layers[layer_name].address_mask + + return [(objects.utility.array_to_string(mod.name), mod.address & mask, (mod.address & mask) + mod.size) for mod in mods] + + @classmethod + def generate_kernel_handler_info(cls, + context: interfaces.context.ContextInterface, + layer_name: str, + kernel, # ikelos - how to type this?? + mods_list: Iterator[Any]): + + try: + start_addr = kernel.object_from_symbol("vm_kernel_stext") + except exceptions.SymbolError: + start_addr = kernel.object_from_symbol("stext") + + try: + end_addr = kernel.object_from_symbol("vm_kernel_etext") + except exceptions.SymbolError: + end_addr = kernel.object_from_symbol("etext") + + mask = context.layers[layer_name].address_mask + + start_addr = start_addr & mask + end_addr = end_addr & mask + + return [("__kernel__", start_addr, end_addr)] + \ + MacUtilities.mask_mods_list(context, layer_name, mods_list) + + @classmethod + def lookup_module_address(cls, + context: interfaces.context.ContextInterface, + handlers: Iterator[Any], + target_address): + mod_name = "UNKNOWN" + symbol_name = "N/A" + + for name, start, end in handlers: + if start <= target_address <= end: + mod_name = name + if name == "__kernel__": + symbols = list(context.symbol_space.get_symbols_by_location(target_address)) + + if len(symbols) > 0: + symbol_name = str(symbols[0].split(constants.BANG)[1]) if constants.BANG in symbols[0] else \ + str(symbols[0]) + + break + + return mod_name, symbol_name + @classmethod def aslr_mask_symbol_table(cls, context: interfaces.context.ContextInterface, diff --git a/volatility/framework/plugins/mac/check_syscall.py b/volatility/framework/plugins/mac/check_syscall.py index d3ba1ea86..2883ee2a9 100644 --- a/volatility/framework/plugins/mac/check_syscall.py +++ b/volatility/framework/plugins/mac/check_syscall.py @@ -2,7 +2,7 @@ # which is available at https://www.volatilityfoundation.org/license/vsl-v1.0 # import logging -from typing import List +from typing import List, Iterator, Any from volatility.framework import exceptions, interfaces from volatility.framework import renderers, constants, contexts @@ -10,6 +10,7 @@ from volatility.framework.automagic import mac from volatility.framework.configuration import requirements from volatility.framework.interfaces import plugins from volatility.framework.renderers import format_hints +from volatility.plugins.mac import lsmod vollog = logging.getLogger(__name__) @@ -23,13 +24,16 @@ class Check_syscall(plugins.PluginInterface): requirements.TranslationLayerRequirement(name = 'primary', description = 'Memory layer for the kernel', architectures = ["Intel32", "Intel64"]), - requirements.SymbolTableRequirement(name = "darwin", description = "Mac kernel symbols") + requirements.SymbolTableRequirement(name = "darwin", description = "Mac kernel symbols"), + requirements.PluginRequirement(name = 'lsmod', plugin = lsmod.Lsmod, version = (1, 0, 0)) ] - def _generator(self): + def _generator(self, mods: Iterator[Any]): mac.MacUtilities.aslr_mask_symbol_table(self.context, self.config['darwin'], self.config['primary']) kernel = contexts.Module(self._context, self.config['darwin'], self.config['primary'], 0) + + handlers = mac.MacUtilities.generate_kernel_handler_info(self.context, self.config['primary'], kernel, mods) nsysent = kernel.object_from_symbol(symbol_name = "nsysent") table = kernel.object_from_symbol(symbol_name = "sysent") @@ -48,16 +52,15 @@ class Check_syscall(plugins.PluginInterface): if not call_addr or call_addr == 0: continue - symbols = list(self.context.symbol_space.get_symbols_by_location(call_addr)) + module_name, symbol_name = mac.MacUtilities.lookup_module_address(self.context, handlers, call_addr) - if len(symbols) > 0: - sym_name = str(symbols[0].split(constants.BANG)[1]) if constants.BANG in symbols[0] else \ - str(symbols[0]) - else: - sym_name = "UNKNOWN" - - yield (0, (format_hints.Hex(table.vol.offset), "SysCall", i, format_hints.Hex(call_addr), sym_name)) + yield (0, (format_hints.Hex(table.vol.offset), "SysCall", i, format_hints.Hex(call_addr), module_name, symbol_name)) def run(self): return renderers.TreeGrid([("Table Address", format_hints.Hex), ("Table Name", str), ("Index", int), - ("Handler Address", format_hints.Hex), ("Handler Symbol", str)], self._generator()) + ("Handler Address", format_hints.Hex), ("Handler Module", str), ("Handler Symbol", str)], + self._generator( + lsmod.Lsmod.list_modules(self.context, self.config['primary'], + self.config['darwin']))) + + diff --git a/volatility/framework/plugins/mac/check_sysctl.py b/volatility/framework/plugins/mac/check_sysctl.py index f678d2029..d6fd52cdf 100644 --- a/volatility/framework/plugins/mac/check_sysctl.py +++ b/volatility/framework/plugins/mac/check_sysctl.py @@ -2,7 +2,7 @@ # which is available at https://www.volatilityfoundation.org/license/vsl-v1.0 # import logging -from typing import List +from typing import List, Iterator, Any import volatility from volatility.framework import exceptions, interfaces @@ -12,6 +12,7 @@ from volatility.framework.configuration import requirements from volatility.framework.interfaces import plugins from volatility.framework.renderers import format_hints from volatility.framework.objects import utility +from volatility.plugins.mac import lsmod vollog = logging.getLogger(__name__) @@ -25,7 +26,8 @@ class Check_sysctl(plugins.PluginInterface): requirements.TranslationLayerRequirement(name = 'primary', description = 'Memory layer for the kernel', architectures = ["Intel32", "Intel64"]), - requirements.SymbolTableRequirement(name = "darwin", description = "Mac kernel symbols") + requirements.SymbolTableRequirement(name = "darwin", description = "Mac kernel symbols"), + requirements.PluginRequirement(name = 'lsmod', plugin = lsmod.Lsmod, version = (1, 0, 0)) ] def _parse_global_variable_sysctls(self, kernel, name): @@ -109,30 +111,28 @@ class Check_sysctl(plugins.PluginInterface): except exceptions.InvalidAddressException: break - def _generator(self): + def _generator(self, mods: Iterator[Any]): mac.MacUtilities.aslr_mask_symbol_table(self.context, self.config['darwin'], self.config['primary']) kernel = contexts.Module(self._context, self.config['darwin'], self.config['primary'], 0) + handlers = mac.MacUtilities.generate_kernel_handler_info(self.context, self.config['primary'], kernel, mods) + sysctl_list = kernel.object_from_symbol(symbol_name = "sysctl__children") for sysctl, name, val in self._process_sysctl_list(kernel, sysctl_list): - check_addr = sysctl.oid_handler + try: + check_addr = sysctl.oid_handler + except exceptions.InvalidAddressException: + continue - if check_addr == 0: - sym_name = "" - else: - symbols = list(self.context.symbol_space.get_symbols_by_location(check_addr)) + module_name, symbol_name = mac.MacUtilities.lookup_module_address(self.context, handlers, check_addr) - if len(symbols) > 0: - sym_name = str(symbols[0].split(constants.BANG)[1]) if constants.BANG in symbols[0] else \ - str(symbols[0]) - else: - sym_name = "UNKNOWN" - - yield (0, (name, sysctl.oid_number, sysctl.get_perms(), format_hints.Hex(check_addr), val, sym_name)) + yield (0, (name, sysctl.oid_number, sysctl.get_perms(), format_hints.Hex(check_addr), val, module_name, symbol_name)) def run(self): - return renderers.TreeGrid([("Name", str), ("Number", int), ("Perms", str), - ("Handler Address", format_hints.Hex), ("Value", str), ("Handler Symbol", str)], - self._generator()) + return renderers.TreeGrid([("Name", str), ("Number", int), ("Perms", str), ("Handler Address", format_hints.Hex), + ("Value", str), ("Handler Module", str), ("Handler Symbol", str)], + self._generator( + lsmod.Lsmod.list_modules(self.context, self.config['primary'], + self.config['darwin']))) diff --git a/volatility/framework/plugins/mac/check_trap_table.py b/volatility/framework/plugins/mac/check_trap_table.py index 618eae38e..d9cb7868c 100644 --- a/volatility/framework/plugins/mac/check_trap_table.py +++ b/volatility/framework/plugins/mac/check_trap_table.py @@ -3,7 +3,7 @@ # import logging -from typing import List +from typing import List, Iterator, Any from volatility.framework import exceptions, interfaces from volatility.framework import renderers, constants, contexts @@ -11,6 +11,7 @@ from volatility.framework.automagic import mac from volatility.framework.configuration import requirements from volatility.framework.interfaces import plugins from volatility.framework.renderers import format_hints +from volatility.plugins.mac import lsmod vollog = logging.getLogger(__name__) @@ -24,35 +25,40 @@ class Check_trap_table(plugins.PluginInterface): requirements.TranslationLayerRequirement(name = 'primary', description = 'Memory layer for the kernel', architectures = ["Intel32", "Intel64"]), - requirements.SymbolTableRequirement(name = "darwin", description = "Mac kernel symbols") + requirements.SymbolTableRequirement(name = "darwin", description = "Mac kernel symbols"), + requirements.PluginRequirement(name = 'lsmod', plugin = lsmod.Lsmod, version = (1, 0, 0)) ] - def _generator(self): + def _generator(self, mods: Iterator[Any]): mac.MacUtilities.aslr_mask_symbol_table(self.context, self.config['darwin'], self.config['primary']) kernel = contexts.Module(self._context, self.config['darwin'], self.config['primary'], 0) + + handlers = mac.MacUtilities.generate_kernel_handler_info(self.context, self.config['primary'], kernel, mods) table = kernel.object_from_symbol(symbol_name = "mach_trap_table") for i, ent in enumerate(table): try: call_addr = ent.mach_trap_function.dereference().vol.offset - except exceptions.InvalidPagedAddressException: + except exceptions.InvalidAddressException: continue if not call_addr or call_addr == 0: continue - symbols = list(self.context.symbol_space.get_symbols_by_location(call_addr)) + module_name, symbol_name = mac.MacUtilities.lookup_module_address(self.context, handlers, call_addr) - if len(symbols) > 0: - sym_name = str(symbols[0].split(constants.BANG)[1]) if constants.BANG in symbols[0] else \ - str(symbols[0]) - else: - sym_name = "UNKNOWN" - - yield (0, (format_hints.Hex(table.vol.offset), "TrapTable", i, format_hints.Hex(call_addr), sym_name)) + yield (0, (format_hints.Hex(table.vol.offset), "TrapTable", i, format_hints.Hex(call_addr), module_name, symbol_name)) def run(self): return renderers.TreeGrid([("Table Address", format_hints.Hex), ("Table Name", str), ("Index", int), - ("Handler Address", format_hints.Hex), ("Handler Symbol", str)], self._generator()) + ("Handler Address", format_hints.Hex), ("Handler Module", str), ("Handler Symbol", str)], + self._generator( + lsmod.Lsmod.list_modules(self.context, self.config['primary'], + self.config['darwin']))) + + + + + diff --git a/volatility/framework/plugins/mac/timers.py b/volatility/framework/plugins/mac/timers.py index 44825da4b..8ad2c04c0 100644 --- a/volatility/framework/plugins/mac/timers.py +++ b/volatility/framework/plugins/mac/timers.py @@ -2,7 +2,7 @@ # which is available at https://www.volatilityfoundation.org/license/vsl-v1.0 # import logging -from typing import List +from typing import List, Iterator, Any import volatility from volatility.framework import exceptions, interfaces @@ -12,6 +12,7 @@ from volatility.framework.configuration import requirements from volatility.framework.interfaces import plugins from volatility.framework.renderers import format_hints from volatility.framework.objects import utility +from volatility.plugins.mac import lsmod vollog = logging.getLogger(__name__) @@ -25,13 +26,16 @@ class Timers(plugins.PluginInterface): requirements.TranslationLayerRequirement(name = 'primary', description = 'Memory layer for the kernel', architectures = ["Intel32", "Intel64"]), - requirements.SymbolTableRequirement(name = "darwin", description = "Mac kernel symbols") + requirements.SymbolTableRequirement(name = "darwin", description = "Mac kernel symbols"), + requirements.PluginRequirement(name = 'lsmod', plugin = lsmod.Lsmod, version = (1, 0, 0)) ] - def _generator(self): + def _generator(self, mods: Iterator[Any]): mac.MacUtilities.aslr_mask_symbol_table(self.context, self.config['darwin'], self.config['primary']) - kernel = contexts.Module(self._context, self.config['darwin'], self.config['primary'], 0) + kernel = contexts.Module(self.context, self.config['darwin'], self.config['primary'], 0) + + handlers = mac.MacUtilities.generate_kernel_handler_info(self.context, self.config['primary'], kernel, mods) real_ncpus = kernel.object_from_symbol(symbol_name = "real_ncpus") @@ -45,7 +49,7 @@ class Timers(plugins.PluginInterface): offset = cpu_data_ptrs_addr, subtype = kernel.get_type('cpu_data'), count = real_ncpus) - + for cpu_data_ptr in cpu_data_ptrs: try: queue = cpu_data_ptr.rtclock_timer.queue.head @@ -54,26 +58,24 @@ class Timers(plugins.PluginInterface): for timer in queue.walk_list(queue, "q_link", "call_entry"): try: - handler = timer.func + handler = timer.func.dereference().vol.offset except exceptions.InvalidAddressException: continue - symbols = list(self.context.symbol_space.get_symbols_by_location(handler)) - - if len(symbols) > 0: - sym_name = str(symbols[0].split(constants.BANG)[1]) if constants.BANG in symbols[0] else \ - str(symbols[0]) - else: - sym_name = "UNKNOWN" - - if hasattr(timer, "entry_time"): + if timer.has_member("entry_time"): entry_time = timer.entry_time else: entry_time = -1 - yield (0, (format_hints.Hex(handler), format_hints.Hex(timer.param0), format_hints.Hex(timer.param1), timer.deadline, entry_time, "kernel", sym_name)) + module_name, symbol_name = mac.MacUtilities.lookup_module_address(self.context, handlers, handler) + + yield (0, (format_hints.Hex(handler), format_hints.Hex(timer.param0), format_hints.Hex(timer.param1), \ + timer.deadline, entry_time, module_name, symbol_name)) def run(self): return renderers.TreeGrid([("Function", format_hints.Hex), ("Param 0", format_hints.Hex), ("Param 1", format_hints.Hex), ("Deadline", int), ("Entry Time", int), ("Module", str), ("Symbol", str)], - self._generator()) + self._generator( + lsmod.Lsmod.list_modules(self.context, self.config['primary'], + self.config['darwin']))) + diff --git a/volatility/framework/plugins/mac/trustedbsd.py b/volatility/framework/plugins/mac/trustedbsd.py index 75672cfdd..0642f1766 100644 --- a/volatility/framework/plugins/mac/trustedbsd.py +++ b/volatility/framework/plugins/mac/trustedbsd.py @@ -34,6 +34,8 @@ class trustedbsd(plugins.PluginInterface): mac.MacUtilities.aslr_mask_symbol_table(self.context, self.config['darwin'], self.config['primary']) kernel = contexts.Module(self._context, self.config['darwin'], self.config['primary'], 0) + + handlers = mac.MacUtilities.generate_kernel_handler_info(self.context, self.config['primary'], kernel, mods) policy_list = kernel.object_from_symbol(symbol_name = "mac_policy_list").cast("mac_policy_list") @@ -41,10 +43,7 @@ class trustedbsd(plugins.PluginInterface): offset = policy_list.entries.dereference().vol.offset, subtype = kernel.get_type('mac_policy_list_element'), count = policy_list.staticmax + 1) - - mask = self.context.layers[self.config['primary']].address_mask - mods_list = [(mod.name, mod.address & mask, (mod.address & mask) + mod.size) for mod in mods] - + for i, ent in enumerate(entries): # I don't know how this can happen, but the kernel makes this check all over the place # the policy isn't useful without any ops so a rootkit can't abuse this @@ -65,23 +64,13 @@ class trustedbsd(plugins.PluginInterface): if call_addr is None or call_addr == 0: continue - found_module = None + module_name, symbol_name = mac.MacUtilities.lookup_module_address(self.context, handlers, call_addr) - for mod_name_info, mod_base, mod_end in mods_list: - if call_addr >= mod_base and call_addr <= mod_end: - found_module = mod_name_info - break - - if found_module: - symbol_module = utility.array_to_string(found_module) - else: - symbol_module = "UNKNOWN" - - yield (0, (check, ent_name, symbol_module, format_hints.Hex(call_addr))) + yield (0, (check, ent_name, format_hints.Hex(call_addr), module_name, symbol_name)) def run(self): - return renderers.TreeGrid([("Member", str), ("Policy Name", str), ("Handler Module", str), - ("Handler Address", format_hints.Hex)], + return renderers.TreeGrid([("Member", str), ("Policy Name", str), ("Handler Address", format_hints.Hex), ("Handler Module", str), + ("Handler Symbol", str)], self._generator( lsmod.Lsmod.list_modules(self.context, self.config['primary'], self.config['darwin'])))