import argparse import base64 import json import logging import os import pathlib import urllib from volatility3.cli import PrintedProgress from volatility3.framework import contexts, constants from volatility3.framework.automagic import linux, mac vollog = logging.getLogger(__name__) class BannerCacheGenerator: def __init__(self, path: str, url_prefix: str): self._path = path self._url_prefix = url_prefix def convert_url(self, url): parsed = urllib.parse.urlparse(url) relpath = os.path.relpath(parsed.path, os.path.abspath(self._path)) return urllib.parse.urljoin(self._url_prefix, relpath) def run(self): context = contexts.Context() json_output = {"version": 1} path = self._path filename = "*" for banner_cache in [linux.LinuxBannerCache, mac.MacBannerCache]: sub_path = banner_cache.os potentials = [] for extension in constants.ISF_EXTENSIONS: # Hopefully these will not be large lists, otherwise this might be slow try: for found in ( pathlib.Path(path) .joinpath(sub_path) .resolve() .rglob(filename + extension) ): potentials.append(found.as_uri()) except FileNotFoundError: # If there's no linux symbols, don't cry about it pass new_banners = banner_cache.read_new_banners( context, "BannerServer", potentials, banner_cache.symbol_name, banner_cache.os, progress_callback=PrintedProgress(), ) result_banners = {} for new_banner in new_banners: # Only accept file schemes value = [ self.convert_url(url) for url in new_banners[new_banner] if urllib.parse.urlparse(url).scheme == "file" ] if value and new_banner: # Convert files into URLs result_banners[str(base64.b64encode(new_banner), "latin-1")] = value json_output[banner_cache.os] = result_banners output_path = os.path.join(self._path, "banners.json") with open(output_path, "w") as fp: vollog.warning(f"Banners file written to {output_path}") json.dump(json_output, fp) if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument("--path", default=os.path.dirname(__file__)) parser.add_argument( "--urlprefix", help="Web prefix that will eventually serve the ISF files", default="http://localhost/symbols", ) args = parser.parse_args() bcg = BannerCacheGenerator(args.path, args.urlprefix) bcg.run()