use core::sync::atomic::{AtomicBool, AtomicU64, Ordering};
use wdk::println;
use wdk_sys::{
ntddk::{CmRegisterCallbackEx, CmUnRegisterCallback},
LARGE_INTEGER, NTSTATUS, PVOID,
STATUS_SUCCESS,
};
static REGISTERED: AtomicBool = AtomicBool::new(false);
static CALLBACK_COOKIE: AtomicU64 = AtomicU64::new(0);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RegistryOperation {
CreateKey,
OpenKey,
DeleteKey,
SetValue,
DeleteValue,
QueryValue,
EnumerateKey,
Other,
}
const PROTECTED_PATHS: &[&str] = &[
"\\Registry\\Machine\\Software\\Microsoft\\Windows\\CurrentVersion\\Run",
"\\Registry\\Machine\\Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce",
"\\Registry\\Machine\\System\\CurrentControlSet\\Services",
"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options",
"\\Registry\\Machine\\SAM",
"\\Registry\\Machine\\SECURITY",
];
pub unsafe fn register() -> Result<(), NTSTATUS> {
if REGISTERED.load(Ordering::SeqCst) {
return Ok(());
}
let mut cookie: LARGE_INTEGER = unsafe { core::mem::zeroed() };
let altitude = wdk_sys::UNICODE_STRING {
Length: 0,
MaximumLength: 0,
Buffer: core::ptr::null_mut(),
};
let status = unsafe {
CmRegisterCallbackEx(
Some(registry_callback),
&altitude,
core::ptr::null_mut(), core::ptr::null_mut(), &mut cookie,
core::ptr::null_mut(), )
};
if status != STATUS_SUCCESS {
println!("[Leviathan] Failed to register registry callback: {:#x}", status);
return Err(status);
}
CALLBACK_COOKIE.store(unsafe { cookie.QuadPart } as u64, Ordering::SeqCst);
REGISTERED.store(true, Ordering::SeqCst);
println!("[Leviathan] Registry callback registered");
Ok(())
}
pub unsafe fn unregister() {
if !REGISTERED.load(Ordering::SeqCst) {
return;
}
let cookie = CALLBACK_COOKIE.load(Ordering::SeqCst);
let mut large_cookie: LARGE_INTEGER = unsafe { core::mem::zeroed() };
large_cookie.QuadPart = cookie as i64;
let status = unsafe { CmUnRegisterCallback(large_cookie) };
if status == STATUS_SUCCESS {
REGISTERED.store(false, Ordering::SeqCst);
println!("[Leviathan] Registry callback unregistered");
}
}
unsafe extern "C" fn registry_callback(
_context: PVOID,
argument1: PVOID,
argument2: PVOID,
) -> NTSTATUS {
let notify_class = argument1 as i32;
let operation = map_notify_class(notify_class);
match operation {
RegistryOperation::SetValue => {
unsafe { handle_set_value(argument2) }
}
RegistryOperation::CreateKey => {
unsafe { handle_create_key(argument2) }
}
RegistryOperation::DeleteKey | RegistryOperation::DeleteValue => {
unsafe { handle_delete_operation(argument2) }
}
_ => STATUS_SUCCESS,
}
}
fn map_notify_class(class: i32) -> RegistryOperation {
const REG_CREATE_KEY_INFORMATION: i32 = 0;
const REG_PRE_CREATE_KEY_INFORMATION: i32 = 1;
const REG_POST_CREATE_KEY_INFORMATION: i32 = 2;
const REG_OPEN_KEY_INFORMATION: i32 = 3;
const REG_PRE_SET_VALUE_KEY_INFORMATION: i32 = 6;
const REG_DELETE_KEY_INFORMATION: i32 = 12;
const REG_DELETE_VALUE_KEY_INFORMATION: i32 = 15;
const REG_QUERY_VALUE_KEY_INFORMATION: i32 = 18;
const REG_ENUMERATE_KEY_INFORMATION: i32 = 21;
match class {
REG_CREATE_KEY_INFORMATION | REG_PRE_CREATE_KEY_INFORMATION | REG_POST_CREATE_KEY_INFORMATION => {
RegistryOperation::CreateKey
}
REG_OPEN_KEY_INFORMATION => RegistryOperation::OpenKey,
REG_DELETE_KEY_INFORMATION => RegistryOperation::DeleteKey,
REG_PRE_SET_VALUE_KEY_INFORMATION => RegistryOperation::SetValue,
REG_DELETE_VALUE_KEY_INFORMATION => RegistryOperation::DeleteValue,
REG_QUERY_VALUE_KEY_INFORMATION => RegistryOperation::QueryValue,
REG_ENUMERATE_KEY_INFORMATION => RegistryOperation::EnumerateKey,
_ => RegistryOperation::Other,
}
}
unsafe fn handle_set_value(_info: PVOID) -> NTSTATUS {
println!("[Leviathan] Registry SetValue operation detected");
STATUS_SUCCESS
}
unsafe fn handle_create_key(_info: PVOID) -> NTSTATUS {
println!("[Leviathan] Registry CreateKey operation detected");
STATUS_SUCCESS
}
unsafe fn handle_delete_operation(_info: PVOID) -> NTSTATUS {
println!("[Leviathan] Registry Delete operation detected");
STATUS_SUCCESS
}
#[allow(dead_code)]
fn is_protected_path(_path: &[u16]) -> bool {
false
}
#[allow(dead_code)]
mod persistence_keys {
pub const HKCU_RUN: &str = "\\Registry\\User\\*\\Software\\Microsoft\\Windows\\CurrentVersion\\Run";
pub const HKLM_RUN: &str = "\\Registry\\Machine\\Software\\Microsoft\\Windows\\CurrentVersion\\Run";
pub const SERVICES: &str = "\\Registry\\Machine\\System\\CurrentControlSet\\Services";
pub const SCHEDULED_TASKS: &str = "\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Schedule";
pub const APPINIT_DLLS: &str = "\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows";
pub const IFEO: &str = "\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options";
pub const SHELL_EXTENSIONS: &str = "\\Registry\\Machine\\Software\\Classes\\*\\shellex";
pub const CLSID: &str = "\\Registry\\Machine\\Software\\Classes\\CLSID";
}