use std::ffi::c_void;
use windows_sys::Win32::Foundation::{CloseHandle, HANDLE, INVALID_HANDLE_VALUE};
use windows_sys::Win32::System::LibraryLoader::{GetModuleHandleW, GetProcAddress};
pub const SYSTEM_EXTENDED_HANDLE_INFORMATION: u32 = 64;
pub const OBJECT_NAME_INFORMATION: u32 = 1;
pub const OBJECT_TYPE_INFORMATION_CLASS: u32 = 2;
pub const STATUS_INFO_LENGTH_MISMATCH: i32 = 0xC000_0004_u32 as i32;
pub const DEFAULT_BUFFER_SIZE: usize = 64 * 1024;
pub const MAX_BUFFER_SIZE: usize = 1024 * 1024 * 1024;
#[repr(C)]
pub struct UnicodeString {
pub length: u16,
pub maximum_length: u16,
pub buffer: *mut u16,
}
#[repr(C)]
pub struct SystemHandleTableEntryInfoEx {
pub object: *mut c_void,
pub unique_process_id: usize,
pub handle_value: usize,
pub granted_access: u32,
pub creator_back_trace_index: u16,
pub object_type_index: u16,
pub handle_attributes: u32,
pub reserved: u32,
}
#[repr(C)]
pub struct SystemHandleInformationEx {
pub number_of_handles: usize,
pub reserved: usize,
pub handles: [SystemHandleTableEntryInfoEx; 0],
}
pub struct SafeHandle(HANDLE);
impl SafeHandle {
pub fn from_raw(handle: HANDLE) -> Option<Self> {
if handle.is_null() || handle == INVALID_HANDLE_VALUE {
None
} else {
Some(Self(handle))
}
}
pub fn from_raw_file(handle: HANDLE) -> Option<Self> {
if handle == INVALID_HANDLE_VALUE {
None
} else {
Some(Self(handle))
}
}
pub fn raw(&self) -> HANDLE {
self.0
}
}
impl Drop for SafeHandle {
fn drop(&mut self) {
unsafe {
CloseHandle(self.0);
}
}
}
type NtQuerySystemInformationFn = unsafe extern "system" fn(
system_information_class: u32,
system_information: *mut c_void,
system_information_length: u32,
return_length: *mut u32,
) -> i32;
type NtQueryObjectFn = unsafe extern "system" fn(
handle: HANDLE,
object_information_class: u32,
object_information: *mut c_void,
object_information_length: u32,
return_length: *mut u32,
) -> i32;
pub struct NtdllFunctions {
query_system_information: NtQuerySystemInformationFn,
query_object: NtQueryObjectFn,
}
impl NtdllFunctions {
pub fn load() -> Option<Self> {
const NTDLL: [u16; 10] = [110, 116, 100, 108, 108, 46, 100, 108, 108, 0];
unsafe {
let module = GetModuleHandleW(NTDLL.as_ptr());
if module.is_null() {
return None;
}
let qsi = GetProcAddress(module, b"NtQuerySystemInformation\0".as_ptr())?;
let qo = GetProcAddress(module, b"NtQueryObject\0".as_ptr())?;
Some(Self {
query_system_information: std::mem::transmute(qsi),
query_object: std::mem::transmute(qo),
})
}
}
pub unsafe fn query_system_information(
&self,
class: u32,
buf: *mut c_void,
len: u32,
ret_len: *mut u32,
) -> i32 {
(self.query_system_information)(class, buf, len, ret_len)
}
pub unsafe fn query_object(
&self,
handle: HANDLE,
class: u32,
buf: *mut c_void,
len: u32,
ret_len: *mut u32,
) -> i32 {
(self.query_object)(handle, class, buf, len, ret_len)
}
}
pub fn nt_query_system_information_loop(ntdll: &NtdllFunctions, class: u32) -> Option<Vec<u8>> {
let mut size = DEFAULT_BUFFER_SIZE;
loop {
let mut buffer = vec![0u8; size];
let mut return_length = 0u32;
let status = unsafe {
ntdll.query_system_information(
class,
buffer.as_mut_ptr().cast(),
size as u32,
&mut return_length,
)
};
if status == STATUS_INFO_LENGTH_MISMATCH {
size *= 2;
if size > MAX_BUFFER_SIZE {
return None;
}
continue;
}
if status < 0 {
return None;
}
return Some(buffer);
}
}
pub unsafe fn read_unicode_string(ptr: *const UnicodeString) -> Vec<u16> {
let us = &*ptr;
if us.buffer.is_null() || us.length == 0 {
return Vec::new();
}
let char_count = us.length as usize / 2;
std::slice::from_raw_parts(us.buffer, char_count).to_vec()
}