Files
suvenka 676d948235 Add process_start_key() to read ProcessStartKey from extended data
Add support for reading EVENT_HEADER_EXT_TYPE_PROCESS_START_KEY from
ETW extended data items, enabled via EVENT_ENABLE_PROPERTY_PROCESS_START_KEY.
The ProcessStartKey uniquely identifies a process instance across a boot
session (unlike PID which can be recycled).

Changes:
- Native C++: schema::process_start_key() in schema.hpp
- Managed .NET: TryGetProcessStartKey() on IEventRecordMetadata/EventRecordMetadata
- Test support: extended_data_builder::add_process_start_key()
- New example: UserTrace008_ProcessStartKey.cs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-06 16:18:29 -08:00

74 lines
3.0 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 demonstrates reading the ProcessStartKey from ETW extended data items.
// The ProcessStartKey uniquely identifies a process instance across a boot session
// (unlike PID which can be recycled).
using System;
using System.Security.Principal;
using System.Threading;
using Microsoft.O365.Security.ETW;
namespace ManagedExamples
{
public static class UserTrace008_ProcessStartKey
{
public static void Start()
{
if (!(new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator)))
{
Console.WriteLine("Microsoft-Windows-Kernel-Process provider requires Administrator privileges.");
return;
}
var trace = new UserTrace("UserTrace008_ProcessStartKey");
var provider = new Provider("Microsoft-Windows-Kernel-Process");
provider.Any = 0x10; // WINEVENT_KEYWORD_PROCESS
provider.TraceFlags |= TraceFlags.IncludeProcessStartKey;
int eventCount = 0;
int eventsWithKey = 0;
const int maxEvents = 10;
// Listen for ProcessStart (1) and ProcessStop (2)
var filter = new EventFilter(Filter.EventIdIs(1).Or(Filter.EventIdIs(2)));
filter.OnEvent += (record) =>
{
var pid = record.GetUInt32("ProcessID");
string imageName;
try { imageName = record.GetUnicodeString("ImageName"); }
catch { try { imageName = record.GetAnsiString("ImageName"); } catch { imageName = "<unknown>"; } }
ulong processStartKey = 0;
bool hasKey = record.TryGetProcessStartKey(out processStartKey);
if (hasKey && processStartKey != 0)
Interlocked.Increment(ref eventsWithKey);
int count = Interlocked.Increment(ref eventCount);
Console.WriteLine($"[{record.TaskName}] PID={pid} ImageName={imageName} " +
$"HasProcessStartKey={hasKey} ProcessStartKey=0x{processStartKey:X}");
if (count >= maxEvents)
{
Console.WriteLine($"\nReceived {count} events, {eventsWithKey} had a non-zero ProcessStartKey.");
if (eventsWithKey > 0)
Console.WriteLine("PASS: ProcessStartKey is being populated in extended data.");
else
Console.WriteLine("FAIL: No events had a ProcessStartKey set.");
trace.Stop();
}
};
provider.AddFilter(filter);
trace.Enable(provider);
Console.WriteLine("Listening for process start/stop events (will stop after 10 events)...");
Console.WriteLine("Tip: Start or stop some processes to generate events.\n");
trace.Start();
}
}
}