mirror of
https://github.com/volatilityfoundation/volatility3.git
synced 2026-08-21 05:52:22 +02:00
81 lines
3.4 KiB
Python
81 lines
3.4 KiB
Python
import logging
|
|
import os
|
|
import pickle
|
|
import typing
|
|
from urllib import parse
|
|
|
|
from volatility.framework import constants, exceptions, interfaces
|
|
from volatility.framework.symbols import intermed
|
|
|
|
vollog = logging.getLogger(__name__)
|
|
|
|
LinuxBanners = typing.Dict[bytes, typing.List[str]]
|
|
|
|
|
|
class LinuxSymbolCache(interfaces.automagic.AutomagicInterface):
|
|
"""Runs through all Linux symbols tables and caches their banners"""
|
|
|
|
# Since this is necessary for ConstructionMagic, we set a lower priority
|
|
# The user would run it eventually either way, but running it first means it can be used that run
|
|
priority = 0
|
|
|
|
@classmethod
|
|
def load_linux_banners(cls) -> LinuxBanners:
|
|
linuxbanners = {} # type: LinuxBanners
|
|
if os.path.exists(constants.LINUX_BANNERS_PATH):
|
|
with open(constants.LINUX_BANNERS_PATH, "rb") as f:
|
|
# We use pickle over JSON because we're dealing with bytes objects
|
|
linuxbanners.update(pickle.load(f))
|
|
|
|
# Remove possibilities that can't exist locally.
|
|
for banner in linuxbanners:
|
|
for path in linuxbanners[banner]:
|
|
url = parse.urlparse(path)
|
|
if url.scheme == 'file' and not os.path.exists(parse.unquote(url.path)):
|
|
vollog.log(constants.LOGLEVEL_V,
|
|
"Removing cached path {} for banner {}: files does not exist".format(path, banner))
|
|
linuxbanners[banner].remove(path)
|
|
return linuxbanners
|
|
|
|
@classmethod
|
|
def save_linux_banners(cls, linuxbanners):
|
|
with open(constants.LINUX_BANNERS_PATH, "wb") as f:
|
|
pickle.dump(linuxbanners, f)
|
|
|
|
def __call__(self, context, config_path, configurable, progress_callback = None):
|
|
"""Runs the automagic over the configurable"""
|
|
# We only need to be called once, so no recursion necessary
|
|
linuxbanners = self.load_linux_banners()
|
|
|
|
cacheables = list(intermed.IntermediateSymbolTable.file_symbol_url("linux"))
|
|
|
|
for banner in linuxbanners:
|
|
for json_file in linuxbanners[banner]:
|
|
if json_file in cacheables:
|
|
cacheables.remove(json_file)
|
|
|
|
total = len(cacheables)
|
|
if total > 0:
|
|
vollog.info("Building linux caches...")
|
|
for current in range(total):
|
|
progress_callback(current * 100 / total, "Building linux caches")
|
|
isf_url = cacheables[current]
|
|
|
|
try:
|
|
# Loading the symbol table will be very slow until it's been validated
|
|
isf = intermed.IntermediateSymbolTable(context, config_path, "temp", isf_url, validate = False)
|
|
|
|
# We should store the banner against the filename
|
|
# We don't bother with the hash (it'll likely take too long to validate)
|
|
# but we should check at least that the banner matches on load.
|
|
banner = isf.get_symbol("linux_banner").constant_data
|
|
vollog.log(constants.LOGLEVEL_V, "Caching banner {} for file {}".format(banner, isf_url))
|
|
bannerlist = linuxbanners.get(banner, [])
|
|
bannerlist.append(isf_url)
|
|
linuxbanners[banner] = bannerlist
|
|
except exceptions.SymbolError:
|
|
pass
|
|
|
|
# Rewrite the cached linuxbanners each run, since writing is faster than the cache validation portion
|
|
self.save_linux_banners(linuxbanners)
|