From ec8e9161bf613b578493a8c25d5b34d3ed094ee0 Mon Sep 17 00:00:00 2001 From: Matt Tressler Date: Wed, 22 Jul 2020 10:02:35 -0400 Subject: [PATCH] created tty_check.py; edited automagic/linux.py to add kernel tracking abilities --- volatility/framework/automagic/linux.py | 58 ++++++++++++++ .../framework/plugins/linux/tty_check.py | 80 +++++++++++++++++++ 2 files changed, 138 insertions(+) create mode 100644 volatility/framework/plugins/linux/tty_check.py diff --git a/volatility/framework/automagic/linux.py b/volatility/framework/automagic/linux.py index 547f60c76..0572b8fbd 100644 --- a/volatility/framework/automagic/linux.py +++ b/volatility/framework/automagic/linux.py @@ -9,6 +9,7 @@ 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.objects import utility vollog = logging.getLogger(__name__) @@ -135,6 +136,63 @@ class LinuxIntelStacker(interfaces.automagic.StackerLayerInterface): return addr - 0xffffffff80000000 return addr - 0xc0000000 + @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 [(utility.array_to_string(mod.name), mod.vol.offset & mask, (mod.vol.offset & mask) + mod.vol.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("_text") + + 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.vol.offset & mask + end_addr = end_addr.vol.offset & mask + + return [("__kernel__", start_addr, end_addr)] + \ + LinuxUtilities.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 class LinuxBannerCache(symbol_cache.SymbolBannerCache): """Caches the banners found in the Linux symbol files.""" diff --git a/volatility/framework/plugins/linux/tty_check.py b/volatility/framework/plugins/linux/tty_check.py new file mode 100644 index 000000000..e93fd4aff --- /dev/null +++ b/volatility/framework/plugins/linux/tty_check.py @@ -0,0 +1,80 @@ +# This file is Copyright 2020 Volatility Foundation and licensed under the Volatility Software License 1.0 +# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0 +# + +import logging +from typing import List + +from volatility.framework import interfaces, renderers, exceptions, constants, contexts +from volatility.framework.automagic import linux +from volatility.framework.configuration import requirements +from volatility.framework.interfaces import plugins +from volatility.framework.layers import intel +from volatility.framework.objects import utility +from volatility.plugins.linux import lsmod +from volatility.framework.renderers import format_hints + +vollog = logging.getLogger(__name__) + + +class tty_check(plugins.PluginInterface): + """Compares module list to sysfs info, if available""" + + @classmethod + def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: + return [ + requirements.TranslationLayerRequirement(name='primary', + description='Memory layer for the kernel', + architectures=["Intel32", "Intel64"]), + requirements.SymbolTableRequirement( + name="vmlinux", description="Linux kernel symbols"), + + requirements.PluginRequirement( + name='lsmod', plugin=lsmod.Lsmod, version=(1, 0, 0)) + ] + + def _generator(self): + vmlinux = contexts.Module( + self.context, self.config['vmlinux'], self.config['primary'], 0) + + modules = lsmod.Lsmod.list_modules(self.context, self.config['primary'], self.config['vmlinux']) + + handles = linux.LinuxUtilities.generate_kernel_handler_info(self.context, self.config['primary'], vmlinux, modules) + + try: + tty_drivers = vmlinux.object_from_symbol("tty_drivers") + except exceptions.SymbolError: + tty_drivers = None + + if not tty_drivers: + raise TypeError("This plugin requires the tty_drivers structure. This structure is not present in the supplied symbol table. This means you are either analyzing an unsupported kernel version or that your symbol table is corrupt.") + + sym_cache = {} + + for tty in tty_drivers.to_list(vmlinux.name + constants.BANG + "tty_driver", "tty_drivers"): + + try: + ttys = utility.array_of_pointers(tty.ttys.dereference(), count=tty.num, subtype=vmlinux.name + constants.BANG + "tty_struct", context=self.context) + except exceptions.PagedInvalidAddressException: + continue + + for tty_dev in ttys: + + if tty_dev == 0: + continue + + name = utility.array_to_string(tty_dev.name) + + recv_buf = tty_dev.ldisc.ops.receive_buf + + module_name, symbol_name = linux.LinuxUtilities.lookup_module_address(self.context, handles, recv_buf) + + sym_cache[recv_buf] = symbol_name + + yield (0, (name, format_hints.Hex(recv_buf), module_name, symbol_name)) + + + + def run(self): + return renderers.TreeGrid([("Name", str), ("Address", format_hints.Hex), ("Module", str), + ("Symbol", str)], self._generator())