Files
Matt Swann b41b57cd42 Send schema errors to OnError callback in all cases (#175)
* Gracefully handle schema errors when applying filters

* Gracefully handle schema errors when applying filters

* Fix error message
Dispose managed error callbacks

* Improve error callback on event_filter

* Rename event callback for improved readability

* Add additional ETW trace flags described in public documentation or Microsoft open-source projects

* Remove TODO which has already been resolved through IEventRecordMetadata

* Add an interface for EventRecordError to enable unit-testing

* Address code review feedback

* Delete extraneous file

* Fix delegate name

* Resolve nits identified during self-review
2021-09-06 12:28:18 -07:00

78 lines
3.8 KiB
C#

// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
// This example shows how to use a user_trace to extract powershell command
// invocations. It demonstrates provider-level filtering to make event handling
// code a little simpler.
using System;
using Microsoft.O365.Security.ETW;
namespace ManagedExamples
{
public static class UserTrace002
{
public static void Start()
{
// UserTrace instances should be used for any non-kernel traces that are defined
// by components or programs in Windows. They can optionally take a name -- if none
// is provided, a random GUID is assigned as the name.
var trace = new UserTrace("Silly Gooby");
// A trace can have any number of providers, which are identified by GUID. These
// GUIDs are defined by the components that emit events, and their GUIDs can
// usually be found with various ETW tools (like wevutil).
var powershellProvider = new Provider(Guid.Parse("{A0C1853B-5C40-4B15-8766-3CF1C58F985A}"));
// UserTrace providers typically have any and all flags, whose meanings are
// unique to the specific providers that are being invoked. To understand these
// flags, you'll need to look to the ETW event producer.
powershellProvider.Any = Provider.AllBitsSet;
// In user_trace_001.cs, we manually filter events by checking the information
// in our callback functions. In this example, we're going to use a provider
// filter to do this for us.
// We instantiate an EventFilter first. An EventFilter is created with a predicate --
// literally just a function that does some check on an EventRecord and returns a boolean
// (true when the even should be passed on to callbacks, false otherwise).
// EventFilters are more than just convenient -- Lobster provides combinators for
// expressing simple but powerful filters that actually execute in the underlying C++
// krabs library. This means that events can be filtered before ever running in the
// CLR (saving us a ton of cost in spinning up objects on event firing).
// The combinators cannot express everything a filter must do, so for complicated
// filters, it's recommended to write the filters in a managed C++/CLI project and
// use those to keep the perf benefits. The filters that Lobster provides are on
// the Filter object (and can be combined with &&, ||, !)
var filter = new EventFilter(Filter.EventIdIs(7937));
// EventFilters have attached callbacks, just like a regular provider.
filter.OnEvent += (record) =>
{
System.Diagnostics.Debug.Assert(record.Id == 7937);
Console.WriteLine("Event 7937 received");
};
filter.OnError += (error) =>
{
Console.WriteLine($"Filter error: {error.Record.Id} {error.Message}");
};
powershellProvider.OnError += (error) =>
{
Console.WriteLine($"Provider error: {error.Record.Id} {error.Message}");
};
// EventFilters are attached to providers. Events that are attached to the filter
// will only be called when the filter allows the event through. Any events attached
// to the provider directly will be called for all events that are fired by the ETW
// producer.
powershellProvider.AddFilter(filter);
trace.Enable(powershellProvider);
trace.Start();
}
}
}