def testIterateVolumes(self): """Test the iterate volumes functionality.""" volume_system = tsk_volume_system.TSKVolumeSystem() volume_system.Open(self._tsk_path_spec) self.assertEqual(volume_system.bytes_per_sector, 512) self.assertEqual(volume_system.number_of_sections, 7) self.assertEqual(volume_system.number_of_volumes, 2) volume = volume_system.GetVolumeByIndex(1) self.assertIsNotNone(volume) self.assertEqual(volume.number_of_extents, 1) self.assertEqual(volume.number_of_attributes, 2) self.assertEqual(volume.identifier, 'p2') expected_value = 6 volume_attribute = volume.GetAttribute('address') self.assertIsNotNone(volume_attribute) self.assertEqual(volume_attribute.value, expected_value) expected_value = 'Linux (0x83)' volume_attribute = volume.GetAttribute('description') self.assertIsNotNone(volume_attribute) self.assertEqual(volume_attribute.value, expected_value) volume = volume_system.GetVolumeByIndex(7) self.assertIsNone(volume)
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 _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.')
def testNormalizedVolumeIdentifiersPartitionedImage(self): """Tests the _NormalizedVolumeIdentifiers function.""" test_mediator = TestVolumeScannerMediator() test_scanner = volume_scanner.VolumeScanner(mediator=test_mediator) test_path = self._GetTestFilePath(['tsk_volume_system.raw']) self._SkipIfPathNotExists(test_path) test_os_path_spec = path_spec_factory.Factory.NewPathSpec( definitions.TYPE_INDICATOR_OS, location=test_path) test_raw_path_spec = path_spec_factory.Factory.NewPathSpec( definitions.TYPE_INDICATOR_RAW, parent=test_os_path_spec) test_tsk_partition_path_spec = path_spec_factory.Factory.NewPathSpec( definitions.TYPE_INDICATOR_TSK_PARTITION, parent=test_raw_path_spec) volume_system = tsk_volume_system.TSKVolumeSystem() volume_system.Open(test_tsk_partition_path_spec) volume_identifiers = test_scanner._NormalizedVolumeIdentifiers( volume_system, ['p1', 'p2'], prefix='p') self.assertEqual(volume_identifiers, ['p1', 'p2']) volume_identifiers = test_scanner._NormalizedVolumeIdentifiers( volume_system, ['1', '2'], prefix='p') self.assertEqual(volume_identifiers, ['p1', 'p2']) volume_identifiers = test_scanner._NormalizedVolumeIdentifiers( volume_system, [1, 2], prefix='p') self.assertEqual(volume_identifiers, ['p1', 'p2']) # Test error conditions. with self.assertRaises(errors.ScannerError): test_scanner._NormalizedVolumeIdentifiers(volume_system, ['p3'], prefix='p')
def _get_tsk_partition_identifiers(self, scan_node, interactive): """Determines the TSK partition identifiers. Args: scan_node: the scan node (instance of dfvfs.ScanNode). Returns: A list of partition identifiers. Raises: RuntimeError: 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 RuntimeError(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: print(u'[WARNING] No partitions found.') return if len(volume_identifiers) == 1: return volume_identifiers # TODO REMOVE INTERACTION # try: # selected_volume_identifier = self._prompt_user_for_partition_identifier( # volume_system, volume_identifiers, interactive) # except KeyboardInterrupt: # raise RuntimeError(u'File system scan aborted.') # # if selected_volume_identifier == u'all': return volume_identifiers
def _GetTSKPartitionIdentifiers(self, scan_node): """Determines the TSK partition identifiers. This method first checks for the preferred partition number, then falls back to prompt the user if no usable preferences were specified. Args: scan_node (dfvfs.SourceScanNode): scan node. Returns: list[str]: TSK partition identifiers. Raises: RuntimeError: if the volume for a specific identifier cannot be retrieved. 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 = 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: if self._unattended_mode: raise errors.SourceScannerError( 'More than 1 parition found but no paritions specified.') try: volume_identifiers = self._PromptUserForPartitionIdentifiers( volume_system, volume_identifiers) except KeyboardInterrupt: raise errors.UserAbort('File system scan aborted.') return self._NormalizedVolumeIdentifiers(volume_system, volume_identifiers, prefix='p')
def _GetTSKPartitionIdentifiers(self, scan_node): if not scan_node or not scan_node.path_spec: raise RuntimeError(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: print(u'[WARNING] No partitions found.') return return volume_identifiers
def testGetVolumeIdentifiers(self): """Test the GetVolumeIdentifiers function.""" test_path = self._GetTestFilePath(['tsk_volume_system.raw']) test_os_path_spec = path_spec_factory.Factory.NewPathSpec( definitions.TYPE_INDICATOR_OS, location=test_path) test_raw_path_spec = path_spec_factory.Factory.NewPathSpec( definitions.TYPE_INDICATOR_RAW, parent=test_os_path_spec) test_tsk_partition_path_spec = path_spec_factory.Factory.NewPathSpec( definitions.TYPE_INDICATOR_TSK_PARTITION, parent=test_raw_path_spec) volume_system = tsk_volume_system.TSKVolumeSystem() volume_system.Open(test_tsk_partition_path_spec) volume_identifiers = self._source_scanner.GetVolumeIdentifiers( volume_system) self.assertEqual(volume_identifiers, ['p1', 'p2'])
def _GetTSKPartitionIdentifiers(self, scan_node): """Determines the TSK partition identifiers. This method first checks for the preferred partition number, then falls back to prompt the user if no usable preferences were specified. Args: scan_node (dfvfs.SourceScanNode): scan node. Returns: list[str]: TSK partition identifiers. Raises: RuntimeError: if the volume for a specific identifier cannot be retrieved. 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 = 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: partitions = range(1, volume_system.number_of_volumes + 1) 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 _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')
def testPrintTSKPartitionIdentifiersOverview(self): """Tests the _PrintTSKPartitionIdentifiersOverview function.""" test_file_path = self._GetTestFilePath(['tsk_volume_system.raw']) self._SkipIfPathNotExists(test_file_path) test_os_path_spec = path_spec_factory.Factory.NewPathSpec( dfvfs_definitions.TYPE_INDICATOR_OS, location=test_file_path) test_raw_path_spec = path_spec_factory.Factory.NewPathSpec( dfvfs_definitions.TYPE_INDICATOR_RAW, parent=test_os_path_spec) test_tsk_partition_path_spec = path_spec_factory.Factory.NewPathSpec( dfvfs_definitions.TYPE_INDICATOR_TSK_PARTITION, parent=test_raw_path_spec) volume_system = tsk_volume_system.TSKVolumeSystem() volume_system.Open(test_tsk_partition_path_spec) file_object = io.BytesIO() test_output_writer = tools.FileObjectOutputWriter(file_object) test_mediator = storage_media_tool.StorageMediaToolMediator( output_writer=test_output_writer) test_mediator._PrintTSKPartitionIdentifiersOverview( volume_system, ['p1', 'p2']) file_object.seek(0, os.SEEK_SET) output_data = file_object.read() expected_output_data = [ b'The following partitions were found:', b'', b'Identifier Offset (in bytes) Size (in bytes)', (b'p1 512 (0x00000200) 175.0KiB / 179.2kB ' b'(179200 B)'), b'p2 180224 (0x0002c000) 1.2MiB / 1.3MB (1294336 B)', b'', b''] if not win32console: # Using join here since Python 3 does not support format of bytes. expected_output_data[2] = b''.join([ b'\x1b[1m', expected_output_data[2], b'\x1b[0m']) self.assertEqual(output_data.split(b'\n'), expected_output_data)
def testPrintTSKPartitionIdentifiersOverview(self): """Tests the _PrintTSKPartitionIdentifiersOverview function.""" test_path = self._GetTestFilePath(['mbr.raw']) self._SkipIfPathNotExists(test_path) test_os_path_spec = path_spec_factory.Factory.NewPathSpec( definitions.TYPE_INDICATOR_OS, location=test_path) test_raw_path_spec = path_spec_factory.Factory.NewPathSpec( definitions.TYPE_INDICATOR_RAW, parent=test_os_path_spec) test_tsk_partition_path_spec = path_spec_factory.Factory.NewPathSpec( definitions.TYPE_INDICATOR_TSK_PARTITION, parent=test_raw_path_spec) volume_system = tsk_volume_system.TSKVolumeSystem() volume_system.Open(test_tsk_partition_path_spec) file_object = io.BytesIO() test_output_writer = command_line.FileObjectOutputWriter(file_object) test_mediator = command_line.CLIVolumeScannerMediator( output_writer=test_output_writer) test_mediator._PrintPartitionIdentifiersOverview( volume_system, ['p1', 'p2']) file_object.seek(0, os.SEEK_SET) output_data = file_object.read() expected_output_data = [ b'The following partitions were found:', b'', b'Identifier Offset (in bytes) Size (in bytes)', b'p1 512 (0x00000200) 64.5KiB / 66.0kB (66048 B)', b'p2 67072 (0x00010600) 64.5KiB / 66.0kB (66048 B)', b'' ] if not win32console: # Using join here since Python 3 does not support format of bytes. expected_output_data[2] = b''.join( [b'\x1b[1m', expected_output_data[2], b'\x1b[0m']) self.assertEqual(output_data.split(b'\n'), expected_output_data)
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: RuntimeError: 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 RuntimeError(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: print(u'[WARNING] No partitions found.') return if len(volume_identifiers) == 1: return volume_identifiers try: selected_volume_identifier = self._PromptUserForPartitionIdentifier( volume_system, volume_identifiers) except KeyboardInterrupt: raise RuntimeError(u'File system scan aborted.') if selected_volume_identifier == u'all': return volume_identifiers return [selected_volume_identifier]
def testGetNormalizedTSKVolumeIdentifiers(self): """Tests the _GetNormalizedTSKVolumeIdentifiers function.""" test_tool = storage_media_tool.StorageMediaTool() test_path = self._GetTestFilePath(['tsk_volume_system.raw']) os_path_spec = path_spec_factory.Factory.NewPathSpec( dfvfs_definitions.TYPE_INDICATOR_OS, location=test_path) tsk_partition_path_spec = path_spec_factory.Factory.NewPathSpec( dfvfs_definitions.TYPE_INDICATOR_TSK_PARTITION, parent=os_path_spec) volume_system = tsk_volume_system.TSKVolumeSystem() volume_system.Open(tsk_partition_path_spec) volume_identifiers = test_tool._GetNormalizedTSKVolumeIdentifiers( volume_system, ['p1', 'p2']) self.assertEqual(volume_identifiers, [1, 2]) with self.assertRaises(KeyError): test_tool._GetNormalizedTSKVolumeIdentifiers(volume_system, [1, 2]) with self.assertRaises(KeyError): test_tool._GetNormalizedTSKVolumeIdentifiers(volume_system, ['p3'])
def _GetNextLevelTSKPartionVolumeSystemPathSpec(self, source_path_spec): """Determines the next level volume system path specification. Args: source_path_spec: the source path specification (instance of dfvfs.PathSpec). Returns: The next level volume system path specification (instance of dfvfs.PathSpec). Raises: RuntimeError: if the format of or within the source is not supported. """ volume_system_path_spec = path_spec_factory.Factory.NewPathSpec( definitions.TYPE_INDICATOR_TSK_PARTITION, location=u'/', parent=source_path_spec) volume_system = tsk_volume_system.TSKVolumeSystem() volume_system.Open(volume_system_path_spec) volume_identifiers = [] for volume in volume_system.volumes: volume_identifier = getattr(volume, 'identifier', None) if volume_identifier: volume_identifiers.append(volume_identifier) if not volume_identifiers: logging.warning(u'No supported partitions found.') return source_path_spec if len(volume_identifiers) == 1: return path_spec_factory.Factory.NewPathSpec( definitions.TYPE_INDICATOR_TSK_PARTITION, location=u'/p1', parent=source_path_spec) print(u'The following partitions were found:') print(u'Identifier\tOffset\t\t\tSize') for volume_identifier in sorted(volume_identifiers): volume = volume_system.GetVolumeByIdentifier(volume_identifier) if not volume: raise RuntimeError( 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._GetHumanReadableSize(volume_extent.size))) print(u'') while True: print( u'Please specify the identifier of the partition that should ' u'be processed:') selected_volume_identifier = sys.stdin.readline() selected_volume_identifier = selected_volume_identifier.strip() 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'') location = u'/{0:s}'.format(selected_volume_identifier) return path_spec_factory.Factory.NewPathSpec( definitions.TYPE_INDICATOR_TSK_PARTITION, location=location, parent=source_path_spec)
def _GetTSKPartitionIdentifiers(self, scan_node, partition_offset=None, partitions=None): """Determines the TSK partition identifiers. This method first checks for the preferred partition number, then for the preferred partition offset and falls back to prompt the user if no usable preferences were specified. Args: scan_node (dfvfs.SourceScanNode): scan node. partition_offset (Optional[int]): preferred partition byte offset. partitions (Optional[list[str]]): preferred partition identifiers. Returns: list[str]: partition identifiers. Raises: RuntimeError: if the volume for a specific identifier cannot be retrieved. SourceScannerError: if the format of or within the source is not supported or the the scan node is invalid. """ 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: self._output_writer.Write('[WARNING] No partitions found.\n') return None normalized_volume_identifiers = self._GetNormalizedTSKVolumeIdentifiers( volume_system, volume_identifiers) if partitions: if partitions == ['all']: partitions = range(1, volume_system.number_of_volumes + 1) if not set(partitions).difference(normalized_volume_identifiers): return [ 'p{0:d}'.format(partition_number) for partition_number in partitions ] if partition_offset is not None: for volume in volume_system.volumes: volume_extent = volume.extents[0] if volume_extent.offset == partition_offset: return [volume.identifier] self._output_writer.Write( ('[WARNING] No such partition with offset: {0:d} ' '(0x{0:08x}).\n').format(partition_offset)) if len(volume_identifiers) == 1: return volume_identifiers try: selected_volume_identifier = self._PromptUserForPartitionIdentifier( volume_system, volume_identifiers) except KeyboardInterrupt: raise errors.UserAbort('File system scan aborted.') if selected_volume_identifier == 'all': return volume_identifiers return [selected_volume_identifier]
def _ProcessPartition(self, evidence_path, path_spec): """Generate RawDiskPartition from a PathSpec. Args: evidence_path (str): Local path of the parent evidence path_spec (dfvfs.PathSpec): dfVFS path spec. Returns: A new RawDiskPartition evidence item and a list of strings containing partition information to add to the status report. """ status_report = [] fs_path_spec = path_spec fs_location = None partition_location = None volume_index = None partition_index = None partition_offset = None partition_size = None # File system location / identifier fs_location = getattr(path_spec, 'location', None) while path_spec.HasParent(): type_indicator = path_spec.type_indicator if type_indicator == dfvfs_definitions.TYPE_INDICATOR_APFS_CONTAINER: # APFS volume index volume_index = getattr(path_spec, 'volume_index', None) if type_indicator == dfvfs_definitions.TYPE_INDICATOR_TSK_PARTITION: if fs_location in ('\\', '/'): # Partition location / identifier fs_location = getattr(path_spec, 'location', None) partition_location = getattr(path_spec, 'location', None) # Partition index partition_index = getattr(path_spec, 'part_index', None) volume_system = tsk_volume_system.TSKVolumeSystem() try: volume_system.Open(path_spec) volume_identifier = partition_location.replace('/', '') volume = volume_system.GetVolumeByIdentifier( volume_identifier) partition_offset = volume.extents[0].offset partition_size = volume.extents[0].size except dfvfs_errors.VolumeSystemError as e: raise TurbiniaException( 'Could not process partition: {0!s}'.format(e)) break path_spec = path_spec.parent status_report.append(fmt.heading5('{0!s}:'.format(fs_location))) if partition_index: if not volume_index is None: status_report.append( fmt.bullet('Volume index: {0!s}'.format(volume_index))) status_report.append( fmt.bullet('Partition index: {0!s}'.format(partition_index))) status_report.append( fmt.bullet('Partition offset: {0!s}'.format(partition_offset))) status_report.append( fmt.bullet('Partition size: {0!s}'.format(partition_size))) else: status_report.append( fmt.bullet('Source evidence is a volume image')) partition_evidence = RawDiskPartition( source_path=evidence_path, path_spec=fs_path_spec, partition_offset=partition_offset, partition_size=partition_size) return partition_evidence, status_report
def _GetVolumeTSKPartition( self, scan_context, partition_number=None, partition_offset=None): """Determines the volume path specification. Args: scan_context: the scan context (instance of dfvfs.ScanContext). partition_number: Optional preferred partition number. The default is None. partition_offset: Optional preferred partition byte offset. The default is None. Returns: The volume scan node (instance of dfvfs.SourceScanNode) or None if no supported partition was found. Raises: SourceScannerError: if the format of or within the source is not supported or the the scan context is invalid. RuntimeError: if the volume for a specific identifier cannot be retrieved. """ if (not scan_context or not scan_context.last_scan_node or not scan_context.last_scan_node.path_spec): raise errors.SourceScannerError(u'Invalid scan context.') volume_system = tsk_volume_system.TSKVolumeSystem() volume_system.Open(scan_context.last_scan_node.path_spec) volume_identifiers = self._source_scanner.GetVolumeIdentifiers( volume_system) if not volume_identifiers: logging.info(u'No supported partitions found.') return if partition_number is not None and partition_number > 0: # Plaso uses partition numbers starting with 1 while dfvfs expects # the volume index to start with 0. volume = volume_system.GetVolumeByIndex(partition_number - 1) if volume: volume_location = u'/{0:s}'.format(volume.identifier) volume_scan_node = scan_context.last_scan_node.GetSubNodeByLocation( volume_location) if not volume_scan_node: raise RuntimeError( u'Unable to retrieve volume scan node by location: {0:s}'.format( volume_location)) return volume_scan_node logging.warning(u'No such partition: {0:d}.'.format(partition_number)) if partition_offset is not None: for volume in volume_system.volumes: volume_extent = volume.extents[0] if volume_extent.offset == partition_offset: volume_location = u'/{0:s}'.format(volume.identifier) volume_scan_node = scan_context.last_scan_node.GetSubNodeByLocation( volume_location) if not volume_scan_node: raise RuntimeError(( u'Unable to retrieve volume scan node by location: ' u'{0:s}').format(volume_location)) return volume_scan_node logging.warning( u'No such partition with offset: {0:d} (0x{0:08x}).'.format( partition_offset)) if len(volume_identifiers) == 1: volume_location = u'/{0:s}'.format(volume_identifiers[0]) else: try: selected_volume_identifier = self._GetPartitionIdentifierFromUser( volume_system, volume_identifiers) except KeyboardInterrupt: raise errors.UserAbort(u'File system scan aborted.') volume = volume_system.GetVolumeByIdentifier(selected_volume_identifier) if not volume: raise RuntimeError( u'Unable to retrieve volume by identifier: {0:s}'.format( selected_volume_identifier)) volume_location = u'/{0:s}'.format(selected_volume_identifier) volume_scan_node = scan_context.last_scan_node.GetSubNodeByLocation( volume_location) if not volume_scan_node: raise RuntimeError( u'Unable to retrieve volume scan node by location: {0:s}'.format( volume_location)) return volume_scan_node
def testGetPartitionIdentifiers(self): """Tests the GetPartitionIdentifiers function.""" test_path = self._GetTestFilePath(['tsk_volume_system.raw']) test_os_path_spec = path_spec_factory.Factory.NewPathSpec( definitions.TYPE_INDICATOR_OS, location=test_path) test_raw_path_spec = path_spec_factory.Factory.NewPathSpec( definitions.TYPE_INDICATOR_RAW, parent=test_os_path_spec) test_tsk_partition_path_spec = path_spec_factory.Factory.NewPathSpec( definitions.TYPE_INDICATOR_TSK_PARTITION, parent=test_raw_path_spec) volume_system = tsk_volume_system.TSKVolumeSystem() volume_system.Open(test_tsk_partition_path_spec) file_object = io.BytesIO() test_output_writer = command_line.FileObjectOutputWriter(file_object) test_mediator = command_line.CLIVolumeScannerMediator( output_writer=test_output_writer) # Test selection of single partition. input_file_object = io.BytesIO(b'2\n') test_input_reader = command_line.FileObjectInputReader( input_file_object) output_file_object = io.BytesIO() test_output_writer = command_line.FileObjectOutputWriter( output_file_object) test_mediator = command_line.CLIVolumeScannerMediator( input_reader=test_input_reader, output_writer=test_output_writer) volume_identifiers = test_mediator.GetPartitionIdentifiers( volume_system, ['p1', 'p2']) self.assertEqual(volume_identifiers, ['p2']) # Test selection of single partition. input_file_object = io.BytesIO(b'p2\n') test_input_reader = command_line.FileObjectInputReader( input_file_object) output_file_object = io.BytesIO() test_output_writer = command_line.FileObjectOutputWriter( output_file_object) test_mediator = command_line.CLIVolumeScannerMediator( input_reader=test_input_reader, output_writer=test_output_writer) volume_identifiers = test_mediator.GetPartitionIdentifiers( volume_system, ['p1', 'p2']) self.assertEqual(volume_identifiers, ['p2']) # Test selection of single partition with invalid input on first attempt. input_file_object = io.BytesIO(b'bogus\np2\n') test_input_reader = command_line.FileObjectInputReader( input_file_object) output_file_object = io.BytesIO() test_output_writer = command_line.FileObjectOutputWriter( output_file_object) test_mediator = command_line.CLIVolumeScannerMediator( input_reader=test_input_reader, output_writer=test_output_writer) volume_identifiers = test_mediator.GetPartitionIdentifiers( volume_system, ['p1', 'p2']) self.assertEqual(volume_identifiers, ['p2']) # Test selection of all partitions. input_file_object = io.BytesIO(b'all\n') test_input_reader = command_line.FileObjectInputReader( input_file_object) output_file_object = io.BytesIO() test_output_writer = command_line.FileObjectOutputWriter( output_file_object) test_mediator = command_line.CLIVolumeScannerMediator( input_reader=test_input_reader, output_writer=test_output_writer) volume_identifiers = test_mediator.GetPartitionIdentifiers( volume_system, ['p1', 'p2']) self.assertEqual(volume_identifiers, ['p1', 'p2']) # Test selection of no partitions. input_file_object = io.BytesIO(b'\n') test_input_reader = command_line.FileObjectInputReader( input_file_object) output_file_object = io.BytesIO() test_output_writer = command_line.FileObjectOutputWriter( output_file_object) test_mediator = command_line.CLIVolumeScannerMediator( input_reader=test_input_reader, output_writer=test_output_writer) volume_identifiers = test_mediator.GetPartitionIdentifiers( volume_system, ['p1', 'p2']) self.assertEqual(volume_identifiers, [])
def _GetTSKPartitionIdentifiers(self, scan_node, partition_string=None, partition_offset=None): """Determines the TSK partition identifiers. This method first checks for the preferred partition number, then for the preferred partition offset and falls back to prompt the user if no usable preferences were specified. Args: scan_node: the scan node (instance of dfvfs.ScanNode). partition_string: Optional preferred partition number string. The default is None. partition_offset: Optional preferred partition byte offset. The default is None. Returns: A list of partition identifiers. Raises: RuntimeError: if the volume for a specific identifier cannot be retrieved. SourceScannerError: if the format of or within the source is not supported or the the scan node is invalid. """ if not scan_node or not scan_node.path_spec: raise errors.SourceScannerError(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: self._output_writer.Write(u'[WARNING] No partitions found.\n') return if partition_string == u'all': return volume_identifiers if partition_string is not None and not partition_string.startswith( u'p'): return volume_identifiers partition_number = None if partition_string: try: partition_number = int(partition_string[1:], 10) except ValueError: pass if partition_number is not None and partition_number > 0: # Plaso uses partition numbers starting with 1 while dfvfs expects # the volume index to start with 0. volume = volume_system.GetVolumeByIndex(partition_number - 1) if volume: return [u'p{0:d}'.format(partition_number)] self._output_writer.Write( u'[WARNING] No such partition: {0:d}.\n'.format( partition_number)) if partition_offset is not None: for volume in volume_system.volumes: volume_extent = volume.extents[0] if volume_extent.offset == partition_offset: return [volume.identifier] self._output_writer.Write( (u'[WARNING] No such partition with offset: {0:d} ' u'(0x{0:08x}).\n').format(partition_offset)) if len(volume_identifiers) == 1: return volume_identifiers try: selected_volume_identifier = self._PromptUserForPartitionIdentifier( volume_system, volume_identifiers) except KeyboardInterrupt: raise errors.UserAbort(u'File system scan aborted.') if selected_volume_identifier == u'all': return volume_identifiers return [selected_volume_identifier]
def _ProcessPartition(self, path_spec): """Generate RawDiskPartition from a PathSpec. Args: path_spec (dfvfs.PathSpec): dfVFS path spec. Returns: A new RawDiskPartition evidence item and a list of strings containing partition information to add to the status report. """ status_report = [] fs_path_spec = path_spec fs_location = None partition_location = None volume_index = None partition_index = None partition_offset = None partition_size = None lv_uuid = None # File system location / identifier is_lvm = False fs_location = getattr(path_spec, 'location', None) while path_spec.HasParent(): type_indicator = path_spec.type_indicator if type_indicator == dfvfs_definitions.TYPE_INDICATOR_APFS_CONTAINER: # APFS volume index volume_index = getattr(path_spec, 'volume_index', None) if type_indicator in ( dfvfs_definitions.TYPE_INDICATOR_GPT, dfvfs_definitions.TYPE_INDICATOR_LVM, dfvfs_definitions.TYPE_INDICATOR_TSK_PARTITION): if fs_location in ('\\', '/'): # Partition location / identifier fs_location = getattr(path_spec, 'location', None) partition_location = getattr(path_spec, 'location', None) # Partition index partition_index = getattr(path_spec, 'part_index', None) if type_indicator == dfvfs_definitions.TYPE_INDICATOR_TSK_PARTITION: volume_system = tsk_volume_system.TSKVolumeSystem() elif type_indicator == dfvfs_definitions.TYPE_INDICATOR_LVM: is_lvm = True volume_system = lvm_volume_system.LVMVolumeSystem() else: volume_system = gpt_volume_system.GPTVolumeSystem() try: volume_system.Open(path_spec) volume_identifier = partition_location.replace('/', '') volume = volume_system.GetVolumeByIdentifier( volume_identifier) if is_lvm: # LVM Logical Volume UUID lv_uuid = volume.GetAttribute('identifier') if lv_uuid: lv_uuid = lv_uuid.value partition_offset = volume.extents[0].offset partition_size = volume.extents[0].size except dfvfs_errors.VolumeSystemError as e: raise TurbiniaException( 'Could not process partition: {0!s}'.format(e)) break path_spec = path_spec.parent status_report.append(fmt.heading5('{0!s}:'.format(fs_location))) status_report.append( fmt.bullet('Filesystem: {0!s}'.format( fs_path_spec.type_indicator))) if volume_index is not None: status_report.append( fmt.bullet('Volume index: {0!s}'.format(volume_index))) if partition_index is not None: status_report.append( fmt.bullet('Partition index: {0!s}'.format(partition_index))) status_report.append( fmt.bullet('Partition offset: {0!s}'.format(partition_offset))) status_report.append( fmt.bullet('Partition size: {0!s}'.format(partition_size))) if volume_index is None and partition_index is None: status_report.append( fmt.bullet('Source evidence is a volume image')) # Not setting path_spec here as it will need to be generated for each task partition_evidence = DiskPartition(partition_location=fs_location, partition_offset=partition_offset, partition_size=partition_size, lv_uuid=lv_uuid) return partition_evidence, status_report
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)
if not type_indicators: # The RAW storage media image type cannot be detected based on # a signature so we try to detect it based on common file naming # schemas. file_system = resolver.Resolver.OpenFileSystem(path_spec) raw_path_spec = path_spec_factory.Factory.NewPathSpec( definitions.TYPE_INDICATOR_RAW, parent=path_spec) glob_results = raw.RawGlobPathSpec(file_system, raw_path_spec) if glob_results: path_spec = raw_path_spec volume_system_path_spec = path_spec_factory.Factory.NewPathSpec( definitions.TYPE_INDICATOR_TSK_PARTITION, location=u'/', parent=path_spec) volume_system = tsk_volume_system.TSKVolumeSystem() volume_system.Open(volume_system_path_spec) volume_identifiers = [] for volume in volume_system.volumes: volume_identifier = getattr(volume, 'identifier', None) if volume_identifier: volume_identifiers.append(volume_identifier) print(u'The following partitions were found:') print(u'Identifier\tOffset\t\t\tSize') for volume_identifier in sorted(volume_identifiers): volume = volume_system.GetVolumeByIdentifier(volume_identifier) if not volume: raise RuntimeError(