mirror of
https://github.com/joaoviictorti/shadow-rs.git
synced 2026-01-15 05:24:21 +01:00
- Updating module documentation - Adding new features - Refactoring all code to improve readability
314 lines
10 KiB
Rust
314 lines
10 KiB
Rust
#![no_std]
|
|
#![allow(unused_must_use)]
|
|
#![allow(unused_variables)]
|
|
#![allow(static_mut_refs)]
|
|
|
|
extern crate alloc;
|
|
|
|
use {
|
|
utils::uni,
|
|
log::{error, info},
|
|
kernel_log::KernelLogger,
|
|
shadowx::error::ShadowError,
|
|
crate::utils::ioctls::IoctlManager,
|
|
wdk_sys::{*, ntddk::*, _MODE::KernelMode},
|
|
core::{ptr::null_mut, sync::atomic::Ordering},
|
|
};
|
|
|
|
#[cfg(not(feature = "mapper"))]
|
|
use shadowx::{
|
|
ThreadCallback, CALLBACK_REGISTRATION_HANDLE_THREAD,
|
|
ProcessCallback, CALLBACK_REGISTRATION_HANDLE_PROCESS,
|
|
registry::callback::{CALLBACK_REGISTRY, registry_callback}
|
|
};
|
|
|
|
#[cfg(not(test))]
|
|
extern crate wdk_panic;
|
|
|
|
#[cfg(not(test))]
|
|
#[global_allocator]
|
|
static GLOBAL_ALLOCATOR: wdk_alloc::WDKAllocator = wdk_alloc::WDKAllocator;
|
|
|
|
mod modules;
|
|
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.
|
|
///
|
|
/// # Arguments
|
|
///
|
|
/// * `driver_object` - Pointer to the driver object.
|
|
/// * `registry_path` - Pointer to the Unicode string that specifies the driver's registry path.
|
|
///
|
|
/// # Returns
|
|
///
|
|
/// * 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");
|
|
|
|
#[cfg(feature = "mapper")] {
|
|
use shadowx::data::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) {
|
|
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.
|
|
///
|
|
/// # Arguments
|
|
///
|
|
/// * `driver_object` - Pointer to the driver object.
|
|
/// * `_registry_path` - Pointer to the Unicode string that specifies the driver's registry path.
|
|
///
|
|
/// # Returns
|
|
///
|
|
/// * 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 {
|
|
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) {
|
|
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);
|
|
error!("IoCreateSymbolicLink 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) {
|
|
error!("register_callbacks Failed With Status: {status}");
|
|
return status;
|
|
}
|
|
}
|
|
|
|
STATUS_SUCCESS
|
|
}
|
|
|
|
lazy_static::lazy_static! {
|
|
pub static ref MANAGER: IoctlManager = {
|
|
let mut manager = IoctlManager::default();
|
|
manager.load_default_handlers();
|
|
manager
|
|
};
|
|
}
|
|
|
|
/// Handles device control commands (IOCTL).
|
|
///
|
|
/// This function is responsible for processing IOCTL commands received by the driver and executing the corresponding actions.
|
|
///
|
|
/// # Arguments
|
|
///
|
|
/// * `_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.
|
|
///
|
|
/// # Returns
|
|
///
|
|
/// * Status code indicating the success or failure of the operation.
|
|
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) = MANAGER.get_handler(control_code) {
|
|
handler(irp, stack)
|
|
} else {
|
|
Err(ShadowError::InvalidDeviceRequest)
|
|
};
|
|
|
|
let status = match status {
|
|
Ok(ntstatus) => ntstatus,
|
|
Err(err) => {
|
|
error!("Error: {err}");
|
|
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.
|
|
///
|
|
/// # Arguments
|
|
///
|
|
/// * `_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.
|
|
///
|
|
/// # Returns
|
|
///
|
|
/// * 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.
|
|
///
|
|
/// # Arguments
|
|
///
|
|
/// * `driver_object` - Pointer to the driver object being unloaded.
|
|
pub unsafe extern "C" fn driver_unload(driver_object: *mut DRIVER_OBJECT) {
|
|
info!("Unloading driver");
|
|
|
|
if shadowx::port::HOOK_INSTALLED.load(Ordering::Relaxed) {
|
|
let hook_status = shadowx::Port::uninstall_hook();
|
|
let mut interval = LARGE_INTEGER {
|
|
QuadPart: -50 * 1000_i64 * 1000_i64,
|
|
};
|
|
|
|
KeDelayExecutionThread(KernelMode as i8, 0, &mut interval);
|
|
}
|
|
|
|
let dos_device_name = uni::str_to_unicode(DOS_DEVICE_NAME);
|
|
IoDeleteSymbolicLink(&mut dos_device_name.to_unicode());
|
|
IoDeleteDevice((*driver_object).DeviceObject);
|
|
|
|
#[cfg(not(feature = "mapper"))] {
|
|
ObUnRegisterCallbacks(CALLBACK_REGISTRATION_HANDLE_PROCESS);
|
|
ObUnRegisterCallbacks(CALLBACK_REGISTRATION_HANDLE_THREAD);
|
|
CmUnRegisterCallback(CALLBACK_REGISTRY);
|
|
}
|
|
|
|
info!("Shadow Unload");
|
|
}
|
|
|
|
/// Register Callbacks.
|
|
///
|
|
/// # Arguments
|
|
///
|
|
/// * `driver_object` - Pointer to the driver object being unloaded.
|
|
///
|
|
/// # Returns
|
|
///
|
|
/// * 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 {
|
|
// Creating callbacks related to Process operations
|
|
let altitude = uni::str_to_unicode("31243.5222");
|
|
let mut op_reg = OB_OPERATION_REGISTRATION {
|
|
ObjectType: PsProcessType,
|
|
Operations: OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE,
|
|
PreOperation: Some(ProcessCallback::on_pre_open_process),
|
|
PostOperation: None,
|
|
};
|
|
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,
|
|
};
|
|
|
|
let mut status = ObRegisterCallbacks(&mut cb_reg,core::ptr::addr_of_mut!(CALLBACK_REGISTRATION_HANDLE_PROCESS));
|
|
if !NT_SUCCESS(status) {
|
|
error!("ObRegisterCallbacks (Process) Failed With Status: {status}");
|
|
return status;
|
|
}
|
|
|
|
// Creating callbacks related to thread operations
|
|
let altitude = uni::str_to_unicode("31243.5223");
|
|
let mut op_reg = OB_OPERATION_REGISTRATION {
|
|
ObjectType: PsThreadType,
|
|
Operations: OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE,
|
|
PreOperation: Some(ThreadCallback::on_pre_open_thread),
|
|
PostOperation: None,
|
|
};
|
|
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) {
|
|
error!("ObRegisterCallbacks (Thread) Failed With Status: {status}");
|
|
return status;
|
|
}
|
|
|
|
// Creating callbacks related to registry operations
|
|
let mut altitude = uni::str_to_unicode("31422.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) {
|
|
error!("CmRegisterCallbackEx Failed With Status: {status}");
|
|
return status;
|
|
}
|
|
|
|
status
|
|
}
|