Example #1
0
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))
Example #2
0
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)
Example #3
0
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)