def create_rekall_profiles(injector: Injector): tmp = None for file in dll_file_list: try: logging.info(f"Fetching rekall profile for {file.path}") local_dll_path = os.path.join(PROFILE_DIR, file.dest) guest_dll_path = str(PureWindowsPath("C:/", file.path)) cmd = injector.read_file(guest_dll_path, local_dll_path) out = json.loads(cmd.stdout.decode()) if out["Status"] == "Error" and out["Error"] in [ "ERROR_FILE_NOT_FOUND", "ERROR_PATH_NOT_FOUND" ]: raise FileNotFoundError if out["Status"] != "Success": logging.debug("stderr: " + cmd.stderr.decode()) logging.debug(out) # Take care if the error message is changed raise Exception("Some error occurred in injector") guid = pdb_guid(local_dll_path) tmp = fetch_pdb(guid["filename"], guid["GUID"], PROFILE_DIR) logging.debug("Parsing PDB into JSON profile...") profile = make_pdb_profile(tmp) with open(os.path.join(PROFILE_DIR, f"{file.dest}.json"), 'w') as f: f.write(profile) except json.JSONDecodeError: logging.debug(f"stdout: {cmd.stdout}") logging.debug(f"stderr: {cmd.stderr}") logging.debug(traceback.format_exc()) raise Exception(f"Failed to parse json response on {file.path}") except FileNotFoundError: logging.warning(f"Failed to copy file {file.path}, skipping...") except RuntimeError: logging.warning( f"Failed to fetch profile for {file.path}, skipping...") except Exception as e: # Take care if the error message is changed if str(e) == "Some error occurred in injector": raise else: logging.warning( f"Unexpected exception while creating rekall profile for {file.path}, skipping..." ) # Can help in debugging logging.debug("stderr: " + cmd.stderr.decode()) logging.debug(out) logging.debug(traceback.format_exc()) finally: safe_delete(local_dll_path) # was crashing here if the first file reached some exception if tmp is not None: safe_delete(os.path.join(PROFILE_DIR, tmp))
def create_rekall_profiles(install_info: InstallInfo): storage_backend = get_storage_backend(install_info) with storage_backend.vm0_root_as_block() as block_device, \ tempfile.TemporaryDirectory() as mount_path: mnt_path_quoted = shlex.quote(mount_path) blk_quoted = shlex.quote(block_device) try: subprocess.check_output( f"mount -t ntfs -o ro {blk_quoted} {mnt_path_quoted}", shell=True) except subprocess.CalledProcessError: raise RuntimeError(f"Failed to mount {block_device} as NTFS.") profiles_path = os.path.join(LIB_DIR, "profiles") for file in dll_file_list: try: logging.info(f"Fetching rekall profile for {file.path}") local_dll_path = os.path.join(profiles_path, file.dest) copyfile(os.path.join(mount_path, file.path), local_dll_path) guid = pdb_guid(local_dll_path) tmp = fetch_pdb(guid["filename"], guid["GUID"], profiles_path) logging.debug("Parsing PDB into JSON profile...") profile = make_pdb_profile(tmp) with open(os.path.join(profiles_path, f"{file.dest}.json"), 'w') as f: f.write(profile) except FileNotFoundError: logging.warning( f"Failed to copy file {file.path}, skipping...") except RuntimeError: logging.warning( f"Failed to fetch profile for {file.path}, skipping...") except Exception: logging.warning( f"Unexpected exception while creating rekall profile for {file.path}, skipping..." ) finally: if os.path.exists(local_dll_path): os.remove(local_dll_path) if os.path.exists(os.path.join(profiles_path, tmp)): os.remove(os.path.join(profiles_path, tmp)) # cleanup subprocess.check_output(f'umount {mnt_path_quoted}', shell=True)
def create_rekall_profiles(install_info: InstallInfo): profiles_path = os.path.join(LIB_DIR, "profiles") with tempfile.TemporaryDirectory() as mount_path: # we mount 2nd partition, as 1st partition is windows boot related and 2nd partition is C:\\ if install_info.storage_backend == "zfs": # workaround for not being able to mount a snapshot base_snap = shlex.quote(os.path.join(install_info.zfs_tank_name, 'vm-0@booted')) tmp_snap = shlex.quote(os.path.join(install_info.zfs_tank_name, 'tmp')) try: subprocess.check_output(f'zfs clone {base_snap} {tmp_snap}', shell=True) except subprocess.CalledProcessError: logging.warning("Failed to clone temporary zfs snapshot. Aborting generation of usermode rekall profiles") return volume_path = os.path.join("/", "dev", "zvol", install_info.zfs_tank_name, "tmp-part2") # Wait for 60s for the volume to appear in /dev/zvol/... for _ in range(60): if os.path.exists(volume_path): break time.sleep(1.0) else: raise RuntimeError(f"ZFS volume not available at {volume_path}") try: # We have to wait for a moment for zvol to appear time.sleep(1.0) tmp_mount = shlex.quote(volume_path) subprocess.check_output(f'mount -t ntfs -o ro {tmp_mount} {mount_path}', shell=True) except subprocess.CalledProcessError: logging.warning("Failed to mount temporary zfs snapshot. Aborting generation of usermode rekall profiles") try: subprocess.check_output(f'zfs destroy {tmp_snap}', shell=True) except subprocess.CalledProcessError: logging.exception('Failed to cleanup after zfs tmp snapshot') return else: # qcow2 try: subprocess.check_output("modprobe nbd", shell=True) except subprocess.CalledProcessError: logging.warning("Failed to load nbd kernel module. Aborting generation of usermode rekall profiles") return # TODO: this assumes /dev/nbd0 is free try: subprocess.check_output(f"qemu-nbd -c /dev/nbd0 --read-only {os.path.join(LIB_DIR, 'volumes', 'vm-0.img')}", shell=True) except subprocess.CalledProcessError: logging.warning("Failed to load quemu image as nbd0. Aborting generation of usermode rekall profiles") return try: subprocess.check_output(f"mount -t ntfs -o ro /dev/nbd0p2 {mount_path}", shell=True) except subprocess.CalledProcessError: logging.warning("Failed to mount nbd0p2. Aborting generation of usermode rekall profiles") try: subprocess.check_output('qemu-nbd --disconnect /dev/nbd0', shell=True) except subprocess.CalledProcessError: logging.exception('Failed to cleanup after nbd0') return for file in dll_file_list: try: logging.info(f"Fetching rekall profile for {file.path}") local_dll_path = os.path.join(profiles_path, file.dest) copyfile(os.path.join(mount_path, file.path), local_dll_path) guid = pdb_guid(local_dll_path) tmp = fetch_pdb(guid["filename"], guid["GUID"], profiles_path) logging.debug("Parsing PDB into JSON profile...") profile = make_pdb_profile(tmp) with open(os.path.join(profiles_path, f"{file.dest}.json"), 'w') as f: f.write(profile) except FileNotFoundError: logging.warning(f"Failed to copy file {file.path}, skipping...") except RuntimeError: logging.warning(f"Failed to fetch profile for {file.path}, skipping...") except Exception: logging.warning(f"Unexpected exception while creating rekall profile for {file.path}, skipping...") finally: if os.path.exists(local_dll_path): os.remove(local_dll_path) if os.path.exists(os.path.join(profiles_path, tmp)): os.remove(os.path.join(profiles_path, tmp)) # cleanup subprocess.check_output(f'umount {mount_path}', shell=True) if install_info.storage_backend == "zfs": subprocess.check_output(f'zfs destroy {tmp_snap}', shell=True) else: # qcow2 subprocess.check_output('qemu-nbd --disconnect /dev/nbd0', shell=True)