示例#1
0
    def testReadAndWriteSerializedSessionStart(self):
        """Test ReadSerialized and WriteSerialized of SessionStart."""
        timestamp = int(time.time() * 1000000)
        session_identifier = u'{0:s}'.format(uuid.uuid4().get_hex())

        expected_session_start = sessions.SessionStart(
            identifier=session_identifier)
        expected_session_start.timestamp = timestamp
        expected_session_start.product_name = u'plaso'
        expected_session_start.product_version = plaso.GetVersion()

        json_string = (json_serializer.JSONAttributeContainerSerializer.
                       WriteSerialized(expected_session_start))

        self.assertIsNotNone(json_string)

        session_start = (json_serializer.JSONAttributeContainerSerializer.
                         ReadSerialized(json_string))

        self.assertIsNotNone(session_start)
        self.assertIsInstance(session_start, sessions.SessionStart)

        expected_session_start_dict = {
            u'debug_mode': False,
            u'identifier': session_identifier,
            u'product_name': u'plaso',
            u'product_version': plaso.GetVersion(),
            u'timestamp': timestamp
        }

        session_start_dict = session_start.CopyToDict()
        self.assertEqual(sorted(session_start_dict.items()),
                         sorted(expected_session_start_dict.items()))
示例#2
0
    def GetPluginData(self):
        """Return a dict object with a list of all available parsers and plugins."""
        return_dict = {}

        # Import all plugins and parsers to print out the necessary information.
        # This is not import at top since this is only required if this parameter
        # is set, otherwise these libraries get imported in their respected
        # locations.

        # The reason why some of these libraries are imported as '_' is to make sure
        # all appropriate parsers and plugins are registered, yet we don't need to
        # directly call these libraries, it is enough to load them up to get them
        # registered.

        # TODO: remove this hack includes should be a the top if this does not work
        # remove the need for implicit behavior on import.
        from plaso import filters
        from plaso import hashers as _  # pylint: disable=redefined-outer-name
        from plaso import parsers as _  # pylint: disable=redefined-outer-name
        from plaso import output as _  # pylint: disable=redefined-outer-name
        from plaso.frontend import presets
        from plaso.output import manager as output_manager

        return_dict[u'Versions'] = [(u'plaso engine', plaso.GetVersion()),
                                    (u'python', sys.version)]

        return_dict[u'Hashers'] = []
        for _, hasher_class in hashers_manager.HashersManager.GetHashers():
            description = getattr(hasher_class, u'DESCRIPTION', u'')
            return_dict[u'Hashers'].append((hasher_class.NAME, description))

        return_dict[u'Parsers'] = []
        for _, parser_class in parsers_manager.ParsersManager.GetParsers():
            description = getattr(parser_class, u'DESCRIPTION', u'')
            return_dict[u'Parsers'].append((parser_class.NAME, description))

        return_dict[u'Parser Lists'] = []
        for category, parsers in sorted(presets.categories.items()):
            return_dict[u'Parser Lists'].append((category, ', '.join(parsers)))

        return_dict[u'Output Modules'] = []
        for name, description in sorted(
                output_manager.OutputManager.GetOutputs()):
            return_dict[u'Output Modules'].append((name, description))

        return_dict[u'Plugins'] = []
        for _, parser_class in parsers_manager.ParsersManager.GetParsers():
            if parser_class.SupportsPlugins():
                for _, plugin_class in parser_class.GetPlugins():
                    description = getattr(plugin_class, u'DESCRIPTION', u'')
                    return_dict[u'Plugins'].append(
                        (plugin_class.NAME, description))

        return_dict[u'Filters'] = []
        for filter_obj in sorted(filters.ListFilters()):
            doc_string, _, _ = filter_obj.__doc__.partition('\n')
            return_dict[u'Filters'].append(
                (filter_obj.filter_name, doc_string))

        return return_dict
示例#3
0
  def testReadAndWriteSerializedSession(self):
    """Test ReadSerialized and WriteSerialized of Session."""
    parsers_counter = collections.Counter()
    parsers_counter[u'filestat'] = 3
    parsers_counter[u'total'] = 3

    expected_session = sessions.Session()
    expected_session.product_name = u'plaso'
    expected_session.product_version = plaso.GetVersion()
    expected_session.parsers_counter = parsers_counter

    json_string = (
        json_serializer.JSONAttributeContainerSerializer.WriteSerialized(
            expected_session))

    self.assertIsNotNone(json_string)

    session = (
        json_serializer.JSONAttributeContainerSerializer.ReadSerialized(
            json_string))

    self.assertIsNotNone(session)
    self.assertIsInstance(session, sessions.Session)

    expected_session_dict = {
        u'aborted': False,
        u'analysis_reports_counter': session.analysis_reports_counter,
        u'debug_mode': False,
        u'event_labels_counter': session.event_labels_counter,
        u'identifier': session.identifier,
        u'parsers_counter': parsers_counter,
        u'preferred_encoding': u'utf-8',
        u'preferred_time_zone': u'UTC',
        u'product_name': u'plaso',
        u'product_version': plaso.GetVersion(),
        u'start_time': session.start_time
    }

    session_dict = session.CopyToDict()
    self.assertEqual(
        sorted(session_dict.items()), sorted(expected_session_dict.items()))
示例#4
0
 def __init__(self):
     """Initializes a session start attribute container."""
     super(SessionStart, self).__init__()
     self.command_line_arguments = u''
     self.debug_mode = False
     self.filter_expression = u''
     self.filter_file = u''
     self.parser_filter_expression = u''
     self.preferred_encoding = u'utf-8'
     self.product_name = u'plaso'
     self.product_version = plaso.GetVersion()
     self.timestamp = int(time.time() * 100000)
示例#5
0
    def testCopyToDict(self):
        """Tests the CopyToDict function."""
        timestamp = int(time.time() * 1000000)
        session_identifier = u'{0:s}'.format(uuid.uuid4().get_hex())
        session_start = sessions.SessionStart(identifier=session_identifier)
        session_start.timestamp = timestamp
        session_start.product_name = u'plaso'
        session_start.product_version = plaso.GetVersion()

        self.assertEquals(session_start.identifier, session_identifier)

        expected_dict = {
            u'debug_mode': False,
            u'identifier': session_start.identifier,
            u'product_name': u'plaso',
            u'product_version': plaso.GetVersion(),
            u'timestamp': timestamp
        }

        test_dict = session_start.CopyToDict()

        self.assertEqual(test_dict, expected_dict)
