dinvk/
macros.rs

1/// Macro to dynamically invoke a function from a specified module.
2/// 
3/// # Arguments
4/// 
5/// * `$module` - Module address for the api to be called (e.g., `"ntdll.dll"`).
6/// * `$function` - A string slice with the name of the function to invoke (e.g., `"NtQueryInformationProcess"`).
7/// * `$ty` - The type of the function to cast to, including its signature.
8/// * `$($arg-expr),*` - A variadic list of arguments to pass to the function.
9/// 
10/// # Example
11/// 
12/// ```rust,ignore
13/// let ntdll = get_ntdll_address();
14/// let result = dinvoke!(ntdll,"NtQueryInformationProcess", extern "system" fn(...) -> u32, arg1, arg2);
15/// ``` 
16#[macro_export]
17macro_rules! dinvoke {
18    ($module:expr, $function:expr, $ty:ty, $($arg:expr),*) => {{
19        // Get the address of the function in the specified module.
20        let address = $crate::GetProcAddress($module, $function, None);
21        if address.is_null() {
22            None
23        } else {
24            unsafe {
25                // Transmute the function pointer to the desired type and invoke it with the provided arguments.
26                let func = core::mem::transmute::<_, $ty>(address);
27                Some(func($($arg),*))
28            }
29        }
30    }};
31}
32
33/// Macro to perform a system call (syscall) by dynamically resolving its function name.
34///
35/// # Arguments
36///
37/// * `$function_name` - A string slice representing the name of the syscall function (e.g., `"NtQueryInformationProcess"`).
38/// * `$($args:expr),+` - A variadic list of arguments to pass to the syscall.
39///
40/// # Example
41///
42/// ```rust,ignore
43/// syscall!("NtQueryInformationProcess", process_handle, process_info_class, process_info, process_info_length, return_length);
44/// ```
45#[macro_export]
46#[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
47macro_rules! syscall {
48    ($function_name:expr, $($y:expr), +) => {{
49        use $crate::*;
50
51        // Retrieve the address of ntdll.dll
52        let ntdll = get_ntdll_address();
53
54        // Get the address of the specified function in ntdll.dll
55        let addr = GetProcAddress(ntdll, $function_name, None);
56
57        // Retrieve the SSN (System Service Number) for the target function
58        ssn($function_name, ntdll).and_then(|ssn| {
59            // Calculate the syscall address
60            get_syscall_address(addr).map(|syscall_addr| {
61                // Count the number of arguments provided
62                let cnt = {
63                    let mut cnt = 0;
64                    $(
65                        let _ = $y;
66                        cnt += 1;
67                    )+
68                    cnt
69                };
70                
71                // Perform the syscall using inline assembly (x86_64 / x86 and with support WOW64)
72                unsafe { asm::do_syscall(ssn, syscall_addr, cnt, $($y), +) }
73            })
74        })
75    }};
76}
77
78/// Declares an external function from a dynamically linked library.
79///
80/// # Arguments
81///
82/// * `$library` - A string literal representing the name of the shared library (e.g., `"ntdll.dll"`).
83/// * `$abi` - A string literal specifying the calling convention (e.g., `"system"` for Windows API calls).
84/// * `$link_name` (optional) - A string literal specifying the actual name of the function in the library.
85/// * `$function` - The function signature to declare.
86///
87/// # Example
88///
89/// ```rust,ignore
90/// link!("ntdll.dll" "system" fn NtQueryInformationProcess(
91///     process_handle: HANDLE,
92///     process_info_class: u32,
93///     process_info: *mut u8,
94///     process_info_length: u32,
95///     return_length: *mut u32
96/// ) -> u32);
97/// ```
98#[macro_export]
99macro_rules! link {
100    ($library:literal $abi:literal $($link_name:literal)? fn $($function:tt)*) => (
101        extern $abi {
102            $(#[link_name=$link_name])?
103            pub(crate) fn $($function)*;
104        }
105    )
106}
107
108/// Prints output to the Windows console using `ConsoleWriter`.
109///
110/// # Example
111/// 
112/// ```rust,ignore
113/// dprintln!("Hello, world!");
114/// dprintln!("Value: {}", 42);
115/// ```
116#[macro_export]
117macro_rules! dprintln {
118    ($($arg:tt)*) => {{
119        use core::fmt::Write;
120        
121        let mut console = $crate::ConsoleWriter;
122        let _ = writeln!(console, $($arg)*);
123    }};
124}