mirror of
https://github.com/safedv/RustiveDump
synced 2026-06-08 17:19:41 +00:00
150 lines
5.3 KiB
Rust
150 lines
5.3 KiB
Rust
#[cfg(feature = "verbose")]
|
|
use libc_print::libc_println;
|
|
|
|
use alloc::vec::Vec;
|
|
use core::{ffi::c_void, ptr::null_mut};
|
|
|
|
use crate::{common::utils::dbj2_hash, debug_println};
|
|
|
|
use super::{
|
|
def::{
|
|
AccessMask, ClientId, ObjectAttributes, SystemProcessInformation, OBJ_CASE_INSENSITIVE,
|
|
STATUS_INFO_LENGTH_MISMATCH,
|
|
},
|
|
g_instance::instance,
|
|
};
|
|
|
|
/// Takes a snapshot of the currently running processes.
|
|
///
|
|
/// This function utilizes the `NtQuerySystemInformation` function from the NT API to retrieve
|
|
/// information about all processes currently running on the system. It first determines the necessary
|
|
/// buffer size, then allocates memory, and finally retrieves the process information.
|
|
pub unsafe fn nt_process_snapshot(
|
|
snapshot: &mut *mut SystemProcessInformation,
|
|
size: &mut usize,
|
|
) -> i32 {
|
|
let mut length: u32 = 0;
|
|
|
|
// First call to determine the required length of the buffer for process information.
|
|
let mut status =
|
|
instance()
|
|
.ntdll
|
|
.nt_query_system_information
|
|
.run(5, null_mut(), 0, &mut length);
|
|
|
|
// Check if the call returned STATUS_INFO_LENGTH_MISMATCH (expected) or another error.
|
|
if status != STATUS_INFO_LENGTH_MISMATCH && status != 0 {
|
|
return status;
|
|
}
|
|
|
|
// Allocate memory for the SystemProcessInformation structure.
|
|
let mut buffer = Vec::new();
|
|
buffer.resize(length as usize, 0);
|
|
|
|
// Second call to actually retrieve the process information into the allocated buffer.
|
|
status = instance().ntdll.nt_query_system_information.run(
|
|
5,
|
|
buffer.as_mut_ptr() as *mut c_void,
|
|
length,
|
|
&mut length,
|
|
);
|
|
|
|
// Check if the process information retrieval was successful.
|
|
if status != 0 {
|
|
return status;
|
|
}
|
|
|
|
// Cast the buffer to the SystemProcessInformation structure.
|
|
*snapshot = buffer.as_mut_ptr() as *mut SystemProcessInformation;
|
|
*size = length as usize;
|
|
|
|
// Keep the buffer alive by preventing its deallocation.
|
|
core::mem::forget(buffer);
|
|
|
|
status
|
|
}
|
|
|
|
/// Retrieves a handle to a process with the specified PID and desired access rights using the NT API.
|
|
///
|
|
/// This function opens a handle to a target process by specifying its process ID (PID) and the desired access rights.
|
|
/// The syscall `NtOpenProcess` is used to obtain the handle, and the function initializes the required structures
|
|
/// (`OBJECT_ATTRIBUTES` and `CLIENT_ID`) needed to make the system call.
|
|
pub unsafe fn get_process_handle(pid: i32, desired_access: AccessMask) -> *mut c_void {
|
|
let mut process_handle: *mut c_void = null_mut();
|
|
|
|
// Initialize object attributes for the process, setting up the basic structure with default options.
|
|
let mut object_attributes = ObjectAttributes::new();
|
|
|
|
ObjectAttributes::initialize(
|
|
&mut object_attributes,
|
|
null_mut(), // No name for the object.
|
|
OBJ_CASE_INSENSITIVE, // Case-insensitive name comparison.
|
|
null_mut(), // No root directory.
|
|
null_mut(), // No security descriptor.
|
|
);
|
|
|
|
// Initialize client ID structure with the target process ID.
|
|
let mut client_id = ClientId::new();
|
|
client_id.unique_process = pid as _;
|
|
|
|
// Perform a system call to NtOpenProcess to obtain a handle to the specified process.
|
|
instance().ntdll.nt_open_process.run(
|
|
&mut process_handle,
|
|
desired_access,
|
|
&mut object_attributes,
|
|
&mut client_id as *mut _ as *mut c_void,
|
|
);
|
|
|
|
process_handle
|
|
}
|
|
|
|
/// Retrieves a handle to a process with the specified name hash and desired access rights using the NT API.
|
|
///
|
|
/// This function takes a process name hash, searches for its process ID (PID) using the `process_snapshot` function,
|
|
/// and then opens a handle to the process using `NtOpenProcess`.
|
|
pub unsafe fn get_process_handle_by_name(name: u32, desired_access: AccessMask) -> *mut c_void {
|
|
let mut snapshot: *mut SystemProcessInformation = null_mut();
|
|
let mut size: usize = 0;
|
|
|
|
// Take a snapshot of all currently running processes.
|
|
let status = nt_process_snapshot(&mut snapshot, &mut size);
|
|
|
|
if status != 0 {
|
|
debug_println!(
|
|
"Failed to retrieve process snapshot: NTSTATUS: 0x{:X}",
|
|
status
|
|
);
|
|
return null_mut();
|
|
}
|
|
|
|
let mut current = snapshot;
|
|
while !current.is_null() {
|
|
// Get the address of the process name.
|
|
let name_addr = (*current).image_name.buffer;
|
|
let name_len = (*current).image_name.length as usize;
|
|
|
|
// Only compare if the process has a name.
|
|
if !name_addr.is_null() && name_len > 0 {
|
|
// Convert the process name to a byte slice.
|
|
let name_slice: &[u8] = core::slice::from_raw_parts(name_addr as _, name_len);
|
|
|
|
// Calculate the hash of the process name.
|
|
let hash = dbj2_hash(name_slice);
|
|
|
|
// If the hash matches the provided hash, open a handle to the process.
|
|
if name == hash {
|
|
return get_process_handle((*current).unique_process_id as i32, desired_access);
|
|
}
|
|
}
|
|
|
|
// Move to the next process in the list.
|
|
if (*current).next_entry_offset == 0 {
|
|
break;
|
|
}
|
|
current = (current as *const u8).add((*current).next_entry_offset as usize)
|
|
as *mut SystemProcessInformation;
|
|
}
|
|
|
|
null_mut()
|
|
}
|