예제 #1
0
    def _ScanVolumeSystemRoot(self, scan_context, scan_node, base_path_specs):

        if not scan_node or not scan_node.path_spec:
            raise errors.SourceScannerError('Invalid scan node.')

        if scan_node.type_indicator == (
                dfvfs_definitions.TYPE_INDICATOR_APFS_CONTAINER):
            volume_identifiers = self._GetAPFSVolumeIdentifiers(scan_node)

        elif scan_node.type_indicator == dfvfs_definitions.TYPE_INDICATOR_VSHADOW:
            #if scan_node.type_indicator == dfvfs_definitions.TYPE_INDICATOR_VSHADOW:
            if self._process_vss:
                volume_identifiers = self._GetVSSStoreIdentifiers(scan_node)
                # Process VSS stores (snapshots) starting with the most recent one.
                volume_identifiers.reverse()
            else:
                volume_identifiers = []

        else:
            raise errors.SourceScannerError(
                'Unsupported volume system type: {0:s}.'.format(
                    scan_node.type_indicator))

        for volume_identifier in volume_identifiers:
            location = '/{0:s}'.format(volume_identifier)
            sub_scan_node = scan_node.GetSubNodeByLocation(location)
            if not sub_scan_node:
                raise errors.SourceScannerError(
                    'Scan node missing for volume identifier: {0:s}.'.format(
                        volume_identifier))

            self._ScanVolume(scan_context, sub_scan_node, base_path_specs)
예제 #2
0
    def ScanSource(self, source_path):

        if os.path.islink(source_path):
            source_path = os.path.realpath(source_path)

        if (not source_path.startswith('\\\\.\\')
                and not os.path.exists(source_path)):
            raise errors.SourceScannerError(
                'No such device, file or directory: {0:s}.'.format(
                    source_path))

        scan_context = source_scanner.SourceScannerContext()
        scan_context.OpenSourcePath(source_path)

        try:
            self._source_scanner.Scan(scan_context)
        except (ValueError, dfvfs_errors.BackEndError) as exception:
            raise errors.SourceScannerError(
                'Unable to scan source with error: {0!s}.'.format(exception))

        # 경로를 입력받을 때
        if scan_context.source_type not in (
                scan_context.SOURCE_TYPE_STORAGE_MEDIA_DEVICE,
                scan_context.SOURCE_TYPE_STORAGE_MEDIA_IMAGE):
            scan_node = scan_context.GetRootScanNode()
            self._source_path_specs.append(scan_node.path_spec)
            return scan_context

        # Get the first node where where we need to decide what to process.
        scan_node = scan_context.GetRootScanNode()
        while len(scan_node.sub_nodes) == 1:
            scan_node = scan_node.sub_nodes[0]

        # if type_indicator가 TSK_PARTITION이 아닌 경우
        base_path_specs = []
        if scan_node.type_indicator != (
                dfvfs_definitions.TYPE_INDICATOR_TSK_PARTITION):
            self._ScanVolume(scan_context, scan_node, base_path_specs)

        # type_indicator가 TSK_PARTITION인 경우
        else:
            # Determine which partition needs to be processed.
            partition_identifiers = self._GetTSKPartitionIdentifiers(scan_node)
            if not partition_identifiers:
                raise errors.SourceScannerError('No partitions found.')

            for partition_identifier in partition_identifiers:
                location = '/{0:s}'.format(partition_identifier)
                sub_scan_node = scan_node.GetSubNodeByLocation(location)
                self._ScanVolume(scan_context, sub_scan_node, base_path_specs)

        if not base_path_specs:
            raise errors.SourceScannerError(
                'No supported file system found in source.')

        self._source_path_specs = base_path_specs

        return scan_context
