diff --git a/volatility/framework/symbols/mac/__init__.py b/volatility/framework/symbols/mac/__init__.py index e57a22125..a9f51ac8a 100644 --- a/volatility/framework/symbols/mac/__init__.py +++ b/volatility/framework/symbols/mac/__init__.py @@ -9,6 +9,12 @@ class MacKernelIntermedSymbols(intermed.IntermediateSymbolTable): def __init__(self, context: interfaces.context.ContextInterface, config_path: str, name: str, isf_url: str) -> None: super().__init__(context = context, config_path = config_path, name = name, isf_url = isf_url) - self.set_type_class('proc', extensions.proc) - # self.set_type_class('fileglob', extensions.fileglob) - # self.set_type_class('vnode', extensions.vnode) + self.set_type_class('proc', extensions.proc) + 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) + + + + diff --git a/volatility/framework/symbols/mac/extensions/__init__.py b/volatility/framework/symbols/mac/extensions/__init__.py index 1168f92ab..932c5a7b0 100644 --- a/volatility/framework/symbols/mac/extensions/__init__.py +++ b/volatility/framework/symbols/mac/extensions/__init__.py @@ -1,20 +1,25 @@ -from typing import Optional +import collections.abc +import typing -from volatility.framework import exceptions, interfaces +import volatility.framework.objects.utility +from volatility.framework import constants +from volatility.framework import exceptions, objects, interfaces +from volatility.framework.automagic import mac from volatility.framework.symbols import generic - +from volatility.framework.objects import utility class proc(generic.GenericIntelProcess): - def get_task(self): return self.task.dereference().cast("task") - def add_process_layer(self, config_prefix: str = None, preferred_name: str = None) -> Optional[str]: + def add_process_layer(self, + config_prefix: str = None, + preferred_name: str = None) -> typing.Optional[str]: """Constructs a new layer based on the process's DTB. Returns the name of the Layer or None. """ parent_layer = self._context.memory[self.vol.layer_name] - + if not isinstance(parent_layer, interfaces.layers.TranslationLayerInterface): raise TypeError("Parent layer is not a translation layer, unable to construct process layer") @@ -25,3 +30,225 @@ class proc(generic.GenericIntelProcess): # Add the constructed layer and return the name return self._add_process_layer(self._context, dtb, config_prefix, preferred_name) + + @property + def map_iter(self) -> typing.Iterable[interfaces.objects.ObjectInterface]: + try: + task = self.get_task() + except exceptions.PagedInvalidAddressException: + return + + try: + map = task.map.hdr.links.next + except exceptions.PagedInvalidAddressException: + return + + seen = set() + + try: + for i in range(task.map.hdr.nentries): + if not map or map.vol.offset in seen: + break + + yield map + seen.add(map.vol.offset) + map = map.links.next + + except Exception as e: + print("broke in iter: {}".format(e)) + sys.exit(1) + + + ###### + # ikelos: this breaks with multi threading on, but works with it disabled + # with multi threading on, it throws that same error about v4 pickle stuff that linux originally did + # the fix for linux was to call int() so that we were not returning vol objects. + # I call int() on these and the code works nearly 1-1 with the linux one so I am very confused + ###### + def get_process_memory_sections(self, + context: interfaces.context.ContextInterface, + config_prefix: str, + rw_no_file: bool = False) -> \ + typing.Generator[typing.Tuple[int, int], None, None]: + """Returns a list of sections based on the memory manager's view of this task's virtual memory""" + for vma in self.map_iter: + start = int(vma.links.start) + end = int(vma.links.end) + + if rw_no_file: + if (vma.get_perms() != "rw" or vma.get_path(context, config_prefix) != ""): + if vma.get_special_path() != "[heap]": + continue + + yield (start, end - start) + +class fileglob(generic.GenericIntelProcess): + def get_fg_type(self): + ret = "INVALID" + if self.has_member("fg_type"): + ret = self.member(attr = 'fg_type') + elif self.fg_ops != 0: + try: + ret = self.fg_ops.fo_type + except exceptions.PagedInvalidAddressException as e: + pass + + return ret.description + +class vm_map_object(generic.GenericIntelProcess): + def get_map_object(self): + if self.has_member("vm_object"): + return self.vm_object + elif self.has_member("vmo_object"): + return self.vmo_object + + raise AttributeError("vm_map_object -> get_object") + +class vnode(generic.GenericIntelProcess): + def _do_calc_path(self, ret, vnodeobj, vname): + if vnodeobj == None: + return + + if vname: + print("adding: {}".format(utility.array_to_string(vname, 255))) + ret.append(utility.pointer_to_string(vname)) + + if int(vnodeobj.v_flag) & 0x000001 != 0 and int(vnodeobj.v_mount) != 0: + if int(vnodeobj.v_mount.mnt_vnodecovered) != 0: + self._do_calc_path(ret, vnodeobj.v_mount.mnt_vnodecovered, vnodeobj.v_mount.mnt_vnodecovered.v_name) + else: + self._do_calc_path(ret, vnodeobj.v_parent, vnodeobj.v_parent.v_name) + + def full_path(self): + if int(self.v_flag) & 0x000001 != 0 and int(self.v_mount) != 0 and int(self.v_mount.mnt_flag) & 0x00004000 != 0: + ret = "/" + else: + elements = [] + files = [] + + self._do_calc_path(elements, self, self.v_name) + elements.reverse() + + for e in elements: + files.append(e.decode("utf-8")) + + ret = "/".join(files) + if ret: + ret = "/" + ret + + return ret + +class vm_map_entry(generic.GenericIntelProcess): + + def get_perms(self): + permask = "rwx" + perms = "" + + for (ctr, i) in enumerate([1, 3, 5]): + if (self.protection & i) == i: + perms = perms + permask[ctr] + else: + perms = perms + "-" + + return perms + + def get_range_alias(self): + if self.has_member("alias"): + ret = int(self.alias) + else: + ret = int(self.vme_offset) & 0xfff + + return ret + + def get_special_path(self): + check = self.get_range_alias() + + if 0 < check < 10: + ret = "[heap]" + elif check == 30: + ret = "[stack]" + else: + ret = "" + + return ret + + def get_path(self, context, config_prefix): + vnode = self.get_vnode(context, config_prefix) + + if type(vnode) == str and vnode == "sub_map": + ret = vnode + elif vnode: + path = [] + while vnode: + v_name = utility.pointer_to_string(vnode.v_name, 255) + path.append(v_name) + vnode = vnode.v_parent + path.reverse() + ret = "/" + "/".join(path) + else: + ret = "" + + return ret + + def get_object(self): + if self.has_member("vme_object"): + return self.vme_object + elif self.has_member("object"): + return self.object + + raise AttributeError("vm_map_entry -> get_object: Unable to determine object") + + def get_offset(self): + if self.has_member("vme_offset"): + return self.vme_offset + elif self.has_member("offset"): + return self.offset + + raise AttributeError("vm_map_entry -> get_offset: Unable to determine offset") + + def get_vnode(self, context, config_prefix): + if self.is_sub_map == 1: + return "sub_map" + + print("Getting vnode object") + # based on find_vnode_object + vnode_object = self.get_object().get_map_object() + + while 1: + try: + tmp_vnode_object = vnode_object.shadow.dereference() + except exceptions.PagedInvalidAddressException: + break + + if tmp_vnode_object.vol.offset == 0: + break + + vnode_object = tmp_vnode_object + + try: + ops = vnode_object.pager.mo_pager_ops.dereference() + except Exception as e: #exceptions.PagedInvalidAddressException: + return None + + found = False + for sym in context.symbol_space.get_symbols_by_location(ops.vol.offset): + if sym.split(constants.BANG)[1] in ["vnode_pager_ops", "_vnode_pager_ops"]: + found = True + break + + if found: + vpager = context.object(config_prefix + constants.BANG + "vnode_pager", layer_name = vnode_object.vol.layer_name, offset = vnode_object.pager) + ret = vpager.vnode_handle + else: + ret = None + + return ret + + + + + + + + +