diff --git a/volatility/framework/automagic/linux.py b/volatility/framework/automagic/linux.py index abb8350d3..312b17f1e 100644 --- a/volatility/framework/automagic/linux.py +++ b/volatility/framework/automagic/linux.py @@ -3,13 +3,13 @@ # import logging -from typing import List, Optional, Tuple, Type +from typing import Optional, Tuple, Type -from volatility.framework import interfaces, constants, exceptions -from volatility.framework import objects +from volatility.framework import interfaces, constants from volatility.framework.automagic import symbol_cache, symbol_finder from volatility.framework.layers import intel, scanners from volatility.framework.symbols import linux +from volatility.framework.symbols.linux import LinuxUtilities vollog = logging.getLogger(__name__) @@ -85,162 +85,6 @@ class LinuxIntelStacker(interfaces.automagic.StackerLayerInterface): return layer return None - -class LinuxUtilities(object): - """Class with multiple useful linux functions.""" - - # based on __d_path from the Linux kernel - @classmethod - def _do_get_path(cls, rdentry, rmnt, dentry, vfsmnt) -> str: - - ret_path = [] # type: List[str] - - while dentry != rdentry or vfsmnt != rmnt: - dname = dentry.path() - if dname == "": - break - - ret_path.insert(0, dname.strip('/')) - if dentry == vfsmnt.get_mnt_root() or dentry == dentry.d_parent: - if vfsmnt.get_mnt_parent() == vfsmnt: - break - - dentry = vfsmnt.get_mnt_mountpoint() - vfsmnt = vfsmnt.get_mnt_parent() - - continue - - parent = dentry.d_parent - dentry = parent - - # if we did not gather any valid dentrys in the path, then the entire file is - # either 1) smeared out of memory or 2) de-allocated and corresponding structures overwritten - # we return an empty string in this case to avoid confusion with something like a handle to the root - # directory (e.g., "/") - if not ret_path: - return "" - - ret_val = '/'.join([str(p) for p in ret_path if p != ""]) - - if ret_val.startswith(("socket:", "pipe:")): - if ret_val.find("]") == -1: - try: - inode = dentry.d_inode - ino = inode.i_ino - except exceptions.InvalidAddressException: - ino = 0 - - ret_val = ret_val[:-1] + ":[{0}]".format(ino) - else: - ret_val = ret_val.replace("/", "") - - elif ret_val != "inotify": - ret_val = '/' + ret_val - - return ret_val - - # method used by 'older' kernels - # TODO: lookup when dentry_operations->d_name was merged into the mainline kernel for exact version - @classmethod - def _get_path_file(cls, task, filp) -> str: - rdentry = task.fs.get_root_dentry() - rmnt = task.fs.get_root_mnt() - dentry = filp.get_dentry() - vfsmnt = filp.get_vfsmnt() - - return LinuxUtilities._do_get_path(rdentry, rmnt, dentry, vfsmnt) - - @classmethod - def _get_new_sock_pipe_path(cls, context, task, filp) -> str: - dentry = filp.get_dentry() - - sym_addr = dentry.d_op.d_dname - - symbol_table_arr = sym_addr.vol.type_name.split("!") - symbol_table = None - if len(symbol_table_arr) == 2: - symbol_table = symbol_table_arr[0] - - symbs = list(context.symbol_space.get_symbols_by_location(sym_addr, table_name = symbol_table)) - - if len(symbs) == 1: - sym = symbs[0].split(constants.BANG)[1] - - if sym == "sockfs_dname": - pre_name = "socket" - - elif sym == "anon_inodefs_dname": - pre_name = "anon_inode" - - elif sym == "pipefs_dname": - pre_name = "pipe" - - elif sym == "simple_dname": - pre_name = cls._get_path_file(task, filp) - - else: - pre_name = "".format(sym) - - ret = "{0}:[{1:d}]".format(pre_name, dentry.d_inode.i_ino) - - else: - ret = " {0:x}".format(sym_addr) - - return ret - - # a 'file' structure doesn't have enough information to properly restore its full path - # we need the root mount information from task_struct to determine this - @classmethod - def path_for_file(cls, context, task, filp) -> str: - try: - dentry = filp.get_dentry() - except exceptions.InvalidAddressException: - return "" - - if dentry == 0: - return "" - - dname_is_valid = False - - # TODO COMPARE THIS IN LSOF OUTPUT TO VOL2 - try: - if dentry.d_op and dentry.d_op.has_member("d_dname") and dentry.d_op.d_dname: - dname_is_valid = True - - except exceptions.InvalidAddressException: - dname_is_valid = False - - if dname_is_valid: - ret = LinuxUtilities._get_new_sock_pipe_path(context, task, filp) - else: - ret = LinuxUtilities._get_path_file(task, filp) - - return ret - - @classmethod - def files_descriptors_for_process(cls, context: interfaces.context.ContextInterface, symbol_table: str, - task: interfaces.objects.ObjectInterface): - - fd_table = task.files.get_fds() - if fd_table == 0: - return - - max_fds = task.files.get_max_fds() - - # corruption check - if max_fds > 500000: - return - - file_type = symbol_table + constants.BANG + 'file' - - fds = objects.utility.array_of_pointers(fd_table, count = max_fds, subtype = file_type, context = context) - - for (fd_num, filp) in enumerate(fds): - if filp != 0: - full_path = LinuxUtilities.path_for_file(context, task, filp) - - yield fd_num, filp, full_path - @classmethod def find_aslr(cls, context: interfaces.context.ContextInterface, @@ -308,4 +152,4 @@ class LinuxSymbolFinder(symbol_finder.SymbolFinder): banner_config_key = "kernel_banner" banner_cache = LinuxBannerCache symbol_class = "volatility.framework.symbols.linux.LinuxKernelIntermedSymbols" - find_aslr = lambda cls, *args: LinuxUtilities.find_aslr(*args)[1] + find_aslr = lambda cls, *args: LinuxIntelStacker.find_aslr(*args)[1] diff --git a/volatility/framework/automagic/mac.py b/volatility/framework/automagic/mac.py index cc3445488..4fb5ba19e 100644 --- a/volatility/framework/automagic/mac.py +++ b/volatility/framework/automagic/mac.py @@ -4,9 +4,9 @@ import logging import struct -from typing import Optional, Iterable, Set, Iterator, Any +from typing import Optional -from volatility.framework import interfaces, constants, layers, exceptions, objects +from volatility.framework import interfaces, constants, layers from volatility.framework.automagic import symbol_cache, symbol_finder from volatility.framework.layers import intel, scanners from volatility.framework.symbols import mac @@ -55,19 +55,18 @@ class MacIntelStacker(interfaces.automagic.StackerLayerInterface): name = table_name, isf_url = isf_path) context.symbol_space.append(table) - kaslr_shift = MacUtilities.find_aslr(context = context, - symbol_table = table_name, - layer_name = layer_name, - compare_banner = banner, - compare_banner_offset = banner_offset, - progress_callback = progress_callback) + kaslr_shift = cls.find_aslr(context = context, + symbol_table = table_name, + layer_name = layer_name, + compare_banner = banner, + compare_banner_offset = banner_offset, + progress_callback = progress_callback) if kaslr_shift == 0: vollog.debug("Invalid kalsr_shift found at offset: {}".format(banner_offset)) continue - bootpml4_addr = MacUtilities.virtual_to_physical_address( - table.get_symbol("BootPML4").address + kaslr_shift) + bootpml4_addr = cls.virtual_to_physical_address(table.get_symbol("BootPML4").address + kaslr_shift) new_layer_name = context.layers.free_layer_name("MacDTBTempLayer") config_path = join("automagic", "MacIntelHelper", new_layer_name) @@ -99,83 +98,6 @@ class MacIntelStacker(interfaces.automagic.StackerLayerInterface): return new_layer return None - -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 _scan_generator(cls, context, layer_name, progress_callback): - darwin_signature = rb"Darwin Kernel Version \d{1,3}\.\d{1,3}\.\d{1,3}: [^\x00]+\x00" - - for offset in context.layers[layer_name].scan(scanner = scanners.RegExScanner(darwin_signature), - context = context, - progress_callback = progress_callback): - - banner = context.layers[layer_name].read(offset, 128) - - idx = banner.find(b"\x00") - if idx != -1: - banner = banner[:idx] - - yield offset, banner - @classmethod def find_aslr(cls, context: interfaces.context.ContextInterface, @@ -191,11 +113,11 @@ class MacUtilities(object): version_major_symbol = symbol_table + constants.BANG + 'version_major' version_major_json_address = context.symbol_space.get_symbol(version_major_symbol).address - version_major_phys_offset = MacUtilities.virtual_to_physical_address(version_major_json_address) + version_major_phys_offset = cls.virtual_to_physical_address(version_major_json_address) version_minor_symbol = symbol_table + constants.BANG + 'version_minor' version_minor_json_address = context.symbol_space.get_symbol(version_minor_symbol).address - version_minor_phys_offset = MacUtilities.virtual_to_physical_address(version_minor_json_address) + version_minor_phys_offset = cls.virtual_to_physical_address(version_minor_json_address) if not compare_banner_offset or not compare_banner: offset_generator = cls._scan_generator(context, layer_name, progress_callback) @@ -238,90 +160,20 @@ class MacUtilities(object): return addr - 0xffffff8000000000 @classmethod - def files_descriptors_for_process(cls, context: interfaces.context.ContextInterface, symbol_table_name: str, - task: interfaces.objects.ObjectInterface): - """Creates a generator for the file descriptors of a process + def _scan_generator(cls, context, layer_name, progress_callback): + darwin_signature = rb"Darwin Kernel Version \d{1,3}\.\d{1,3}\.\d{1,3}: [^\x00]+\x00" - Args: - symbol_table_name: The name of the symbol table associated with the process - context: - task: The process structure to enumerate file descriptors from + for offset in context.layers[layer_name].scan(scanner = scanners.RegExScanner(darwin_signature), + context = context, + progress_callback = progress_callback): - Return: - A 3 element tuple is yielded for each file descriptor: - 1) The file's object - 2) The path referenced by the descriptor. - The path is either empty, the full path of the file in the file system, or the formatted name for sockets, pipes, etc. - 3) The file descriptor number - """ + banner = context.layers[layer_name].read(offset, 128) - try: - num_fds = task.p_fd.fd_lastfile - except exceptions.InvalidAddressException: - num_fds = 1024 + idx = banner.find(b"\x00") + if idx != -1: + banner = banner[:idx] - try: - nfiles = task.p_fd.fd_nfiles - except exceptions.InvalidAddressException: - nfiles = 1024 - - if nfiles > num_fds: - num_fds = nfiles - - if num_fds > 4096: - num_fds = 1024 - - file_type = symbol_table_name + constants.BANG + 'fileproc' - - try: - table_addr = task.p_fd.fd_ofiles.dereference() - except exceptions.InvalidAddressException: - return - - fds = objects.utility.array_of_pointers(table_addr, count = num_fds, subtype = file_type, context = context) - - for fd_num, f in enumerate(fds): - if f != 0: - try: - ftype = f.f_fglob.get_fg_type() - except exceptions.InvalidAddressException: - continue - - if ftype == 'VNODE': - vnode = f.f_fglob.fg_data.dereference().cast("vnode") - path = vnode.full_path() - elif ftype: - path = "<{}>".format(ftype.lower()) - - yield f, path, fd_num - - @classmethod - def walk_tailq(cls, - queue: interfaces.objects.ObjectInterface, - next_member: str, - max_elements: int = 4096) -> Iterable[interfaces.objects.ObjectInterface]: - seen = set() # type: Set[int] - - try: - current = queue.tqh_first - except exceptions.InvalidAddressException: - return - - while current: - if current.vol.offset in seen: - break - - seen.add(current.vol.offset) - - if len(seen) == max_elements: - break - - yield current - - try: - current = current.member(attr = next_member).tqe_next - except exceptions.InvalidAddressException: - break + yield offset, banner class MacBannerCache(symbol_cache.SymbolBannerCache): @@ -336,5 +188,5 @@ class MacSymbolFinder(symbol_finder.SymbolFinder): banner_config_key = 'kernel_banner' banner_cache = MacBannerCache - find_aslr = MacUtilities.find_aslr + find_aslr = MacIntelStacker.find_aslr symbol_class = "volatility.framework.symbols.mac.MacKernelIntermedSymbols" diff --git a/volatility/framework/plugins/linux/lsof.py b/volatility/framework/plugins/linux/lsof.py index 68e275b05..f1b8d1c71 100644 --- a/volatility/framework/plugins/linux/lsof.py +++ b/volatility/framework/plugins/linux/lsof.py @@ -7,10 +7,10 @@ import logging from typing import List from volatility.framework import renderers, interfaces, constants -from volatility.framework.automagic import linux from volatility.framework.configuration import requirements from volatility.framework.interfaces import plugins from volatility.framework.objects import utility +from volatility.framework.symbols import linux from volatility.plugins.linux import pslist vollog = logging.getLogger(__name__) diff --git a/volatility/framework/plugins/mac/check_syscall.py b/volatility/framework/plugins/mac/check_syscall.py index 37a843385..46dd1f736 100644 --- a/volatility/framework/plugins/mac/check_syscall.py +++ b/volatility/framework/plugins/mac/check_syscall.py @@ -6,10 +6,10 @@ from typing import List from volatility.framework import exceptions, interfaces from volatility.framework import renderers, contexts -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.framework.symbols import mac from volatility.plugins.mac import lsmod vollog = logging.getLogger(__name__) @@ -46,7 +46,7 @@ class Check_syscall(plugins.PluginInterface): for (i, ent) in enumerate(table): try: call_addr = ent.sy_call.dereference().vol.offset - except exceptions.InvalidPagedAddressException: + except exceptions.InvalidAddressException: continue if not call_addr or call_addr == 0: diff --git a/volatility/framework/plugins/mac/check_sysctl.py b/volatility/framework/plugins/mac/check_sysctl.py index 5fcf82518..ac3b102ec 100644 --- a/volatility/framework/plugins/mac/check_sysctl.py +++ b/volatility/framework/plugins/mac/check_sysctl.py @@ -7,11 +7,11 @@ from typing import List import volatility from volatility.framework import exceptions, interfaces from volatility.framework import renderers, contexts -from volatility.framework.automagic import mac from volatility.framework.configuration import requirements from volatility.framework.interfaces import plugins from volatility.framework.objects import utility from volatility.framework.renderers import format_hints +from volatility.framework.symbols import mac from volatility.plugins.mac import lsmod vollog = logging.getLogger(__name__) diff --git a/volatility/framework/plugins/mac/check_trap_table.py b/volatility/framework/plugins/mac/check_trap_table.py index c78933a51..f6a8542c1 100644 --- a/volatility/framework/plugins/mac/check_trap_table.py +++ b/volatility/framework/plugins/mac/check_trap_table.py @@ -7,10 +7,10 @@ from typing import List from volatility.framework import exceptions, interfaces from volatility.framework import renderers, contexts -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.framework.symbols import mac from volatility.plugins.mac import lsmod vollog = logging.getLogger(__name__) diff --git a/volatility/framework/plugins/mac/ifconfig.py b/volatility/framework/plugins/mac/ifconfig.py index 3dd52a00b..e972876dc 100644 --- a/volatility/framework/plugins/mac/ifconfig.py +++ b/volatility/framework/plugins/mac/ifconfig.py @@ -1,12 +1,11 @@ # This file is Copyright 2019 Volatility Foundation and licensed under the Volatility Software License 1.0 # which is available at https://www.volatilityfoundation.org/license/vsl-v1.0 # - from volatility.framework import exceptions, renderers, contexts -from volatility.framework.automagic import mac from volatility.framework.configuration import requirements from volatility.framework.interfaces import plugins from volatility.framework.objects import utility +from volatility.framework.symbols import mac class Ifconfig(plugins.PluginInterface): diff --git a/volatility/framework/plugins/mac/lsof.py b/volatility/framework/plugins/mac/lsof.py index 2737cd7c1..55a88d20f 100644 --- a/volatility/framework/plugins/mac/lsof.py +++ b/volatility/framework/plugins/mac/lsof.py @@ -5,9 +5,9 @@ import logging from volatility.framework import renderers -from volatility.framework.automagic import mac from volatility.framework.configuration import requirements from volatility.framework.interfaces import plugins +from volatility.framework.symbols import mac from volatility.plugins.mac import pslist vollog = logging.getLogger(__name__) diff --git a/volatility/framework/plugins/mac/netstat.py b/volatility/framework/plugins/mac/netstat.py index 3554f2d2c..f9f11594c 100644 --- a/volatility/framework/plugins/mac/netstat.py +++ b/volatility/framework/plugins/mac/netstat.py @@ -6,11 +6,11 @@ import logging from typing import Iterable, Callable from volatility.framework import exceptions, renderers, interfaces -from volatility.framework.automagic import mac from volatility.framework.configuration import requirements from volatility.framework.interfaces import plugins from volatility.framework.objects import utility from volatility.framework.renderers import format_hints +from volatility.framework.symbols import mac from volatility.plugins.mac import pslist vollog = logging.getLogger(__name__) diff --git a/volatility/framework/plugins/mac/timers.py b/volatility/framework/plugins/mac/timers.py index 0dd2b003c..9da84326a 100644 --- a/volatility/framework/plugins/mac/timers.py +++ b/volatility/framework/plugins/mac/timers.py @@ -6,10 +6,10 @@ from typing import List from volatility.framework import exceptions, interfaces from volatility.framework import renderers, contexts -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.framework.symbols import mac from volatility.plugins.mac import lsmod vollog = logging.getLogger(__name__) diff --git a/volatility/framework/plugins/mac/trustedbsd.py b/volatility/framework/plugins/mac/trustedbsd.py index 85fbdb754..23b43276f 100644 --- a/volatility/framework/plugins/mac/trustedbsd.py +++ b/volatility/framework/plugins/mac/trustedbsd.py @@ -7,11 +7,11 @@ from typing import List, Iterator, Any from volatility.framework import exceptions, interfaces from volatility.framework import renderers, contexts -from volatility.framework.automagic import mac from volatility.framework.configuration import requirements from volatility.framework.interfaces import plugins from volatility.framework.objects import utility from volatility.framework.renderers import format_hints +from volatility.framework.symbols import mac from volatility.plugins.mac import lsmod vollog = logging.getLogger(__name__) diff --git a/volatility/framework/symbols/linux/__init__.py b/volatility/framework/symbols/linux/__init__.py index 4e5688ce5..992f036ba 100644 --- a/volatility/framework/symbols/linux/__init__.py +++ b/volatility/framework/symbols/linux/__init__.py @@ -1,7 +1,7 @@ # This file is Copyright 2019 Volatility Foundation and licensed under the Volatility Software License 1.0 # which is available at https://www.volatilityfoundation.org/license/vsl-v1.0 # - +from volatility.framework import exceptions, constants, interfaces, objects from volatility.framework.symbols import intermed from volatility.framework.symbols.linux import extensions @@ -31,3 +31,159 @@ class LinuxKernelIntermedSymbols(intermed.IntermediateSymbolTable): if 'mount' in self.types: self.set_type_class('mount', extensions.mount) + + +class LinuxUtilities(object): + """Class with multiple useful linux functions.""" + + # based on __d_path from the Linux kernel + @classmethod + def _do_get_path(cls, rdentry, rmnt, dentry, vfsmnt) -> str: + + ret_path = [] # type: List[str] + + while dentry != rdentry or vfsmnt != rmnt: + dname = dentry.path() + if dname == "": + break + + ret_path.insert(0, dname.strip('/')) + if dentry == vfsmnt.get_mnt_root() or dentry == dentry.d_parent: + if vfsmnt.get_mnt_parent() == vfsmnt: + break + + dentry = vfsmnt.get_mnt_mountpoint() + vfsmnt = vfsmnt.get_mnt_parent() + + continue + + parent = dentry.d_parent + dentry = parent + + # if we did not gather any valid dentrys in the path, then the entire file is + # either 1) smeared out of memory or 2) de-allocated and corresponding structures overwritten + # we return an empty string in this case to avoid confusion with something like a handle to the root + # directory (e.g., "/") + if not ret_path: + return "" + + ret_val = '/'.join([str(p) for p in ret_path if p != ""]) + + if ret_val.startswith(("socket:", "pipe:")): + if ret_val.find("]") == -1: + try: + inode = dentry.d_inode + ino = inode.i_ino + except exceptions.InvalidAddressException: + ino = 0 + + ret_val = ret_val[:-1] + ":[{0}]".format(ino) + else: + ret_val = ret_val.replace("/", "") + + elif ret_val != "inotify": + ret_val = '/' + ret_val + + return ret_val + + # method used by 'older' kernels + # TODO: lookup when dentry_operations->d_name was merged into the mainline kernel for exact version + @classmethod + def _get_path_file(cls, task, filp) -> str: + rdentry = task.fs.get_root_dentry() + rmnt = task.fs.get_root_mnt() + dentry = filp.get_dentry() + vfsmnt = filp.get_vfsmnt() + + return LinuxUtilities._do_get_path(rdentry, rmnt, dentry, vfsmnt) + + @classmethod + def _get_new_sock_pipe_path(cls, context, task, filp) -> str: + dentry = filp.get_dentry() + + sym_addr = dentry.d_op.d_dname + + symbol_table_arr = sym_addr.vol.type_name.split("!") + symbol_table = None + if len(symbol_table_arr) == 2: + symbol_table = symbol_table_arr[0] + + symbs = list(context.symbol_space.get_symbols_by_location(sym_addr, table_name = symbol_table)) + + if len(symbs) == 1: + sym = symbs[0].split(constants.BANG)[1] + + if sym == "sockfs_dname": + pre_name = "socket" + + elif sym == "anon_inodefs_dname": + pre_name = "anon_inode" + + elif sym == "pipefs_dname": + pre_name = "pipe" + + elif sym == "simple_dname": + pre_name = cls._get_path_file(task, filp) + + else: + pre_name = "".format(sym) + + ret = "{0}:[{1:d}]".format(pre_name, dentry.d_inode.i_ino) + + else: + ret = " {0:x}".format(sym_addr) + + return ret + + # a 'file' structure doesn't have enough information to properly restore its full path + # we need the root mount information from task_struct to determine this + @classmethod + def path_for_file(cls, context, task, filp) -> str: + try: + dentry = filp.get_dentry() + except exceptions.InvalidAddressException: + return "" + + if dentry == 0: + return "" + + dname_is_valid = False + + # TODO COMPARE THIS IN LSOF OUTPUT TO VOL2 + try: + if dentry.d_op and dentry.d_op.has_member("d_dname") and dentry.d_op.d_dname: + dname_is_valid = True + + except exceptions.InvalidAddressException: + dname_is_valid = False + + if dname_is_valid: + ret = LinuxUtilities._get_new_sock_pipe_path(context, task, filp) + else: + ret = LinuxUtilities._get_path_file(task, filp) + + return ret + + @classmethod + def files_descriptors_for_process(cls, context: interfaces.context.ContextInterface, symbol_table: str, + task: interfaces.objects.ObjectInterface): + + fd_table = task.files.get_fds() + if fd_table == 0: + return + + max_fds = task.files.get_max_fds() + + # corruption check + if max_fds > 500000: + return + + file_type = symbol_table + constants.BANG + 'file' + + fds = objects.utility.array_of_pointers(fd_table, count = max_fds, subtype = file_type, context = context) + + for (fd_num, filp) in enumerate(fds): + if filp != 0: + full_path = LinuxUtilities.path_for_file(context, task, filp) + + yield fd_num, filp, full_path diff --git a/volatility/framework/symbols/linux/extensions/__init__.py b/volatility/framework/symbols/linux/extensions/__init__.py index 9d6769b1f..e9f736450 100644 --- a/volatility/framework/symbols/linux/extensions/__init__.py +++ b/volatility/framework/symbols/linux/extensions/__init__.py @@ -8,9 +8,8 @@ from typing import Generator, Iterable, Iterator, Optional, Tuple from volatility.framework import constants from volatility.framework import exceptions, objects, interfaces -from volatility.framework.automagic import linux from volatility.framework.layers import linear -from volatility.framework.symbols import generic +from volatility.framework.symbols import generic, linux vollog = logging.getLogger(__name__) diff --git a/volatility/framework/symbols/mac/__init__.py b/volatility/framework/symbols/mac/__init__.py index 9a4283217..50ccef62a 100644 --- a/volatility/framework/symbols/mac/__init__.py +++ b/volatility/framework/symbols/mac/__init__.py @@ -1,7 +1,9 @@ # This file is Copyright 2019 Volatility Foundation and licensed under the Volatility Software License 1.0 # which is available at https://www.volatilityfoundation.org/license/vsl-v1.0 # +from typing import Iterator, Any, Iterable +from volatility.framework import interfaces, objects, exceptions, constants from volatility.framework.symbols import intermed from volatility.framework.symbols.mac import extensions @@ -24,3 +26,150 @@ class MacKernelIntermedSymbols(intermed.IntermediateSymbolTable): self.set_type_class('sockaddr_dl', extensions.sockaddr_dl) self.set_type_class('sockaddr', extensions.sockaddr) self.set_type_class('sysctl_oid', extensions.sysctl_oid) + + +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 files_descriptors_for_process(cls, context: interfaces.context.ContextInterface, symbol_table_name: str, + task: interfaces.objects.ObjectInterface): + """Creates a generator for the file descriptors of a process + + Args: + symbol_table_name: The name of the symbol table associated with the process + context: + task: The process structure to enumerate file descriptors from + + Return: + A 3 element tuple is yielded for each file descriptor: + 1) The file's object + 2) The path referenced by the descriptor. + The path is either empty, the full path of the file in the file system, or the formatted name for sockets, pipes, etc. + 3) The file descriptor number + """ + + try: + num_fds = task.p_fd.fd_lastfile + except exceptions.InvalidAddressException: + num_fds = 1024 + + try: + nfiles = task.p_fd.fd_nfiles + except exceptions.InvalidAddressException: + nfiles = 1024 + + if nfiles > num_fds: + num_fds = nfiles + + if num_fds > 4096: + num_fds = 1024 + + file_type = symbol_table_name + constants.BANG + 'fileproc' + + try: + table_addr = task.p_fd.fd_ofiles.dereference() + except exceptions.InvalidAddressException: + return + + fds = objects.utility.array_of_pointers(table_addr, count = num_fds, subtype = file_type, context = context) + + for fd_num, f in enumerate(fds): + if f != 0: + try: + ftype = f.f_fglob.get_fg_type() + except exceptions.InvalidAddressException: + continue + + if ftype == 'VNODE': + vnode = f.f_fglob.fg_data.dereference().cast("vnode") + path = vnode.full_path() + elif ftype: + path = "<{}>".format(ftype.lower()) + + yield f, path, fd_num + + @classmethod + def walk_tailq(cls, + queue: interfaces.objects.ObjectInterface, + next_member: str, + max_elements: int = 4096) -> Iterable[interfaces.objects.ObjectInterface]: + seen = set() # type: Set[int] + + try: + current = queue.tqh_first + except exceptions.InvalidAddressException: + return + + while current: + if current.vol.offset in seen: + break + + seen.add(current.vol.offset) + + if len(seen) == max_elements: + break + + yield current + + try: + current = current.member(attr = next_member).tqe_next + except exceptions.InvalidAddressException: + break