use core::sync::atomic::{AtomicBool, Ordering};
use core::ptr;
use wdk::println;
use wdk_sys::{
ntddk::{ObRegisterCallbacks, ObUnRegisterCallbacks, PsGetCurrentProcessId, PsGetProcessId},
ACCESS_MASK, NTSTATUS, OB_CALLBACK_REGISTRATION, OB_OPERATION_HANDLE_CREATE,
OB_OPERATION_HANDLE_DUPLICATE, OB_OPERATION_REGISTRATION, OB_PRE_OPERATION_INFORMATION,
PEPROCESS, PVOID, STATUS_SUCCESS,
};
pub const PROCESS_TERMINATE: ACCESS_MASK = 0x0001;
pub const PROCESS_VM_READ: ACCESS_MASK = 0x0010;
pub const PROCESS_VM_WRITE: ACCESS_MASK = 0x0020;
static REGISTERED: AtomicBool = AtomicBool::new(false);
static mut REGISTRATION_HANDLE: PVOID = ptr::null_mut();
static mut PROTECTED_PIDS: [usize; 16] = [0; 16];
static PROTECTED_COUNT: core::sync::atomic::AtomicUsize =
core::sync::atomic::AtomicUsize::new(0);
const DANGEROUS_PROCESS_ACCESS: ACCESS_MASK =
PROCESS_TERMINATE | PROCESS_VM_READ | PROCESS_VM_WRITE;
const DANGEROUS_THREAD_ACCESS: ACCESS_MASK = 0x0002 | 0x0008;
pub unsafe fn register() -> Result<(), NTSTATUS> {
if REGISTERED.load(Ordering::SeqCst) {
return Ok(());
}
let mut operation_registration: [OB_OPERATION_REGISTRATION; 2] = unsafe { core::mem::zeroed() };
operation_registration[0].ObjectType = unsafe { wdk_sys::PsProcessType };
operation_registration[0].Operations =
OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE;
operation_registration[0].PreOperation = Some(pre_operation_callback);
operation_registration[0].PostOperation = None;
operation_registration[1].ObjectType = unsafe { wdk_sys::PsThreadType };
operation_registration[1].Operations =
OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE;
operation_registration[1].PreOperation = Some(pre_operation_callback);
operation_registration[1].PostOperation = None;
let altitude = wdk_sys::UNICODE_STRING {
Length: 0,
MaximumLength: 0,
Buffer: ptr::null_mut(),
};
let mut callback_registration: OB_CALLBACK_REGISTRATION = unsafe { core::mem::zeroed() };
callback_registration.Version = wdk_sys::OB_FLT_REGISTRATION_VERSION as u16;
callback_registration.OperationRegistrationCount = 2;
callback_registration.Altitude = altitude;
callback_registration.RegistrationContext = ptr::null_mut();
callback_registration.OperationRegistration = operation_registration.as_mut_ptr();
let mut handle: PVOID = ptr::null_mut();
let status = unsafe { ObRegisterCallbacks(&mut callback_registration, &mut handle) };
if status != STATUS_SUCCESS {
println!(
"[Leviathan] Failed to register object callbacks: {:#x}",
status
);
println!("[Leviathan] Note: Requires signed driver with /INTEGRITYCHECK");
return Err(status);
}
unsafe {
REGISTRATION_HANDLE = handle;
}
REGISTERED.store(true, Ordering::SeqCst);
println!("[Leviathan] Object callbacks registered");
Ok(())
}
pub unsafe fn unregister() {
if !REGISTERED.load(Ordering::SeqCst) {
return;
}
let handle = unsafe { REGISTRATION_HANDLE };
if !handle.is_null() {
unsafe { ObUnRegisterCallbacks(handle) };
unsafe { REGISTRATION_HANDLE = ptr::null_mut() };
}
REGISTERED.store(false, Ordering::SeqCst);
println!("[Leviathan] Object callbacks unregistered");
}
unsafe extern "C" fn pre_operation_callback(
_context: PVOID,
info: *mut OB_PRE_OPERATION_INFORMATION,
) -> i32 {
if info.is_null() {
return wdk_sys::_OB_PREOP_CALLBACK_STATUS::OB_PREOP_SUCCESS;
}
let info = unsafe { &mut *info };
let target_object = info.Object;
if target_object.is_null() {
return wdk_sys::_OB_PREOP_CALLBACK_STATUS::OB_PREOP_SUCCESS;
}
let target_process = target_object as PEPROCESS;
let target_pid = unsafe { PsGetProcessId(target_process) } as usize;
let requestor_pid = unsafe { PsGetCurrentProcessId() } as usize;
if requestor_pid == target_pid {
return wdk_sys::_OB_PREOP_CALLBACK_STATUS::OB_PREOP_SUCCESS;
}
if is_protected_process(target_pid) {
unsafe { strip_dangerous_access(info) };
println!(
"[Leviathan] Protected process access: {} -> {} (stripped dangerous rights)",
requestor_pid, target_pid
);
}
if is_sensitive_process(target_pid) {
let requested_access = get_requested_access(info);
if (requested_access & DANGEROUS_PROCESS_ACCESS) != 0 {
println!(
"[Leviathan] ALERT: Dangerous access to sensitive process! Requestor={}, Target={}, Access={:#x}",
requestor_pid, target_pid, requested_access
);
unsafe { strip_dangerous_access(info) };
}
}
wdk_sys::_OB_PREOP_CALLBACK_STATUS::OB_PREOP_SUCCESS
}
unsafe fn strip_dangerous_access(info: &mut OB_PRE_OPERATION_INFORMATION) {
let params = info.Parameters;
if info.Operation == OB_OPERATION_HANDLE_CREATE {
unsafe {
let create_info = &mut (*params).CreateHandleInformation;
create_info.DesiredAccess &= !DANGEROUS_PROCESS_ACCESS;
}
}
else if info.Operation == OB_OPERATION_HANDLE_DUPLICATE {
unsafe {
let dup_info = &mut (*params).DuplicateHandleInformation;
dup_info.DesiredAccess &= !DANGEROUS_PROCESS_ACCESS;
}
}
}
fn get_requested_access(info: &OB_PRE_OPERATION_INFORMATION) -> ACCESS_MASK {
let params = info.Parameters;
if info.Operation == OB_OPERATION_HANDLE_CREATE {
unsafe { (*params).CreateHandleInformation.DesiredAccess }
} else if info.Operation == OB_OPERATION_HANDLE_DUPLICATE {
unsafe { (*params).DuplicateHandleInformation.DesiredAccess }
} else {
0
}
}
fn is_protected_process(pid: usize) -> bool {
let count = PROTECTED_COUNT.load(Ordering::SeqCst);
for i in 0..count {
if unsafe { PROTECTED_PIDS[i] } == pid {
return true;
}
}
false
}
fn is_sensitive_process(_pid: usize) -> bool {
false
}
#[allow(dead_code)]
pub unsafe fn protect_process(pid: usize) -> bool {
let count = PROTECTED_COUNT.load(Ordering::SeqCst);
if count >= 16 {
return false;
}
unsafe {
PROTECTED_PIDS[count] = pid;
}
PROTECTED_COUNT.store(count + 1, Ordering::SeqCst);
println!("[Leviathan] Process {} added to protected list", pid);
true
}
#[allow(dead_code)]
pub fn unprotect_process(pid: usize) {
let count = PROTECTED_COUNT.load(Ordering::SeqCst);
for i in 0..count {
if unsafe { PROTECTED_PIDS[i] } == pid {
for j in i..count - 1 {
unsafe {
PROTECTED_PIDS[j] = PROTECTED_PIDS[j + 1];
}
}
PROTECTED_COUNT.store(count - 1, Ordering::SeqCst);
println!("[Leviathan] Process {} removed from protected list", pid);
return;
}
}
}