def _extract_files(self, artifact: ResolvedArtifact,
                       artifact_output: ForensicStore) -> bool:
        """
        Extract an artifact's files and folders to the forensic store
        :param artifact: artifact to extract
        :param artifact_output: Output forensic store
        :type artifact_output: ForensicStore
        :type artifact: ResolvedArtifact
        :return: True on success, False if nothing was written
        """

        artifact_name = artifact.artifact.name
        success = False

        for export_file in artifact.files:
            success = True
            file_infos = get_file_infos(export_file)
            if not file_infos:
                LOGGER.warning("Could not get file infos for \"%s\". Skipping",
                               dfvfs_helper.reconstruct_full_path(export_file))
                continue

            if file_infos['type'] != dfvfs_defs.FILE_ENTRY_TYPE_FILE:
                LOGGER.debug("Not exporting entry of wrong type: %s",
                             dfvfs_helper.reconstruct_full_path(export_file))
                continue

            file_contents = dfvfs_helper.get_file_handle(export_file)
            if not file_contents:
                LOGGER.warning("Could not get file contents for \"%s\"",
                               dfvfs_helper.reconstruct_full_path(export_file))
                success = False
                continue
            store_obj_id = artifact_output.add_file_element(
                artifact_name,
                file_infos['name'],
                created=file_infos.get('created', None),
                modified=file_infos.get('modified', None),
                accessed=file_infos.get('accessed', None),
                origin={
                    'path': file_infos['path'],
                    'partition': self.partition_name
                },
                errors=None)
            output_name = f"{self.partition_name}_" \
                          f"{dfvfs_helper.get_relative_path(export_file).replace('/', '_').strip('_')}"
            with artifact_output.add_file_element_export(
                    store_obj_id, export_name=output_name) as file_export:
                chunk_size = 65536
                data = file_contents.read(chunk_size)
                while data:
                    file_export.write(data)
                    data = file_contents.read(chunk_size)
            file_contents.close()

        return success
 def __init__(self, source_paths: List[str], result_root: fs.base.FS,
              artifact_registry: Registry,
              encryption_handler: dfvfs_helper.EncryptionHandler):
     self.dfvfs_list = []
     self.artifact_registry = artifact_registry
     self.tmp_dir = None
     new_source_path = source_paths[0]
     self.dfvfs_list = [
         dfvfs_helper.DFVFSHelper(new_source_path, encryption_handler)
     ]
     self.encryption_handler = encryption_handler
     # noinspection PyTypeChecker
     self.store = ForensicStore(result_root)
Beispiel #3
0
def find_store(local_path):
    store = None
    for root, dirs, files in os.walk(local_path):
        if root.endswith('.forensicstore'):
            assert store is None  # There is only one partition here
            store = ForensicStore(root)
    assert store is not None
    return store
    def _key_to_forensicstore(store: ForensicStore,
                              key: WinRegistryKey,
                              values: Optional[List[str]] = None,
                              artifact: str = '') -> None:
        """ Export a registry key to the forensicstore, optionally only picking certain values from the key """
        last_write_tuple = key.last_written_time.CopyToStatTimeTuple()
        if last_write_tuple[0]:
            last_write_date = datetime.utcfromtimestamp(last_write_tuple[0])
            last_write_date = last_write_date.replace(
                microsecond=(int(last_write_tuple[1] / 10)))
        else:
            last_write_date = datetime.utcfromtimestamp(0)
        try:
            key_item_id = store.add_registry_key_element(
                artifact=artifact,
                modified=last_write_date,
                key=key.path,
                errors=None)
        except TypeError as err:
            LOGGER.exception("Error adding registry key: %s", err)
            return

        for value in key.GetValues():
            name = value.name
            if values and name not in values:
                continue
            if name is None:
                name = '(Default)'
            type_str = value.data_type_string
            if type_str == 'REG_DWORD_LE':
                type_str = 'REG_DWORD'
            # if value.data and (value.DataIsBinaryData() or value.data_type_string == "REG_NONE"):
            #     data = value.data
            # elif value.data:
            #     data = '{}'.format(value.GetDataAsObject())
            # else:
            #     data = b""

            try:
                store.add_registry_value_element(key_item_id, type_str,
                                                 value.data, name)
            except sqlite3.OperationalError:
                LOGGER.exception("Error updating value")
                continue
