Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to process different events from the same TraceLogging provider #109

Closed
matterpreter opened this issue Aug 5, 2023 · 1 comment
Closed

Comments

@matterpreter
Copy link
Contributor

I have a provider binary that emits n number of different events over the same provider GUID using TraceLogging. Here's an example:

static const SID sid = { SID_REVISION, 1, 5, { 18 } };

TRACELOGGING_DECLARE_PROVIDER(g_hProvider);
// 3B9CAB28-762A-4740-A82B-B6829CC90ADF
TRACELOGGING_DEFINE_PROVIDER(
    g_hProvider,
    "My-Test-Provider",
    (0x3b9cab28, 0x762a, 0x4740, 0xa8, 0x2b, 0xb6, 0x82, 0x9c, 0xc9, 0xa, 0xdf));

int main() {
    TraceLoggingRegister(g_hProvider);

    EmitEID1();

    for (int i = 0; i < 5; i++) {
        EmitEID2();
    }

    TraceLoggingUnregister(g_hProvider);
}

void EmitEID1() {
    TraceLoggingWrite(g_hProvider,
        "ProcessCreation",
        TraceLoggingUInt8(1, "EventId"),
        TraceLoggingUInt32(44, "Pid"),
        TraceLoggingUInt32(400, "ParentPid"),
        TraceLoggingWideString(L"test-provider.exe", "ParentProcessName"),
        TraceLoggingUInt32(600, "CreatorPid"),
        TraceLoggingWideString(L"test-provider.exe", "CreatorProcessName"),
        TraceLoggingWideString(L"test-provider.exe", "FileName"),
        TraceLoggingBoolean(TRUE, "ExactFileName"),
        TraceLoggingWideString(L"testing", "CommandLine"),
        TraceLoggingSid(&sid, "Sid"),
        TraceLoggingBoolean(FALSE, "SubsystemProcess")
    );
}

void EmitEID2() {
    TraceLoggingWrite(g_hProvider,
        "ThreadCreation",
        TraceLoggingUInt8(2, "EventId"),
        TraceLoggingUInt32(6000, "CreatorPid"),
        TraceLoggingWideString(L"test-provider.exe", "CreatorProcessName"),
        TraceLoggingUInt32(444, "TargetPid"),
        TraceLoggingWideString(L"test-provider.exe", "TargetProcessName"),
        TraceLoggingUInt32(6464, "TargetThreadId"),
        TraceLoggingSid(&sid, "Sid")
    );
}

I've written a basic consumer application that parses the events into a struct.

use ferristetw::*;

fn main() {
    let test_provider = provider::Provider
        ::by_guid("3B9CAB28-762A-4740-A82B-B6829CC90ADF")
        .add_callback(test_callback)
        .build();

    let test_trace = UserTrace::new()
        .enable(test_provider)
        .start_and_process()
        .unwrap();

    std::thread::sleep(std::time::Duration::new(60, 0));

    test_trace.stop().unwrap();
}

fn test_callback(record: &EventRecord, schema_locator: &SchemaLocator) {
    match schema_locator.event_schema(record) {
        Err(err) => println!("Unable to get the ETW schema for event: {:?}", err),
        Ok(schema) => parse_event(&schema, record)
    }    
}

fn parse_event(schema: &schema::Schema, record: &EventRecord) {
    let parser = parser::Parser::create(record, schema);
    match parser.try_parse::<u8>("EventId").unwrap_or(0) {
        2 => {
            let event = ThreadCreatedEvent {
                id: 2,
                description: String::from("Thread created"),
                creator_pid: parser.try_parse::<u32>("CreatorPid").unwrap_or(0),
                creator_process_name: parser.try_parse::<String>("CreatorProcessName").unwrap_or_else(|_| String::from("")),
                target_pid: parser.try_parse::<u32>("TargetPid").unwrap_or(0),
                target_process_name: parser.try_parse::<String>("TargetProcessName").unwrap_or_else(|_| String::from("")),
                target_thread_id: parser.try_parse::<u32>("TargetThreadId").unwrap_or(0),
                sid: parser.try_parse::<String>("Sid").unwrap_or_else(|_| String::from(""))
            };
        
            println!("{:?}", event);
        }
        _ => {}
    }
}

In the example, I emit Event 1 once before emitting Event 2 five times. My problem is that all instances of Event 2 will fail to parse correctly (specifically with TdhNativeError(IoError(Os { code: 1168, kind: Uncategorized, message: "Element not found." })). If I remove the line containing EmitEID1() from the example, the events will parse properly. I'm not exactly sure why I'm unable to parse multiple events and any help would be much appreciated.

@matterpreter matterpreter changed the title Unable to process different events from the same provider Unable to process different events from the same TraceLogging provider Aug 6, 2023
@matterpreter
Copy link
Contributor Author

Adding a note that I validated that the producer is emitting both events properly using traceview

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant