"""Parser for Windows EventLog (EVT) files."""
import pyevt
from dfdatetime import posix_time as dfdatetime_posix_time
from plaso.containers import events
from plaso.lib import specification
from plaso.parsers import interface
from plaso.parsers import manager
[docs]
class WinEvtRecordEventData(events.EventData):
"""Windows EventLog (EVT) record event data.
Attributes:
creation_time (dfdatetime.DateTimeValues): event record creation date and time.
event_category (int): event category.
event_identifier (int): event identifier.
event_type (int): event type.
facility (int): event facility.
hostname (str): hostname or computer name stored in the event record.
message_identifier (int): event message identifier.
offset (int): offset of the event record relative to the start of the file, from
which the event data was extracted.
record_number (int): event record number.
severity (int): event severity.
source_name (str): name of the event source.
strings (list[str]): event strings.
user_sid (str): user security identifier (SID) stored in the event record.
written_time (dfdatetime.DateTimeValues): event record written date and time.
"""
DATA_TYPE = "windows:evt:record"
[docs]
def __init__(self):
"""Initializes event data."""
super().__init__(data_type=self.DATA_TYPE)
self.creation_time = None
self.event_category = None
self.event_identifier = None
self.event_type = None
self.facility = None
self.hostname = None
self.message_identifier = None
self.offset = None
self.record_number = None
self.severity = None
self.source_name = None
self.strings = None
self.user_sid = None
self.written_time = None
[docs]
class WinEvtParser(interface.FileObjectParser):
"""Parses Windows EventLog (EVT) files."""
_INITIAL_FILE_OFFSET = None
NAME = "winevt"
DATA_FORMAT = "Windows EventLog (EVT) file"
def _ParseRecord(self, parser_mediator, record_index, evt_record, recovered=False):
"""Parses a Windows EventLog (EVT) record.
Args:
parser_mediator (ParserMediator): mediates interactions between parsers and
other components, such as storage and dfVFS.
record_index (int): event record index.
evt_record (pyevt.record): event record.
recovered (Optional[bool]): True if the record was recovered.
"""
corrupted = False
event_data = WinEvtRecordEventData()
try:
event_data.record_number = evt_record.identifier
except OverflowError as exception:
warning_message = (
f"unable to read record identifier from event record: {record_index:d} "
f"with error: {exception!s}"
)
parser_mediator.ProduceWarning(warning_message, recovered=recovered)
corrupted = True
try:
event_identifier = evt_record.event_identifier
except OverflowError as exception:
warning_message = (
f"unable to read event identifier from event record: {record_index:d} "
f"with error: {exception!s}"
)
parser_mediator.ProduceWarning(warning_message, recovered=recovered)
event_identifier = None
corrupted = True
event_data.offset = evt_record.offset
# We want the event identifier to match the behavior of that of the EVTX event
# records.
if event_identifier is not None:
event_data.event_identifier = event_identifier & 0xFFFF
event_data.facility = (event_identifier >> 16) & 0x0FFF
event_data.severity = event_identifier >> 30
event_data.message_identifier = event_identifier
event_data.event_type = evt_record.event_type
event_data.event_category = evt_record.event_category
event_data.source_name = evt_record.source_name
# Computer name is the value stored in the event record and does not necessarily
# correspond with the system hostname.
event_data.hostname = evt_record.computer_name
event_data.user_sid = evt_record.user_security_identifier
event_data.strings = list(evt_record.strings)
try:
timestamp = evt_record.get_creation_time_as_integer()
event_data.creation_time = dfdatetime_posix_time.PosixTime(
timestamp=timestamp
)
except OverflowError as exception:
warning_message = (
f"unable to read creation time from event record: {record_index:d} "
f"with error: {exception!s}"
)
parser_mediator.ProduceWarning(warning_message, recovered=recovered)
corrupted = True
try:
timestamp = evt_record.get_written_time_as_integer()
event_data.written_time = dfdatetime_posix_time.PosixTime(
timestamp=timestamp
)
except OverflowError as exception:
warning_message = (
f"unable to read written time from event record: {record_index:d} "
f"with error: {exception!s}"
)
parser_mediator.ProduceWarning(warning_message, recovered=recovered)
corrupted = True
parser_mediator.ProduceEventData(
event_data, corrupted=corrupted, recovered=recovered
)
def _ParseRecords(self, parser_mediator, evt_file):
"""Parses Windows EventLog (EVT) records.
Args:
parser_mediator (ParserMediator): mediates interactions between parsers and
other components, such as storage and dfVFS.
evt_file (pyevt.file): Windows EventLog (EVT) file.
"""
# To handle errors when parsing a Windows EventLog (EVT) file in the most
# granular way the following code iterates over every event record. The call
# to evt_file.get_record() and access to members of evt_record should be called
# within a try-except.
for record_index in range(evt_file.number_of_records):
if parser_mediator.abort:
break
try:
evt_record = evt_file.get_record(record_index)
self._ParseRecord(parser_mediator, record_index, evt_record)
except OSError as exception:
warning_message = (
f"unable to parse event record: {record_index:d} with error: "
f"{exception!s}"
)
parser_mediator.ProduceWarning(warning_message)
for record_index in range(evt_file.number_of_recovered_records):
if parser_mediator.abort:
break
try:
evt_record = evt_file.get_recovered_record(record_index)
self._ParseRecord(
parser_mediator, record_index, evt_record, recovered=True
)
except OSError as exception:
warning_message = (
f"unable to parse recovered event record: {record_index:d} with "
f"error: {exception!s}"
)
parser_mediator.ProduceWarning(warning_message, recovered=True)
[docs]
def ParseFileObject(self, parser_mediator, file_object):
"""Parses a Windows EventLog (EVT) file-like object.
Args:
parser_mediator (ParserMediator): mediates interactions between parsers and
other components, such as storage and dfVFS.
file_object (dfvfs.FileIO): a file-like object.
"""
code_page = parser_mediator.GetCodePage()
evt_file = pyevt.file()
evt_file.set_ascii_codepage(code_page)
try:
evt_file.open_file_object(file_object)
except OSError as exception:
warning_message = f"unable to open file with error: {exception!s}"
parser_mediator.ProduceWarning(warning_message)
return
try:
self._ParseRecords(parser_mediator, evt_file)
finally:
evt_file.close()
manager.ParsersManager.RegisterParser(WinEvtParser)