//! Use the DNS provider to test a few things regarding user traces use std::time::Duration; use ferrisetw::parser::Parser; use ferrisetw::provider::kernel_providers; use ferrisetw::provider::{EventFilter, Provider}; use ferrisetw::schema_locator::SchemaLocator; use ferrisetw::trace::KernelTrace; use ferrisetw::EventRecord; use windows::core::HSTRING; use windows::Win32::Foundation::HANDLE; use windows::Win32::System::LibraryLoader::{LoadLibraryExW, LOAD_LIBRARY_FLAGS}; mod utils; use utils::{Status, StatusNotifier, TestKind}; const TEST_LIBRARY_NAME: &str = "crypt32.dll"; // this DLL is available on all Windows versions (so that the test can run everywhere) #[test] fn kernel_trace_tests() { let passed1 = Status::new(TestKind::ExpectSuccess); let notifier1 = passed1.notifier(); // Calling a sub-function, and getting the trace back. This ensures we are able to move the Trace around the stack // (see https://github.com/n4r1b/ferrisetw/pull/28) let moved_trace = create_simple_kernel_trace_trace(notifier1); generate_image_load_events(); passed1.assert_passed(); moved_trace.stop().unwrap(); println!("Test passed"); } fn create_simple_kernel_trace_trace(notifier: StatusNotifier) -> KernelTrace { println!("We are process {}", std::process::id()); let our_process_only = EventFilter::ByPids(vec![std::process::id() as _]); let kernel_provider = Provider::kernel(&kernel_providers::IMAGE_LOAD_PROVIDER) .add_filter(our_process_only) .add_callback( move |record: &EventRecord, schema_locator: &SchemaLocator| { let schema = schema_locator.event_schema(record).unwrap(); let parser = Parser::create(record, &schema); // By-PID filters are not working (yet?) // See See https://github.com/n4r1b/ferrisetw/issues/51 // if has_seen_other_pid(record) { // notifier2.notify_failure(); // } if has_seen_dll_load(record, &parser) { notifier.notify_success(); } }, ) .build(); KernelTrace::new() .enable(kernel_provider) .start_and_process() .unwrap() } fn load_library(libname: &str) { let widename = HSTRING::from(libname); // Safety: LoadLibraryExW expects a valid string in lpLibFileName. let res = unsafe { LoadLibraryExW(&widename, HANDLE::default(), LOAD_LIBRARY_FLAGS::default()) }; res.unwrap(); } fn generate_image_load_events() { std::thread::sleep(Duration::from_secs(1)); println!("Will load a specific DLL..."); load_library(TEST_LIBRARY_NAME); println!("Loading done."); } fn has_seen_dll_load(record: &EventRecord, parser: &Parser) -> bool { if record.process_id() == std::process::id() { let filename = parser.try_parse::("FileName"); println!(" this one's for us: {:?}", filename); if let Ok(filename) = filename { if filename.ends_with(TEST_LIBRARY_NAME) { return true; } } } false }