示例#6
0
    def _GetPluginData(self):
        """Return a dict object with a list of all available parsers and plugins."""
        return_dict = {}

        # Import all plugins and parsers to print out the necessary information.
        # This is not import at top since this is only required if this parameter
        # is set, otherwise these libraries get imported in their respected
        # locations.

        # The reason why some of these libraries are imported as '_' is to make sure
        # all appropriate parsers and plugins are registered, yet we don't need to
        # directly call these libraries, it is enough to load them up to get them
        # registered.
        from plaso import filters
        from plaso import parsers as _
        from plaso import output as _
        from plaso.frontend import presets
        from plaso.lib import output
        from plaso.lib import plugin

        return_dict['Versions'] = [('plaso engine', plaso.GetVersion()),
                                   ('python', sys.version)]

        return_dict['Parsers'] = []
        for parser in sorted(putils.FindAllParsers()['all']):
            doc_string, _, _ = parser.__doc__.partition('\n')
            return_dict['Parsers'].append((parser.parser_name, doc_string))

        return_dict['Parser Lists'] = []
        for category, parsers in sorted(presets.categories.items()):
            return_dict['Parser Lists'].append((category, ', '.join(parsers)))

        return_dict['Output Modules'] = []
        for name, description in sorted(output.ListOutputFormatters()):
            return_dict['Output Modules'].append((name, description))

        return_dict['Plugins'] = []

        for plugin, obj in sorted(plugin.BasePlugin.classes.iteritems()):
            doc_string, _, _ = obj.__doc__.partition('\n')
            return_dict['Plugins'].append((plugin, doc_string))

        return_dict['Filters'] = []
        for filter_obj in sorted(filters.ListFilters()):
            doc_string, _, _ = filter_obj.__doc__.partition('\n')
            return_dict['Filters'].append((filter_obj.filter_name, doc_string))

        return return_dict
示例#7
0
  def AddBasicOptions(self, argument_group):
    """Adds the basic options to the argument group.

    Args:
      argument_group (argparse._ArgumentGroup): argparse argument group.
    """
    version_string = u'plaso - {0:s} version {1:s}'.format(
        self.NAME, plaso.GetVersion())

    # We want a custom help message and not the default argparse one.
    argument_group.add_argument(
        u'-h', u'--help', action=u'help',
        help=u'show this help message and exit.')

    argument_group.add_argument(
        u'-V', u'--version', dest=u'version', action=u'version',
        version=version_string, help=u'show the version information.')
示例#8
0
  def _PrintStatusUpdate(self, processing_status):
    """Prints the processing status.

    Args:
      processing_status (ProcessingStatus): processing status.
    """
    if self._stdout_output_writer:
      self._ClearScreen()

    self._output_writer.Write(
        u'plaso - {0:s} version {1:s}\n'.format(
            self.NAME, plaso.GetVersion()))
    self._output_writer.Write(u'\n')

    self._PrintStatusHeader()

    # TODO: for win32console get current color and set intensity,
    # write the header separately then reset intensity.
    status_header = u'Identifier\t\tPID\tStatus\t\tEvents\t\tTags\t\tReports'
    if not win32console:
      status_header = u'\x1b[1m{0:s}\x1b[0m'.format(status_header)

    status_table = [status_header]

    status_row = self._FormatStatusTableRow(processing_status.foreman_status)
    status_table.append(status_row)

    for worker_status in processing_status.workers_status:
      status_row = self._FormatStatusTableRow(worker_status)
      status_table.append(status_row)

    status_table.append(u'')
    self._output_writer.Write(u'\n'.join(status_table))
    self._output_writer.Write(u'\n')

    if processing_status.aborted:
      self._output_writer.Write(
          u'Processing aborted - waiting for clean up.\n\n')

    # TODO: remove update flicker. For win32console we could set the cursor
    # top left, write the table, clean the remainder of the screen buffer
    # and set the cursor at the end of the table.
    if self._stdout_output_writer:
      # We need to explicitly flush stdout to prevent partial status updates.
      sys.stdout.flush()
示例#9
0
    def GetPluginData(self):
        """Retrieves the version and various plugin information.

    Returns:
      A dictionary object with lists of available parsers and plugins.
    """
        return_dict = {}

        return_dict[u'Versions'] = [(u'plaso engine', plaso.GetVersion()),
                                    (u'python', sys.version)]

        return_dict[u'Hashers'] = self.GetHashersInformation()
        return_dict[u'Parsers'] = self.GetParsersInformation()
        return_dict[u'Parser Plugins'] = self.GetParserPluginsInformation()
        return_dict[u'Parser Presets'] = self.GetParserPresetsInformation()
        return_dict[u'Output Modules'] = self._GetOutputModulesInformation()
        return_dict[u'Filters'] = self._GetFiltersInformation()

        return return_dict
示例#10
0
 def __init__(self):
     """Initializes a session attribute container."""
     super(Session, self).__init__()
     self.aborted = False
     self.analysis_reports_counter = collections.Counter()
     self.command_line_arguments = None
     self.completion_time = None
     self.debug_mode = False
     self.enabled_parser_names = None
     self.event_labels_counter = collections.Counter()
     self.filter_expression = None
     self.filter_file = None
     self.identifier = u'{0:s}'.format(uuid.uuid4().get_hex())
     self.parser_filter_expression = None
     self.parsers_counter = collections.Counter()
     self.preferred_encoding = u'utf-8'
     self.preferred_year = None
     self.product_name = u'plaso'
     self.product_version = plaso.GetVersion()
     self.start_time = int(time.time() * 1000000)
示例#11
0
    def AddBasicOptions(self, argument_group):
        """Adds the basic options to the argument group.

    Args:
      argument_group: The argparse argument group (instance of
                      argparse._ArgumentGroup).
    """
        version_string = u'plaso - {0:s} version {1:s}'.format(
            self.NAME, plaso.GetVersion())

        argument_group.add_argument(u'-h',
                                    u'--help',
                                    action=u'help',
                                    help=(u'Show this help message and exit.'))

        argument_group.add_argument(u'-v',
                                    u'--version',
                                    dest=u'version',
                                    action=u'version',
                                    version=version_string,
                                    help=u'Show the current version.')
示例#12
0
def PrintHeader(options):
    """Print header information, including library versions."""
    print frontend_utils.FormatHeader('File Parsed')
    print u'{:>20s}'.format(options.file_to_parse)

    print frontend_utils.FormatHeader('Versions')
    print frontend_utils.FormatOutputString('plaso engine', plaso.GetVersion())
    print frontend_utils.FormatOutputString('pyevt', pyevt.get_version())
    print frontend_utils.FormatOutputString('pyevtx', pyevtx.get_version())
    print frontend_utils.FormatOutputString('pylnk', pylnk.get_version())
    print frontend_utils.FormatOutputString('pymsiecf', pymsiecf.get_version())
    print frontend_utils.FormatOutputString('pyregf', pyregf.get_version())

    if options.filter:
        print frontend_utils.FormatHeader('Filter Used')
        print frontend_utils.FormatOutputString('Filter String',
                                                options.filter)

    if options.parsers:
        print frontend_utils.FormatHeader('Parser Filter Used')
        print frontend_utils.FormatOutputString('Parser String',
                                                options.parsers)