예제 #3
0
    def _NormalizedVolumeIdentifiers(self,
                                     volume_system,
                                     volume_identifiers,
                                     prefix='v'):

        normalized_volume_identifiers = []
        for volume_identifier in volume_identifiers:
            if isinstance(volume_identifier, int):
                volume_identifier = '{0:s}{1:d}'.format(
                    prefix, volume_identifier)

            elif not volume_identifier.startswith(prefix):
                try:
                    volume_identifier = int(volume_identifier, 10)
                    volume_identifier = '{0:s}{1:d}'.format(
                        prefix, volume_identifier)
                except (TypeError, ValueError):
                    pass

            try:
                volume = volume_system.GetVolumeByIdentifier(volume_identifier)
            except KeyError:
                volume = None

            if not volume:
                raise errors.SourceScannerError(
                    'Volume missing for identifier: {0:s}.'.format(
                        volume_identifier))

            normalized_volume_identifiers.append(volume_identifier)

        return normalized_volume_identifiers
예제 #4
0
    def _GetVSSStoreIdentifiers(self, scan_node):

        if not scan_node or not scan_node.path_spec:
            raise errors.SourceScannerError('Invalid scan node.')

        volume_system = vshadow_volume_system.VShadowVolumeSystem()
        volume_system.Open(scan_node.path_spec)

        volume_identifiers = self._source_scanner.GetVolumeIdentifiers(
            volume_system)
        if not volume_identifiers:
            return []

        # TODO: refactor to use scan options.
        if self._vss_stores:
            if self._vss_stores == 'all':
                vss_stores = range(1, volume_system.number_of_volumes + 1)
            else:
                vss_stores = self._ParseVolumeIdentifiersString(
                    self._vss_stores, prefix='vss')

            selected_volume_identifiers = self._NormalizedVolumeIdentifiers(
                volume_system, vss_stores, prefix='vss')

            if not set(selected_volume_identifiers).difference(
                    volume_identifiers):
                return selected_volume_identifiers

        return self._NormalizedVolumeIdentifiers(volume_system,
                                                 volume_identifiers,
                                                 prefix='vss')
예제 #5
0
    def _GetTSKPartitionIdentifiers(self, scan_node):

        if not scan_node or not scan_node.path_spec:
            raise errors.SourceScannerError('Invalid scan node.')

        volume_system = tsk_volume_system.TSKVolumeSystem()
        volume_system.Open(scan_node.path_spec)

        volume_identifiers = self._source_scanner.GetVolumeIdentifiers(
            volume_system)
        if not volume_identifiers:
            return []

        # TODO: refactor self._partitions to use scan options.
        if self._partitions:
            if self._partitions == 'all':
                partitions = range(1, volume_system.number_of_volumes + 1)
            else:
                partitions = self._ParseVolumeIdentifiersString(
                    self._partitions, prefix='p')

            selected_volume_identifiers = self._NormalizedVolumeIdentifiers(
                volume_system, partitions, prefix='p')

            if not set(selected_volume_identifiers).difference(
                    volume_identifiers):
                return selected_volume_identifiers

        if len(volume_identifiers) == 1:
            return volume_identifiers

        return self._NormalizedVolumeIdentifiers(volume_system,
                                                 volume_identifiers,
                                                 prefix='p')
예제 #6
0
    def _ScanFileSystem(self, scan_node, base_path_specs):

        if not scan_node or not scan_node.path_spec:
            raise errors.SourceScannerError(
                'Invalid or missing file system scan node.')

        base_path_specs.append(scan_node.path_spec)
예제 #7
0
    def _ScanEncryptedVolume(self, scan_context, scan_node):
        """Scans an encrypted volume scan node for volume and file systems.

        Args:
          scan_context (SourceScannerContext): source scanner context.
          scan_node (SourceScanNode): volume scan node.

        Raises:
          SourceScannerError: if the format of or within the source is not
              supported, the scan node is invalid or there are no credentials
              defined for the format.
        """
        if not scan_node or not scan_node.path_spec:
            raise errors.SourceScannerError('Invalid or missing scan node.')

        credentials = credentials_manager.CredentialsManager.GetCredentials(
            scan_node.path_spec)
        if not credentials:
            raise errors.SourceScannerError(
                'Missing credentials for scan node.')

        credentials_dict = dict(self._credentials)

        is_unlocked = False
        for credential_type in credentials.CREDENTIALS:
            credential_data = credentials_dict.get(credential_type, None)
            if not credential_data:
                continue

            is_unlocked = self._source_scanner.Unlock(scan_context,
                                                      scan_node.path_spec,
                                                      credential_type,
                                                      credential_data)
            if is_unlocked:
                break

        if not is_unlocked:
            raise errors.Error('unlocked')
            # is_unlocked = self._PromptUserForEncryptedVolumeCredential(
            #     scan_context, scan_node, credentials)

        if is_unlocked:
            self._source_scanner.Scan(scan_context,
                                      scan_path_spec=scan_node.path_spec)
