use core::sync::atomic::{AtomicBool, Ordering};
use core::ptr;
use wdk::println;
use wdk_sys::{
NTSTATUS, PFLT_FILTER, PFLT_INSTANCE, PFLT_VOLUME, PVOID,
STATUS_SUCCESS, STATUS_FLT_DO_NOT_ATTACH,
FLT_REGISTRATION, FLT_OPERATION_REGISTRATION, FLT_PREOP_CALLBACK_STATUS,
FLT_POSTOP_CALLBACK_STATUS, PFLT_CALLBACK_DATA, PCFLT_RELATED_OBJECTS,
};
static REGISTERED: AtomicBool = AtomicBool::new(false);
static mut FILTER_HANDLE: PFLT_FILTER = ptr::null_mut();
pub const FILTER_ALTITUDE: &str = "370030";
const SCANNABLE_EXTENSIONS: &[&str] = &[
".exe", ".dll", ".sys", ".scr", ".bat", ".cmd", ".ps1",
".vbs", ".js", ".hta", ".msi", ".jar",
];
const PROTECTED_PATHS: &[&str] = &[
"\\Windows\\System32\\",
"\\Windows\\SysWOW64\\",
"\\Program Files\\",
"\\Program Files (x86)\\",
];
const RANSOMWARE_EXTENSIONS: &[&str] = &[
".encrypted", ".locked", ".crypto", ".locky", ".zepto",
".cerber", ".crypt", ".cry", ".wncry",
];
mod irp_mj {
pub const CREATE: u8 = 0x00;
pub const READ: u8 = 0x03;
pub const WRITE: u8 = 0x04;
pub const SET_INFORMATION: u8 = 0x06; pub const CLEANUP: u8 = 0x12;
pub const CLOSE: u8 = 0x02;
}
pub unsafe fn register(_driver_object: PVOID) -> Result<(), NTSTATUS> {
if REGISTERED.load(Ordering::SeqCst) {
return Ok(());
}
let operations: [FLT_OPERATION_REGISTRATION; 6] = [
FLT_OPERATION_REGISTRATION {
MajorFunction: irp_mj::CREATE,
Flags: 0,
PreOperation: Some(pre_create),
PostOperation: Some(post_create),
Reserved1: ptr::null_mut(),
},
FLT_OPERATION_REGISTRATION {
MajorFunction: irp_mj::READ,
Flags: 0,
PreOperation: Some(pre_read),
PostOperation: None,
Reserved1: ptr::null_mut(),
},
FLT_OPERATION_REGISTRATION {
MajorFunction: irp_mj::WRITE,
Flags: 0,
PreOperation: Some(pre_write),
PostOperation: None,
Reserved1: ptr::null_mut(),
},
FLT_OPERATION_REGISTRATION {
MajorFunction: irp_mj::SET_INFORMATION,
Flags: 0,
PreOperation: Some(pre_set_information),
PostOperation: None,
Reserved1: ptr::null_mut(),
},
FLT_OPERATION_REGISTRATION {
MajorFunction: irp_mj::CLEANUP,
Flags: 0,
PreOperation: None,
PostOperation: Some(post_cleanup),
Reserved1: ptr::null_mut(),
},
FLT_OPERATION_REGISTRATION {
MajorFunction: 0x80, Flags: 0,
PreOperation: None,
PostOperation: None,
Reserved1: ptr::null_mut(),
},
];
let registration = FLT_REGISTRATION {
Size: core::mem::size_of::<FLT_REGISTRATION>() as u16,
Version: 0x0203, Flags: 0,
ContextRegistration: ptr::null(),
OperationRegistration: operations.as_ptr(),
FilterUnloadCallback: Some(filter_unload),
InstanceSetupCallback: Some(instance_setup),
InstanceQueryTeardownCallback: None,
InstanceTeardownStartCallback: None,
InstanceTeardownCompleteCallback: None,
GenerateFileNameCallback: None,
NormalizeNameComponentCallback: None,
NormalizeContextCleanupCallback: None,
TransactionNotificationCallback: None,
NormalizeNameComponentExCallback: None,
SectionNotificationCallback: None,
};
let mut filter_handle: PFLT_FILTER = ptr::null_mut();
let status = unsafe {
wdk_sys::fltKernel::FltRegisterFilter(
_driver_object,
®istration,
&mut filter_handle,
)
};
if status != STATUS_SUCCESS {
println!("[Leviathan] Failed to register minifilter: {:#x}", status);
return Err(status);
}
unsafe { FILTER_HANDLE = filter_handle };
let status = unsafe { wdk_sys::fltKernel::FltStartFiltering(filter_handle) };
if status != STATUS_SUCCESS {
unsafe { wdk_sys::fltKernel::FltUnregisterFilter(filter_handle) };
println!("[Leviathan] Failed to start filtering: {:#x}", status);
return Err(status);
}
REGISTERED.store(true, Ordering::SeqCst);
println!("[Leviathan] Minifilter registered and started");
Ok(())
}
pub unsafe fn unregister() {
if !REGISTERED.load(Ordering::SeqCst) {
return;
}
let handle = unsafe { FILTER_HANDLE };
if !handle.is_null() {
unsafe { wdk_sys::fltKernel::FltUnregisterFilter(handle) };
unsafe { FILTER_HANDLE = ptr::null_mut() };
}
REGISTERED.store(false, Ordering::SeqCst);
println!("[Leviathan] Minifilter unregistered");
}
unsafe extern "C" fn filter_unload(_flags: u32) -> NTSTATUS {
println!("[Leviathan] Minifilter unload requested");
unsafe { unregister() };
STATUS_SUCCESS
}
unsafe extern "C" fn instance_setup(
_flt_objects: PCFLT_RELATED_OBJECTS,
_flags: u32,
_volume_device_type: u32,
_volume_filesystem_type: u32,
) -> NTSTATUS {
println!("[Leviathan] Attaching to volume");
STATUS_SUCCESS
}
unsafe extern "C" fn pre_create(
data: PFLT_CALLBACK_DATA,
_flt_objects: PCFLT_RELATED_OBJECTS,
_completion_context: *mut PVOID,
) -> FLT_PREOP_CALLBACK_STATUS {
if data.is_null() {
return wdk_sys::FLT_PREOP_SUCCESS_NO_CALLBACK;
}
wdk_sys::FLT_PREOP_SUCCESS_WITH_CALLBACK
}
unsafe extern "C" fn post_create(
data: PFLT_CALLBACK_DATA,
_flt_objects: PCFLT_RELATED_OBJECTS,
_completion_context: PVOID,
_flags: u32,
) -> FLT_POSTOP_CALLBACK_STATUS {
if data.is_null() {
return wdk_sys::FLT_POSTOP_FINISHED_PROCESSING;
}
wdk_sys::FLT_POSTOP_FINISHED_PROCESSING
}
unsafe extern "C" fn pre_read(
_data: PFLT_CALLBACK_DATA,
_flt_objects: PCFLT_RELATED_OBJECTS,
_completion_context: *mut PVOID,
) -> FLT_PREOP_CALLBACK_STATUS {
wdk_sys::FLT_PREOP_SUCCESS_NO_CALLBACK
}
unsafe extern "C" fn pre_write(
_data: PFLT_CALLBACK_DATA,
_flt_objects: PCFLT_RELATED_OBJECTS,
_completion_context: *mut PVOID,
) -> FLT_PREOP_CALLBACK_STATUS {
wdk_sys::FLT_PREOP_SUCCESS_NO_CALLBACK
}
unsafe extern "C" fn pre_set_information(
_data: PFLT_CALLBACK_DATA,
_flt_objects: PCFLT_RELATED_OBJECTS,
_completion_context: *mut PVOID,
) -> FLT_PREOP_CALLBACK_STATUS {
wdk_sys::FLT_PREOP_SUCCESS_NO_CALLBACK
}
unsafe extern "C" fn post_cleanup(
_data: PFLT_CALLBACK_DATA,
_flt_objects: PCFLT_RELATED_OBJECTS,
_completion_context: PVOID,
_flags: u32,
) -> FLT_POSTOP_CALLBACK_STATUS {
wdk_sys::FLT_POSTOP_FINISHED_PROCESSING
}
#[allow(dead_code)]
fn calculate_entropy(data: &[u8]) -> f32 {
if data.is_empty() {
return 0.0;
}
let mut freq = [0u32; 256];
for &byte in data {
freq[byte as usize] += 1;
}
let len = data.len() as f32;
let mut entropy = 0.0f32;
for &count in &freq {
if count > 0 {
let p = count as f32 / len;
entropy -= p * p.log2();
}
}
entropy
}
#[allow(dead_code)]
fn is_ransomware_behavior(
_process_id: usize,
_files_modified: usize,
_files_renamed: usize,
avg_entropy: f32,
) -> bool {
avg_entropy > 7.5
}