示例#13
0
    def testCopyToDict(self):
        """Tests the CopyToDict function."""
        session = sessions.Session()

        self.assertIsNotNone(session.identifier)
        self.assertIsNotNone(session.start_time)
        self.assertIsNone(session.completion_time)

        expected_dict = {
            u'aborted': False,
            u'analysis_reports_counter': session.analysis_reports_counter,
            u'debug_mode': False,
            u'event_labels_counter': session.event_labels_counter,
            u'identifier': session.identifier,
            u'parsers_counter': session.parsers_counter,
            u'preferred_encoding': u'utf-8',
            u'product_name': u'plaso',
            u'product_version': plaso.GetVersion(),
            u'start_time': session.start_time
        }

        test_dict = session.CopyToDict()

        self.assertEqual(test_dict, expected_dict)
示例#14
0
文件: psort.py 项目: f-s-p/plaso
def Main(arguments=None):
    """Start the tool."""
    multiprocessing.freeze_support()

    front_end = psort.PsortFrontend()

    arg_parser = argparse.ArgumentParser(
        description=(u'PSORT - Application to read, filter and process '
                     u'output from a plaso storage file.'),
        add_help=False)

    tool_group = arg_parser.add_argument_group(u'Optional arguments For psort')
    output_group = arg_parser.add_argument_group(
        u'Optional arguments for output modules')
    analysis_group = arg_parser.add_argument_group(
        u'Optional arguments for analysis modules')

    tool_group.add_argument(u'-d',
                            u'--debug',
                            action=u'store_true',
                            dest=u'debug',
                            default=False,
                            help=u'Fall back to debug shell if psort fails.')

    tool_group.add_argument(u'-q',
                            u'--quiet',
                            action=u'store_true',
                            dest=u'quiet',
                            default=False,
                            help=u'Do not print a summary after processing.')

    tool_group.add_argument(u'-h',
                            u'--help',
                            action=u'help',
                            help=u'Show this help message and exit.')

    tool_group.add_argument(
        u'-a',
        u'--include_all',
        action=u'store_false',
        dest=u'dedup',
        default=True,
        help=(
            u'By default the psort removes duplicate entries from the output. '
            u'This parameter changes that behavior so all events are included.'
        ))

    tool_group.add_argument(
        u'-o',
        u'--output_format',
        u'--output-format',
        metavar=u'FORMAT',
        dest=u'output_format',
        default=u'dynamic',
        help=(u'The output format. Use "-o list" to see a list of available '
              u'output formats.'))

    tool_group.add_argument(
        u'--analysis',
        metavar=u'PLUGIN_LIST',
        dest=u'analysis_plugins',
        default=u'',
        action=u'store',
        type=unicode,
        help=(u'A comma separated list of analysis plugin names to be loaded '
              u'or "--analysis list" to see a list of available plugins.'))

    tool_group.add_argument(u'--data',
                            metavar=u'PATH',
                            dest=u'data_location',
                            default=u'',
                            action=u'store',
                            type=unicode,
                            help=u'The location of the analysis data.')

    tool_group.add_argument(
        u'--language',
        metavar=u'LANGUAGE',
        dest=u'preferred_language',
        default=u'en-US',
        type=unicode,
        help=(
            u'The preferred language identifier for Windows Event Log message '
            u'strings. Use "--language list" to see a list of available '
            u'language identifiers. Note that formatting will fall back on '
            u'en-US (LCID 0x0409) if the preferred language is not available '
            u'in the database of message string templates.'))

    tool_group.add_argument(
        u'-z',
        u'--zone',
        metavar=u'TIMEZONE',
        dest=u'timezone',
        default=u'UTC',
        type=unicode,
        help=(u'The timezone in which to represent the date and time values. '
              u'Use "-z list" to see a list of available timezones.'))

    tool_group.add_argument(u'-w',
                            u'--write',
                            metavar=u'OUTPUTFILE',
                            dest=u'write',
                            help=u'Output filename, defaults to stdout.')

    tool_group.add_argument(
        u'--slice',
        metavar=u'DATE',
        dest=u'slice',
        type=str,
        default=u'',
        action=u'store',
        help=
        (u'Create a time slice around a certain date. This parameter, if '
         u'defined will display all events that happened X minutes before and '
         u'after the defined date. X is controlled by the parameter '
         u'--slice_size but defaults to 5 minutes.'))

    tool_group.add_argument(
        u'--slicer',
        dest=u'slicer',
        action=u'store_true',
        default=False,
        help=
        (u'Create a time slice around every filter match. This parameter, if '
         u'defined will save all X events before and after a filter match has '
         u'been made. X is defined by the --slice_size parameter.'))

    tool_group.add_argument(
        u'--slice_size',
        dest=u'slice_size',
        type=int,
        default=5,
        action=u'store',
        help=(
            u'Defines the slice size. In the case of a regular time slice it '
            u'defines the number of minutes the slice size should be. In the '
            u'case of the --slicer it determines the number of events before '
            u'and after a filter match has been made that will be included in '
            u'the result set. The default value is 5]. See --slice or --slicer '
            u'for more details about this option.'))

    tool_group.add_argument(
        u'-v',
        u'--version',
        dest=u'version',
        action=u'version',
        version=u'log2timeline - psort version {0:s}'.format(
            plaso.GetVersion()),
        help=u'Show the current version of psort.')

    front_end.AddStorageFileOptions(tool_group)

    tool_group.add_argument(
        u'filter',
        nargs=u'?',
        action=u'store',
        metavar=u'FILTER',
        default=None,
        type=unicode,
        help=(u'A filter that can be used to filter the dataset before it '
              u'is written into storage. More information about the filters'
              u' and it\'s usage can be found here: http://plaso.kiddaland.'
              u'net/usage/filters'))

    if arguments is None:
        arguments = sys.argv[1:]

    # Add the output module options.
    if u'-o' in arguments:
        argument_index = arguments.index(u'-o') + 1
    elif u'--output_format' in arguments:
        argument_index = arguments.index(u'--output_format') + 1
    elif u'--output-format' in arguments:
        argument_index = arguments.index(u'--output-format') + 1
    else:
        argument_index = 0

    if argument_index > 0:
        module_names = arguments[argument_index]
        front_end.AddOutputModuleOptions(output_group, [module_names])

    # Add the analysis plugin options.
    if u'--analysis' in arguments:
        argument_index = arguments.index(u'--analysis') + 1

        # Get the names of the analysis plugins that should be loaded.
        plugin_names = arguments[argument_index]
        try:
            front_end.AddAnalysisPluginOptions(analysis_group, plugin_names)
        except errors.BadConfigOption as exception:
            arg_parser.print_help()
            print u''
            logging.error(u'{0:s}'.format(exception))
            return False

    options = arg_parser.parse_args(args=arguments)

    format_str = u'[%(levelname)s] %(message)s'
    if getattr(options, u'debug', False):
        logging.basicConfig(level=logging.DEBUG, format=format_str)
    else:
        logging.basicConfig(level=logging.INFO, format=format_str)

    have_list_option = False
    if options.analysis_plugins == u'list':
        front_end.ListAnalysisPlugins()
        have_list_option = True

    if options.output_format == u'list':
        front_end.ListOutputModules()
        have_list_option = True

    if options.preferred_language == u'list':
        front_end.ListLanguageIdentifiers()
        have_list_option = True

    if options.timezone == u'list':
        front_end.ListTimeZones()
        have_list_option = True

    if have_list_option:
        return True

    if not getattr(options, u'data_location', None):
        # Determine if we are running from the source directory.
        options.data_location = os.path.dirname(__file__)
        options.data_location = os.path.dirname(options.data_location)
        options.data_location = os.path.join(options.data_location, u'data')

        if not os.path.exists(options.data_location):
            # Otherwise determine if there is shared plaso data location.
            options.data_location = os.path.join(sys.prefix, u'share',
                                                 u'plaso')

        if not os.path.exists(options.data_location):
            logging.warning(
                u'Unable to automatically determine data location.')
            options.data_location = None

    try:
        front_end.ParseOptions(options)
    except errors.BadConfigOption as exception:
        arg_parser.print_help()
        print u''
        logging.error(u'{0:s}'.format(exception))
        return False

    if front_end.preferred_encoding == u'ascii':
        logging.warning(
            u'The preferred encoding of your system is ASCII, which is not optimal '
            u'for the typically non-ASCII characters that need to be parsed and '
            u'processed. The tool will most likely crash and die, perhaps in a way '
            u'that may not be recoverable. A five second delay is introduced to '
            u'give you time to cancel the runtime and reconfigure your preferred '
            u'encoding, otherwise continue at own risk.')
        time.sleep(5)

    try:
        counter = front_end.ProcessStorage(options)

        if not options.quiet:
            logging.info(frontend_utils.FormatHeader(u'Counter'))
            for element, count in counter.most_common():
                logging.info(frontend_utils.FormatOutputString(element, count))

    except IOError as exception:
        # Piping results to "|head" for instance causes an IOError.
        if u'Broken pipe' not in exception:
            logging.error(
                u'Processing stopped early: {0:s}.'.format(exception))

    except KeyboardInterrupt:
        pass

    # Catching every remaining exception in case we are debugging.
    except Exception as exception:
        if not options.debug:
            raise
        logging.error(u'{0:s}'.format(exception))
        pdb.post_mortem()

    return True
