1 //! Module for importing functions from ntdll.dll.
2 //! The winapi crate does not expose these Windows API functions.
3 
4 #![allow(nonstandard_style)]
5 
6 use std::ffi::c_void;
7 use std::os::raw::c_ulong;
8 use std::os::windows::prelude::RawHandle;
9 use std::sync::atomic::{AtomicUsize, Ordering};
10 use winapi::shared::ntdef::NTSTATUS;
11 use winapi::um::libloaderapi::{GetModuleHandleA, GetProcAddress};
12 use winapi::um::winnt::ACCESS_MASK;
13 
14 #[repr(C)]
15 #[derive(Copy, Clone)]
16 pub(crate) enum FILE_INFORMATION_CLASS {
17     FileAccessInformation = 8,
18     FileModeInformation = 16,
19 }
20 
21 #[repr(C)]
22 #[derive(Copy, Clone)]
23 pub(crate) union IO_STATUS_BLOCK_u {
24     pub Status: NTSTATUS,
25     pub Pointer: *mut c_void,
26 }
27 
28 #[repr(C)]
29 #[derive(Copy, Clone)]
30 pub(crate) struct IO_STATUS_BLOCK {
31     pub u: IO_STATUS_BLOCK_u,
32     pub Information: *mut c_void,
33 }
34 
35 #[repr(C)]
36 #[derive(Copy, Clone, Default)]
37 pub(crate) struct FILE_ACCESS_INFORMATION {
38     pub AccessFlags: ACCESS_MASK,
39 }
40 
41 #[repr(C)]
42 #[derive(Copy, Clone, Default)]
43 pub(crate) struct FILE_MODE_INFORMATION {
44     pub Mode: c_ulong,
45 }
46 
47 impl Default for IO_STATUS_BLOCK {
48     #[inline]
default() -> Self49     fn default() -> Self {
50         unsafe { std::mem::zeroed() }
51     }
52 }
53 
54 macro_rules! ntdll_import {
55     { fn $name:ident($($arg:ident: $argty:ty),*) -> $retty:ty; $($tail:tt)* } => {
56         pub(crate) unsafe fn $name($($arg: $argty),*) -> $retty {
57             static ADDRESS: AtomicUsize = AtomicUsize::new(0);
58             let address = match ADDRESS.load(Ordering::Relaxed) {
59                 0 => {
60                     let ntdll = GetModuleHandleA("ntdll\0".as_ptr() as *const i8);
61                     let address = GetProcAddress(
62                         ntdll,
63                         concat!(stringify!($name), "\0").as_ptr() as *const i8,
64                     ) as usize;
65                     assert!(address != 0);
66                     ADDRESS.store(address, Ordering::Relaxed);
67                     address
68                 }
69                 address => address
70             };
71             let func: unsafe fn($($argty),*) -> $retty = std::mem::transmute(address);
72             func($($arg),*)
73         }
74         ntdll_import! { $($tail)* }
75     };
76     {} => {};
77 }
78 
79 ntdll_import! {
80     // https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-ntqueryinformationfile
81     fn NtQueryInformationFile(
82         FileHandle: RawHandle,
83         IoStatusBlock: *mut IO_STATUS_BLOCK,
84         FileInformation: *mut c_void,
85         Length: c_ulong,
86         FileInformationClass: FILE_INFORMATION_CLASS
87     ) -> NTSTATUS;
88     // https://docs.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-rtlntstatustodoserror
89     fn RtlNtStatusToDosError(status: NTSTATUS) -> c_ulong;
90 }
91