Skip to content

Commit

Permalink
Changes for Windows EventLog resources support #636 (#3867)
Browse files Browse the repository at this point in the history
  • Loading branch information
joachimmetz committed Oct 16, 2021
1 parent 747c2f8 commit 083fb79
Show file tree
Hide file tree
Showing 9 changed files with 155 additions and 34 deletions.
14 changes: 11 additions & 3 deletions plaso/containers/artifacts.py
Expand Up @@ -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.
Expand All @@ -675,29 +677,35 @@ 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:
category_message_files (Optional[list[str]]): filenames of the category
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.
"""
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

Expand Down
12 changes: 12 additions & 0 deletions plaso/engine/knowledge_base.py
Expand Up @@ -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.
Expand Down
55 changes: 40 additions & 15 deletions plaso/output/winevt_rc.py
Expand Up @@ -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


Expand Down Expand Up @@ -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.
Expand All @@ -478,14 +481,16 @@ 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

if not storage_reader.HasAttributeContainers(
'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)
Expand All @@ -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

Expand All @@ -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.
Expand Down
5 changes: 5 additions & 0 deletions plaso/parsers/winevtx.py
Expand Up @@ -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.
Expand All @@ -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
Expand Down Expand Up @@ -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

Expand Down
56 changes: 49 additions & 7 deletions plaso/preprocessors/mediator.py
Expand Up @@ -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):
Expand Down Expand Up @@ -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.
Expand Down
30 changes: 22 additions & 8 deletions plaso/preprocessors/windows.py
Expand Up @@ -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)
Expand Down Expand Up @@ -375,28 +379,38 @@ 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]
log_type = key_path_segments[-2]

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)
Expand Down
14 changes: 14 additions & 0 deletions plaso/storage/writer.py
Expand Up @@ -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.
Expand Down
1 change: 1 addition & 0 deletions tests/parsers/winevtx.py
Expand Up @@ -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]}
Expand Down
2 changes: 1 addition & 1 deletion tests/preprocessors/windows.py
Expand Up @@ -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):
Expand Down

0 comments on commit 083fb79

Please sign in to comment.