class ArtifactExtractor(object):
    """
    This is the main class that manages the artifact extraction from any dfVFS-supported input
    """

    # pylint: disable=too-few-public-methods

    def __init__(self, source_paths: List[str], result_root: fs.base.FS,
                 artifact_registry: Registry,
                 encryption_handler: dfvfs_helper.EncryptionHandler):
        self.dfvfs_list = []
        self.artifact_registry = artifact_registry
        self.tmp_dir = None
        new_source_path = source_paths[0]
        self.dfvfs_list = [
            dfvfs_helper.DFVFSHelper(new_source_path, encryption_handler)
        ]
        self.encryption_handler = encryption_handler
        # noinspection PyTypeChecker
        self.store = ForensicStore(result_root)

    def clean_up(self):
        """ Called when no more actions will be called in this object """
        for d in self.dfvfs_list:
            d.clean_up()
        self.dfvfs_list = None
        self.encryption_handler = None
        if self.tmp_dir:
            self.tmp_dir.cleanup()
            self.tmp_dir = None

    def extract_artifact(self, artifact_name):  # pylint: disable=invalid-name
        """
        Extract a particular artifact from all possible locations within this dfvfs-image
        """
        real_partitions: List[PartitionInfo] = []

        # forensic images can have more than one partition, but we always only process one image at a time
        real_partitions = [
            PartitionInfo(helper=self.dfvfs_list[0],
                          path_spec=partition,
                          name=chr(ord('c') + i))
            for i, partition in enumerate(self.dfvfs_list[0].partitions())
            if not dfvfs_utils.is_on_filesystem(
                partition, dfvfs_defs.TYPE_INDICATOR_VSHADOW)
        ]
        LOGGER.info("Found %d partitions", len(real_partitions))
        for partinfo in real_partitions:
            current_os = self._guess_os(partinfo.helper, partinfo.path_spec)
            try:
                if current_os == definitions.OPERATING_SYSTEM_WINDOWS:
                    system = WindowsSystem(partinfo.helper, partinfo.path_spec)

                elif current_os == definitions.OPERATING_SYSTEM_UNKNOWN:
                    system = UnknownOS()
                    LOGGER.warning(
                        "Operating system not detected on partition %s. Only basic extraction possible.",
                        dfvfs_utils.reconstruct_full_path(partinfo.path_spec))
                else:
                    LOGGER.warning(
                        "Operating system %s is not yet supported on %s. Using basic extraction.",
                        dfvfs_utils.reconstruct_full_path(partinfo.path_spec),
                        current_os)
                    system = UnknownOS()

                LOGGER.info("=== Starting processing of partition")
                resolver = ArtifactResolver(partinfo, self.artifact_registry,
                                            system)
                resolver.process_artifact(artifact_name, self.store)

                if current_os == definitions.OPERATING_SYSTEM_WINDOWS:
                    system._reg_reader._cleanup_open_files("")  # TODO

            except RuntimeError as err:
                LOGGER.exception(
                    "Encountered exception during processing of %s: %s",
                    dfvfs_utils.reconstruct_full_path(partinfo.path_spec), err)
                if 'pytest' in sys.modules:
                    raise  # we want to see what exactly is failing when tests are running

        self.store.close()

    @staticmethod
    def _guess_os(dfvfs, partition):
        """Tries to determine the underlying operating system.
        Adapted from plaso/engine.py
        Returns:
          str: operating system, for example "Windows". This should be one of
              the values in definitions.OPERATING_SYSTEMS.
        """
        find_specs = [
            '/etc',
            '/System/Library',
            '/Windows/System32',
            '/WINNT/System32',
            '/WINNT35/System32',
            '/WTSRV/System32',
        ]

        locations = []
        for path_spec in dfvfs.find_paths(find_specs, partitions=[partition]):
            path = dfvfs_utils.get_relative_path(path_spec)
            if path:
                locations.append(path.lower().rstrip('/'))

        # We need to check for both forward and backward slashes since the path
        # spec will be OS dependent, as in running the tool on Windows will return
        # Windows paths (backward slash) vs. forward slash on *NIX systems.
        windows_locations = {
            '/windows/system32', '\\windows\\system32', '/winnt/system32',
            '\\winnt\\system32', '/winnt35/system32', '\\winnt35\\system32',
            '\\wtsrv\\system32', '/wtsrv/system32'
        }

        if windows_locations.intersection(set(locations)):
            return definitions.OPERATING_SYSTEM_WINDOWS
        if '/system/library' in locations:
            return definitions.OPERATING_SYSTEM_MACOSX
        if '/etc' in locations:
            return definitions.OPERATING_SYSTEM_LINUX
        return definitions.OPERATING_SYSTEM_UNKNOWN