예제 #1
0
    def _GetVSSStoreIdentifiers(self, scan_node):
        """Determines the VSS store identifiers.

    Args:
      scan_node: the scan node (instance of dfvfs.ScanNode).

    Returns:
      A list of VSS store identifiers.

    Raises:
      ScannerError: if the format of or within the source is not supported,
                    the the scan node is invalid or no mediator is provided
                    and VSS store identifiers are found.
    """
        if not scan_node or not scan_node.path_spec:
            raise errors.ScannerError(u'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 self._mediator and not volume_identifiers:
            return []

        if not self._mediator:
            raise errors.ScannerError(
                u'Unable to proceed VSS. Identifiers found but no mediator to '
                u'determine how they should be used.')

        try:
            return self._mediator.GetVSSStoreIdentifiers(
                volume_system, volume_identifiers)
        except KeyboardInterrupt:
            raise errors.UserAbort(u'File system scan aborted.')
예제 #2
0
  def OpenFile(self, windows_path):
    """Opens the file specified by the Windows path.

    Args:
      windows_path (str): Windows path to the file.

    Returns:
      dfvfs.FileIO: file-like object or None if the file does not exist.

    Raises:
      ScannerError: if the scan node is invalid or the scanner does not know
          how to proceed.
    """
    windows_path_upper = windows_path.upper()
    if windows_path_upper.startswith('%USERPROFILE%'):
      if not self._mediator:
        raise dfvfs_errors.ScannerError(
            'Unable to proceed. %UserProfile% found in Windows path but no '
            'mediator to determine which user to select.')

      users_path_spec = self._path_resolver.ResolvePath('\\Users')
      # TODO: handle alternative users path locations
      if users_path_spec is None:
        raise dfvfs_errors.ScannerError(
            'Unable to proceed. %UserProfile% found in Windows path but no '
            'users path found to determine which user to select.')

      users_file_entry = dfvfs_resolver.Resolver.OpenFileEntry(users_path_spec)
      self._mediator.PrintUsersSubDirectoriesOverview(users_file_entry)

      # TODO: list users and determine corresponding windows_path

    return super(WindowsRegistryVolumeScanner, self).OpenFile(windows_path)
예제 #3
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:
      ScannerError: if the format of or within the source is not supported,
          the scan node is invalid, there are no credentials defined for
          the format or no mediator is provided and a locked scan node was
          found, e.g. an encrypted volume,
    """
    if not scan_node or not scan_node.path_spec:
      raise errors.ScannerError('Invalid or missing scan node.')

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

    if not self._mediator:
      raise errors.ScannerError(
          'Unable to proceed. Encrypted volume found but no mediator to '
          'determine how it should be unlocked.')

    if self._mediator.UnlockEncryptedVolume(
        self._source_scanner, scan_context, scan_node, credentials):
      self._source_scanner.Scan(
          scan_context, scan_path_spec=scan_node.path_spec)
예제 #4
0
    def _GetTSKPartitionIdentifiers(self, scan_node):
        """Determines the TSK partition identifiers.

    Args:
      scan_node: the scan node (instance of dfvfs.ScanNode).

    Returns:
      A list of partition identifiers.

    Raises:
      ScannerError: if the format of or within the source is not supported or
                    the the scan node is invalid or if the volume for
                    a specific identifier cannot be retrieved.
    """
        if not scan_node or not scan_node.path_spec:
            raise errors.ScannerError(u'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:
            raise errors.ScannerError(u'No partitions found.')

        if not self._mediator or len(volume_identifiers) == 1:
            return volume_identifiers

        try:
            return self._mediator.GetPartitionIdentifiers(
                volume_system, volume_identifiers)
        except KeyboardInterrupt:
            raise errors.ScannerError(u'File system scan aborted.')
예제 #5
0
    def _GetVSSStoreIdentifiers(self, scan_node, options):
        """Determines the VSS store identifiers.

    Args:
      scan_node (SourceScanNode): scan node.
      options (VolumeScannerOptions): volume scanner options.

    Returns:
      list[str]: VSS store identifiers.

    Raises:
      ScannerError: if the format the scan node is invalid or no mediator
          is provided and VSS store identifiers are found.
      UserAbort: if the user requested to abort.
    """
        if not scan_node or not scan_node.path_spec:
            raise errors.ScannerError('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 []

        if options.snapshots:
            if options.snapshots == ['all']:
                snapshots = range(1, volume_system.number_of_volumes + 1)
            elif options.snapshots == ['none']:
                snapshots = []
            else:
                snapshots = options.snapshots

            try:
                selected_volumes = self._NormalizedVolumeIdentifiers(
                    volume_system, snapshots, prefix='vss')

                if not set(selected_volumes).difference(volume_identifiers):
                    return selected_volumes
            except errors.ScannerError as exception:
                if self._mediator:
                    self._mediator.PrintWarning('{0!s}'.format(exception))

        if not self._mediator:
            raise errors.ScannerError(
                'Unable to proceed. VSS stores found but no mediator to determine '
                'how they should be used.')

        try:
            volume_identifiers = self._mediator.GetVSSStoreIdentifiers(
                volume_system, volume_identifiers)

        except KeyboardInterrupt:
            raise errors.UserAbort('File system scan aborted.')

        return self._NormalizedVolumeIdentifiers(volume_system,
                                                 volume_identifiers,
                                                 prefix='vss')
예제 #6
0
    def _GetAPFSVolumeIdentifiers(self, scan_node, options):
        """Determines the APFS volume identifiers.

    Args:
      scan_node (SourceScanNode): scan node.
      options (VolumeScannerOptions): volume scanner options.

    Returns:
      list[str]: APFS volume identifiers.

    Raises:
      ScannerError: 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.ScannerError('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 []

        if options.volumes:
            if options.volumes == ['all']:
                volumes = range(1, volume_system.number_of_volumes + 1)
            else:
                volumes = options.volumes

            try:
                selected_volumes = self._NormalizedVolumeIdentifiers(
                    volume_system, volumes, prefix='apfs')

                if not set(selected_volumes).difference(volume_identifiers):
                    return selected_volumes
            except errors.ScannerError as exception:
                if self._mediator:
                    self._mediator.PrintWarning('{0!s}'.format(exception))

        if len(volume_identifiers) > 1:
            if not self._mediator:
                raise errors.ScannerError(
                    'Unable to proceed. APFS volumes found but no mediator to '
                    'determine how they should be used.')

            try:
                volume_identifiers = self._mediator.GetAPFSVolumeIdentifiers(
                    volume_system, volume_identifiers)
            except KeyboardInterrupt:
                raise errors.UserAbort('File system scan aborted.')

        return self._NormalizedVolumeIdentifiers(volume_system,
                                                 volume_identifiers,
                                                 prefix='apfs')
예제 #7
0
    def _ScanFileSystem(self, scan_node, base_path_specs):
        """Scans a file system scan node for file systems.

    This method checks if the file system contains a known Windows directory.

    Args:
      scan_node (SourceScanNode): file system scan node.
      base_path_specs (list[PathSpec]): file system base path specifications.

    Raises:
      ScannerError: if the scan node is invalid.
    """
        if not scan_node or not scan_node.path_spec:
            raise errors.ScannerError(
                'Invalid or missing file system scan node.')

        file_system = resolver.Resolver.OpenFileSystem(scan_node.path_spec)
        if not file_system:
            return

        try:
            path_resolver = windows_path_resolver.WindowsPathResolver(
                file_system, scan_node.path_spec.parent)

            if self._ScanFileSystemForWindowsDirectory(path_resolver):
                base_path_specs.append(scan_node.path_spec)

        finally:
            file_system.Close()
예제 #8
0
    def _PrintAPFSVolumeIdentifiersOverview(self, volume_system,
                                            volume_identifiers):
        """Prints an overview of APFS volume identifiers.

    Args:
      volume_system (APFSVolumeSystem): volume system.
      volume_identifiers (list[str]): allowed volume identifiers.

    Raises:
      ScannerError: if a volume cannot be resolved from the volume identifier.
    """
        header = 'The following Apple File System (APFS) volumes were found:\n'
        self._output_writer.Write(header)

        column_names = ['Identifier', 'Name']
        table_view = CLITabularTableView(column_names=column_names)

        for volume_identifier in volume_identifiers:
            volume = volume_system.GetVolumeByIdentifier(volume_identifier)
            if not volume:
                raise errors.ScannerError(
                    'Volume missing for identifier: {0:s}.'.format(
                        volume_identifier))

            volume_attribute = volume.GetAttribute('name')
            table_view.AddRow([volume.identifier, volume_attribute.value])

        self._output_writer.Write('\n')
        table_view.Write(self._output_writer)
예제 #9
0
    def _PrintPartitionIdentifiersOverview(self, volume_system,
                                           volume_identifiers):
        """Prints an overview of TSK partition identifiers.

    Args:
      volume_system (TSKVolumeSystem): volume system.
      volume_identifiers (list[str]): allowed volume identifiers.

    Raises:
      ScannerError: if a volume cannot be resolved from the volume identifier.
    """
        header = 'The following partitions were found:\n'
        self._output_writer.Write(header)

        column_names = ['Identifier', 'Offset (in bytes)', 'Size (in bytes)']
        table_view = CLITabularTableView(column_names=column_names)

        for volume_identifier in sorted(volume_identifiers):
            volume = volume_system.GetVolumeByIdentifier(volume_identifier)
            if not volume:
                raise errors.ScannerError(
                    'Partition missing for identifier: {0:s}.'.format(
                        volume_identifier))

            volume_extent = volume.extents[0]
            volume_offset = '{0:d} (0x{0:08x})'.format(volume_extent.offset)
            volume_size = self._FormatHumanReadableSize(volume_extent.size)

            table_view.AddRow([volume.identifier, volume_offset, volume_size])

        self._output_writer.Write('\n')
        table_view.Write(self._output_writer)
예제 #10
0
  def GetPartitionIdentifiers(self, volume_system, volume_identifiers):
    """Retrieves partition identifiers.

    This method can be used to prompt the user to provide partition identifiers.

    Args:
      volume_system: the volume system (instance of dfvfs.TSKVolumeSystem).
      volume_identifiers: a list of strings containing the volume identifiers.

    Returns:
      A list of strings containing the selected partition identifiers or None.

    Raises:
      ScannerError: if the source cannot be processed.
    """
    print(u'The following partitions were found:')
    print(u'Identifier\tOffset (in bytes)\tSize (in bytes)')

    for volume_identifier in sorted(volume_identifiers):
      volume = volume_system.GetVolumeByIdentifier(volume_identifier)
      if not volume:
        raise errors.ScannerError(
            u'Volume missing for identifier: {0:s}.'.format(volume_identifier))

      volume_extent = volume.extents[0]
      print(u'{0:s}\t\t{1:d} (0x{1:08x})\t{2:s}'.format(
          volume.identifier, volume_extent.offset,
          self._FormatHumanReadableSize(volume_extent.size)))

    while True:
      print(
          u'Please specify the identifier of the partition that should be '
          u'processed.')
      print(
          u'All partitions can be defined as: "all". Note that you '
          u'can abort with Ctrl^C.')

      selected_volume_identifier = sys.stdin.readline()
      selected_volume_identifier = selected_volume_identifier.strip()

      if not selected_volume_identifier.startswith(u'p'):
        try:
          partition_number = int(selected_volume_identifier, 10)
          selected_volume_identifier = u'p{0:d}'.format(partition_number)
        except ValueError:
          pass

      if selected_volume_identifier == u'all':
        return volume_identifiers

      if selected_volume_identifier in volume_identifiers:
        break

      print(u'')
      print(
          u'Unsupported partition identifier, please try again or abort '
          u'with Ctrl^C.')
      print(u'')

    return [selected_volume_identifier]
예제 #11
0
  def _PrintLVMVolumeIdentifiersOverview(
      self, volume_system, volume_identifiers):
    """Prints an overview of LVM volume identifiers.

    Args:
      volume_system (LVMVolumeSystem): volume system.
      volume_identifiers (list[str]): allowed volume identifiers.

    Raises:
      ScannerError: if a volume cannot be resolved from the volume identifier.
    """
    header = 'The following Logical Volume Manager (LVM) volumes were found:\n'
    self._output_writer.Write(header)

    column_names = ['Identifier']
    table_view = CLITabularTableView(column_names=column_names)

    # Sort the volume identifiers in alphanumeric order.
    for volume_identifier in sorted(volume_identifiers, key=lambda string: int(
        ''.join([character for character in string if character.isdigit()]))):
      volume = volume_system.GetVolumeByIdentifier(volume_identifier)
      if not volume:
        raise errors.ScannerError(
            'Volume missing for identifier: {0:s}.'.format(
                volume_identifier))

      table_view.AddRow([volume.identifier])

    self._output_writer.Write('\n')
    table_view.Write(self._output_writer)
예제 #12
0
    def _ScanVolumeScanNodeEncrypted(self, scan_context, volume_scan_node,
                                     base_path_specs):
        """Scans an encrypted volume scan node for volume and file systems.

    Args:
      scan_context (SourceScannerContext): source scanner context.
      volume_scan_node (SourceScanNode): volume scan node.
      base_path_specs (list[PathSpec]): file system base path specifications.

    Raises:
      ScannerError: if the scan node is invalid.
    """
        if not volume_scan_node or not volume_scan_node.path_spec:
            raise errors.ScannerError(u'Invalid or missing volume scan node.')

        result = not scan_context.IsLockedScanNode(volume_scan_node.path_spec)
        if not result:
            credentials = credentials_manager.CredentialsManager.GetCredentials(
                volume_scan_node.path_spec)

            result = self._mediator.UnlockEncryptedVolume(
                self._source_scanner, scan_context, volume_scan_node,
                credentials)

        if result:
            self._source_scanner.Scan(
                scan_context, scan_path_spec=volume_scan_node.path_spec)
            self._ScanVolume(scan_context, volume_scan_node, base_path_specs)
예제 #13
0
    def _ScanVolume(self, scan_context, volume_scan_node, base_path_specs):
        """Scans the volume scan node for volume and file systems.

    Args:
      scan_context (SourceScannerContext): source scanner context.
      volume_scan_node (SourceScanNode): volume scan node.
      base_path_specs (list[PathSpec]): file system base path specifications.

    Raises:
      ScannerError: if the format of or within the source
                    is not supported or the scan node is invalid.
    """
        if not volume_scan_node or not volume_scan_node.path_spec:
            raise errors.ScannerError(u'Invalid or missing volume scan node.')

        if len(volume_scan_node.sub_nodes) == 0:
            self._ScanVolumeScanNode(scan_context, volume_scan_node,
                                     base_path_specs)

        else:
            # Some volumes contain other volume or file systems e.g. BitLocker ToGo
            # has an encrypted and unencrypted volume.
            for sub_scan_node in volume_scan_node.sub_nodes:
                self._ScanVolumeScanNode(scan_context, sub_scan_node,
                                         base_path_specs)
예제 #14
0
  def _ScanVolumeSystemRoot(
      self, scan_context, scan_node, options, base_path_specs):
    """Scans a volume system root scan node for volume and file systems.

    Args:
      scan_context (SourceScannerContext): source scanner context.
      scan_node (SourceScanNode): volume system root scan node.
      options (VolumeScannerOptions): volume scanner options.
      base_path_specs (list[PathSpec]): file system base path specifications.

    Raises:
      ScannerError: if the scan node is invalid, the scan node type is not
          supported or if a sub scan node cannot be retrieved.
    """
    if not scan_node or not scan_node.path_spec:
      raise errors.ScannerError('Invalid scan node.')

    if scan_node.type_indicator == definitions.TYPE_INDICATOR_APFS_CONTAINER:
      volume_identifiers = self._GetAPFSVolumeIdentifiers(scan_node, options)

    elif scan_node.type_indicator == definitions.TYPE_INDICATOR_GPT:
      volume_identifiers = self._GetPartitionIdentifiers(scan_node, options)

    elif scan_node.type_indicator == definitions.TYPE_INDICATOR_LVM:
      volume_identifiers = self._GetLVMVolumeIdentifiers(scan_node, options)

    elif scan_node.type_indicator == definitions.TYPE_INDICATOR_VSHADOW:
      volume_identifiers = self._GetVSSStoreIdentifiers(scan_node, options)
      # Process VSS stores (snapshots) starting with the most recent one.
      volume_identifiers.reverse()

    else:
      raise errors.ScannerError(
          '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.ScannerError(
            'Scan node missing for volume identifier: {0:s}.'.format(
                volume_identifier))

      self._ScanVolume(scan_context, sub_scan_node, options, base_path_specs)
예제 #15
0
    def _GetTSKPartitionIdentifiers(self, scan_node):
        """Determines the TSK partition identifiers.

    Args:
      scan_node (SourceScanNode): scan node.

    Returns:
      list[str]: TSK partition identifiers.

    Raises:
      ScannerError: if the format of or within the source is not supported or
          the scan node is invalid or if the volume for a specific identifier
          cannot be retrieved.
      UserAbort: if the user requested to abort.
    """
        if not scan_node or not scan_node.path_spec:
            raise errors.ScannerError('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 []

        if len(volume_identifiers) == 1:
            return volume_identifiers

        if not self._mediator:
            raise errors.ScannerError(
                'Unable to proceed. Partitions found but no mediator to determine '
                'how they should be used.')

        try:
            volume_identifiers = self._mediator.GetPartitionIdentifiers(
                volume_system, volume_identifiers)

        except KeyboardInterrupt:
            raise errors.UserAbort('File system scan aborted.')

        return self._NormalizedVolumeIdentifiers(volume_system,
                                                 volume_identifiers,
                                                 prefix='p')
예제 #16
0
    def _GetAPFSVolumeIdentifiers(self, scan_node):
        """Determines the APFS volume identifiers.

    Args:
      scan_node (SourceScanNode): scan node.

    Returns:
      list[str]: APFS volume identifiers.

    Raises:
      ScannerError: 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.ScannerError('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 []

        if len(volume_identifiers) > 1:
            if not self._mediator:
                raise errors.ScannerError(
                    'Unable to proceed. APFS volumes found but no mediator to '
                    'determine how they should be used.')

            try:
                volume_identifiers = self._mediator.GetAPFSVolumeIdentifiers(
                    volume_system, volume_identifiers)
            except KeyboardInterrupt:
                raise errors.UserAbort('File system scan aborted.')

        return self._NormalizedVolumeIdentifiers(volume_system,
                                                 volume_identifiers,
                                                 prefix='apfs')
예제 #17
0
    def _ScanVolumeScanNodeVSS(self, volume_scan_node, base_path_specs):
        """Scans a VSS volume scan node for volume and file systems.

    Args:
      volume_scan_node (SourceScanNode): volume scan node.
      base_path_specs (list[PathSpec]): file system base path specifications.

    Raises:
      ScannerError: if a VSS sub scan node scannot be retrieved or
                    if the scan node is invalid.
    """
        if not volume_scan_node or not volume_scan_node.path_spec:
            raise errors.ScannerError(u'Invalid or missing volume scan node.')

        # Do not scan inside individual VSS store scan nodes.
        location = getattr(volume_scan_node.path_spec, u'location', None)
        if location != u'/':
            return

        vss_store_identifiers = self._GetVSSStoreIdentifiers(volume_scan_node)

        self._vss_stores = list(vss_store_identifiers)

        # Process VSS stores starting with the most recent one.
        vss_store_identifiers.reverse()
        for vss_store_identifier in vss_store_identifiers:
            location = u'/vss{0:d}'.format(vss_store_identifier)
            sub_scan_node = volume_scan_node.GetSubNodeByLocation(location)
            if not sub_scan_node:
                raise errors.ScannerError(
                    u'Scan node missing for VSS store identifier: {0:d}.'.
                    format(vss_store_identifier))

            # 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(
                definitions.TYPE_INDICATOR_TSK,
                location=u'/',
                parent=sub_scan_node.path_spec)
            base_path_specs.append(path_spec)
예제 #18
0
    def _GetVSSStoreIdentifiers(self, scan_node):
        """Determines the VSS store identifiers.

    Args:
      scan_node (SourceScanNode): scan node.

    Returns:
      list[str]: VSS store identifiers.

    Raises:
      ScannerError: if the format the scan node is invalid or no mediator
          is provided and VSS store identifiers are found.
      UserAbort: if the user requested to abort.
    """
        if not scan_node or not scan_node.path_spec:
            raise errors.ScannerError('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 []

        if not self._mediator:
            raise errors.ScannerError(
                'Unable to proceed. VSS stores found but no mediator to determine '
                'how they should be used.')

        try:
            volume_identifiers = self._mediator.GetVSSStoreIdentifiers(
                volume_system, volume_identifiers)

        except KeyboardInterrupt:
            raise errors.UserAbort('File system scan aborted.')

        return self._NormalizedVolumeIdentifiers(volume_system,
                                                 volume_identifiers,
                                                 prefix='vss')
예제 #19
0
  def _ScanFileSystem(self, scan_node, base_path_specs):
    """Scans a file system scan node for file systems.

    Args:
      scan_node (SourceScanNode): file system scan node.
      base_path_specs (list[PathSpec]): file system base path specifications.

    Raises:
      ScannerError: if the scan node is invalid.
    """
    if not scan_node or not scan_node.path_spec:
      raise errors.ScannerError('Invalid or missing file system scan node.')

    base_path_specs.append(scan_node.path_spec)
예제 #20
0
    def _GetBasePathSpecs(self, scan_context, options):
        """Determines the base path specifications.

    Args:
      scan_context (SourceScannerContext): source scanner context.
      options (VolumeScannerOptions): volume scanner options.

    Returns:
      list[PathSpec]: path specifications.

    Raises:
      dfvfs.ScannerError: if the format of or within the source is not
          supported or no partitions were found.
    """
        # TODO: difference with dfVFS.
        self._snapshots_only = options.snapshots_only

        scan_node = scan_context.GetRootScanNode()

        if scan_context.source_type not in (
                scan_context.SOURCE_TYPE_STORAGE_MEDIA_DEVICE,
                scan_context.SOURCE_TYPE_STORAGE_MEDIA_IMAGE):
            return [scan_node.path_spec]

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

        base_path_specs = []
        if scan_node.type_indicator not in (
                dfvfs_definitions.TYPE_INDICATOR_GPT,
                dfvfs_definitions.TYPE_INDICATOR_TSK_PARTITION):
            self._ScanVolume(scan_context, scan_node, options, base_path_specs)

        else:
            # Determine which partition needs to be processed.
            partition_identifiers = self._GetPartitionIdentifiers(
                scan_node, options)
            # TODO: difference with dfVFS.
            if not partition_identifiers:
                raise dfvfs_errors.ScannerError('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, options,
                                 base_path_specs)

        return base_path_specs
예제 #21
0
    def _ScanVolume(self, scan_context, scan_node, options, base_path_specs):
        """Scans a volume scan node for volume and file systems.
    Args:
      scan_context (SourceScannerContext): source scanner context.
      scan_node (SourceScanNode): volume scan node.
      options (VolumeScannerOptions): volume scanner options.
      base_path_specs (list[PathSpec]): file system base path specifications.

    Raises:
      ScannerError: if the format of or within the source
          is not supported or the scan node is invalid.
    """
        if not scan_node or not scan_node.path_spec:
            raise errors.ScannerError('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():
            if options.scan_mode in (options.SCAN_MODE_ALL,
                                     options.SCAN_MODE_SNAPSHOTS_ONLY):
                self._ScanVolumeSystemRoot(scan_context, scan_node, options,
                                           base_path_specs)

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

        elif scan_node.type_indicator == definitions.TYPE_INDICATOR_VSHADOW:
            # 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(
                definitions.TYPE_INDICATOR_TSK,
                location='/',
                parent=scan_node.path_spec)

            base_path_specs.append(path_spec)

        else:
            for sub_scan_node in scan_node.sub_nodes:
                self._ScanVolume(scan_context, sub_scan_node, options,
                                 base_path_specs)
예제 #22
0
    def _ScanFileSystem(self, file_system_scan_node, base_path_specs):
        """Scans a file system scan node for file systems.

    Args:
      file_system_scan_node: the file system scan node (instance of
                             dfvfs.ScanNode).
      base_path_specs: a list of source path specification (instances
                       of dfvfs.PathSpec).

    Raises:
      ScannerError: if the scan node is invalid.
    """
        if not file_system_scan_node or not file_system_scan_node.path_spec:
            raise errors.ScannerError(
                u'Invalid or missing file system scan node.')

        base_path_specs.append(file_system_scan_node.path_spec)
예제 #23
0
    def _NormalizedVolumeIdentifiers(self,
                                     volume_system,
                                     volume_identifiers,
                                     prefix='v'):
        """Normalizes volume identifiers.

    Args:
      volume_system (VolumeSystem): volume system.
      volume_identifiers (list[int|str]): allowed volume identifiers, formatted
          as an integer or string with prefix.
      prefix (Optional[str]): volume identifier prefix.

    Returns:
      list[str]: volume identifiers with prefix.

    Raises:
      ScannerError: if the volume identifier is not supported or no volume
          could be found that corresponds with the identifier.
    """
        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.ScannerError(
                    'Volume missing for identifier: {0:s}.'.format(
                        volume_identifier))

            normalized_volume_identifiers.append(volume_identifier)

        return normalized_volume_identifiers
예제 #24
0
    def GetPartitionIdentifiers(self, volume_system, volume_identifiers):
        """Retrieves partition identifiers that should be scanned

        Args:
          volume_system: the volume system (instance of dfvfs.TSKVolumeSystem).
          volume_identifiers: a list of strings containing the volume identifiers.

        Returns:
          A list of strings containing the selected partition identifiers or None.

        Raises:
          ScannerError: if the source cannot be processed.
        """

        LOGGER.info('The following partitions were found:')
        LOGGER.info('Identifier\tOffset (in bytes)\tSize (in bytes)')

        for volume_identifier in sorted(volume_identifiers):
            volume = volume_system.GetVolumeByIdentifier(volume_identifier)
            if not volume:
                raise dfvfs_errors.ScannerError(
                    'Volume missing for identifier: {0:s}.'.format(
                        volume_identifier))

            volume_extent = volume.extents[0]
            LOGGER.info('{0:s}\t\t{1:d} (0x{1:08x})\t{2:s}'.format(
                volume.identifier, volume_extent.offset,
                self._FormatHumanReadableSize(volume_extent.size)))

        selected_volume_identifier = self._partitions
        selected_volume_identifier = selected_volume_identifier.strip()

        if not selected_volume_identifier.startswith('p'):
            try:
                partition_number = int(selected_volume_identifier, 10)
                selected_volume_identifier = 'p{0:d}'.format(partition_number)
            except ValueError:
                pass

        LOGGER.info("Selected partition(s): %s", selected_volume_identifier)
        if selected_volume_identifier == 'all':
            return volume_identifiers

        return [selected_volume_identifier]
예제 #25
0
    def _ScanFileSystem(self, scan_node, base_path_specs):
        """Scans a file system scan node for file systems.

    Args:
      scan_node (SourceScanNode): file system scan node.
      base_path_specs (list[PathSpec]): file system base path specifications.

    Raises:
      dfvfs.ScannerError: if the scan node is invalid.
    """
        if not scan_node or not scan_node.path_spec:
            raise dfvfs_errors.ScannerError(
                'Invalid or missing file system scan node.')

        # TODO: difference with dfVFS for current VSS volume support.
        if self._snapshots_only:
            if scan_node.parent_node.sub_nodes[0].type_indicator == (
                    dfvfs_definitions.TYPE_INDICATOR_VSHADOW):
                return

        base_path_specs.append(scan_node.path_spec)
예제 #26
0
    def _ScanVolumeScanNode(self, scan_context, volume_scan_node,
                            base_path_specs):
        """Scans an individual volume scan node for volume and file systems.

    Args:
      scan_context: the source scanner context (instance of
                    SourceScannerContext).
      volume_scan_node: the volume scan node (instance of dfvfs.ScanNode).
      base_path_specs: a list of source path specification (instances
                       of dfvfs.PathSpec).

    Raises:
      ScannerError: if the format of or within the source
                    is not supported or the the scan node is invalid.
    """
        if not volume_scan_node or not volume_scan_node.path_spec:
            raise errors.ScannerError(u'Invalid or missing volume scan node.')

        # Get the first node where where we need to decide what to process.
        scan_node = volume_scan_node
        while len(scan_node.sub_nodes) == 1:
            # Make sure that we prompt the user about VSS selection.
            if scan_node.type_indicator == definitions.TYPE_INDICATOR_VSHADOW:
                location = getattr(scan_node.path_spec, u'location', None)
                if location == u'/':
                    break

            scan_node = scan_node.sub_nodes[0]

        # The source scanner found an encrypted volume and we need
        # a credential to unlock the volume.
        if scan_node.type_indicator in definitions.ENCRYPTED_VOLUME_TYPE_INDICATORS:
            self._ScanVolumeScanNodeEncrypted(scan_context, scan_node,
                                              base_path_specs)

        elif scan_node.type_indicator == definitions.TYPE_INDICATOR_VSHADOW:
            self._ScanVolumeScanNodeVSS(scan_node, base_path_specs)

        elif scan_node.type_indicator in definitions.FILE_SYSTEM_TYPE_INDICATORS:
            self._ScanFileSystem(scan_node, base_path_specs)
예제 #27
0
  def _PrintVSSStoreIdentifiersOverview(
      self, volume_system, volume_identifiers):
    """Prints an overview of VSS store identifiers.

    Args:
      volume_system (VShadowVolumeSystem): volume system.
      volume_identifiers (list[str]): allowed volume identifiers.

    Raises:
      ScannerError: if a volume cannot be resolved from the volume identifier.
    """
    header = 'The following Volume Shadow Snapshots (VSS) were found:\n'
    self._output_writer.Write(header)

    column_names = ['Identifier', 'Creation Time']
    table_view = CLITabularTableView(column_names=column_names)

    # Sort the volume identifiers in alphanumeric order.
    for volume_identifier in sorted(volume_identifiers, key=lambda string: int(
        ''.join([character for character in string if character.isdigit()]))):
      volume = volume_system.GetVolumeByIdentifier(volume_identifier)
      if not volume:
        raise errors.ScannerError(
            'Volume missing for identifier: {0:s}.'.format(
                volume_identifier))

      volume_attribute = volume.GetAttribute('creation_time')
      filetime = dfdatetime_filetime.Filetime(timestamp=volume_attribute.value)
      creation_time = filetime.CopyToDateTimeString()

      if volume.HasExternalData():
        creation_time = '{0:s}\tWARNING: data stored outside volume'.format(
            creation_time)

      table_view.AddRow([volume.identifier, creation_time])

    self._output_writer.Write('\n')
    table_view.Write(self._output_writer)
예제 #28
0
    def GetVSSStoreIdentifiers(self, volume_system, volume_identifiers):
        """Retrieves VSS store identifiers.

    This method can be used to prompt the user to provide VSS store identifiers.

    Args:
      volume_system (VShadowVolumeSystem): volume system.
      volume_identifiers (list[str]): volume identifiers.

    Returns:
      list[int]: selected VSS store numbers or None.

    Raises:
      ScannerError: if the source cannot be processed.
    """
        normalized_volume_identifiers = []
        for volume_identifier in volume_identifiers:
            volume = volume_system.GetVolumeByIdentifier(volume_identifier)
            if not volume:
                raise errors.ScannerError(
                    'Volume missing for identifier: {0:s}.'.format(
                        volume_identifier))

            try:
                volume_identifier = int(volume.identifier[3:], 10)
                normalized_volume_identifiers.append(volume_identifier)
            except ValueError:
                pass

        print_header = True
        while True:
            if print_header:
                print(
                    'The following Volume Shadow Snapshots (VSS) were found:')
                print('Identifier\tVSS store identifier')

                for volume_identifier in volume_identifiers:
                    volume = volume_system.GetVolumeByIdentifier(
                        volume_identifier)
                    if not volume:
                        raise errors.ScannerError(
                            'Volume missing for identifier: {0:s}.'.format(
                                volume_identifier))

                    vss_identifier = volume.GetAttribute('identifier')
                    print('{0:s}\t\t{1:s}'.format(volume.identifier,
                                                  vss_identifier.value))

                print('')

                print_header = False

            print('Please specify the identifier(s) of the VSS that should be '
                  'processed:')
            print(
                'Note that a range of stores can be defined as: 3..5. Multiple '
                'stores can')
            print(
                'be defined as: 1,3,5 (a list of comma separated values). Ranges '
                'and lists can')
            print(
                'also be combined as: 1,3..5. The first store is 1. All stores '
                'can be defined')
            print(
                'as "all". If no stores are specified none will be processed. Yo'
            )
            print('can abort with Ctrl^C.')

            selected_vss_stores = sys.stdin.readline()

            selected_vss_stores = selected_vss_stores.strip()
            if not selected_vss_stores:
                selected_vss_stores = []
                break

            try:
                selected_vss_stores = self._ParseVSSStoresString(
                    selected_vss_stores)
            except ValueError:
                selected_vss_stores = []

            if selected_vss_stores == ['all']:
                # We need to set the stores to cover all vss stores.
                selected_vss_stores = range(
                    1, volume_system.number_of_volumes + 1)

            if not set(selected_vss_stores).difference(
                    normalized_volume_identifiers):
                break

            print('')
            print(
                'Unsupported VSS identifier(s), please try again or abort with '
                'Ctrl^C.')
            print('')

        return selected_vss_stores
예제 #29
0
  def GetBasePathSpecs(self, source_path, options=None):
    """Determines the base path specifications.

    Args:
      source_path (str): source path.
      options (Optional[VolumeScannerOptions]): volume scanner options. If None
          the default volume scanner options are used, which are defined in the
          VolumeScannerOptions class.

    Returns:
      list[PathSpec]: path specifications.

    Raises:
      ScannerError: if the source path does not exists, or if the source path
          is not a file or directory, or if the format of or within the source
          file is not supported.
    """
    if not options:
      options = VolumeScannerOptions()

    if not source_path:
      raise errors.ScannerError('Invalid source path.')

    # Note that os.path.exists() does not support Windows device paths.
    if (not source_path.startswith('\\\\.\\') and
        not os.path.exists(source_path)):
      raise errors.ScannerError(
          '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, errors.BackEndError) as exception:
      raise errors.ScannerError(
          'Unable to scan source with error: {0!s}'.format(exception))

    self._source_path = source_path
    self._source_type = scan_context.source_type

    if self._source_type not in [
        definitions.SOURCE_TYPE_STORAGE_MEDIA_DEVICE,
        definitions.SOURCE_TYPE_STORAGE_MEDIA_IMAGE]:
      scan_node = scan_context.GetRootScanNode()
      return [scan_node.path_spec]

    # 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]

    base_path_specs = []
    if scan_node.type_indicator not in (
          definitions.TYPE_INDICATOR_GPT,
          definitions.TYPE_INDICATOR_TSK_PARTITION):
      self._ScanVolume(scan_context, scan_node, options, base_path_specs)

    else:
      # Determine which partition needs to be processed.
      partition_identifiers = self._GetPartitionIdentifiers(scan_node, options)
      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, options, base_path_specs)

    return base_path_specs
예제 #30
0
  def _GetPartitionIdentifiers(self, scan_node, options):
    """Determines the partition identifiers.

    This function determines which partition identifiers need to be scanned
    based on the volume scanner options. If no options are provided and there
    is more than a single partition the mediator is used to ask the user.

    Args:
      scan_node (SourceScanNode): scan node.
      options (VolumeScannerOptions): volume scanner options.

    Returns:
      list[str]: partition identifiers.

    Raises:
      ScannerError: if the scan node is invalid or the scanner does not know
          how to proceed.
      UserAbort: if the user requested to abort.
    """
    if not scan_node or not scan_node.path_spec:
      raise errors.ScannerError('Invalid scan node.')

    if scan_node.path_spec.type_indicator == definitions.TYPE_INDICATOR_GPT:
      volume_system = gpt_volume_system.GPTVolumeSystem()
      volume_system.Open(scan_node.path_spec)
      prefix = 'gpt'
    else:
      volume_system = tsk_volume_system.TSKVolumeSystem()
      volume_system.Open(scan_node.path_spec)
      prefix = 'p'

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

    if options.partitions:
      if options.partitions == ['all']:
        partitions = range(1, volume_system.number_of_volumes + 1)
      else:
        partitions = options.partitions

      try:
        selected_volumes = self._NormalizedVolumeIdentifiers(
            volume_system, partitions, prefix=prefix)

        if not set(selected_volumes).difference(volume_identifiers):
          return selected_volumes
      except errors.ScannerError as exception:
        if self._mediator:
          self._mediator.PrintWarning('{0!s}'.format(exception))

    if len(volume_identifiers) > 1:
      if not self._mediator:
        raise errors.ScannerError(
            'Unable to proceed. More than one partitions found but no mediator '
            'to determine how they should be used.')

      try:
        volume_identifiers = self._mediator.GetPartitionIdentifiers(
            volume_system, volume_identifiers)

      except KeyboardInterrupt:
        raise errors.UserAbort('File system scan aborted.')

    return self._NormalizedVolumeIdentifiers(
        volume_system, volume_identifiers, prefix=prefix)