I have a Windows Service which has a thread that polls particular Windows Event logs every 5 minutes, looking for events that match a particular EventID.
This service is running on Win10 1607 Enterprise LTSB systems, with .NET Framework 4.0.30319.42000 (4.6.1).
Here's a snippet for querying the Windows Firewall event log:
try
{
// ******************************
// Windows Firewall Events.
// ******************************
// Event log query
var firewallQuery = new EventLogQuery("Microsoft-Windows-Windows Firewall With Advanced Security/Firewall", PathType.LogName, "*[System[EventID=2004 or EventID=2005 or EventID=2006]]");
var firewallReader = new EventLogReader(firewallQuery);
EventRecord firewallEntry;
// Iterate the event search results
while ((firewallEntry = firewallReader.ReadEvent()) != null)
{
// Did the event occur >current baseline?
if (firewallEntry.TimeCreated.HasValue &&
firewallEntry.TimeCreated.Value.CompareTo(BaselineTimestamp) > 0)
{
try
{
// Select the relavent properties
EventLogPropertySelector fwEventPropSelector = new EventLogPropertySelector(new[] {
"Event/EventData/Data[@Name='RuleName']",
"Event/EventData/Data[@Name='Profiles']",
"Event/EventData/Data[@Name='Direction']",
"Event/EventData/Data[@Name='Action']",
"Event/EventData/Data[@Name='ApplicationPath']",
"Event/EventData/Data[@Name='ServiceName']",
"Event/EventData/Data[@Name='Protocol']",
"Event/EventData/Data[@Name='LocalPorts']",
"Event/EventData/Data[@Name='RemotePorts']",
"Event/EventData/Data[@Name='ModifyingUser']",
"Event/EventData/Data[@Name='ModifyingApplication']"});
// Retrieve enumeration of selected values
IList<object> fwEventPropValues = ((EventLogRecord)firewallEntry).GetPropertyValues(fwEventPropSelector);
// Free resource.
fwEventPropSelector.Dispose();
// Object to store any new event
WindowsEvent curEvent = null;
// Which event?
switch (firewallEntry.Id)
{
case 2004:
// Firewall rule added
curEvent = new WindowsEvent("Windows Firewall",
firewallEntry.TimeCreated.Value.ToString(),
firewallEntry.Id,
"Firewall - Add Rule",
"Rule=" + fwEventPropValues[0].ToString() + ";" +
"Profile=" + fwProfile.FirstOrDefault(v => v.Item1 == fwEventPropValues[1].ToString()).Item2 + ";" +
"Direction=" + fwDirection.FirstOrDefault(v => v.Item1 == fwEventPropValues[2].ToString()).Item2 + ";" +
"Action=" + fwAction.FirstOrDefault(v => v.Item1 == fwEventPropValues[3].ToString()).Item2 + ";" +
"App=" + fwEventPropValues[4].ToString() + ";" +
"Service=" + fwEventPropValues[5].ToString() + ";" +
"Protocol=" + fwProtocol.FirstOrDefault(v => v.Item1 == fwEventPropValues[6].ToString()).Item2 + ";" +
"LocalPort=" + fwEventPropValues[7].ToString() + ";" +
"RemotePort=" + fwEventPropValues[8].ToString() + ";" +
"ModifyUser=" + new System.Security.Principal.SecurityIdentifier(
fwEventPropValues[9].ToString()).Translate(typeof(System.Security.Principal.NTAccount)).ToString() + ";" +
"ModifyApp=" + fwEventPropValues[10].ToString() + ";");
break;
case 2005:
// Firewall rule changed
curEvent = new WindowsEvent("Windows Firewall",
firewallEntry.TimeCreated.Value.ToString(),
firewallEntry.Id,
"Firewall - Changed Rule",
"Rule=" + fwEventPropValues[0].ToString() + ";" +
"Profile=" + fwProfile.FirstOrDefault(v => v.Item1 == fwEventPropValues[1].ToString()).Item2 + ";" +
"Direction=" + fwDirection.FirstOrDefault(v => v.Item1 == fwEventPropValues[2].ToString()).Item2 + ";" +
"Action=" + fwAction.FirstOrDefault(v => v.Item1 == fwEventPropValues[3].ToString()).Item2 + ";" +
"App=" + fwEventPropValues[4].ToString() + ";" +
"Service=" + fwEventPropValues[5].ToString() + ";" +
"Protocol=" + fwProtocol.FirstOrDefault(v => v.Item1 == fwEventPropValues[6].ToString()).Item2 + ";" +
"LocalPort=" + fwEventPropValues[7].ToString() + ";" +
"RemotePort=" + fwEventPropValues[8].ToString() + ";" +
"ModifyUser=" + new System.Security.Principal.SecurityIdentifier(
fwEventPropValues[9].ToString()).Translate(typeof(System.Security.Principal.NTAccount)).ToString() + ";" +
"ModifyApp=" + fwEventPropValues[10].ToString() + ";");
break;
case 2006:
// Firewall rule deleted
curEvent = new WindowsEvent("Windows Firewall",
firewallEntry.TimeCreated.Value.ToString(),
firewallEntry.Id,
"Firewall - Deleted Rule",
"Rule=" + fwEventPropValues[0].ToString() + ";" +
"ModifyUser=" + new System.Security.Principal.SecurityIdentifier(
fwEventPropValues[9].ToString()).Translate(typeof(System.Security.Principal.NTAccount)).ToString() + ";" +
"ModifyApp=" + fwEventPropValues[10].ToString() + ";");
break;
default:
// Not an event we planned for
Logger.WriteDebug(callStack, "Unrecognized event code:" + firewallEntry.Id.ToString(), true);
break;
}
// Did we capture an event?
if (curEvent != null)
{
// Set flag
bool uniqueEvent = true;
// Iterate all recorded events
foreach (WindowsEvent we in WindowsEvent.EventList)
{
// Does the event match an existing event?
if (we.Equals(curEvent))
{
// Unset flag
uniqueEvent = false;
break;
}
}
// Is this a unique event?
if (uniqueEvent)
{
// Set flag
unreportedWindowsEvent = true;
// Add to list
WindowsEvent.EventList.Add(curEvent);
}
}
}
catch (Exception e)
{
Logger.WriteException(callStack, e, "Failed to process record [" + firewallEntry.FormatDescription().Replace(Environment.NewLine, " | ") + "]");
}
}
}
// Dispose resources.
firewallReader.Dispose();
}
catch (Exception e)
{
Logger.WriteException(callStack, e, "Unable to read security events.");
}
There are about (4) other similar blocks of code, polling from the Defender, Security and System event logs, each for particular EventIDs. Each snippet has it's own try/catch, wrapped in an outer try/catch.
The EventLogReader object implemented IDisposed, so it's disposed at the end of each operation.
THE PROBLEM: Approximately once or twice a month, the entire thread/Windows Service will crash with:
Application: MyService.exe
Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.AccessViolationException
at Microsoft.Win32.UnsafeNativeMethods.EvtClose(IntPtr)
at System.Diagnostics.Eventing.Reader.EventLogHandle.ReleaseHandle()
at System.Runtime.InteropServices.SafeHandle.InternalFinalize()
at System.Runtime.InteropServices.SafeHandle.Finalize()
Faulting application name: MyService.exe, version: 1.9.7543.25123, time stamp: 0x5f46a286
Faulting module name: wevtapi.dll, version: 10.0.14393.2457, time stamp: 0x5b7e2ba7
Exception code: 0xc0000005
Fault offset: 0x0000000000008636
Faulting process id: 0x99c
Faulting application start time: 0x01d698f934ae131f
Faulting application path: C:\...
Faulting module path: C:\WINDOWS\SYSTEM32\wevtapi.dll
Report Id: 36cded2c-137d-429f-b4cc-4c19b8005dd5
Faulting package full name:
Faulting package-relative application ID:
To me, this appears to be a case of Managed code having a crash calling Un-Managed code on the backend. But my BIG QUESTION, is why/how this eludes capture by the try/catch blocks?
User contributions licensed under CC BY-SA 3.0