microsoft / krabsetw

KrabsETW provides a modern C++ wrapper and a .NET wrapper around the low-level ETW trace consumption functions.
Other
604 stars 149 forks source link

How to use kernel rundown provider with krabsetw #138

Closed DavidXanatos closed 3 years ago

DavidXanatos commented 4 years ago

How to use kernel rundown provier with krabsetw

jdu2600 commented 3 years ago

It looks like you need to send an extra control code to the trace to request the rundown events. EnableTraceEx2(EVENT_CONTROL_CODE_CAPTURE_STATE)

I don't think that krabs wraps this currently. You'd need to make the call directly yourself.

See https://stackoverflow.com/questions/63279041/in-etw-how-to-enable-processrundown-events-for-microsoft-windows-kernel-process

jdu2600 commented 3 years ago

Hmm. Or are you referring to the KernelRundownProvider that processhacker uses to enumerate open files?

https://github.com/processhacker/processhacker/blob/e2cb31c0386a76b3043fca1f6331898eb1ae5253/plugins/ExtendedTools/etwmon.c#L541

DavidXanatos commented 3 years ago

Hmm. Or are you referring to the KernelRundownProvider that processhacker uses to enumerate open files?

https://github.com/processhacker/processhacker/blob/e2cb31c0386a76b3043fca1f6331898eb1ae5253/plugins/ExtendedTools/etwmon.c#L541

yes that's what I'm referring to

jdu2600 commented 3 years ago
static GUID KernelRundownGuid = { 0x3b9c9951, 0x3480, 0x4220, { 0x93, 0x77, 0x9c, 0x8e, 0x51, 0x84, 0xf5, 0xcd } };

krabs::user_trace trace(L"KernelRundown_example");

krabs::provider<> fileio_provider(krabs::guids::file_io);
fileio_provider.add_on_event_callback([](const EVENT_RECORD& record, const krabs::trace_context& trace_context) {
    krabs::schema schema(record, trace_context.schema_locator);

    // https://docs.microsoft.com/en-us/windows/win32/etw/fileio
    if (schema.event_opcode() == 36) {  // FileRundown
        krabs::parser parser(schema);
        std::wstring filename = parser.parse<std::wstring>(L"FileName");
        std::wcout << L"FileRundown " << filename << std::endl;
    }
    });
trace.enable(fileio_provider);

krabs::provider<> rundown_provider(KernelRundownGuid);
rundown_provider.any(0x10);  // FileRundown flag - from processhacker
trace.enable(rundown_provider);

trace.start();
jdu2600 commented 3 years ago

It looks like the KernelRundown "provider" is actually a psuedo-provider that controls the kernel provider. In this case, flag 0x10 enables the FileRundown events.

Other flags presumably enable other rundown event types.

jdu2600 commented 3 years ago

And yes - I had to use a "user_trace" for the kernel provider in this example. The way that krabs wraps the kernel provider is currently incompatible with the kernel rundown provider.

jdu2600 commented 3 years ago

^^^^ @pathtofile - interesting ETW edge case.

pathtofile commented 3 years ago

@jdu2600 huh, weird?, are there any others?

DavidXanatos commented 3 years ago

And yes - I had to use a "user_trace" for the kernel provider in this example. The way that krabs wraps the kernel provider is currently incompatible with the kernel rundown provider.

do you have an example how you did it?

jdu2600 commented 3 years ago

The above pasted code is a working example.

jdu2600 commented 3 years ago

Hmm. I can't reproduce that behaviour that process hacker relies on with the KernelRundown GUID anymore...

But it turns out that the file rundown events are enabled by EVENT_TRACE_FLAG_DISK_FILE_IO... See hint here - https://lowleveldesign.org/2020/08/15/fixing-empty-paths-in-fileio-events-etw/

krabs::kernel_trace file_trace;
krabs::kernel_provider fileio_provider(EVENT_TRACE_FLAG_DISK_FILE_IO, krabs::guids::file_io);
fileio_provider.add_on_event_callback([](const EVENT_RECORD& record, const krabs::trace_context& trace_context) {
    if (record.EventHeader.EventDescriptor.Opcode == 36) {  // FileRundown
        krabs::schema schema(record, trace_context.schema_locator);
        krabs::parser parser(schema);
        std::wstring filename = parser.parse<std::wstring>(L"FileName");
        std::wcout << L" FileName=" << filename << std::endl;
    }
    });
file_trace.enable(fileio_provider);

// Start and stop the trace to trigger the rundown events.
std::thread file_thread([&file_trace]() { file_trace.start(); });
Sleep(100);
file_trace.stop();
file_thread.join();
swannman commented 3 years ago

Resolved by #155. Thanks @jdu2600!