microsoft / krabsetw

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

The object_manager_provider does not support DuplicateHandle events #212

Open jstarink opened 1 year ago

jstarink commented 1 year ago

Summary

I am trying to track object creation, destruction and duplication on a live Windows 10 machine. According to the MOF definitions on MSDN, these events correspond to opcodes 32, 33 and 34 respectively:

According to the examples, object_manager_provider is the struct to go for when tracking these events. And indeed, I can receive and parse events with opcode 32 and 33. However, events with opcode 34 seem to never be reported by the callback. Am I missing something, should I enable some extra flags/options, or could this be a bug?

To Reproduce

I use the following source code, which is heavily inspired by the provided examples:

krabstest.cpp ```cpp #include #include // Mapping for process IDs to their image names. std::map process_names; // Set of image names that we want to print out to the console. std::set included_processes; /** * Prints "[ ]: " */ void print_header(const EVENT_RECORD& record) { auto entry = process_names.find(record.EventHeader.ProcessId); auto process_name = entry != process_names.end() ? entry->second : ""; std::cout << "[" << std::dec << record.EventHeader.ProcessId << " " << process_name << "]: "; } int main() { // Set up some processes to print output for. included_processes.insert("notepad.exe"); included_processes.insert("TesterApp.exe"); krabs::kernel_trace trace(L"My Trace"); // In order to filter events by process name, we need to track all process start/stop events to translate IDs to names. krabs::kernel::process_provider process_provider; process_provider.add_on_event_callback([](const EVENT_RECORD& record, const krabs::trace_context& context) { // For maintaining the process_names mapping, we only care about start, end and DC start events. if (record.EventHeader.EventDescriptor.Opcode > 3) return; // Obtain schema. krabs::schema schema(record, context.schema_locator); krabs::parser parser(schema); // Parse out proc id and file name. auto processId = parser.parse(L"ProcessId"); auto imageName = parser.parse(L"ImageFileName"); // Update process_names mapping accordingly. switch (record.EventHeader.EventDescriptor.Opcode) { case 1: // Process start case 3: // Process DC Start process_names[processId] = imageName; break; case 2: // Process end process_names.erase(processId); break; } }); trace.enable(process_provider); // Set up the object ETW source. krabs::kernel::object_manager_provider ob_provider; ob_provider.add_on_event_callback([](const EVENT_RECORD& record, const krabs::trace_context& context) { // Should we print information for this process? auto processName = process_names.find(record.EventHeader.ProcessId); if (processName == process_names.end() || included_processes.find(processName->second) == included_processes.end()) { return; } // Obtain event data schema. krabs::schema schema(record, context.schema_locator); krabs::parser parser(schema); switch (record.EventHeader.EventDescriptor.Opcode) { case 32: // CreateHandle print_header(record); std::cout << "CreateHandle" << "(Handle: " << std::hex << parser.parse(L"Handle") << ")" << std::endl; break; case 33: // CloseHandle print_header(record); std::cout << "CloseHandle" << "(Handle: " << std::hex << parser.parse(L"Handle") << ")" << std::endl; break; case 34: // DuplicateHandle print_header(record); std::cout << "DuplicateHandle" << "(SourceHandle: " << std::hex << parser.parse(L"SourceHandle") << ", TargetHandle: " << std::hex << parser.parse(L"TargetHandle") << ", TargetProcessId: " << std::hex << parser.parse(L"TargetProcessId") << ")" << std::endl; break; default: std::wcout << L"Unhandled object event " << schema.opcode_name() << std::endl; break; } }); trace.enable(ob_provider); std::cout << "Starting trace...\n"; trace.start(); } ```

As a test application, I have a basic program that creates a new file object, duplicates it 10 times, then closes all duplicated handles, and finally closes the main handle.

testerapp.cpp ```cpp #include #include int main() { std::cin.get(); // activate the krabs log before pressing enter to clearly see which handles are belonging to the following code. auto handle = CreateFile(L"file.txt", GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); std::cout << "Opened file (" << std::hex << handle << ")" << std::endl; const size_t duplicate_count = 10; auto duplicates = new HANDLE[duplicate_count]; for (size_t i = 0; i < duplicate_count; i++) { !DuplicateHandle( GetCurrentProcess(), handle, GetCurrentProcess(), &duplicates[i], 0, TRUE, DUPLICATE_SAME_ACCESS ); std::cout << "Duplicated file (" << std::hex << duplicates[i] << ")" << std::endl; } for (size_t i = 0; i < duplicate_count; i++) { CloseHandle(duplicates[i]); std::cout << "Closed duplicated file (" << std::hex << duplicates[i] << ")" << std::endl; } CloseHandle(handle); std::cout << "Closed main handle file (" << std::hex << handle << ")" << std::endl; std::cin.get(); } ```

When running this with admin rights on a Windows 10 Pro N x64 machine, version 22H2, build 19045.3086, I only get the following output:

screenshot

Notice how a single file object creation (12c) is directly followed up by 11 handle closure events, without any report of the file handle being duplicated.

Additional Context

It is maybe worth mentioning that other libraries that consume ETW events do seem to be able to report on object duplication. For example, using Microsoft.Diagnostics.Tracing.TraceEvent of the perfview project, reporting on handle duplication works fine:

screenshot2

jstarink commented 1 year ago

Update: If it may be of any help, when I inspect errors using add_on_error_callback, I get the following message for every duplicate handle event (34):

Could not find the schema: status_code=1168 provider_id=89497f50-effe-4440-8cf2-ce6b1cdcaca7 event_id=0

I suppose 1168 refers to ERROR_NOT_FOUND. It seems krabs cannot obtain the schema for this type of event.