示例#15
0
    def _PreprocessSetCollectionInformation(self,
                                            pre_obj,
                                            source_type,
                                            unused_engine,
                                            filter_file=None,
                                            parser_filter_string=None,
                                            preferred_encoding=u'utf-8'):
        """Sets the collection information as part of the preprocessing.

    Args:
      pre_obj: the preprocess object (instance of PreprocessObject).
      source_type: the dfVFS source type definition.
      engine: the engine object (instance of BaseEngine).
      filter_file: a path to a file that contains find specifications.
                   The default is None.
      parser_filter_string: optional parser filter string. The default is None.
      preferred_encoding: optional preferred encoding. The default is UTF-8.
    """
        collection_information = {}

        # TODO: informational values.
        collection_information[u'version'] = plaso.GetVersion()
        collection_information[u'debug'] = self._debug_mode

        # TODO: extraction preferences:
        if not parser_filter_string:
            parser_filter_string = u'(no list set)'
        collection_information[u'parser_selection'] = parser_filter_string
        collection_information[u'preferred_encoding'] = preferred_encoding

        # TODO: extraction info:
        collection_information[u'configured_zone'] = pre_obj.zone
        collection_information[u'parsers'] = self._parser_names
        collection_information[u'preprocess'] = self._enable_preprocessing

        if self._filter_expression:
            collection_information[u'filter'] = self._filter_expression

        if filter_file and os.path.isfile(filter_file):
            filters = []
            with open(filter_file, 'rb') as file_object:
                for line in file_object.readlines():
                    filters.append(line.rstrip())
            collection_information[u'file_filter'] = u', '.join(filters)

        if self._operating_system:
            collection_information[u'os_detected'] = self._operating_system
        else:
            collection_information[u'os_detected'] = u'N/A'

        # TODO: processing settings:
        collection_information[u'protobuf_size'] = self._buffer_size
        collection_information[u'time_of_run'] = timelib.Timestamp.GetNow()

        if self._single_process_mode:
            collection_information[u'runtime'] = u'single process mode'
        else:
            collection_information[u'runtime'] = u'multi process mode'
            # TODO: retrieve this value from the multi-process engine.
            # refactor engine to set number_of_extraction_workers
            # before ProcessSources.
            collection_information[u'workers'] = 0

        # TODO: output/storage settings:
        collection_information[u'output_file'] = self._storage_file_path

        # TODO: source settings:

        # TODO: move source_scanner.SourceScannerContext.SOURCE_TYPE_
        # to definitions.SOURCE_TYPE_.
        if source_type == source_scanner.SourceScannerContext.SOURCE_TYPE_DIRECTORY:
            recursive = True
        else:
            recursive = False

        # TODO: replace by scan node.
        # collection_information[u'file_processed'] = self._source_path
        collection_information[u'recursive'] = recursive
        # TODO: replace by scan node.
        # collection_information[u'vss parsing'] = bool(self.vss_stores)

        # TODO: move source_scanner.SourceScannerContext.SOURCE_TYPE_
        # to definitions.SOURCE_TYPE_.
        if source_type in [
                source_scanner.SourceScannerContext.
                SOURCE_TYPE_STORAGE_MEDIA_DEVICE, source_scanner.
                SourceScannerContext.SOURCE_TYPE_STORAGE_MEDIA_IMAGE
        ]:
            collection_information[u'method'] = u'imaged processed'
            # TODO: replace by scan node.
            # collection_information[u'image_offset'] = self.partition_offset
        else:
            collection_information[u'method'] = u'OS collection'

        pre_obj.collection_information = collection_information
