use core::sync::atomic::{AtomicBool, Ordering};
use wdk::println;
use wdk_sys::{
ntddk::PsSetCreateProcessNotifyRoutineEx,
HANDLE, NTSTATUS, PEPROCESS, PPS_CREATE_NOTIFY_INFO, STATUS_SUCCESS,
};
static REGISTERED: AtomicBool = AtomicBool::new(false);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ProcessEventType {
Create,
Terminate,
}
#[repr(C)]
#[derive(Debug)]
pub struct ProcessEvent {
pub event_type: ProcessEventType,
pub process_id: usize,
pub parent_process_id: usize,
pub blocked: bool,
}
pub unsafe fn register() -> Result<(), NTSTATUS> {
if REGISTERED.load(Ordering::SeqCst) {
return Ok(());
}
let status = unsafe {
PsSetCreateProcessNotifyRoutineEx(Some(process_notify_callback), 0)
};
if status != STATUS_SUCCESS {
println!("[Leviathan] Failed to register process callback: {:#x}", status);
return Err(status);
}
REGISTERED.store(true, Ordering::SeqCst);
println!("[Leviathan] Process creation callback registered");
Ok(())
}
pub unsafe fn unregister() {
if !REGISTERED.load(Ordering::SeqCst) {
return;
}
let status = unsafe {
PsSetCreateProcessNotifyRoutineEx(Some(process_notify_callback), 1)
};
if status == STATUS_SUCCESS {
REGISTERED.store(false, Ordering::SeqCst);
println!("[Leviathan] Process creation callback unregistered");
}
}
unsafe extern "C" fn process_notify_callback(
process: PEPROCESS,
process_id: HANDLE,
create_info: PPS_CREATE_NOTIFY_INFO,
) {
let pid = process_id as usize;
if create_info.is_null() {
handle_process_terminate(pid);
} else {
unsafe { handle_process_create(process, pid, create_info) };
}
}
unsafe fn handle_process_create(
_process: PEPROCESS,
process_id: usize,
create_info: PPS_CREATE_NOTIFY_INFO,
) {
let info = unsafe { &mut *create_info };
let parent_pid = info.ParentProcessId as usize;
println!(
"[Leviathan] Process CREATE: PID={}, ParentPID={}",
process_id, parent_pid
);
if !info.CommandLine.is_null() {
let cmd_line = unsafe { &*info.CommandLine };
println!(
"[Leviathan] Command line length: {} chars",
cmd_line.Length / 2
);
}
if !info.ImageFileName.is_null() {
let image_name = unsafe { &*info.ImageFileName };
println!(
"[Leviathan] Image file length: {} chars",
image_name.Length / 2
);
}
}
fn handle_process_terminate(process_id: usize) {
println!("[Leviathan] Process TERMINATE: PID={}", process_id);
}
#[allow(dead_code)]
fn should_block_process(_image_path: &[u16], _command_line: &[u16]) -> bool {
false
}