mirror of
https://github.com/volatilityfoundation/volatility3.git
synced 2026-08-22 22:32:22 +02:00
118 lines
5.7 KiB
Python
118 lines
5.7 KiB
Python
import logging
|
|
|
|
from volatility.framework import interfaces
|
|
from volatility.framework.automagic import linux_symbol_cache
|
|
from volatility.framework.layers import intel, scanners
|
|
|
|
vollog = logging.getLogger(__name__)
|
|
|
|
|
|
class LinuxSymbolFinder(interfaces.automagic.AutomagicInterface):
|
|
"""Linux symbol loader based on uname signature strings"""
|
|
priority = 40
|
|
|
|
def __init__(self, context, config_path):
|
|
super().__init__(context, config_path)
|
|
self._requirements = None
|
|
self._linux_banners = linux_symbol_cache.LinuxSymbolCache.load_linux_banners()
|
|
|
|
def __call__(self, context, config_path, requirement, progress_callback = None):
|
|
"""Searches for LinuxSymbolRequirements and attempt to populate them"""
|
|
self._requirements = self.find_requirements(context, config_path, requirement,
|
|
(interfaces.configuration.TranslationLayerRequirement,
|
|
interfaces.configuration.SymbolRequirement),
|
|
shortcut = False)
|
|
|
|
for (path, sub_path, requirement) in self._requirements:
|
|
if (isinstance(requirement, interfaces.configuration.SymbolRequirement) and
|
|
requirement.unsatisfied(context, path)):
|
|
for (tl_path, tl_sub_path, tl_requirement) in self._requirements:
|
|
# Find the TranslationLayer sibling to the SymbolRequirement
|
|
if (isinstance(tl_requirement, interfaces.configuration.TranslationLayerRequirement) and
|
|
tl_path == path):
|
|
# TODO: Find the physical layer properly, not just for Intel
|
|
physical_path = interfaces.configuration.path_join(tl_sub_path, "memory_layer")
|
|
# Ensure the stackers succeeded
|
|
if context.config.get(physical_path, None):
|
|
self._banner_scan(context, path, requirement, context.config[physical_path],
|
|
progress_callback)
|
|
break
|
|
|
|
def _banner_scan(self, context, config_path, requirement, layer_name, progress_callback = None):
|
|
"""Accepts a context, config_path and SymbolRequirement, with a constructed layer_name
|
|
and scans the layer for linux banners"""
|
|
|
|
# Bomb out early if there's no banners
|
|
if not self._linux_banners:
|
|
return
|
|
|
|
mss = scanners.MultiStringScanner([x for x in self._linux_banners if x is not None])
|
|
|
|
layer = context.memory[layer_name]
|
|
|
|
for offset, banner in layer.scan(context = context, scanner = mss, progress_callback = progress_callback):
|
|
vollog.debug("Identified banner: {}".format(repr(banner)))
|
|
symbol_files = self._linux_banners[banner]
|
|
if symbol_files:
|
|
isf_path = symbol_files[0]
|
|
vollog.debug("Using symbol library: {}".format(symbol_files[0]))
|
|
clazz = "volatility.framework.symbols.linux.LinuxKernelIntermedSymbols"
|
|
# Set the discovered options
|
|
path_join = interfaces.configuration.path_join
|
|
context.config[path_join(config_path, requirement.name, "class")] = clazz
|
|
context.config[path_join(config_path, requirement.name, "isf_filepath")] = isf_path
|
|
# Construct the appropriate symbol table
|
|
requirement.construct(context, config_path)
|
|
break
|
|
else:
|
|
vollog.debug("Symbol library path not found: {}".format(symbol_files[0]))
|
|
# print("Kernel", banner, hex(banner_offset))
|
|
else:
|
|
vollog.debug("No existing linux banners found")
|
|
# TODO: Fallback to generic regex search?
|
|
|
|
|
|
class LintelStacker(interfaces.automagic.StackerLayerInterface):
|
|
linux_signature = b"SYMBOL\(swapper_pg_dir\)=.*"
|
|
stack_order = 12
|
|
|
|
@classmethod
|
|
def stack(cls, context, layer_name, progress_callback = None):
|
|
"""Attempts to identify linux within this layer"""
|
|
layer = context.memory[layer_name]
|
|
|
|
# Bail out if we're not a physical layer
|
|
# TODO: We need a better way of doing this
|
|
if isinstance(layer, intel.Intel):
|
|
return None
|
|
|
|
swapper_pg_dirs = []
|
|
for offset in layer.scan(scanner = scanners.RegExScanner(cls.linux_signature), context = context):
|
|
swapper_pg_dir_text = context.memory[layer_name].read(offset, len(cls.linux_signature) + 20)
|
|
swapper_pg_dir = int(swapper_pg_dir_text[
|
|
swapper_pg_dir_text.index(b"=") + 1:swapper_pg_dir_text.index(b"\n")], 16)
|
|
swapper_pg_dirs.append(swapper_pg_dir)
|
|
|
|
dtb = 0
|
|
if swapper_pg_dirs:
|
|
best_swapper_pg_dir = \
|
|
list(reversed(sorted(set(swapper_pg_dirs), key = lambda x: swapper_pg_dirs.count(x))))[0]
|
|
|
|
if best_swapper_pg_dir > 0xffffffff80000000:
|
|
shift = 0xffffffff80000000
|
|
layer_class = intel.Intel32e
|
|
else:
|
|
shift = 0xc0000000
|
|
layer_class = intel.Intel
|
|
dtb = best_swapper_pg_dir - shift
|
|
|
|
new_layer_name = context.memory.free_layer_name("IntelLayer")
|
|
config_path = interfaces.configuration.path_join("IntelHelper", new_layer_name)
|
|
context.config[interfaces.configuration.path_join(config_path, "memory_layer")] = layer_name
|
|
context.config[interfaces.configuration.path_join(config_path, "page_map_offset")] = dtb
|
|
|
|
layer = layer_class(context, config_path = config_path, name = new_layer_name)
|
|
if layer:
|
|
vollog.debug("DTB was found at: 0x{:0x}".format(dtb))
|
|
return layer
|