mirror of
https://github.com/hakril/PythonForWindows
synced 2026-06-08 14:31:45 +00:00
Add doc/sample/test for event log code
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
Event Log
|
||||
=========
|
||||
|
||||
.. module:: windows.winobject.event_log
|
||||
|
||||
|
||||
Some part of the Event Log WINAPI are not straightforward.
|
||||
|
||||
I have tried to offer some abstraction without completly hidding the some underlying subtilities (for now).
|
||||
|
||||
The current API may need some works to provide simpler/highter level API in the future.
|
||||
|
||||
For now, the best thing to do is look at the sample:
|
||||
|
||||
.. note::
|
||||
|
||||
See sample :ref:`sample_event_log`
|
||||
|
||||
.. warning::
|
||||
|
||||
This API have not been tested on real case yet and may be subject to changes.
|
||||
|
||||
|
||||
EvtlogManager
|
||||
"""""""""""""
|
||||
|
||||
.. autoclass:: EvtlogManager
|
||||
:special-members: __getitem__
|
||||
|
||||
|
||||
Channel
|
||||
"""""""
|
||||
|
||||
EvtChannel
|
||||
''''''''''
|
||||
|
||||
.. autoclass:: EvtChannel
|
||||
|
||||
ChannelConfig
|
||||
'''''''''''''
|
||||
|
||||
.. autoclass:: ChannelConfig
|
||||
|
||||
|
||||
Publisher
|
||||
"""""""""
|
||||
|
||||
EvtPublisher
|
||||
''''''''''''
|
||||
|
||||
.. autoclass:: EvtPublisher
|
||||
|
||||
PublisherMetadata
|
||||
'''''''''''''''''
|
||||
|
||||
.. autoclass:: PublisherMetadata
|
||||
|
||||
|
||||
EvtFile
|
||||
"""""""
|
||||
|
||||
.. autoclass:: EvtFile
|
||||
|
||||
|
||||
Event
|
||||
"""""
|
||||
|
||||
EvtEvent
|
||||
''''''''
|
||||
|
||||
.. autoclass:: EvtEvent
|
||||
|
||||
EventMetadata
|
||||
'''''''''''''
|
||||
|
||||
.. autoclass:: EventMetadata
|
||||
|
||||
|
||||
EvtQuery
|
||||
''''''''
|
||||
|
||||
.. autoclass:: EvtQuery
|
||||
|
||||
|
||||
|
||||
TODO
|
||||
""""
|
||||
|
||||
.. autoclass:: PropertyArray
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
(cmd) python event_log\eventlog.py
|
||||
Event log Manager is: <windows.winobject.event_log.EvtlogManager object at 0x0592DB70>
|
||||
They are <1155> channels
|
||||
They are <1179> publishers
|
||||
Openning channel <Microsoft-Windows-Windows Firewall With Advanced Security/Firewall>
|
||||
Channel is <EvtChannel "Microsoft-Windows-Windows Firewall With Advanced Security/Firewall">
|
||||
The channel contains <1037> events
|
||||
|
||||
Querying "Event/EventData[Data='C:\WINDOWS\System32\svchost.exe'] and Event/System[EventID=2006]">
|
||||
Query is <EvtQuery object at 0x06E9F440>
|
||||
List contains 304 event
|
||||
|
||||
First event is <EvtEvent id="2006" time="2018-05-06 08:03:06.210109">
|
||||
System values:
|
||||
* ID: 2006
|
||||
* version: 0
|
||||
* level: 4
|
||||
* opcode: 0
|
||||
* time_created: 131700673862101088
|
||||
* ID: 2006
|
||||
Event specific values:
|
||||
* <ModifyingUser> -> <108703760>
|
||||
* <RuleName> -> <ByteCodeGeneration>
|
||||
* <ModifyingApplication> -> <C:\WINDOWS\System32\svchost.exe>
|
||||
* <RuleId> -> <{318EF1CF-A3FA-4B04-8AAC-712276661117}>
|
||||
|
||||
Event metadata is <EventMetadata object at 0x06EB96C0>
|
||||
* id : 2006
|
||||
* channel_id : 16
|
||||
* message_id : 2986346454
|
||||
* event_data : [u'RuleId', u'RuleName', u'ModifyingUser', u'ModifyingApplication']
|
||||
* EventData template :
|
||||
<template xmlns="http://schemas.microsoft.com/win/2004/08/events">
|
||||
<data name="RuleId" inType="win:UnicodeString" outType="xs:string"/>
|
||||
<data name="RuleName" inType="win:UnicodeString" outType="xs:string"/>
|
||||
<data name="ModifyingUser" inType="win:SID" outType="xs:string"/>
|
||||
<data name="ModifyingApplication" inType="win:UnicodeString" outType="xs:string"/>
|
||||
</template>
|
||||
|
||||
|
||||
Exploring complex Evt types:
|
||||
Channel is still <EvtChannel "Microsoft-Windows-Windows Firewall With Advanced Security/Firewall">
|
||||
Channel config is <ChannelConfig "Microsoft-Windows-Windows Firewall With Advanced Security/Firewall">
|
||||
Channel publisher is <EvtPublisher "Microsoft-Windows-Windows Firewall With Advanced Security">
|
||||
Channel publisher metadata is <PublisherMetadata "Microsoft-Windows-Windows Firewall With Advanced Security">
|
||||
Publisher's channels are:
|
||||
* <EvtChannel "Microsoft-Windows-Windows Firewall With Advanced Security/Firewall">
|
||||
* <EvtChannel "Microsoft-Windows-Windows Firewall With Advanced Security/ConnectionSecurity">
|
||||
* <EvtChannel "Microsoft-Windows-Windows Firewall With Advanced Security/FirewallVerbose">
|
||||
* <EvtChannel "Microsoft-Windows-Windows Firewall With Advanced Security/ConnectionSecurityVerbose">
|
||||
* <EvtChannel "Network Isolation Operational">
|
||||
Some publisher's event metadata are:
|
||||
* <EventMetadata object at 0x06EBE710>: id=2000
|
||||
* <EventMetadata object at 0x06EBE7B0>: id=2001
|
||||
* <EventMetadata object at 0x06EBE3F0>: id=2002
|
||||
@@ -0,0 +1,65 @@
|
||||
import windows
|
||||
import windows.generated_def as gdef
|
||||
|
||||
evtlogmgr = windows.system.event_log
|
||||
print("Event log Manager is: {0}".format(evtlogmgr))
|
||||
print("They are <{0}> channels".format(len(list(evtlogmgr.channels))))
|
||||
print("They are <{0}> publishers".format(len(list(evtlogmgr.publishers))))
|
||||
|
||||
|
||||
FIREWALL_CHANNEL = "Microsoft-Windows-Windows Firewall With Advanced Security/Firewall"
|
||||
print("Openning channel <{0}>".format(FIREWALL_CHANNEL))
|
||||
evtchan = evtlogmgr[FIREWALL_CHANNEL]
|
||||
print("Channel is {0}".format(evtchan))
|
||||
# Note that `evtchan.events` is an alias for `evtchan.query().all()`
|
||||
print("The channel contains <{0}> events".format(len(evtchan.events)))
|
||||
|
||||
print("")
|
||||
EVT_QUERY = "Event/EventData[Data='C:\\WINDOWS\\System32\\svchost.exe'] and Event/System[EventID=2006]"
|
||||
print("""Querying "{0}">""".format(EVT_QUERY))
|
||||
query = evtchan.query(EVT_QUERY)
|
||||
print("Query is {0}".format(query))
|
||||
event_list = list(query)
|
||||
print("List contains {0} event".format(len(event_list)))
|
||||
event = event_list[0]
|
||||
|
||||
print("")
|
||||
print("First event is {0}".format(event))
|
||||
print("System values:")
|
||||
print(" * ID: {0}".format(event.id))
|
||||
print(" * version: {0}".format(event.version))
|
||||
print(" * level: {0}".format(event.level))
|
||||
print(" * opcode: {0}".format(event.opcode))
|
||||
print(" * time_created: {0}".format(event.time_created))
|
||||
print(" * ID: {0}".format(event.id))
|
||||
|
||||
print("Event specific values:")
|
||||
for name, value in event.data.items():
|
||||
print(" * <{0}> -> <{1}>".format(name, value))
|
||||
|
||||
print("")
|
||||
evtmeta = event.metadata
|
||||
print("Event metadata is {0}".format(evtmeta))
|
||||
print(" * id : {0}".format(evtmeta.id))
|
||||
print(" * channel_id : {0}".format(evtmeta.channel_id))
|
||||
print(" * message_id : {0}".format(evtmeta.message_id))
|
||||
print(" * event_data : {0}".format(evtmeta.event_data))
|
||||
print(" * EventData template :\n{0}".format(evtmeta.template.replace("\r\n", "\n")))
|
||||
|
||||
|
||||
print("")
|
||||
print("Exploring complex Evt types:")
|
||||
|
||||
print("Channel is still {0}".format(evtchan))
|
||||
print("Channel config is {0}".format(evtchan.config))
|
||||
publisher = evtchan.config.publisher
|
||||
print("Channel publisher is {0}".format(publisher))
|
||||
print("Channel publisher metadata is {0}".format(publisher.metadata))
|
||||
|
||||
print("Publisher's channels are:")
|
||||
for chan in publisher.metadata.channels:
|
||||
print(" * {0}".format(chan))
|
||||
|
||||
print("Some publisher's event metadata are:")
|
||||
for evtmeta in list(publisher.metadata.events_metadata)[:3]:
|
||||
print(" * {0}: id={1}".format(evtmeta, evtmeta.id))
|
||||
@@ -0,0 +1,74 @@
|
||||
import pytest
|
||||
import subprocess
|
||||
import os.path
|
||||
|
||||
import windows
|
||||
import windows.generated_def as gdef
|
||||
|
||||
import windows.winobject.event_log as evtl
|
||||
|
||||
|
||||
CHANNEL_NAME = "Microsoft-Windows-Windows Firewall With Advanced Security/Firewall"
|
||||
PUBLISHER_NAME = "Microsoft-Windows-Windows Firewall With Advanced Security"
|
||||
|
||||
ALL_FIREWALL_CHAN = ["Microsoft-Windows-Windows Firewall With Advanced Security/Firewall",
|
||||
"Microsoft-Windows-Windows Firewall With Advanced Security/ConnectionSecurity",
|
||||
"Microsoft-Windows-Windows Firewall With Advanced Security/FirewallVerbose",
|
||||
"Microsoft-Windows-Windows Firewall With Advanced Security/ConnectionSecurityVerbose",
|
||||
"Network Isolation Operational"]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("name, publisher_name", [(CHANNEL_NAME, PUBLISHER_NAME)])
|
||||
def test_event_channel(name, publisher_name):
|
||||
chan = windows.system.event_log[name]
|
||||
assert isinstance(chan, evtl.EvtChannel)
|
||||
assert chan.name == name
|
||||
assert chan.config.publisher.name == publisher_name
|
||||
assert not chan.config.classic
|
||||
|
||||
@pytest.mark.parametrize("name, eventid", [(CHANNEL_NAME, 2004)])
|
||||
def test_event_channel_query(name, eventid):
|
||||
chan = windows.system.event_log[name]
|
||||
all_events = chan.events
|
||||
assert len(all_events) # Should have some event to test | skip else ?
|
||||
eventquery = chan.query(ids=2004)
|
||||
assert isinstance(eventquery, evtl.EvtQuery)
|
||||
all_id_events = eventquery.all()
|
||||
assert len(all_id_events)
|
||||
assert len(all_id_events) <= len(all_events)
|
||||
assert all(evt.id == eventid for evt in all_id_events)
|
||||
# Extract event metadata
|
||||
event_data_names = chan.get_event_metadata(eventid).event_data
|
||||
# Check all event data match event metadata description
|
||||
for evt in all_id_events:
|
||||
assert set(evt.data.keys()) == set(event_data_names)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("name, chans, eventid", [(PUBLISHER_NAME, ALL_FIREWALL_CHAN, 2004)])
|
||||
def test_event_publisher(name, chans, eventid):
|
||||
publisher = windows.system.event_log[name]
|
||||
assert isinstance(publisher, evtl.EvtPublisher)
|
||||
assert publisher.name == name
|
||||
pmetadata = publisher.metadata
|
||||
assert set(chan.name for chan in pmetadata.channels) == set(chans)
|
||||
assert eventid in [evtmedata.id for evtmedata in pmetadata.events_metadata]
|
||||
|
||||
POWERSHELL_PATH = r"C:\Windows\System32\WindowsPowershell\v1.0\powershell.exe"
|
||||
POWERSHELL_ARG = "PFW_TEST_STRING.NOTEXISTS"
|
||||
|
||||
def test_new_event():
|
||||
chan = windows.system.event_log["Microsoft-Windows-PowerShell/Operational"]
|
||||
pre_events = chan.events
|
||||
p = windows.utils.create_process(POWERSHELL_PATH, ["PFW_TEST_STRING.NOTEXISTS"], show_windows=False)
|
||||
p.wait()
|
||||
import time; time.sleep(1) # It seems to take some time to log the event
|
||||
post_events = chan.events
|
||||
assert len(post_events) > len(pre_events)
|
||||
nb_new_events = len(post_events) - len(pre_events)
|
||||
new_events = post_events[-nb_new_events:]
|
||||
# Check that some new event were triggered by our powershell
|
||||
# TODO: should be nice to find simpler event log to trigger with controled data
|
||||
assert any(evt.pid == p.pid for evt in new_events)
|
||||
|
||||
|
||||
|
||||
@@ -52,6 +52,7 @@ publishinfo = generate_query_function(winproxy.EvtGetPublisherMetadataProperty)
|
||||
|
||||
# Class high-level API
|
||||
class EvtQuery(gdef.EVT_HANDLE):
|
||||
"""Represent an Event-log query"""
|
||||
TIMEOUT = 0x1000
|
||||
|
||||
def __init__(self, handle=0, channel=None):
|
||||
@@ -59,6 +60,7 @@ class EvtQuery(gdef.EVT_HANDLE):
|
||||
self.channel = channel
|
||||
|
||||
def __next__(self):
|
||||
"""Return the next :class:`EvtEvent` matching the query"""
|
||||
try:
|
||||
event = EvtEvent(channel=self.channel)
|
||||
ret = gdef.DWORD()
|
||||
@@ -76,10 +78,15 @@ class EvtQuery(gdef.EVT_HANDLE):
|
||||
next = __next__ # Yep.. real name is 'next' in Py2 :D
|
||||
|
||||
def all(self): # SqlAlchemy like :)
|
||||
"""Return a list with all the query results
|
||||
|
||||
:rtype: [:class:`EvtEvent`] -- A list of Event
|
||||
"""
|
||||
return list(self)
|
||||
|
||||
|
||||
class EvtEvent(gdef.EVT_HANDLE):
|
||||
"""An Event log"""
|
||||
def __init__(self, handle=0, channel=None):
|
||||
super(EvtEvent, self).__init__(handle)
|
||||
self.channel = channel
|
||||
@@ -111,6 +118,10 @@ class EvtEvent(gdef.EVT_HANDLE):
|
||||
return xml[:-1]
|
||||
|
||||
def value(self, name, **kwargs):
|
||||
"""Retrieve a value from the event.
|
||||
``name`` is an XPath expressions that uniquely identify a node or attribute in the event.
|
||||
(see https://msdn.microsoft.com/en-us/library/windows/desktop/aa385352(v=vs.85).aspx)
|
||||
"""
|
||||
values = self.get_values((name,), **kwargs)
|
||||
assert len(values) == 1
|
||||
return values[0]
|
||||
@@ -126,12 +137,12 @@ class EvtEvent(gdef.EVT_HANDLE):
|
||||
result = self.render(ctx, gdef.EvtRenderEventValues)
|
||||
return [r.value for r in result]
|
||||
|
||||
def system(self): # POC: use this for all @property based on system data ?
|
||||
def system_values(self): # POC: use this for all @property based on system data ?
|
||||
ctx = windows.winproxy.EvtCreateRenderContext(0, None, gdef.EvtRenderContextSystem)
|
||||
result = self.render(ctx, gdef.EvtRenderEventValues)
|
||||
return [r.value for r in result]
|
||||
|
||||
def user(self):
|
||||
def event_values(self):
|
||||
ctx = windows.winproxy.EvtCreateRenderContext(0, None, gdef.EvtRenderContextUser)
|
||||
result = self.render(ctx, gdef.EvtRenderEventValues)
|
||||
return [r.value for r in result]
|
||||
@@ -139,33 +150,55 @@ class EvtEvent(gdef.EVT_HANDLE):
|
||||
# Properties arround common Event/System values
|
||||
@property
|
||||
def id(self):
|
||||
"""The ID of the Event"""
|
||||
return self.value("Event/System/EventID")
|
||||
|
||||
@property
|
||||
def version(self):
|
||||
"""The version of the Event"""
|
||||
return self.value("Event/System/Version")
|
||||
|
||||
@property
|
||||
def level(self):
|
||||
"""The level of the Event"""
|
||||
return self.value("Event/System/Level")
|
||||
|
||||
@property
|
||||
def opcode(self):
|
||||
"""The opcode of the Event"""
|
||||
return self.value("Event/System/Opcode")
|
||||
|
||||
@property
|
||||
def time_created(self):
|
||||
"""The creation time of the Event"""
|
||||
return self.value("Event/System/TimeCreated/@SystemTime")
|
||||
|
||||
@property
|
||||
def pid(self):
|
||||
"""The process ID of the Event"""
|
||||
return self.value("Event/System/Execution/@ProcessID")
|
||||
|
||||
@property
|
||||
def tid(self):
|
||||
"""The process ID of the Event"""
|
||||
return self.value("Event/System/Execution/@ThreadID")
|
||||
|
||||
@property
|
||||
def metadata(self):
|
||||
"HEAVY CALL"
|
||||
"""The medata for the current Event
|
||||
|
||||
:type: :class:`EventMetadata`
|
||||
"""
|
||||
return self.channel.get_event_metadata(self.id)
|
||||
|
||||
# Test
|
||||
@property
|
||||
def data(self): # user/event specifique data
|
||||
return {k:v for k,v in zip(self.metadata.user_data, self.user())}
|
||||
"""A dict of EventData Name:Value for the current dict.
|
||||
|
||||
:type: :class:`dict`
|
||||
"""
|
||||
return {k:v for k,v in zip(self.metadata.event_data, self.event_values())}
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
@@ -216,43 +249,8 @@ class ImprovedEVT_VARIANT(gdef.EVT_VARIANT):
|
||||
return "<{0} of type={1}>".format(type(self).__name__, self.Type)
|
||||
|
||||
|
||||
def channels():
|
||||
h = windows.winproxy.EvtOpenChannelEnum(None, 0)
|
||||
size = 0x1000
|
||||
buffer = ctypes.create_unicode_buffer(size)
|
||||
ressize = gdef.DWORD()
|
||||
try:
|
||||
while True:
|
||||
try:
|
||||
windows.winproxy.EvtNextChannelPath(h, size, buffer, ressize)
|
||||
except WindowsError as e:
|
||||
if e.winerror != gdef.ERROR_NO_MORE_ITEMS:
|
||||
raise
|
||||
return
|
||||
assert buffer[ressize.value - 1] == "\x00"
|
||||
yield buffer[:ressize.value - 1]
|
||||
finally: # TODO: ctx manager
|
||||
windows.winproxy.EvtClose(h)
|
||||
|
||||
|
||||
def publishers():
|
||||
h = windows.winproxy.EvtOpenPublisherEnum(None, 0)
|
||||
size = 0x1000
|
||||
buffer = ctypes.create_unicode_buffer(size)
|
||||
ressize = gdef.DWORD()
|
||||
try:
|
||||
while True:
|
||||
try:
|
||||
windows.winproxy.EvtNextPublisherId(h, size, buffer, ressize)
|
||||
except WindowsError as e:
|
||||
if e.winerror != gdef.ERROR_NO_MORE_ITEMS:
|
||||
raise
|
||||
return
|
||||
assert buffer[ressize.value - 1] == "\x00"
|
||||
yield buffer[:ressize.value - 1]
|
||||
finally: # TODO: ctx manager
|
||||
windows.winproxy.EvtClose(h)
|
||||
|
||||
|
||||
|
||||
# x = windows.winproxy.EvtQuery(None,
|
||||
@@ -273,13 +271,33 @@ def publishers():
|
||||
# list(channels())
|
||||
|
||||
class EvtChannel(object):
|
||||
"""An Event Log channel"""
|
||||
DEFAULT_QUERY_FLAGS = gdef.EvtQueryChannelPath + gdef.EvtQueryForwardDirection
|
||||
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
self.event_metadata_by_id = {}
|
||||
|
||||
def query(self, ids=None, filter=None):
|
||||
def query(self, filter=None, ids=None):
|
||||
"""Query the event with the ``ids`` or perform a query with the raw query ``filter``
|
||||
|
||||
Both parameters are mutually exclusive.
|
||||
|
||||
.. note:: Here are some query examples
|
||||
|
||||
List all events with a event data attribute named 'RuleName':
|
||||
``Event/EventData/Data[@Name='RuleName']``
|
||||
|
||||
List all events with a event data value of 'C:\\\\WINDOWS\\\\System32\\\\svchost.exe':
|
||||
``Event/EventData[Data='C:\\WINDOWS\\System32\\svchost.exe']``
|
||||
|
||||
List all events with an EventID of 2006:
|
||||
``Event/System[EventID=2006]``
|
||||
|
||||
:rtype: :class:`EvtQuery`
|
||||
"""
|
||||
if ids and filter:
|
||||
raise ValueError("<ids> and <filter> are mutually exclusive")
|
||||
if ids is not None:
|
||||
if isinstance(ids, (long, int)):
|
||||
ids = (ids,)
|
||||
@@ -288,11 +306,27 @@ class EvtChannel(object):
|
||||
query_handle = winproxy.EvtQuery(None, self.name, filter, self.DEFAULT_QUERY_FLAGS)
|
||||
return EvtQuery(query_handle, self)
|
||||
|
||||
@property
|
||||
def events(self):
|
||||
"""The list of all events in the channels, an alias for ``channel.query().all()``
|
||||
|
||||
:type: [:class:`EvtEvent`] -- A list of :class:`EvtEvent`
|
||||
"""
|
||||
return self.query().all()
|
||||
|
||||
@property
|
||||
def config(self):
|
||||
"""The configuration of the channel
|
||||
|
||||
:type: :class:`ChannelConfig`
|
||||
"""
|
||||
return ChannelConfig.from_channel_name(self.name)
|
||||
|
||||
def get_event_metadata(self, id):
|
||||
"""Return the metadata for the event ID ``id``
|
||||
|
||||
:rtype: :class:`EventMetadata`
|
||||
"""
|
||||
try:
|
||||
return self.event_metadata_by_id[id]
|
||||
except KeyError as e:
|
||||
@@ -308,36 +342,55 @@ class EvtChannel(object):
|
||||
|
||||
|
||||
class EvtFile(EvtChannel):
|
||||
"""Represent an Evtx file"""
|
||||
DEFAULT_QUERY_FLAGS = gdef.EvtQueryFilePath + gdef.EvtQueryForwardDirection
|
||||
|
||||
@property
|
||||
def config(self):
|
||||
"""Not implemented for EvtFile
|
||||
|
||||
:raise: :class:`NotImplementedError`
|
||||
"""
|
||||
raise NotImplementedError("Cannot retrieve the configuration of an EvtFile")
|
||||
|
||||
|
||||
class ChannelConfig(gdef.EVT_HANDLE):
|
||||
"""The configuration of a event channel"""
|
||||
def __init__(self, handle, name=None):
|
||||
super(ChannelConfig, self).__init__(handle)
|
||||
self.name = name
|
||||
|
||||
@classmethod
|
||||
def from_channel_name(cls, channel_name):
|
||||
return cls(winproxy.EvtOpenChannelConfig(None, channel_name, 0), channel_name)
|
||||
def from_channel_name(cls, name):
|
||||
"""Return the :class:`ChannelConfig` for the channel ``name``"""
|
||||
return cls(winproxy.EvtOpenChannelConfig(None, name, 0), name)
|
||||
|
||||
@property
|
||||
def publisher(self):
|
||||
"""The :class:`EvtPublisher` for the channel"""
|
||||
return EvtPublisher(chaninfo(self, gdef.EvtChannelConfigOwningPublisher).value)
|
||||
|
||||
|
||||
@property
|
||||
def classic(self):
|
||||
"""``True`` if the channel is a classic event channel (for example the Application or System log)"""
|
||||
return bool(chaninfo(self, gdef.EvtChannelConfigClassicEventlog).value)
|
||||
|
||||
def __repr__(self):
|
||||
return '<{0} "{1}">'.format(type(self).__name__, self.name)
|
||||
|
||||
|
||||
class EvtPublisher(object):
|
||||
"""An Event provider"""
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
|
||||
@property
|
||||
def metadata(self):
|
||||
"""Return the metadata for this publisher
|
||||
|
||||
:type: :class:`PublisherMetadata`
|
||||
"""
|
||||
return PublisherMetadata.from_publisher_name(self.name)
|
||||
|
||||
def __repr__(self):
|
||||
@@ -345,20 +398,30 @@ class EvtPublisher(object):
|
||||
|
||||
|
||||
class PublisherMetadata(gdef.EVT_HANDLE):
|
||||
"""The metadata about an event provider"""
|
||||
def __init__(self, handle, name=None):
|
||||
super(PublisherMetadata, self).__init__(handle)
|
||||
self.name = name
|
||||
|
||||
@classmethod
|
||||
def from_publisher_name(cls, publisher_name):
|
||||
return cls(winproxy.EvtOpenPublisherMetadata(None, publisher_name, None, 0, 0), publisher_name)
|
||||
def from_publisher_name(cls, name):
|
||||
"""The :class:`PublisherMetadata` for the publisher ``name``"""
|
||||
return cls(winproxy.EvtOpenPublisherMetadata(None, name, None, 0, 0), name)
|
||||
|
||||
@property
|
||||
def chanrefs(self):
|
||||
"""Identifies the channels child element of the provider.
|
||||
|
||||
:type: :class:`PropertyArray`
|
||||
"""
|
||||
return PropertyArray(publishinfo(self, gdef.EvtPublisherMetadataChannelReferences).value)
|
||||
|
||||
@property
|
||||
def events_metadata(self):
|
||||
"""The :class:`EventMetadata` for each event this provider defines
|
||||
|
||||
:yield: :class:`EventMetadata`
|
||||
"""
|
||||
eh = winproxy.EvtOpenEventMetadataEnum(self, 0)
|
||||
with ClosingEvtHandle(eh):
|
||||
while True:
|
||||
@@ -370,16 +433,32 @@ class PublisherMetadata(gdef.EVT_HANDLE):
|
||||
raise
|
||||
break
|
||||
|
||||
@property
|
||||
def channel_name_by_id(self):
|
||||
"""The dict of channel defined by this provider by their id
|
||||
|
||||
:type: :class:`dict`
|
||||
"""
|
||||
chansref = self.chanrefs
|
||||
channame_by_value_id = {}
|
||||
for i in range(chansref.size):
|
||||
value = chansref.propery(gdef.EvtPublisherMetadataChannelReferenceID, i)
|
||||
name = chansref.propery(gdef.EvtPublisherMetadataChannelReferencePath, i)
|
||||
value = chansref.property(gdef.EvtPublisherMetadataChannelReferenceID, i)
|
||||
name = chansref.property(gdef.EvtPublisherMetadataChannelReferencePath, i)
|
||||
channame_by_value_id[value] = name
|
||||
return channame_by_value_id
|
||||
|
||||
@property
|
||||
def channels(self):
|
||||
"""The list of :class:`EvtChannel` defined by this provider
|
||||
|
||||
:type: [:class:`EvtChannel`] -- A list of :class:`EvtChannel`
|
||||
"""
|
||||
chansref = self.chanrefs
|
||||
propertyid = gdef.EvtPublisherMetadataChannelReferencePath
|
||||
return [EvtChannel(chansref.property(propertyid, i)) for i in range(chansref.size)]
|
||||
|
||||
def message(self, msgid):
|
||||
"TODO"
|
||||
size = 0x1000
|
||||
buffer = ctypes.c_buffer(size)
|
||||
sbuff = ctypes.cast(buffer, gdef.LPWSTR)
|
||||
@@ -396,65 +475,143 @@ class PublisherMetadata(gdef.EVT_HANDLE):
|
||||
|
||||
|
||||
class PropertyArray(gdef.EVT_OBJECT_ARRAY_PROPERTY_HANDLE):
|
||||
"TODO"
|
||||
@property
|
||||
def size(self):
|
||||
array_size = gdef.DWORD()
|
||||
windows.winproxy.EvtGetObjectArraySize(self, array_size)
|
||||
return array_size.value
|
||||
|
||||
def propery(self, type, index):
|
||||
def property(self, type, index):
|
||||
return arrayproperty(self, type, index).value
|
||||
|
||||
class EventMetadata(gdef.EVT_HANDLE):
|
||||
"""The Metadata about a given Event type
|
||||
|
||||
|
||||
see: https://msdn.microsoft.com/en-us/library/windows/desktop/aa385517(v=vs.85).aspx
|
||||
"""
|
||||
|
||||
@property
|
||||
def id(self):
|
||||
"""The ID of the Event"""
|
||||
return eventinfo(self, gdef.EventMetadataEventID).value
|
||||
|
||||
@property
|
||||
def channel_id(self):
|
||||
"""The the Channel attribute of the Event definition"""
|
||||
return eventinfo(self, gdef.EventMetadataEventChannel).value
|
||||
|
||||
@property
|
||||
def message_id(self):
|
||||
"""Identifies the message attribute of the event definition."""
|
||||
return eventinfo(self, gdef.EventMetadataEventMessageID).value
|
||||
|
||||
@property
|
||||
def template(self):
|
||||
"""Identifies the template attribute of the event definition which is an XML string"""
|
||||
return eventinfo(self, gdef.EventMetadataEventTemplate).value
|
||||
|
||||
@property
|
||||
def user_data(self):
|
||||
def event_data(self):
|
||||
"""The list of attribute specifique for this event.
|
||||
Retrieved by parsing :data:`EventMetadata.template`
|
||||
"""
|
||||
result = []
|
||||
xmltemplate = xml.dom.minidom.parseString(self.template)
|
||||
template = self.template
|
||||
if not template:
|
||||
return {}
|
||||
xmltemplate = xml.dom.minidom.parseString(template)
|
||||
for data in xmltemplate.getElementsByTagName("data"):
|
||||
result.append(data.attributes["name"].value)
|
||||
return result
|
||||
|
||||
|
||||
class EvtlogManager(object):
|
||||
"TODO: doc -> the frontend API object"
|
||||
"""The main Evt class to open Evt channel/publisher and evtx file"""
|
||||
# https://msdn.microsoft.com/en-us/library/windows/desktop/aa385784(v=vs.85).aspx
|
||||
|
||||
def open_channel(self, channel_name):
|
||||
chan = EvtChannel(channel_name)
|
||||
def is_implemented(self):
|
||||
"""Return ``True`` if the new Evt-API is implemented on the current computer
|
||||
|
||||
see: https://msdn.microsoft.com/en-us/library/windows/desktop/aa385784(v=vs.85).aspx
|
||||
"""
|
||||
return windows.winproxy.is_implemented(windows.winproxy.EvtQuery)
|
||||
|
||||
@property
|
||||
def channels(self):
|
||||
h = windows.winproxy.EvtOpenChannelEnum(None, 0)
|
||||
size = 0x1000
|
||||
buffer = ctypes.create_unicode_buffer(size)
|
||||
ressize = gdef.DWORD()
|
||||
with ClosingEvtHandle(h):
|
||||
while True:
|
||||
try:
|
||||
windows.winproxy.EvtNextChannelPath(h, size, buffer, ressize)
|
||||
except WindowsError as e:
|
||||
if e.winerror != gdef.ERROR_NO_MORE_ITEMS:
|
||||
raise
|
||||
return
|
||||
assert buffer[ressize.value - 1] == "\x00"
|
||||
name = buffer[:ressize.value - 1]
|
||||
chan = EvtChannel(name)
|
||||
yield chan
|
||||
|
||||
@property
|
||||
def publishers(self):
|
||||
h = windows.winproxy.EvtOpenPublisherEnum(None, 0)
|
||||
size = 0x1000
|
||||
buffer = ctypes.create_unicode_buffer(size)
|
||||
ressize = gdef.DWORD()
|
||||
with ClosingEvtHandle(h):
|
||||
while True:
|
||||
try:
|
||||
windows.winproxy.EvtNextPublisherId(h, size, buffer, ressize)
|
||||
except WindowsError as e:
|
||||
if e.winerror != gdef.ERROR_NO_MORE_ITEMS:
|
||||
raise
|
||||
return
|
||||
assert buffer[ressize.value - 1] == "\x00"
|
||||
name = buffer[:ressize.value - 1]
|
||||
publisher = EvtPublisher(name)
|
||||
yield publisher
|
||||
|
||||
|
||||
|
||||
def open_channel(self, name):
|
||||
"""Open the Evt channel with ``name``
|
||||
|
||||
:rtype: :class:`EvtChannel`
|
||||
"""
|
||||
chan = EvtChannel(name)
|
||||
chan.config # Force to retrieve a handle (check channel exists)
|
||||
return chan
|
||||
|
||||
def open_evtx_file(self, filename):
|
||||
# We don't check if file exists because of 32->64 redirection
|
||||
# Do a check with FSRedirection disabled ?
|
||||
"""Open the evtx file with ``filename``
|
||||
|
||||
:rtype: :class:`EvtFile`
|
||||
"""
|
||||
with windows.utils.DisableWow64FsRedirection():
|
||||
if not os.path.exists(filename):
|
||||
raise WindowsError(gdef.ERROR_FILE_NOT_FOUND, "Could not find file <{0}>".format(filename))
|
||||
file = EvtFile(filename)
|
||||
return file
|
||||
|
||||
def open_publisher(self, publisher_name):
|
||||
publisher = EvtPublisher(publisher_name)
|
||||
def open_publisher(self, name):
|
||||
"""Open the Evt publisher with ``name``
|
||||
|
||||
:rtype: :class:`EvtPublisher`
|
||||
"""
|
||||
publisher = EvtPublisher(name)
|
||||
publisher.metadata # Force to retrieve a handle (check channel exists)
|
||||
return publisher
|
||||
|
||||
def __getitem__(self, name):
|
||||
"""Open the Evt Channel/Publisher or Evtx file with ``name``
|
||||
|
||||
:rtype: :class:`EvtChannel` or :class:`EvtPublisher` or :class:`EvtFile`
|
||||
"""
|
||||
try:
|
||||
return self.open_channel(name)
|
||||
except WindowsError as e:
|
||||
@@ -18,6 +18,7 @@ from windows.winobject import volume
|
||||
from windows.winobject import wmi
|
||||
from windows.winobject import kernobj
|
||||
from windows.winobject import handle
|
||||
from windows.winobject import event_log
|
||||
from windows.winobject import task_scheduler
|
||||
|
||||
from windows.generated_def.winstructs import *
|
||||
@@ -89,6 +90,11 @@ class System(object):
|
||||
return wmi.WmiManager()
|
||||
|
||||
|
||||
@utils.fixedpropety
|
||||
def event_log(self):
|
||||
return event_log.EvtlogManager()
|
||||
|
||||
|
||||
@utils.fixedpropety
|
||||
def task_scheduler(self):
|
||||
"""An object able to manage scheduled tasks on the local system
|
||||
@@ -98,6 +104,8 @@ class System(object):
|
||||
windows.com.init()
|
||||
clsid_task_scheduler = gdef.IID.from_string("0f87369f-a4e5-4cfc-bd3e-73e6154572dd")
|
||||
task_service = task_scheduler.TaskService()
|
||||
# What is non-implemented (WinXP)
|
||||
# Raise (NotImplementedError?) ? Return NotImplemented ?
|
||||
windows.com.create_instance(clsid_task_scheduler, task_service)
|
||||
task_service.connect()
|
||||
return task_service
|
||||
|
||||
Reference in New Issue
Block a user