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)
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
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
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')
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')
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)
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)
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')
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)