From 428e8a255fe56e2e55f8877688f570b0678df9a8 Mon Sep 17 00:00:00 2001 From: Abyss Watcher Date: Mon, 18 Mar 2024 16:05:40 +0100 Subject: [PATCH 01/22] get_task p_proc_ro attribute check --- volatility3/framework/symbols/mac/extensions/__init__.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/volatility3/framework/symbols/mac/extensions/__init__.py b/volatility3/framework/symbols/mac/extensions/__init__.py index 15fe7aeda9..1421a19d47 100644 --- a/volatility3/framework/symbols/mac/extensions/__init__.py +++ b/volatility3/framework/symbols/mac/extensions/__init__.py @@ -15,7 +15,11 @@ class proc(generic.GenericIntelProcess): def get_task(self): - return self.task.dereference().cast("task") + if hasattr(self, "p_proc_ro"): + task = self.p_proc_ro.pr_task.dereference() + else: + task = self.task.dereference().cast("task") + return task def add_process_layer( self, config_prefix: str = None, preferred_name: str = None From 0cff113f5af3ee2e9ddcceb7e8d75b2390817706 Mon Sep 17 00:00:00 2001 From: Abyss Watcher Date: Mon, 18 Mar 2024 16:07:56 +0100 Subject: [PATCH 02/22] set type hinting for kernel module --- volatility3/framework/symbols/mac/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/volatility3/framework/symbols/mac/__init__.py b/volatility3/framework/symbols/mac/__init__.py index c695ca77a7..5d513d862e 100644 --- a/volatility3/framework/symbols/mac/__init__.py +++ b/volatility3/framework/symbols/mac/__init__.py @@ -69,7 +69,7 @@ def generate_kernel_handler_info( cls, context: interfaces.context.ContextInterface, layer_name: str, - kernel, # ikelos - how to type this?? + kernel: interfaces.context.ModuleInterface, mods_list: Iterator[Any], ): try: From 4d37db1a32d165f51d6c95d6e723711ff8c52033 Mon Sep 17 00:00:00 2001 From: Abyss Watcher Date: Mon, 18 Mar 2024 16:08:39 +0100 Subject: [PATCH 03/22] task.p_fd check for newer kernels --- volatility3/framework/symbols/mac/__init__.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/volatility3/framework/symbols/mac/__init__.py b/volatility3/framework/symbols/mac/__init__.py index 5d513d862e..d12365a403 100644 --- a/volatility3/framework/symbols/mac/__init__.py +++ b/volatility3/framework/symbols/mac/__init__.py @@ -151,7 +151,10 @@ def files_descriptors_for_process( """ try: - num_fds = task.p_fd.fd_lastfile + if hasattr(task.p_fd, "fd_lastfile"): + num_fds = task.p_fd.fd_lastfile + elif hasattr(task.p_fd, "fd_afterlast"): + num_fds = task.p_fd.fd_afterlast except exceptions.InvalidAddressException: num_fds = 1024 From 507afae7a1ee03c46614ff96a770e29fa18a40db Mon Sep 17 00:00:00 2001 From: Abyss Watcher Date: Mon, 18 Mar 2024 16:09:34 +0100 Subject: [PATCH 04/22] fileglob fp_glob check for newer kernels --- volatility3/framework/symbols/mac/__init__.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/volatility3/framework/symbols/mac/__init__.py b/volatility3/framework/symbols/mac/__init__.py index d12365a403..fb2ae97768 100644 --- a/volatility3/framework/symbols/mac/__init__.py +++ b/volatility3/framework/symbols/mac/__init__.py @@ -182,8 +182,14 @@ def files_descriptors_for_process( for fd_num, f in enumerate(fds): if f != 0: + if hasattr(f, "f_fglob"): + glob = f.f_fglob + elif hasattr(f, "fp_glob"): + glob = f.fp_glob + else: + raise AttributeError("fileglob", "f_fglob || fp_glob") try: - ftype = f.f_fglob.get_fg_type() + ftype = glob.get_fg_type() except exceptions.InvalidAddressException: continue From 0b2759873d8b648cea4383e68d3302259e4d14ca Mon Sep 17 00:00:00 2001 From: Abyss Watcher Date: Mon, 18 Mar 2024 16:10:23 +0100 Subject: [PATCH 05/22] handle fg_data as a uintptr_t/base type --- volatility3/framework/symbols/mac/__init__.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/volatility3/framework/symbols/mac/__init__.py b/volatility3/framework/symbols/mac/__init__.py index fb2ae97768..f64da7e838 100644 --- a/volatility3/framework/symbols/mac/__init__.py +++ b/volatility3/framework/symbols/mac/__init__.py @@ -194,7 +194,15 @@ def files_descriptors_for_process( continue if ftype == "VNODE": - vnode = f.f_fglob.fg_data.dereference().cast("vnode") + if type(glob.fg_data) == objects.Pointer: + vnode = glob.fg_data.dereference().cast("vnode") + else: + # On macOS 14+ versions, glob.fg_data is an uintptr_t + # ASLR is not applied with casting, + # Hardcoding "kernel" string as there isn't a way to get the proper config key ? + vnode = context.modules["kernel"].object( + "vnode", glob.fg_data, absolute=True + ) path = vnode.full_path() elif ftype: path = f"<{ftype.lower()}>" From ea7c7853b99ca4050de7784c987e8b72b1bd71a8 Mon Sep 17 00:00:00 2001 From: Abyss Watcher Date: Mon, 18 Mar 2024 16:11:36 +0100 Subject: [PATCH 06/22] check task.bsd_info_ro for newer kernels --- volatility3/framework/plugins/mac/pslist.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/volatility3/framework/plugins/mac/pslist.py b/volatility3/framework/plugins/mac/pslist.py index 9b570f3f9c..9fdc21cc83 100644 --- a/volatility3/framework/plugins/mac/pslist.py +++ b/volatility3/framework/plugins/mac/pslist.py @@ -200,7 +200,10 @@ def list_tasks_tasks( seen[task.vol.offset] = 1 try: - proc = task.bsd_info.dereference().cast("proc") + if hasattr(task, "bsd_info"): + proc = task.bsd_info.dereference().cast("proc") + elif hasattr(task, "bsd_info_ro"): + proc = task.bsd_info_ro.pr_proc.dereference() except exceptions.InvalidAddressException: continue From 82657a5a3c0de57ed429136e4b7aa8928faf5b3c Mon Sep 17 00:00:00 2001 From: Abyss Watcher Date: Mon, 18 Mar 2024 16:13:53 +0100 Subject: [PATCH 07/22] fileglob fp_glob check for newer kernels --- volatility3/framework/plugins/mac/netstat.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/volatility3/framework/plugins/mac/netstat.py b/volatility3/framework/plugins/mac/netstat.py index 76bba25f68..d6f01674fa 100644 --- a/volatility3/framework/plugins/mac/netstat.py +++ b/volatility3/framework/plugins/mac/netstat.py @@ -74,14 +74,20 @@ def list_sockets( for filp, _, _ in mac.MacUtilities.files_descriptors_for_process( context, context.modules[kernel_module_name].symbol_table_name, task ): + if hasattr(filp, "f_fglob"): + glob = filp.f_fglob + elif hasattr(filp, "fp_glob"): + glob = filp.fp_glob + else: + raise AttributeError("fileglob", "f_fglob || fp_glob") + try: - ftype = filp.f_fglob.get_fg_type() + ftype = glob.get_fg_type() except exceptions.InvalidAddressException: continue if ftype != "SOCKET": continue - try: socket = filp.f_fglob.fg_data.dereference().cast("socket") except exceptions.InvalidAddressException: From 1de638b9eebf3e94bd2d339ab7ed2167a38a6c65 Mon Sep 17 00:00:00 2001 From: Abyss Watcher Date: Mon, 18 Mar 2024 16:14:15 +0100 Subject: [PATCH 08/22] handle fg_data as a uintptr_t/base type --- volatility3/framework/plugins/mac/netstat.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/volatility3/framework/plugins/mac/netstat.py b/volatility3/framework/plugins/mac/netstat.py index d6f01674fa..0a74f7279f 100644 --- a/volatility3/framework/plugins/mac/netstat.py +++ b/volatility3/framework/plugins/mac/netstat.py @@ -8,7 +8,7 @@ from volatility3.framework import exceptions, renderers, interfaces from volatility3.framework.configuration import requirements from volatility3.framework.interfaces import plugins -from volatility3.framework.objects import utility +from volatility3.framework.objects import utility, Pointer from volatility3.framework.renderers import format_hints from volatility3.framework.symbols import mac from volatility3.plugins.mac import pslist @@ -89,7 +89,12 @@ def list_sockets( if ftype != "SOCKET": continue try: - socket = filp.f_fglob.fg_data.dereference().cast("socket") + if type(glob.fg_data) == Pointer: + socket = glob.fg_data.dereference().cast("socket") + else: + socket = context.modules[kernel_module_name].object( + "socket", glob.fg_data, absolute=True + ) except exceptions.InvalidAddressException: continue From 38516dedd345be867f4cfc782156fb3999911e9b Mon Sep 17 00:00:00 2001 From: Abyss Watcher Date: Mon, 18 Mar 2024 22:59:44 +0100 Subject: [PATCH 09/22] temporary vm_map_object workaround --- volatility3/framework/symbols/mac/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/volatility3/framework/symbols/mac/__init__.py b/volatility3/framework/symbols/mac/__init__.py index f64da7e838..e912a5cc8f 100644 --- a/volatility3/framework/symbols/mac/__init__.py +++ b/volatility3/framework/symbols/mac/__init__.py @@ -18,7 +18,8 @@ def __init__(self, *args, **kwargs) -> None: self.set_type_class("fileglob", extensions.fileglob) self.set_type_class("vnode", extensions.vnode) self.set_type_class("vm_map_entry", extensions.vm_map_entry) - self.set_type_class("vm_map_object", extensions.vm_map_object) + # FIXME: Issue #848 + self.optional_set_type_class("vm_map_object", extensions.vm_map_object) self.set_type_class("socket", extensions.socket) self.set_type_class("inpcb", extensions.inpcb) self.set_type_class("ifnet", extensions.ifnet) From 69e536c541e54de0e50bcc6d831e87e35fde04ef Mon Sep 17 00:00:00 2001 From: Abyss Watcher Date: Mon, 18 Mar 2024 23:07:35 +0100 Subject: [PATCH 10/22] prefer iterative to recursive to avoid maximum recursion depth limit reaching --- .../framework/plugins/mac/list_files.py | 56 ++++++++++++------- 1 file changed, 36 insertions(+), 20 deletions(-) diff --git a/volatility3/framework/plugins/mac/list_files.py b/volatility3/framework/plugins/mac/list_files.py index c18b0b7a25..f2d4a45530 100644 --- a/volatility3/framework/plugins/mac/list_files.py +++ b/volatility3/framework/plugins/mac/list_files.py @@ -98,56 +98,72 @@ def _add_vnode(cls, context, vnode, loop_vnodes): return added @classmethod - def _walk_vnode(cls, context, vnode, loop_vnodes): + def _walk_vnode( + cls, context, vnode, loop_vnodes, to_explore: list, visited_vnodes: set + ): """ Iterates over the list of vnodes associated with the given one. Also traverses the parent chain for the vnode and adds each one. """ - added = False while vnode: - if vnode in loop_vnodes: - return added + if vnode in loop_vnodes or vnode in visited_vnodes: + return to_explore + + visited_vnodes.add(vnode) if not cls._add_vnode(context, vnode, loop_vnodes): break - added = True - parent = cls._get_parent(context, vnode) - while parent and parent not in loop_vnodes: - if not cls._walk_vnode(context, parent, loop_vnodes): - break - - parent = cls._get_parent(context, parent) + if parent not in to_explore: + to_explore.append(parent) try: vnode = vnode.v_mntvnodes.tqe_next.dereference() except exceptions.InvalidAddressException: break - return added + return to_explore + + @classmethod + def _walk_vnode_iterative(cls, context, vnode, loop_vnodes, visited_vnodes): + to_explore = [vnode] + while to_explore: + vnode = to_explore.pop(-1) + to_explore = cls._walk_vnode( + context, vnode, loop_vnodes, to_explore, visited_vnodes + ) @classmethod - def _walk_vnodelist(cls, context, list_head, loop_vnodes): + def _walk_vnodelist(cls, context, list_head, loop_vnodes, visited_vnodes): for vnode in mac.MacUtilities.walk_tailq(list_head, "v_mntvnodes"): - cls._walk_vnode(context, vnode, loop_vnodes) + cls._walk_vnode_iterative(context, vnode, loop_vnodes, visited_vnodes) @classmethod def _walk_mounts( cls, context: interfaces.context.ContextInterface, kernel_module_name: str ) -> Iterable[interfaces.objects.ObjectInterface]: loop_vnodes = {} + visited_vnodes = set() # iterate each vnode source from each mount list_mounts = mount.Mount.list_mounts(context, kernel_module_name) for mnt in list_mounts: - cls._walk_vnodelist(context, mnt.mnt_vnodelist, loop_vnodes) - cls._walk_vnodelist(context, mnt.mnt_workerqueue, loop_vnodes) - cls._walk_vnodelist(context, mnt.mnt_newvnodes, loop_vnodes) - cls._walk_vnode(context, mnt.mnt_vnodecovered, loop_vnodes) - cls._walk_vnode(context, mnt.mnt_realrootvp, loop_vnodes) - cls._walk_vnode(context, mnt.mnt_devvp, loop_vnodes) + cls._walk_vnodelist(context, mnt.mnt_vnodelist, loop_vnodes, visited_vnodes) + cls._walk_vnodelist( + context, mnt.mnt_workerqueue, loop_vnodes, visited_vnodes + ) + cls._walk_vnodelist(context, mnt.mnt_newvnodes, loop_vnodes, visited_vnodes) + cls._walk_vnode_iterative( + context, mnt.mnt_vnodecovered, loop_vnodes, visited_vnodes + ) + cls._walk_vnode_iterative( + context, mnt.mnt_realrootvp, loop_vnodes, visited_vnodes + ) + cls._walk_vnode_iterative( + context, mnt.mnt_devvp, loop_vnodes, visited_vnodes + ) return loop_vnodes From 307e9a2097a2d9b5c725d006442916f2b176158c Mon Sep 17 00:00:00 2001 From: Abyss Watcher Date: Wed, 20 Mar 2024 14:00:28 +0100 Subject: [PATCH 11/22] remove fixme --- volatility3/framework/symbols/mac/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/volatility3/framework/symbols/mac/__init__.py b/volatility3/framework/symbols/mac/__init__.py index e912a5cc8f..76200f75a8 100644 --- a/volatility3/framework/symbols/mac/__init__.py +++ b/volatility3/framework/symbols/mac/__init__.py @@ -18,7 +18,6 @@ def __init__(self, *args, **kwargs) -> None: self.set_type_class("fileglob", extensions.fileglob) self.set_type_class("vnode", extensions.vnode) self.set_type_class("vm_map_entry", extensions.vm_map_entry) - # FIXME: Issue #848 self.optional_set_type_class("vm_map_object", extensions.vm_map_object) self.set_type_class("socket", extensions.socket) self.set_type_class("inpcb", extensions.inpcb) From 57787686041189f8d8f6b0d0905db282f3e68e6c Mon Sep 17 00:00:00 2001 From: Abyss Watcher Date: Wed, 20 Mar 2024 14:01:06 +0100 Subject: [PATCH 12/22] remove hardcoded kernel module name, use introspection to get name instead --- volatility3/framework/symbols/mac/__init__.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/volatility3/framework/symbols/mac/__init__.py b/volatility3/framework/symbols/mac/__init__.py index 76200f75a8..f0846d3e66 100644 --- a/volatility3/framework/symbols/mac/__init__.py +++ b/volatility3/framework/symbols/mac/__init__.py @@ -179,7 +179,12 @@ def files_descriptors_for_process( fds = objects.utility.array_of_pointers( table_addr, count=num_fds, subtype=file_type, context=context ) - + kernel_config_path = context.layers[ + glob.vol.layer_name + ].config_path.rsplit(context.config.separator, 1)[0] + kernel_module = context.modules[ + context.config[kernel_config_path] + ] for fd_num, f in enumerate(fds): if f != 0: if hasattr(f, "f_fglob"): @@ -198,9 +203,7 @@ def files_descriptors_for_process( vnode = glob.fg_data.dereference().cast("vnode") else: # On macOS 14+ versions, glob.fg_data is an uintptr_t - # ASLR is not applied with casting, - # Hardcoding "kernel" string as there isn't a way to get the proper config key ? - vnode = context.modules["kernel"].object( + vnode = kernel_module.object( "vnode", glob.fg_data, absolute=True ) path = vnode.full_path() From 683dba8d6a2391eb63d11b0740d8ec58a7930c0b Mon Sep 17 00:00:00 2001 From: Abyss Watcher Date: Wed, 20 Mar 2024 14:02:59 +0100 Subject: [PATCH 13/22] add struct module import --- volatility3/framework/symbols/mac/extensions/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/volatility3/framework/symbols/mac/extensions/__init__.py b/volatility3/framework/symbols/mac/extensions/__init__.py index 1421a19d47..89daec4ea5 100644 --- a/volatility3/framework/symbols/mac/extensions/__init__.py +++ b/volatility3/framework/symbols/mac/extensions/__init__.py @@ -3,6 +3,7 @@ # import contextlib import logging +import struct from typing import Generator, Iterable, Optional, Set, Tuple from volatility3.framework import constants, exceptions, interfaces, objects From ab55018d47de5c11ac03f35b5a1a6fb09d01dda6 Mon Sep 17 00:00:00 2001 From: Abyss Watcher Date: Wed, 20 Mar 2024 14:03:34 +0100 Subject: [PATCH 14/22] vm_pointer_unpack function --- .../symbols/mac/extensions/__init__.py | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/volatility3/framework/symbols/mac/extensions/__init__.py b/volatility3/framework/symbols/mac/extensions/__init__.py index 89daec4ea5..f496c61d67 100644 --- a/volatility3/framework/symbols/mac/extensions/__init__.py +++ b/volatility3/framework/symbols/mac/extensions/__init__.py @@ -268,6 +268,30 @@ def get_path(self, context, config_prefix): return ret + def vm_pointer_unpack( + self, + context: interfaces.context.ContextInterface, + kernel_module_name: str, + packed: int, + ) -> int: + """ + https://github.com/apple-open-source/macos/blob/ea4cd5a06831aca49e33df829d2976d6de5316ec/xnu/tools/lldbmacros/kmemory/kmem.py#L34 + """ + kernel_module = context.modules[kernel_module_name] + vm_page_packing = kernel_module.object_from_symbol("vm_page_packing_params") + base_relative = vm_page_packing.vmpp_base_relative + bits = vm_page_packing.vmpp_bits + shift = vm_page_packing.vmpp_shift + base = vm_page_packing.vmpp_base + + if base_relative: + addr = (packed << shift) + base + else: + addr = struct.unpack(">= 64 - bits - shift + + return addr & 0xFFFFFFFFFFFFFFFF + def get_object(self): if self.has_member("vme_object"): return self.vme_object From 23fc9c8c211fb103961d05ff54e92492a687038e Mon Sep 17 00:00:00 2001 From: Abyss Watcher Date: Wed, 20 Mar 2024 14:03:51 +0100 Subject: [PATCH 15/22] update get_object for recent kernels --- .../symbols/mac/extensions/__init__.py | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/volatility3/framework/symbols/mac/extensions/__init__.py b/volatility3/framework/symbols/mac/extensions/__init__.py index f496c61d67..963a7ecda8 100644 --- a/volatility3/framework/symbols/mac/extensions/__init__.py +++ b/volatility3/framework/symbols/mac/extensions/__init__.py @@ -297,8 +297,28 @@ def get_object(self): return self.vme_object elif self.has_member("object"): return self.object - - raise AttributeError("vm_map_entry -> get_object: Unable to determine object") + # https://github.com/apple-open-source/macos/blob/ea4cd5a06831aca49e33df829d2976d6de5316ec/xnu/tools/lldbmacros/memory.py#L35 + else: + kernel_config_path = self._context.layers[ + self.vol.layer_name + ].config_path.rsplit(self._context.config.separator, 1)[0] + kernel_module = self._context.modules[ + self._context.config[kernel_config_path] + ] + if self.vme_kernel_object: + return kernel_module.get_absolute_symbol_address("kernel_object_store") + else: + packed = self.vme_object_or_delta + # https://github.com/apple-open-source/macos/blob/14.3/xnu/osfmk/vm/vm_map.h#L253 + if isinstance(packed, int): + addr = self.vm_pointer_unpack( + self._context, self._context.config[kernel_config_path], packed + ) + if addr: + return kernel_module.object("vm_object", addr, absolute=True) + else: + return packed + return 0 def get_offset(self): if self.has_member("vme_offset"): From 2abf5f8647d46f9375ccda1e0a4a9eb459e409c7 Mon Sep 17 00:00:00 2001 From: Abyss Watcher Date: Wed, 20 Mar 2024 14:04:47 +0100 Subject: [PATCH 16/22] add a check for older and recent kernels, on vm_object --- volatility3/framework/symbols/mac/extensions/__init__.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/volatility3/framework/symbols/mac/extensions/__init__.py b/volatility3/framework/symbols/mac/extensions/__init__.py index 963a7ecda8..4bfb940e20 100644 --- a/volatility3/framework/symbols/mac/extensions/__init__.py +++ b/volatility3/framework/symbols/mac/extensions/__init__.py @@ -333,7 +333,12 @@ def get_vnode(self, context, config_prefix): return "sub_map" # based on find_vnode_object - vnode_object = self.get_object().get_map_object() + tmp_object = self.get_object() + if type(tmp_object) == vm_map_object: + vnode_object = tmp_object.get_map_object() + else: + vnode_object = tmp_object + if vnode_object == 0: return None From e30deeb99529446de8c483c179d94a2993742765 Mon Sep 17 00:00:00 2001 From: Abyss Watcher Date: Wed, 20 Mar 2024 14:08:01 +0100 Subject: [PATCH 17/22] wrong object to get layer_name from --- volatility3/framework/symbols/mac/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/volatility3/framework/symbols/mac/__init__.py b/volatility3/framework/symbols/mac/__init__.py index f0846d3e66..3b3607534f 100644 --- a/volatility3/framework/symbols/mac/__init__.py +++ b/volatility3/framework/symbols/mac/__init__.py @@ -180,7 +180,7 @@ def files_descriptors_for_process( table_addr, count=num_fds, subtype=file_type, context=context ) kernel_config_path = context.layers[ - glob.vol.layer_name + task.vol.layer_name ].config_path.rsplit(context.config.separator, 1)[0] kernel_module = context.modules[ context.config[kernel_config_path] From 4a7fffb5c9bd25b475bf13e31e2e678f972d68f9 Mon Sep 17 00:00:00 2001 From: Abyss Watcher Date: Wed, 20 Mar 2024 18:12:52 +0100 Subject: [PATCH 18/22] kernel timer structure update --- volatility3/framework/plugins/mac/timers.py | 72 ++++++++++++++------- 1 file changed, 49 insertions(+), 23 deletions(-) diff --git a/volatility3/framework/plugins/mac/timers.py b/volatility3/framework/plugins/mac/timers.py index 8a267bd557..97fc769071 100644 --- a/volatility3/framework/plugins/mac/timers.py +++ b/volatility3/framework/plugins/mac/timers.py @@ -3,6 +3,7 @@ # import logging from typing import List +from dataclasses import dataclass from volatility3.framework import exceptions, interfaces from volatility3.framework import renderers @@ -10,11 +11,23 @@ from volatility3.framework.interfaces import plugins from volatility3.framework.renderers import format_hints from volatility3.framework.symbols import mac +from volatility3.framework.objects import utility from volatility3.plugins.mac import lsmod vollog = logging.getLogger(__name__) +@dataclass +class TimerStructure: + type_name: str + func: str + qlink: str + entry_time: str + param0: str + param1: str + deadline: str + + class Timers(plugins.PluginInterface): """Check for malicious kernel timers.""" @@ -45,23 +58,35 @@ def _generator(self): self.context, kernel.layer_name, kernel, mods ) - real_ncpus = kernel.object_from_symbol(symbol_name="real_ncpus") - cpu_data_ptrs_ptr = kernel.get_symbol("cpu_data_ptr").address + if kernel.has_type("call_entry"): + timer_struct = TimerStructure( + type_name="call_entry", + func="func", + qlink="q_link", + entry_time="entry_time", + param0="param0", + param1="param1", + deadline="deadline", + ) + elif kernel.has_type("timer_call"): + timer_struct = TimerStructure( + type_name="timer_call", + func="tc_func", + qlink="tc_qlink", + entry_time="tc_entry_time", + param0="tc_param0", + param1="tc_param1", + deadline="tc_soft_deadline", + ) - # Returns the a pointer to the absolute address - cpu_data_ptrs_addr = kernel.object( - object_type="pointer", - offset=cpu_data_ptrs_ptr, - subtype=kernel.get_type("long unsigned int"), - ) - - cpu_data_ptrs = kernel.object( - object_type="array", - offset=cpu_data_ptrs_addr, - absolute=True, - subtype=kernel.get_type("cpu_data"), - count=real_ncpus, + real_ncpus = kernel.object_from_symbol(symbol_name="real_ncpus") + cpu_data_ptrs_ptr = kernel.object_from_symbol("cpu_data_ptr") + cpu_data_ptrs = utility.array_of_pointers( + cpu_data_ptrs_ptr, + real_ncpus, + cpu_data_ptrs_ptr.vol.subtype, + self.context, ) for cpu_data_ptr in cpu_data_ptrs: @@ -70,14 +95,15 @@ def _generator(self): except exceptions.InvalidAddressException: break - for timer in queue.walk_list(queue, "q_link", "call_entry"): + for timer in queue.walk_list( + queue, timer_struct.qlink, timer_struct.type_name + ): try: - handler = timer.func.dereference().vol.offset + handler = getattr(timer, timer_struct.func).dereference().vol.offset except exceptions.InvalidAddressException: continue - - if timer.has_member("entry_time"): - entry_time = timer.entry_time + if timer.has_member(timer_struct.entry_time): + entry_time = getattr(timer, timer_struct.entry_time) else: entry_time = -1 @@ -89,9 +115,9 @@ def _generator(self): 0, ( format_hints.Hex(handler), - format_hints.Hex(timer.param0), - format_hints.Hex(timer.param1), - timer.deadline, + format_hints.Hex(getattr(timer, timer_struct.param0)), + format_hints.Hex(getattr(timer, timer_struct.param1)), + getattr(timer, timer_struct.deadline), entry_time, module_name, symbol_name, From c0e85f4c2f9d044c391438385e2f1f9dfe96ef86 Mon Sep 17 00:00:00 2001 From: Abyss Watcher Date: Wed, 20 Mar 2024 18:31:51 +0100 Subject: [PATCH 19/22] structures attributes update --- volatility3/framework/plugins/mac/kevents.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/volatility3/framework/plugins/mac/kevents.py b/volatility3/framework/plugins/mac/kevents.py index 2a8692b772..23c072e843 100644 --- a/volatility3/framework/plugins/mac/kevents.py +++ b/volatility3/framework/plugins/mac/kevents.py @@ -184,18 +184,29 @@ def _generator(self): for task_name, pid, kn in self.list_kernel_events( self.context, self.config["kernel"], filter_func=filter_func ): - filter_index = kn.kn_kevent.filter * -1 + if hasattr(kn.kn_kevent, "filter"): + filter = kn.kn_kevent.filter + elif hasattr(kn.kn_kevent, "kei_filter"): + filter = kn.kn_kevent.kei_filter + filter_index = filter * -1 if filter_index in self.event_types: filter_name = self.event_types[filter_index] else: continue try: - ident = kn.kn_kevent.ident + if hasattr(kn.kn_kevent, "ident"): + ident = kn.kn_kevent.ident + elif hasattr(kn.kn_kevent, "kei_ident"): + ident = kn.kn_kevent.kei_ident except exceptions.InvalidAddressException: continue - context = self._parse_flags(filter_index, kn.kn_sfflags) + if hasattr(kn, "kn_sfflags"): + sfflags = kn.kn_sfflags + elif hasattr(kn.kn_kevent, "kei_sfflags"): + sfflags = kn.kn_kevent.kei_sfflags + context = self._parse_flags(filter_index, sfflags) yield (0, (pid, task_name, ident, filter_name, context)) From 87f950a950327b8b6f3fc93ac1257d8f705908e3 Mon Sep 17 00:00:00 2001 From: Abyss Watcher Date: Thu, 21 Mar 2024 10:22:44 +0100 Subject: [PATCH 20/22] handle unknown ftype --- volatility3/framework/symbols/mac/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/volatility3/framework/symbols/mac/__init__.py b/volatility3/framework/symbols/mac/__init__.py index 3b3607534f..6e8d6554f2 100644 --- a/volatility3/framework/symbols/mac/__init__.py +++ b/volatility3/framework/symbols/mac/__init__.py @@ -209,7 +209,8 @@ def files_descriptors_for_process( path = vnode.full_path() elif ftype: path = f"<{ftype.lower()}>" - + else: + path = "UNKNOWN" yield f, path, fd_num @classmethod From 64ffe0d51e46b817aa726caca3645588ae7707c6 Mon Sep 17 00:00:00 2001 From: Abyss Watcher Date: Thu, 21 Mar 2024 10:33:39 +0100 Subject: [PATCH 21/22] handle unreachable object --- volatility3/framework/symbols/mac/extensions/__init__.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/volatility3/framework/symbols/mac/extensions/__init__.py b/volatility3/framework/symbols/mac/extensions/__init__.py index 4bfb940e20..92c2b8c45f 100644 --- a/volatility3/framework/symbols/mac/extensions/__init__.py +++ b/volatility3/framework/symbols/mac/extensions/__init__.py @@ -333,7 +333,11 @@ def get_vnode(self, context, config_prefix): return "sub_map" # based on find_vnode_object - tmp_object = self.get_object() + try: + tmp_object = self.get_object() + except exceptions.InvalidAddressException: + return None + if type(tmp_object) == vm_map_object: vnode_object = tmp_object.get_map_object() else: From c93fba4457a0e2fe3969ebee6b70d31ad6cfebcc Mon Sep 17 00:00:00 2001 From: Abyss Watcher Date: Sat, 23 Mar 2024 17:42:05 +0100 Subject: [PATCH 22/22] black formatting --- volatility3/framework/plugins/mac/timers.py | 1 - volatility3/framework/symbols/mac/__init__.py | 10 ++++------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/volatility3/framework/plugins/mac/timers.py b/volatility3/framework/plugins/mac/timers.py index 97fc769071..80d451429a 100644 --- a/volatility3/framework/plugins/mac/timers.py +++ b/volatility3/framework/plugins/mac/timers.py @@ -58,7 +58,6 @@ def _generator(self): self.context, kernel.layer_name, kernel, mods ) - if kernel.has_type("call_entry"): timer_struct = TimerStructure( type_name="call_entry", diff --git a/volatility3/framework/symbols/mac/__init__.py b/volatility3/framework/symbols/mac/__init__.py index 6e8d6554f2..31258f5b78 100644 --- a/volatility3/framework/symbols/mac/__init__.py +++ b/volatility3/framework/symbols/mac/__init__.py @@ -179,12 +179,10 @@ def files_descriptors_for_process( fds = objects.utility.array_of_pointers( table_addr, count=num_fds, subtype=file_type, context=context ) - kernel_config_path = context.layers[ - task.vol.layer_name - ].config_path.rsplit(context.config.separator, 1)[0] - kernel_module = context.modules[ - context.config[kernel_config_path] - ] + kernel_config_path = context.layers[task.vol.layer_name].config_path.rsplit( + context.config.separator, 1 + )[0] + kernel_module = context.modules[context.config[kernel_config_path]] for fd_num, f in enumerate(fds): if f != 0: if hasattr(f, "f_fglob"):