use core::sync::atomic::{AtomicBool, Ordering};
use wdk::println;
use wdk_sys::{
ntddk::{PsSetCreateThreadNotifyRoutine, PsGetCurrentProcessId},
HANDLE, NTSTATUS, STATUS_SUCCESS,
};
static REGISTERED: AtomicBool = AtomicBool::new(false);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ThreadEventType {
Create,
Terminate,
}
#[repr(C)]
#[derive(Debug)]
pub struct ThreadEvent {
pub event_type: ThreadEventType,
pub process_id: usize,
pub thread_id: usize,
pub is_remote_thread: bool,
pub is_system_thread: bool,
}
pub unsafe fn register() -> Result<(), NTSTATUS> {
if REGISTERED.load(Ordering::SeqCst) {
return Ok(());
}
let status = unsafe {
PsSetCreateThreadNotifyRoutine(Some(thread_notify_callback))
};
if status != STATUS_SUCCESS {
println!("[Leviathan] Failed to register thread callback: {:#x}", status);
return Err(status);
}
REGISTERED.store(true, Ordering::SeqCst);
println!("[Leviathan] Thread creation callback registered");
Ok(())
}
pub unsafe fn unregister() {
if !REGISTERED.load(Ordering::SeqCst) {
return;
}
let status = unsafe {
wdk_sys::ntddk::PsRemoveCreateThreadNotifyRoutine(Some(thread_notify_callback))
};
if status == STATUS_SUCCESS {
REGISTERED.store(false, Ordering::SeqCst);
println!("[Leviathan] Thread creation callback unregistered");
}
}
unsafe extern "C" fn thread_notify_callback(
process_id: HANDLE,
thread_id: HANDLE,
create: u8,
) {
let pid = process_id as usize;
let tid = thread_id as usize;
if create != 0 {
unsafe { handle_thread_create(pid, tid) };
} else {
handle_thread_terminate(pid, tid);
}
}
unsafe fn handle_thread_create(process_id: usize, thread_id: usize) {
let current_pid = unsafe { PsGetCurrentProcessId() } as usize;
let is_remote = current_pid != process_id && current_pid != 0;
if is_remote {
println!(
"[Leviathan] REMOTE Thread CREATE: TID={} in PID={} (from PID={})",
thread_id, process_id, current_pid
);
} else {
println!(
"[Leviathan] Thread CREATE: TID={} in PID={}",
thread_id, process_id
);
}
}
fn handle_thread_terminate(process_id: usize, thread_id: usize) {
println!(
"[Leviathan] Thread TERMINATE: TID={} in PID={}",
thread_id, process_id
);
}
#[allow(dead_code)]
fn is_suspicious_thread_creation(
source_pid: usize,
target_pid: usize,
_thread_start_address: usize,
) -> bool {
let _sensitive_processes = [
"lsass.exe",
"csrss.exe",
"services.exe",
"winlogon.exe",
];
source_pid != target_pid }