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}