예제 #8
0
    def _GetAPFSVolumeIdentifiers(self, scan_node):
        """Determines the APFS volume identifiers.

        Args:
          scan_node (dfvfs.SourceScanNode): scan node.

        Returns:
          list[str]: APFS volume identifiers.

        Raises:
          SourceScannerError: if the format of or within the source is not
              supported or the the scan node is invalid.
          UserAbort: if the user requested to abort.
        """
        if not scan_node or not scan_node.path_spec:
            raise errors.SourceScannerError('Invalid scan node.')

        volume_system = apfs_volume_system.APFSVolumeSystem()
        volume_system.Open(scan_node.path_spec)

        volume_identifiers = self._source_scanner.GetVolumeIdentifiers(
            volume_system)
        if not volume_identifiers:
            return []

        # TODO: refactor self._volumes to use scan options.
        if self._volumes:
            if self._volumes == 'all':
                volumes = range(1, volume_system.number_of_volumes + 1)
            else:
                volumes = self._ParseVolumeIdentifiersString(self._volumes,
                                                             prefix='apfs')

            selected_volume_identifiers = self._NormalizedVolumeIdentifiers(
                volume_system, volumes, prefix='apfs')

            if not set(selected_volume_identifiers).difference(
                    volume_identifiers):
                return selected_volume_identifiers
        """if len(volume_identifiers) > 1:
            try:
                volume_identifiers = self._PromptUserForAPFSVolumeIdentifiers(
                    volume_system, volume_identifiers)
            except KeyboardInterrupt:
                raise errors.UserAbort('File system scan aborted.')"""

        return self._NormalizedVolumeIdentifiers(volume_system,
                                                 volume_identifiers,
                                                 prefix='apfs')
예제 #9
0
    def _ScanVolume(self, scan_context, scan_node, base_path_specs):

        if not scan_node or not scan_node.path_spec:
            raise errors.SourceScannerError('Invalid or missing scan node.')

        if scan_context.IsLockedScanNode(scan_node.path_spec):
            # The source scanner found a locked volume and we need a credential to
            # unlock it.
            self._ScanEncryptedVolume(scan_context, scan_node)

            if scan_context.IsLockedScanNode(scan_node.path_spec):
                return

        if scan_node.IsVolumeSystemRoot():
            self._ScanVolumeSystemRoot(scan_context, scan_node,
                                       base_path_specs)

        elif scan_node.IsFileSystem():
            self._ScanFileSystem(scan_node, base_path_specs)

        elif scan_node.type_indicator == dfvfs_definitions.TYPE_INDICATOR_VSHADOW:
            if self._process_vss:
                # TODO: look into building VSS store on demand.

                # We "optimize" here for user experience, alternatively we could scan
                # for a file system instead of hard coding a TSK child path
                # specification.
                path_spec = path_spec_factory.Factory.NewPathSpec(
                    dfvfs_definitions.TYPE_INDICATOR_TSK,
                    location='/',
                    parent=scan_node.path_spec)

                base_path_specs.append(path_spec)

        elif not scan_node.sub_nodes:
            if scan_node.type_indicator == dfvfs_definitions.TYPE_INDICATOR_TSK_PARTITION:
                base_path_specs.append(scan_node.path_spec)

        else:
            for sub_scan_node in scan_node.sub_nodes:
                self._ScanVolume(scan_context, sub_scan_node, base_path_specs)