示例#16
0
    def Process(self, persistent_disk_name, project_name, disk_name):
        """Configure and run Plaso processing.

    Args:
        persistent_disk_name: Name of disk to process (created from snapshot).
        project_name: Project name of remote project being processed.
        disk_name: Name of remote disk that the snapshot was created from.
    """
        compute_client = CreateServiceClient(u'compute')
        path = u'/dev/disk/by-id/google-' + config.DEVICE_NAME

        if IsBlockDevice(path):
            WriteToStdOut(u'Disk already attached!')
            self._DetachDisk(compute_client)

        # Mount the disk
        disk_path = (u'projects/' + config.PROJECT + u'/zones/' + config.ZONE +
                     u'/disks/' + persistent_disk_name)
        self._AttachDisk(compute_client, disk_path)
        output_file_basename = project_name + disk_name + GetCurrentTimeUTC()

        # Make sure we have a proper block device
        _RETRY_MAX = 10
        _RETRY_COUNT = 0
        while _RETRY_COUNT < _RETRY_MAX:
            if IsBlockDevice(path):
                WriteToStdOut(u'Block device: OK')
                break
            if os.path.exists(path):
                WriteToStdOut(u'Block device: Current mode is {0}'.format(
                    os.stat(path).st_mode))
            _RETRY_COUNT += 1
            time.sleep(1)

        # Configure Log2Timeline
        tool = log2timeline.Log2TimelineTool()
        options = argparse.Namespace()
        options.debug = True
        options.hashers = u'all'
        options.dependencies_check = False
        options.serializer_format = u'json'
        options.status_view_mode = u'none'
        options.vss_stores = u'all'
        options.partition_number = u'all'
        options.log_file = os.path.join(config.SCRATCH_PATH,
                                        output_file_basename + u'.log')
        # Let plaso choose the appropriate number of workers
        options.workers = 0
        options.source = u'/dev/disk/by-id/google-' + config.DEVICE_NAME
        options.output = os.path.join(config.SCRATCH_PATH,
                                      output_file_basename + u'.plaso')
        tool.ParseOptions(options)
        WriteToStdOut(u'Plaso {0:s} {1:s} START'.format(
            plaso.GetVersion(), project_name))
        tool.ProcessSources()
        WriteToStdOut(u'Plaso {0:s} {1:s} END'.format(plaso.GetVersion(),
                                                      project_name))

        # Add to timesketch
        timesketch_client = TimesketchApiClient(config.TIMESKETCH_HOST,
                                                config.TIMESKETCH_USER,
                                                config.TIMESKETCH_PASSWORD)
        # Create sketch
        sketch_id = timesketch_client.CreateSketch(name=sketch_name,
                                                   description=sketch_name)
        # Create index from Plaso storage file
        index_id = timesketch_client.UploadTimeline(
            timeline_name=timeline_name, plaso_storage_path=storage_file)
        # Create sketch
        timesketch_client.AddTimelineToSketch(sketch_id, index_id)

        # Upload to GCS
        storage_client = CreateServiceClient(u'storage')
        self._CopyFileToBucket(storage_client, options.log_file,
                               output_file_basename + u'.log')
        self._CopyFileToBucket(storage_client, options.output,
                               output_file_basename + u'.plaso')
        self._DetachDisk(compute_client)
示例#17
0
  def testPrintStatusUpdate(self):
    """Tests the PrintStatusUpdate function."""
    input_reader = tools.StdinInputReader(encoding=u'ascii')
    output_writer = test_lib.TestOutputWriter()

    status_view_tool = TestStatusViewTool(
        input_reader=input_reader, output_writer=output_writer)

    status_view_tool._PrintStatusHeader()

    process_status = processing_status.ProcessingStatus()
    process_status.UpdateForemanStatus(
        u'f_identifier', u'f_status', 123, 0,
        u'f_test_file', 1, 29, 3, 456, 5, 6, 7,
        8, 9, 10)
    status_view_tool._PrintStatusUpdate(process_status)

    string = output_writer.ReadOutput()

    plaso_version = plaso.GetVersion()

    table_header = (
        b'Identifier\tPID\tStatus\t\tMemory\t\tSources\t\tEvents\t\tFile')
    if not sys.platform.startswith(u'win'):
      table_header = b'\x1b[1m{0:s}\x1b[0m'.format(table_header)

    expected_lines = [
        b'Source path\t: /test/source/path',
        b'Source type\t: TESTSOURCE',
        b'',
        b'plaso -  version {0:s}'.format(plaso_version),
        b'',
        b'Source path\t: /test/source/path',
        b'Source type\t: TESTSOURCE',
        b'',
        table_header,
        (b'f_identifier\t123\tf_status\t0 B\t\t29 (29)\t\t456 (456)\t'
         b'f_test_file'),
        b'',
        b'']
    self.assertEqual(string.split(b'\n'), expected_lines)

    process_status.UpdateWorkerStatus(
        u'w_identifier', u'w_status', 123, 0,
        u'w_test_file', 1, 2, 3, 4, 5, 6, 7, 8, 9,
        10)
    status_view_tool._PrintStatusUpdate(process_status)
    string = output_writer.ReadOutput()

    expected_lines = [
        b'plaso -  version {0:s}'.format(plaso_version),
        b'',
        b'Source path\t: /test/source/path',
        b'Source type\t: TESTSOURCE',
        b'',
        table_header,
        (b'f_identifier\t123\tf_status\t0 B\t\t29 (29)\t\t456 (456)\t'
         b'f_test_file'),
        b'w_identifier\t123\tw_status\t0 B\t\t2 (2)\t\t4 (4)\t\tw_test_file',
        b'',
        b'']
    self.assertEqual(string.split(b'\n'), expected_lines)
示例#18
0
def Main():
    """Start the tool."""
    multiprocessing.freeze_support()

    front_end = log2timeline.Log2TimelineFrontend()

    epilog = u'\n'.join([
        u'', u'Example usage:', u'',
        u'Run the tool against an image (full kitchen sink)',
        u'    log2timeline.py /cases/mycase/plaso.dump ímynd.dd', u'',
        u'Instead of answering questions, indicate some of the options on the',
        u'command line (including data from particular VSS stores).',
        (u'    log2timeline.py -o 63 --vss_stores 1,2 /cases/plaso_vss.dump '
         u'image.E01'), u'',
        u'And that\'s how you build a timeline using log2timeline...', u''
    ])

    description = u'\n'.join([
        u'',
        u'log2timeline is the main front-end to the plaso back-end, used to',
        u'collect and correlate events extracted from a filesystem.', u'',
        u'More information can be gathered from here:',
        u'    http://plaso.kiddaland.net/usage/log2timeline', u''
    ])

    arg_parser = argparse.ArgumentParser(
        description=textwrap.dedent(description),
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog=textwrap.dedent(epilog),
        add_help=False)

    # Create few argument groups to make formatting help messages clearer.
    info_group = arg_parser.add_argument_group('Informational Arguments')
    function_group = arg_parser.add_argument_group('Functional Arguments')
    deep_group = arg_parser.add_argument_group('Deep Analysis Arguments')
    performance_group = arg_parser.add_argument_group('Performance Arguments')

    function_group.add_argument(
        '-z',
        '--zone',
        '--timezone',
        dest='timezone',
        action='store',
        type=str,
        default='UTC',
        help=
        (u'Define the timezone of the IMAGE (not the output). This is usually '
         u'discovered automatically by preprocessing but might need to be '
         u'specifically set if preprocessing does not properly detect or to '
         u'overwrite the detected time zone.'))

    function_group.add_argument(
        '-t',
        '--text',
        dest='text_prepend',
        action='store',
        type=unicode,
        default=u'',
        metavar='TEXT',
        help=(u'Define a free form text string that is prepended to each path '
              u'to make it easier to distinguish one record from another in a '
              u'timeline (like c:\\, or host_w_c:\\)'))

    function_group.add_argument(
        '--parsers',
        dest='parsers',
        type=str,
        action='store',
        default='',
        metavar='PARSER_LIST',
        help=
        (u'Define a list of parsers to use by the tool. This is a comma '
         u'separated list where each entry can be either a name of a parser '
         u'or a parser list. Each entry can be prepended with a minus sign '
         u'to negate the selection (exclude it). The list match is an '
         u'exact match while an individual parser matching is a case '
         u'insensitive substring match, with support for glob patterns. '
         u'Examples would be: "reg" that matches the substring "reg" in '
         u'all parser names or the glob pattern "sky[pd]" that would match '
         u'all parsers that have the string "skyp" or "skyd" in it\'s name. '
         u'All matching is case insensitive.'))

    function_group.add_argument(
        '--hashers',
        dest='hashers',
        type=str,
        action='store',
        default='',
        metavar='HASHER_LIST',
        help=(
            u'Define a list of hashers to use by the tool. This is a comma '
            u'separated list where each entry is the name of a hasher. eg. md5,'
            u'sha256.'))

    info_group.add_argument('-h',
                            '--help',
                            action='help',
                            help=u'Show this help message and exit.')

    info_group.add_argument(
        '--logfile',
        action='store',
        metavar='FILENAME',
        dest='logfile',
        type=unicode,
        default=u'',
        help=(u'If defined all log messages will be redirected to this file '
              u'instead the default STDERR.'))

    function_group.add_argument(
        '-p',
        '--preprocess',
        dest='preprocess',
        action='store_true',
        default=False,
        help=(u'Turn on preprocessing. Preprocessing is turned on by default '
              u'when parsing image files, however if a mount point is being '
              u'parsed then this parameter needs to be set manually.'))

    front_end.AddPerformanceOptions(performance_group)

    performance_group.add_argument(
        '--workers',
        dest='workers',
        action='store',
        type=int,
        default=0,
        help=(u'The number of worker threads [defaults to available system '
              u'CPU\'s minus three].'))

    # TODO: seems to be no longer used, remove.
    # function_group.add_argument(
    #     '-i', '--image', dest='image', action='store_true', default=False,
    #     help=(
    #         'Indicates that this is an image instead of a regular file. It is '
    #         'not necessary to include this option if -o (offset) is used, then '
    #         'this option is assumed. Use this when parsing an image with an '
    #         'offset of zero.'))

    front_end.AddVssProcessingOptions(deep_group)

    performance_group.add_argument(
        '--single_thread',
        '--single-thread',
        '--single_process',
        '--single-process',
        dest='single_process',
        action='store_true',
        default=False,
        help=(u'Indicate that the tool should run in a single process.'))

    function_group.add_argument(
        '-f',
        '--file_filter',
        '--file-filter',
        dest='file_filter',
        action='store',
        type=unicode,
        default=None,
        help=(
            u'List of files to include for targeted collection of files to '
            u'parse, one line per file path, setup is /path|file - where each '
            u'element can contain either a variable set in the preprocessing '
            u'stage or a regular expression.'))

    deep_group.add_argument('--scan_archives',
                            dest='scan_archives',
                            action='store_true',
                            default=False,
                            help=argparse.SUPPRESS)

    # This option is "hidden" for the time being, still left in there for testing
    # purposes, but hidden from the tool usage and help messages.
    #    help=('Indicate that the tool should try to open files to extract embedd'
    #          'ed files within them, for instance to extract files from compress'
    #          'ed containers, etc. Be AWARE THAT THIS IS EXTREMELY SLOW.'))

    front_end.AddImageOptions(function_group)

    function_group.add_argument(
        '--partition',
        dest='partition_number',
        action='store',
        type=int,
        default=None,
        help=(u'Choose a partition number from a disk image. This partition '
              u'number should correspond to the partion number on the disk '
              u'image, starting from partition 1.'))

    # Build the version information.
    version_string = u'log2timeline - plaso back-end {0:s}'.format(
        plaso.GetVersion())

    info_group.add_argument('-v',
                            '--version',
                            action='version',
                            version=version_string,
                            help=u'Show the current version of the back-end.')

    info_group.add_argument(
        '--info',
        dest='show_info',
        action='store_true',
        default=False,
        help=u'Print out information about supported plugins and parsers.')

    info_group.add_argument(
        '--show_memory_usage',
        '--show-memory-usage',
        action='store_true',
        default=False,
        dest='foreman_verbose',
        help=(u'Indicates that basic memory usage should be included in the '
              u'output of the process monitor. If this option is not set the '
              u'tool only displays basic status and counter information.'))

    info_group.add_argument(
        '--disable_worker_monitor',
        '--disable-worker-monitor',
        action='store_false',
        default=True,
        dest='foreman_enabled',
        help=
        (u'Turn off the foreman. The foreman monitors all worker processes '
         u'and periodically prints out information about all running workers.'
         u'By default the foreman is run, but it can be turned off using this '
         u'parameter.'))

    front_end.AddExtractionOptions(function_group)

    function_group.add_argument(
        '--output',
        dest='output_module',
        action='store',
        type=unicode,
        default='',
        help=(
            u'Bypass the storage module directly storing events according to '
            u'the output module. This means that the output will not be in the '
            u'pstorage format but in the format chosen by the output module. '
            u'[Please not this feature is EXPERIMENTAL at this time, use at '
            u'own risk (eg. sqlite output does not yet work)]'))

    function_group.add_argument(
        '--serializer-format',
        '--serializer_format',
        dest='serializer_format',
        action='store',
        default='proto',
        metavar='FORMAT',
        help=(u'By default the storage uses protobufs for serializing event '
              u'objects. This parameter can be used to change that behavior. '
              u'The choices are "proto" and "json".'))

    front_end.AddInformationalOptions(info_group)

    arg_parser.add_argument(
        'output',
        action='store',
        metavar='STORAGE_FILE',
        nargs='?',
        type=unicode,
        help=(u'The path to the output file, if the file exists it will get '
              u'appended to.'))

    arg_parser.add_argument(
        'source',
        action='store',
        metavar='SOURCE',
        nargs='?',
        type=unicode,
        help=
        (u'The path to the source device, file or directory. If the source is '
         u'a supported storage media device or image file, archive file or '
         u'a directory, the files within are processed recursively.'))

    arg_parser.add_argument(
        'filter',
        action='store',
        metavar='FILTER',
        nargs='?',
        default=None,
        type=unicode,
        help=(u'A filter that can be used to filter the dataset before it '
              u'is written into storage. More information about the filters '
              u'and it\'s usage can be found here: http://plaso.kiddaland.'
              u'net/usage/filters'))

    # Properly prepare the attributes according to local encoding.
    if front_end.preferred_encoding == 'ascii':
        logging.warning(
            u'The preferred encoding of your system is ASCII, which is not optimal '
            u'for the typically non-ASCII characters that need to be parsed and '
            u'processed. The tool will most likely crash and die, perhaps in a way '
            u'that may not be recoverable. A five second delay is introduced to '
            u'give you time to cancel the runtime and reconfigure your preferred '
            u'encoding, otherwise continue at own risk.')
        time.sleep(5)

    u_argv = [x.decode(front_end.preferred_encoding) for x in sys.argv]
    sys.argv = u_argv
    try:
        options = arg_parser.parse_args()
    except UnicodeEncodeError:
        # If we get here we are attempting to print help in a "dumb" terminal.
        print arg_parser.format_help().encode(front_end.preferred_encoding)
        return False

    if options.timezone == 'list':
        front_end.ListTimeZones()
        return True

    if options.show_info:
        front_end.ListPluginInformation()
        return True

    format_str = (
        u'%(asctime)s [%(levelname)s] (%(processName)-10s) PID:%(process)d '
        u'<%(module)s> %(message)s')

    if options.debug:
        if options.logfile:
            logging.basicConfig(level=logging.DEBUG,
                                format=format_str,
                                filename=options.logfile)
        else:
            logging.basicConfig(level=logging.DEBUG, format=format_str)

        logging_filter = log2timeline.LoggingFilter()
        root_logger = logging.getLogger()
        root_logger.addFilter(logging_filter)
    elif options.logfile:
        logging.basicConfig(level=logging.INFO,
                            format=format_str,
                            filename=options.logfile)
    else:
        logging.basicConfig(level=logging.INFO, format=format_str)

    if not options.output:
        arg_parser.print_help()
        print u''
        arg_parser.print_usage()
        print u''
        logging.error(u'Wrong usage: need to define an output.')
        return False

    try:
        front_end.ParseOptions(options)
        front_end.SetStorageFile(options.output)
    except errors.BadConfigOption as exception:
        arg_parser.print_help()
        print u''
        logging.error(u'{0:s}'.format(exception))
        return False

    # Configure the foreman (monitors workers).
    front_end.SetShowMemoryInformation(show_memory=options.foreman_verbose)
    front_end.SetRunForeman(run_foreman=options.foreman_enabled)

    try:
        front_end.ProcessSource(options)
        logging.info(u'Processing completed.')

    except (KeyboardInterrupt, errors.UserAbort):
        logging.warning(u'Aborted by user.')
        return False

    except errors.SourceScannerError as exception:
        logging.warning(
            (u'Unable to scan for a supported filesystem with error: {0:s}\n'
             u'Most likely the image format is not supported by the '
             u'tool.').format(exception))
        return False

    return True
