-
Notifications
You must be signed in to change notification settings - Fork 25
/
Copy pathkernel_trace.rs
95 lines (76 loc) · 3.08 KB
/
kernel_trace.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
//! 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::<String>("FileName");
println!(" this one's for us: {:?}", filename);
if let Ok(filename) = filename {
if filename.ends_with(TEST_LIBRARY_NAME) {
return true;
}
}
}
false
}