n4r1b / ferrisetw

Basically a KrabsETW rip-off written in Rust
Other
63 stars 20 forks source link

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

Closed matterpreter closed 6 months ago

matterpreter commented 1 year ago

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 commented 1 year ago

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