示例#19
0
master_doc = 'index'

# General information about the project.
project = u'Plaso'
# This is a built in, but also apparently a sphinx config option.
# pylint: disable=redefined-builtin
copyright = u'The Plaso Project Authors'

# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = plaso.__version__
# The full version, including alpha/beta/rc tags.
release = plaso.GetVersion()

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None

# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'

# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']
示例#20
0
  encoding = locale.getpreferredencoding()

# Make sure the default encoding is set correctly otherwise
# setup.py sdist will fail to include filenames with Unicode characters.
reload(sys)
sys.setdefaultencoding(encoding)

# Unicode in the description will break python-setuptools, hence
# "Plaso Langar Að Safna Öllu" was removed.
plaso_description = (
    u'plaso is a tool designed to extract timestamps from various files found '
    u'on a typical computer system(s) and aggregate them.')

setup(
    name='plaso',
    version=plaso.GetVersion(),
    description=plaso_description,
    long_description=plaso_description,
    license='Apache License, Version 2.0',
    url='https://sites.google.com/a/kiddaland.net/plaso',
    maintainer='Plaso development team',
    maintainer_email='*****@*****.**',
    scripts=GetScripts(),
    cmdclass={'test': TestCommand},
    classifiers=[
        'Development Status :: 4 - Beta',
        'Environment :: Console',
        'Operating System :: OS Independent',
        'Programming Language :: Python',
    ],
    packages=find_packages('.', exclude=[u'tests', u'tests.*', u'tools']),
示例#21
0
  def _PreprocessSetCollectionInformation(
      self, pre_obj, unused_engine, filter_file=None,
      parser_filter_string=None):
    """Sets the collection information as part of the preprocessing.

    Args:
      pre_obj: the preprocess object (instance of PreprocessObject).
      engine: the engine object (instance of BaseEngine).
      filter_file: a path to a file that contains find specifications.
                   The default is None.
      parser_filter_string: optional parser filter string. The default is None.
    """
    collection_information = {}

    # TODO: informational values.
    collection_information[u'version'] = plaso.GetVersion()
    collection_information[u'debug'] = self._debug_mode

    # TODO: extraction preferences:
    if not parser_filter_string:
      parser_filter_string = u'(no list set)'
    collection_information[u'parser_selection'] = parser_filter_string
    collection_information[u'preferred_encoding'] = self.preferred_encoding

    # TODO: extraction info:
    collection_information[u'configured_zone'] = pre_obj.zone
    collection_information[u'parsers'] = self._parser_names
    collection_information[u'preprocess'] = self._preprocess

    if self._filter_expression:
      collection_information[u'filter'] = self._filter_expression

    if filter_file and os.path.isfile(filter_file):
      filters = []
      with open(filter_file, 'rb') as file_object:
        for line in file_object.readlines():
          filters.append(line.rstrip())
      collection_information[u'file_filter'] = u', '.join(filters)

    if self._operating_system:
      collection_information[u'os_detected'] = self._operating_system
    else:
      collection_information[u'os_detected'] = 'N/A'

    # TODO: processing settings:
    collection_information[u'protobuf_size'] = self._buffer_size
    collection_information[u'time_of_run'] = timelib.Timestamp.GetNow()

    if self._single_process_mode:
      collection_information[u'runtime'] = u'single process mode'
    else:
      collection_information[u'runtime'] = u'multi process mode'
      # TODO: retrieve this value from the multi-process engine.
      # refactor engine to set number_of_extraction_workers
      # before ProcessSource.
      collection_information[u'workers'] = 0

    # TODO: output/storage settings:
    collection_information[u'output_file'] = self._storage_file_path

    # TODO: source settings:
    if self.SourceIsDirectory():
      recursive = True
    else:
      recursive = False

    collection_information[u'file_processed'] = self._source_path
    collection_information[u'recursive'] = recursive
    collection_information[u'vss parsing'] = bool(self.vss_stores)

    if self.SourceIsStorageMediaImage():
      collection_information[u'method'] = u'imaged processed'
      collection_information[u'image_offset'] = self.partition_offset
    else:
      collection_information[u'method'] = u'OS collection'

    pre_obj.collection_information = collection_information
示例#22
0
  def _PreprocessSetCollectionInformation(self, options, pre_obj):
    """Sets the collection information as part of the preprocessing.

    Args:
      options: the command line arguments (instance of argparse.Namespace).
      pre_obj: the preprocess object (instance of PreprocessObject).
    """
    collection_information = {}

    collection_information['version'] = plaso.GetVersion()
    collection_information['configured_zone'] = self._timezone
    collection_information['file_processed'] = self._source_path
    collection_information['output_file'] = self._storage_file_path
    collection_information['protobuf_size'] = self._buffer_size
    collection_information['parser_selection'] = getattr(
        options, 'parsers', '(no list set)')
    collection_information['preferred_encoding'] = self.preferred_encoding
    collection_information['time_of_run'] = timelib.Timestamp.GetNow()

    collection_information['parsers'] = self._parser_names
    collection_information['preprocess'] = self._preprocess

    if self._scan_context.source_type in [
        self._scan_context.SOURCE_TYPE_DIRECTORY]:
      recursive = True
    else:
      recursive = False
    collection_information['recursive'] = recursive
    collection_information['debug'] = self._debug_mode
    collection_information['vss parsing'] = bool(self._vss_stores)

    if self._filter_expression:
      collection_information['filter'] = self._filter_expression

    filter_file = getattr(options, 'file_filter', None)
    if filter_file:
      if os.path.isfile(filter_file):
        filters = []
        with open(filter_file, 'rb') as fh:
          for line in fh:
            filters.append(line.rstrip())
        collection_information['file_filter'] = ', '.join(filters)

    if self._operating_system:
      collection_information['os_detected'] = self._operating_system
    else:
      collection_information['os_detected'] = 'N/A'

    if self._scan_context.source_type in [
        self._scan_context.SOURCE_TYPE_STORAGE_MEDIA_DEVICE,
        self._scan_context.SOURCE_TYPE_STORAGE_MEDIA_IMAGE]:
      collection_information['method'] = 'imaged processed'
      collection_information['image_offset'] = self._partition_offset
    else:
      collection_information['method'] = 'OS collection'

    if self._single_process_mode:
      collection_information['runtime'] = 'single process mode'
    else:
      collection_information['runtime'] = 'multi process mode'
      collection_information['workers'] = self._number_of_worker_processes

    pre_obj.collection_information = collection_information
示例#23
0
    def _PrintStatusUpdate(self, processing_status):
        """Prints the processing status.

    Args:
      processing_status: the processing status (instance of ProcessingStatus).
    """
        if self._stdout_output_writer:
            self._ClearScreen()

        self._output_writer.Write(u'plaso - {0:s} version {1:s}\n'.format(
            self.NAME, plaso.GetVersion()))
        self._output_writer.Write(u'\n')

        self._PrintStatusHeader()

        # TODO: for win32console get current color and set intensity,
        # write the header separately then reset intensity.
        status_header = u'Identifier\tPID\tStatus\t\tEvents\t\tFile'
        if not win32console:
            status_header = u'\x1b[1m{0:s}\x1b[0m'.format(status_header)

        status_table = [status_header]

        status_row = self._FormatStatusTableRow(
            processing_status.collector.identifier,
            processing_status.collector.pid,
            processing_status.collector.status,
            processing_status.collector.process_status, None, None, u'')

        status_table.append(status_row)

        for extraction_worker_status in processing_status.extraction_workers:
            status_row = self._FormatStatusTableRow(
                extraction_worker_status.identifier,
                extraction_worker_status.pid, extraction_worker_status.status,
                extraction_worker_status.process_status,
                extraction_worker_status.number_of_events,
                extraction_worker_status.number_of_events_delta,
                extraction_worker_status.display_name)

            status_table.append(status_row)

        if processing_status.storage_writer:
            status_row = self._FormatStatusTableRow(
                processing_status.storage_writer.identifier,
                processing_status.storage_writer.pid,
                processing_status.storage_writer.status,
                processing_status.storage_writer.process_status,
                processing_status.storage_writer.number_of_events,
                processing_status.storage_writer.number_of_events_delta, u'')

        status_table.append(status_row)

        status_table.append(u'')
        self._output_writer.Write(u'\n'.join(status_table))
        self._output_writer.Write(u'\n')

        if processing_status.GetExtractionCompleted():
            self._output_writer.Write(
                u'All extraction workers completed - waiting for storage.\n')
            self._output_writer.Write(u'\n')

        # TODO: remove update flicker. For win32console we could set the cursor
        # top left, write the table, clean the remainder of the screen buffer
        # and set the cursor at the end of the table.
        if self._stdout_output_writer:
            # We need to explicitly flush stdout to prevent partial status updates.
            sys.stdout.flush()