diff --git a/plaso/containers/artifacts.py b/plaso/containers/artifacts.py index 9c3fae1cce..a5c3cc2054 100644 --- a/plaso/containers/artifacts.py +++ b/plaso/containers/artifacts.py @@ -664,7 +664,9 @@ class WindowsEventLogProviderArtifact( Attributes: category_message_files (list[str]): filenames of the category message files. event_message_files (list[str]): filenames of the event message files. - log_source (str): Windows EventLog source. + identifier (str): identifier of the provider, contains a GUID. + log_source (str): name of the Windows EventLog source. + log_source_alias (str): alternate name of the Windows EventLog source. log_type (str): Windows EventLog type. parameter_message_files (list[str]): filenames of the parameter message files. @@ -675,13 +677,16 @@ class WindowsEventLogProviderArtifact( '_system_configuration_row_identifier': 'AttributeContainerIdentifier', 'category_message_files': 'List[str]', 'event_message_files': 'List[str]', + 'identifier': 'str', 'log_source': 'str', + 'log_source_alias': 'str', 'log_type': 'str', 'parameter_message_files': 'List[str]'} def __init__( self, category_message_files=None, event_message_files=None, - log_source=None, log_type=None, parameter_message_files=None): + identifier=None, log_source=None, log_type=None, + parameter_message_files=None): """Initializes a Windows EventLog provider artifact. Args: @@ -689,7 +694,8 @@ def __init__( message files. event_message_files (Optional[list[str]]): filenames of the event message files. - log_source (Optional[str]): Windows EventLog source. + identifier (Optional[str]): identifier of the provider, contains a GUID. + log_source (Optional[str]): name of the Windows EventLog source. log_type (Optional[str]): Windows EventLog type. parameter_message_files (Optional[list[str]]): filenames of the parameter message files. @@ -697,7 +703,9 @@ def __init__( super(WindowsEventLogProviderArtifact, self).__init__() self.category_message_files = category_message_files self.event_message_files = event_message_files + self.identifier = identifier self.log_source = log_source + self.log_source_alias = None self.log_type = log_type self.parameter_message_files = parameter_message_files diff --git a/plaso/engine/knowledge_base.py b/plaso/engine/knowledge_base.py index 4b4c1a6e73..d0384fd762 100644 --- a/plaso/engine/knowledge_base.py +++ b/plaso/engine/knowledge_base.py @@ -350,6 +350,18 @@ def GetValue(self, identifier, default_value=None): identifier = identifier.lower() return self._values.get(identifier, default_value) + def GetWindowsEventLogProvider(self, log_source): + """Retrieves a Windows EventLog provider by log source. + + Args: + log_source (str): EventLog source, such as "Application Error". + + Returns: + WindowsEventLogProviderArtifact: Windows EventLog provider artifact or + None if not available. + """ + return self._windows_eventlog_providers.get(log_source, None) + def GetWindowsEventLogProviders(self): """Retrieves the Windows EventLog providers. diff --git a/plaso/output/winevt_rc.py b/plaso/output/winevt_rc.py index efe260778a..6f896b2116 100644 --- a/plaso/output/winevt_rc.py +++ b/plaso/output/winevt_rc.py @@ -7,6 +7,7 @@ from plaso.containers import artifacts from plaso.engine import path_helper +from plaso.output import logger from plaso.winnt import resource_files @@ -465,6 +466,8 @@ def _ReadWindowsEventLogMessageString( Args: storage_reader (StorageReader): storage reader. + log_source (str): EventLog source, such as "Application Error". + message_identifier (int): message identifier. Returns: str: message string or None if not available. @@ -478,7 +481,8 @@ def _ReadWindowsEventLogMessageString( if self._windows_eventlog_message_files is None: self._ReadWindowsEventLogMessageFiles(storage_reader) - provider = self._windows_eventlog_providers.get(log_source, None) + provider = self._windows_eventlog_providers.get( + log_source.lower(), None) if not provider: return None @@ -486,6 +490,7 @@ def _ReadWindowsEventLogMessageString( 'windows_eventlog_message_string'): return None + message_file_identifiers = [] for windows_path in provider.event_message_files or []: path, filename = path_helper.PathHelper.GetWindowsSystemPath( windows_path, self._environment_variables) @@ -495,19 +500,33 @@ def _ReadWindowsEventLogMessageString( lookup_path, None) if message_file_identifier: message_file_identifier = message_file_identifier.CopyToString() - # TODO: filter message file - filter_expression = ( - 'language_identifier == {0:d} and ' - 'message_identifier == {1:d}').format( - self._lcid, message_identifier) - - for message_string in storage_reader.GetAttributeContainers( - 'windows_eventlog_message_string', - filter_expression=filter_expression): - identifier = message_string.GetMessageFileIdentifier() - identifier = identifier.CopyToString() - if identifier == message_file_identifier: - return message_string.string + message_file_identifiers.append(message_file_identifier) + + message_strings = [] + if message_file_identifiers: + filter_expression = ( + 'language_identifier == {0:d} and ' + 'message_identifier == {1:d}').format( + self._lcid, message_identifier) + + # TODO: add message_file_identifiers to filter_expression + for message_string in storage_reader.GetAttributeContainers( + 'windows_eventlog_message_string', + filter_expression=filter_expression): + identifier = message_string.GetMessageFileIdentifier() + identifier = identifier.CopyToString() + if identifier in message_file_identifiers: + message_strings.append(message_string) + + if not message_strings: + logger.error( + 'No match for message: 0x{0:08x} of source: {1:s}'.format( + message_identifier, log_source)) + + # TODO: add support for mappings in the WEVT_TEMPLATE PE/COFF resource + + if message_strings: + return message_strings[0].string return None @@ -521,7 +540,13 @@ def _ReadWindowsEventLogProviders(self, storage_reader): if storage_reader.HasAttributeContainers('windows_eventlog_provider'): for provider in storage_reader.GetAttributeContainers( 'windows_eventlog_provider'): - self._windows_eventlog_providers[provider.log_source] = provider + + log_source = provider.log_source.lower() + self._windows_eventlog_providers[log_source] = provider + + if provider.log_source_alias: + log_source = provider.log_source_alias.lower() + self._windows_eventlog_providers[log_source] = provider def GetMessageString(self, log_source, message_identifier): """Retrieves a specific Windows EventLog message string. diff --git a/plaso/parsers/winevtx.py b/plaso/parsers/winevtx.py index 2a7027fa2c..4279c1c130 100644 --- a/plaso/parsers/winevtx.py +++ b/plaso/parsers/winevtx.py @@ -24,6 +24,7 @@ class WinEvtxRecordEventData(events.EventData): message_identifier (int): event message identifier. offset (int): offset of the EVTX record relative to the start of the file, from which the event data was extracted. + provider_identifier (str): identifier of the EventLog provider. record_number (int): event record number. recovered (bool): True if the record was recovered. source_name (str): name of the event source. @@ -42,6 +43,7 @@ def __init__(self): self.event_level = None self.message_identifier = None self.offset = None + self.provider_identifier = None self.record_number = None self.recovered = None self.source_name = None @@ -121,6 +123,9 @@ def _GetEventDataFromRecord( if event_identifier_qualifiers is not None: event_data.message_identifier |= event_identifier_qualifiers << 16 + if evtx_record.provider_identifier: + event_data.provider_identifier = evtx_record.provider_identifier.lower() + event_data.event_level = evtx_record.event_level event_data.source_name = evtx_record.source_name diff --git a/plaso/preprocessors/mediator.py b/plaso/preprocessors/mediator.py index f334e0b85c..6c792f441d 100644 --- a/plaso/preprocessors/mediator.py +++ b/plaso/preprocessors/mediator.py @@ -23,6 +23,7 @@ def __init__(self, session, storage_writer, knowledge_base): self._knowledge_base = knowledge_base self._session = session self._storage_writer = storage_writer + self._windows_eventlog_providers_by_identifier = {} @property def knowledge_base(self): @@ -86,15 +87,56 @@ def AddWindowsEventLogProvider(self, windows_eventlog_provider): Raises: KeyError: if the Windows EventLog provider already exists. """ - if self._storage_writer: - system_configuration_identifier = ( - self._storage_writer.GetSystemConfigurationIdentifier()) - windows_eventlog_provider.SetSystemConfigurationIdentifier( - system_configuration_identifier) + provider_identifier = windows_eventlog_provider.identifier + + existing_provider = self._knowledge_base.GetWindowsEventLogProvider( + windows_eventlog_provider.log_source) + + if not existing_provider and provider_identifier: + existing_provider = self._windows_eventlog_providers_by_identifier.get( + provider_identifier, None) + + if existing_provider: + existing_provider.log_source_alias = existing_provider.log_source + existing_provider.log_source = windows_eventlog_provider.log_source + + if existing_provider: + if not existing_provider.category_message_files: + existing_provider.category_message_files = ( + windows_eventlog_provider.category_message_files) + + if not existing_provider.event_message_files: + existing_provider.event_message_files = ( + windows_eventlog_provider.event_message_files) + + if not existing_provider.identifier: + existing_provider.identifier = windows_eventlog_provider.identifier + + if not existing_provider.log_type: + existing_provider.log_type = windows_eventlog_provider.log_type + + if not existing_provider.parameter_message_files: + existing_provider.parameter_message_files = ( + windows_eventlog_provider.parameter_message_files) + + if self._storage_writer: + self._storage_writer.UpdateAttributeContainer(existing_provider) + + else: + if self._storage_writer: + system_configuration_identifier = ( + self._storage_writer.GetSystemConfigurationIdentifier()) + windows_eventlog_provider.SetSystemConfigurationIdentifier( + system_configuration_identifier) + + self._storage_writer.AddAttributeContainer(windows_eventlog_provider) - self._storage_writer.AddAttributeContainer(windows_eventlog_provider) + self._knowledge_base.AddWindowsEventLogProvider( + windows_eventlog_provider) - self._knowledge_base.AddWindowsEventLogProvider(windows_eventlog_provider) + if provider_identifier: + self._windows_eventlog_providers_by_identifier[provider_identifier] = ( + windows_eventlog_provider) def GetEnvironmentVariable(self, name): """Retrieves an environment variable. diff --git a/plaso/preprocessors/windows.py b/plaso/preprocessors/windows.py index cafb3b4218..b2680efe6d 100644 --- a/plaso/preprocessors/windows.py +++ b/plaso/preprocessors/windows.py @@ -335,13 +335,17 @@ def _ParseKey(self, mediator, registry_key, value_name): log_source = registry_value.GetDataAsObject() event_message_files = None - registry_value = registry_key.GetValueByName('MessageFile') + registry_value = registry_key.GetValueByName('MessageFileName') if registry_value: event_message_files = registry_value.GetDataAsObject() - event_message_files = event_message_files.split(';') + event_message_files = sorted(filter(None, [ + path.strip().lower() for path in event_message_files.split(';')])) + + provider_identifier = registry_key.name.lower() windows_event_log_provider = artifacts.WindowsEventLogProviderArtifact( - event_message_files=event_message_files, log_source=log_source) + event_message_files=event_message_files, identifier=provider_identifier, + log_source=log_source) try: mediator.AddWindowsEventLogProvider(windows_event_log_provider) @@ -375,19 +379,28 @@ def _ParseKey(self, mediator, registry_key, value_name): registry_value = registry_key.GetValueByName('CategoryMessageFile') if registry_value: category_message_files = registry_value.GetDataAsObject() - category_message_files = category_message_files.split(';') + category_message_files = sorted(filter(None, [ + path.strip().lower() for path in category_message_files.split(';')])) event_message_files = None registry_value = registry_key.GetValueByName('EventMessageFile') if registry_value: event_message_files = registry_value.GetDataAsObject() - event_message_files = event_message_files.split(';') + event_message_files = sorted(filter(None, [ + path.strip().lower() for path in event_message_files.split(';')])) parameter_message_files = None registry_value = registry_key.GetValueByName('ParameterMessageFile') if registry_value: parameter_message_files = registry_value.GetDataAsObject() - parameter_message_files = parameter_message_files.split(';') + parameter_message_files = sorted(filter(None, [ + path.strip().lower() for path in parameter_message_files.split(';')])) + + provider_identifier = None + registry_value = registry_key.GetValueByName('ProviderGuid') + if registry_value: + provider_identifier = registry_value.GetDataAsObject() + provider_identifier = provider_identifier.lower() key_path_segments = registry_key.path.split('\\') log_source = key_path_segments[-1] @@ -395,8 +408,9 @@ def _ParseKey(self, mediator, registry_key, value_name): windows_event_log_provider = artifacts.WindowsEventLogProviderArtifact( category_message_files=category_message_files, - event_message_files=event_message_files, log_source=log_source, - log_type=log_type, parameter_message_files=parameter_message_files) + event_message_files=event_message_files, identifier=provider_identifier, + log_source=log_source, log_type=log_type, + parameter_message_files=parameter_message_files) try: mediator.AddWindowsEventLogProvider(windows_event_log_provider) diff --git a/plaso/storage/writer.py b/plaso/storage/writer.py index da95c59429..ea77e039b9 100644 --- a/plaso/storage/writer.py +++ b/plaso/storage/writer.py @@ -292,6 +292,20 @@ def SetStorageProfiler(self, storage_profiler): if self._store: self._store.SetStorageProfiler(storage_profiler) + def UpdateAttributeContainer(self, container): + """Updates an existing attribute container. + + Args: + container (AttributeContainer): attribute container. + + Raises: + IOError: when the storage writer is closed. + OSError: when the storage writer is closed. + """ + self._RaiseIfNotWritable() + + self._store.UpdateAttributeContainer(container) + def WriteSessionCompletion(self, session): """Writes session completion information. diff --git a/tests/parsers/winevtx.py b/tests/parsers/winevtx.py index 350896ef35..1e46f83571 100644 --- a/tests/parsers/winevtx.py +++ b/tests/parsers/winevtx.py @@ -52,6 +52,7 @@ def testParse(self): 'event_identifier': 105, 'event_level': 4, 'message_identifier': 105, + 'provider_identifier': '{fc65ddd8-d6ef-4962-83d5-6e5cfe9ce148}', 'record_number': 12049, 'source_name': 'Microsoft-Windows-Eventlog', 'strings': ['System', expected_string2]} diff --git a/tests/preprocessors/windows.py b/tests/preprocessors/windows.py index d915500763..6c841fcf80 100644 --- a/tests/preprocessors/windows.py +++ b/tests/preprocessors/windows.py @@ -274,7 +274,7 @@ def testParseValueData(self): windows_eventlog_providers = ( test_mediator.knowledge_base.GetWindowsEventLogProviders()) - self.assertEqual(len(windows_eventlog_providers), 400) + self.assertEqual(len(windows_eventlog_providers), 374) class WindowsHostnamePluginTest(test_lib.ArtifactPreprocessorPluginTestCase):