LibETW is a high-performance, concurrent-safe C library designed for consuming and controlling Event Tracing for Windows (ETW) events. Built for Cyber Security products (EDR/XDR) and high-throughput telemetry agents, it prioritizes ABI stability, low resource usage, and instruction cache locality.
- High Performance: Optimized hot path with internal TDH schema caching and zero-allocation property access where possible.
- ABI Stable: Uses opaque handles (
HETWCONSUMER,HETWCONTROLLER) and the PIMPL idiom to ensure binary compatibility. - Concurrency Safe: Thread-safe stopping mechanisms; designed for highly concurrent environments.
- No Implicit Threading: The library does not spawn background threads. You control the threading model (1:1, Thread Pool, etc.).
- Modern C: Written in standard C17.
- Flexible Build: Supports both Static Library (
.lib) and Dynamic Library (.dll) builds via a Shared Items Project structure.
The solution is organized to separate the public API from the internal implementation:
- LibETWFiles (Shared Items): Contains the core source code and internal logic.
- ETWStaticLib: Wrapper project to build a static library (
.lib). - ETWDynamicLinkLib: Wrapper project to build a dynamic library (
.dll). Example/TestConsumer*: A sample console applications demonstrating usage of both static and dynamic linking.
- Visual Studio 2022
- Windows SDK 10.0+
The project uses preprocessor definitions to control symbol visibility:
- Building DLL:
LIBETW_EXPORTS - Building/Using Static Lib:
LIBETW_STATIC
The Controller API manages the Kernel Trace Session. You must run as Administrator.
#include <libetw/controller.h>
ETW_CONTROLLER_CONFIG config = { 0 };
config.SessionName = L"MySecureSession";
config.Mode = ETW_MODE_REALTIME;
config.BufferSizeKB = 64; // 64KB buffers
config.MinimumBuffers = 2;
config.MaximumBuffers = 20;
HETWCONTROLLER hController;
ETW_RESULT hr = EtwControllerStart(&config, &hController);
// Enable "Microsoft-Windows-Kernel-Process"
static const GUID ProcessProvider = { 0x22FB2CD6, 0x0E7B, 0x422B, { 0xA0, 0xC7, 0x2F, 0xAD, 0x1F, 0xD0, 0xE7, 0x16 } };
EtwControllerEnableProvider(hController, &ProcessProvider, TRACE_LEVEL_INFORMATION, 0, 0);The Consumer API reads events from the session. The EtwConsumerProcess function blocks the calling thread, allowing you to pin it to specific cores if needed.
#include <libetw/consumer.h>
void ETW_CALL MyEventCallback(HETWEVENT hEvent, PVOID pContext) {
PEVENT_HEADER pHeader;
EtwEventGetHeader(hEvent, &pHeader);
// Filter for Process Start (Id 1)
if (pHeader->EventDescriptor.Id == 1) {
ULONG idxImage = 0;
LPCWSTR imageName = NULL;
// Retrieve cached property index (Fast)
if (EtwEventGetPropertyIndex(hEvent, L"ImageName", &idxImage) == ETW_S_OK) {
// Zero-copy extraction (returns pointer to internal buffer)
EtwEventReadString(hEvent, idxImage, &imageName, NULL);
printf("Process Started: %ls\n", imageName);
}
}
}
// In your worker thread:
HETWCONSUMER hConsumer;
EtwConsumerOpen(L"MySecureSession", ETW_MODE_REALTIME, MyEventCallback, NULL, NULL, &hConsumer);
EtwConsumerProcess(hConsumer); // Blocks until stoppedEtwConsumerStop(hConsumer); // Signals loop to exit
EtwConsumerClose(hConsumer); // Frees memory
EtwControllerStop(hController);
EtwControllerClose(hController);EtwControllerStart: Starts a kernel trace session.EtwControllerEnableProvider: Enables a provider viaEnableTraceEx2.EtwControllerStop: Flushes buffers and stops the session.
EtwConsumerOpen: Prepares a consumer handle for Realtime or File modes.EtwConsumerProcess: Enters the blocking processing loop.EtwEventGetPropertyIndex: Resolves a property name to an index (uses internal caching).EtwEventReadString/EtwEventReadUInt32: High-performance data extraction.
- TDH Caching:
LibETWimplements a "Last-Seen" cache for TDH metadata. Bursts of identical event types (common in high-load scenarios) incur near-zero lookup overhead. - Scratch Buffers: String extraction uses thread-local scratch buffers to avoid
mallocin the hot path. - Opaque Handles: Prevents users from accessing internal structures, allowing internal optimizations without breaking ABI.
MIT