dinvk/
wrappers.rs

1use crate::data::*;
2use obfstr::obfstr as s;
3use core::ffi::c_void;
4use crate::{
5    GetModuleHandle, 
6    dinvoke, get_ntdll_address,
7};
8
9#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
10use crate::breakpoint::{
11    is_breakpoint_enabled, 
12    set_breakpoint, 
13    WINAPI, CURRENT_API
14};
15
16/// Wrapper for the `LoadLibraryA` function from `KERNEL32.DLL`.
17pub fn LoadLibraryA(module: &str) -> *mut c_void {
18    let name = alloc::format!("{}\0", module);
19    let kernel32 = GetModuleHandle(s!("KERNEL32.DLL"), None);
20    dinvoke!(
21        kernel32,
22        s!("LoadLibraryA"),
23        LoadLibraryA,
24        name.as_ptr()
25    )
26    .unwrap_or(core::ptr::null_mut())
27}
28
29/// Wrapper for the `NtAllocateVirtualMemory` function from `NTDLL.DLL`.
30#[allow(unused_mut)]
31pub fn NtAllocateVirtualMemory(
32    mut process_handle: HANDLE,
33    base_address: *mut *mut c_void,
34    zero_bits: usize,
35    region_size: *mut usize,
36    allocation_type: u32,
37    mut protect: u32,
38) -> NTSTATUS {
39    // Retrieve the address of the ntdll.dll module in memory.
40    let ntdll = get_ntdll_address();
41
42    cfg_if::cfg_if! {
43        if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
44            // Handle debugging breakpoints, if enabled.
45            if is_breakpoint_enabled() {
46                unsafe {
47                    CURRENT_API = Some(WINAPI::NtAllocateVirtualMemory {
48                        ProcessHandle: process_handle,
49                        Protect: protect,
50                    });
51                }
52                
53                // Argument tampering before syscall execution.
54                // Modifies the memory protection to PAGE_READONLY.
55                protect = 0x02;
56        
57                // Replaces the process handle with an arbitrary value.
58                process_handle = -23isize as HANDLE; 
59                
60                // Locate and set a breakpoint on the NtAllocateVirtualMemory syscall.
61                let addr = crate::GetProcAddress(ntdll, s!("NtAllocateVirtualMemory"), None);
62                if let Some(syscall_addr) = crate::get_syscall_address(addr) {
63                    set_breakpoint(syscall_addr);
64                }
65            }
66        }
67    }
68
69    dinvoke!(
70        ntdll,
71        s!("NtAllocateVirtualMemory"),
72        NtAllocateVirtualMemory,
73        process_handle,
74        base_address,
75        zero_bits,
76        region_size,
77        allocation_type, 
78        protect
79    )
80    .unwrap_or(STATUS_UNSUCCESSFUL)
81}
82
83/// Wrapper for the `NtProtectVirtualMemory` function from `NTDLL.DLL`.
84#[allow(unused_mut)]
85pub fn NtProtectVirtualMemory(
86    mut process_handle: *mut c_void,
87    base_address: *mut *mut c_void,
88    region_size: *mut usize,
89    mut new_protect: u32,
90    old_protect: *mut u32,
91) -> NTSTATUS {
92    // Retrieve the address of the ntdll.dll module in memory.
93    let ntdll = get_ntdll_address();
94
95    cfg_if::cfg_if! {
96        if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
97            // Handle debugging breakpoints, if enabled.
98            if is_breakpoint_enabled() {
99                unsafe {
100                    CURRENT_API = Some(WINAPI::NtProtectVirtualMemory {
101                        ProcessHandle: process_handle,
102                        NewProtect: new_protect,
103                    });
104                }
105                
106                // Modifies the memory protection to PAGE_READONLY.
107                new_protect = 0x02;
108
109                // Replaces the process handle with an arbitrary value.
110                process_handle = -23isize as HANDLE; 
111
112                // Locate and set a breakpoint on the NtProtectVirtualMemory syscall.
113                let addr = crate::GetProcAddress(ntdll, s!("NtProtectVirtualMemory"), None);
114                if let Some(syscall_addr) = crate::get_syscall_address(addr) {
115                    set_breakpoint(syscall_addr);
116                }
117            }
118        }
119    }
120
121    dinvoke!(
122        ntdll,
123        s!("NtProtectVirtualMemory"),
124        NtProtectVirtualMemory,
125        process_handle,
126        base_address,
127        region_size,
128        new_protect, 
129        old_protect
130    )
131    .unwrap_or(STATUS_UNSUCCESSFUL)
132}
133
134/// Wrapper for the `NtCreateThreadEx` function from `NTDLL.DLL`.
135#[allow(unused_mut)]
136pub fn NtCreateThreadEx(
137    mut thread_handle: *mut HANDLE,
138    mut desired_access: u32,
139    mut object_attributes: *mut OBJECT_ATTRIBUTES,
140    mut process_handle: HANDLE,
141    start_routine: *mut c_void,
142    argument: *mut c_void,
143    create_flags: u32,
144    zero_bits: usize,
145    stack_size: usize,
146    maximum_stack_size: usize,
147    attribute_list: *mut PS_ATTRIBUTE_LIST
148) -> NTSTATUS {
149    // Retrieve the address of the ntdll.dll module in memory.
150    let ntdll = get_ntdll_address();
151
152    cfg_if::cfg_if! {
153        if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
154            // Handle debugging breakpoints, if enabled.
155            if is_breakpoint_enabled() {
156                unsafe {
157                    CURRENT_API = Some(WINAPI::NtCreateThreadEx {
158                        ProcessHandle: process_handle,
159                        ThreadHandle: thread_handle,
160                        DesiredAccess: desired_access,
161                        ObjectAttributes: object_attributes
162                    });
163                }
164                
165                // Replacing process handle and thread handle with arbitrary values.
166                process_handle = -12isize as HANDLE;
167                thread_handle = -43isize as *mut HANDLE;
168
169                // Modifying desired access permissions.
170                desired_access = 0x80;
171
172                // Modifying object attributes before the syscall.
173                object_attributes = alloc::boxed::Box::leak(alloc::boxed::Box::new(OBJECT_ATTRIBUTES::default()));
174
175                // Locate and set a breakpoint on the NtCreateThreadEx syscall.
176                let addr = crate::GetProcAddress(ntdll, s!("NtCreateThreadEx"), None);
177                if let Some(addr) = crate::get_syscall_address(addr) {
178                    set_breakpoint(addr);
179                }
180            }
181        }
182    }
183
184    dinvoke!(
185        ntdll,
186        s!("NtCreateThreadEx"),
187        NtCreateThreadEx,
188        thread_handle,
189        desired_access,
190        object_attributes,
191        process_handle,
192        start_routine,
193        argument,
194        create_flags,
195        zero_bits,
196        stack_size,
197        maximum_stack_size,
198        attribute_list
199    )
200    .unwrap_or(STATUS_UNSUCCESSFUL)
201}
202
203/// Wrapper for the `NtWriteVirtualMemory` function from `NTDLL.DLL`.
204#[allow(unused_mut)]
205pub fn NtWriteVirtualMemory(
206    mut process_handle: HANDLE,
207    base_address: *mut c_void,
208    mut buffer: *mut c_void,
209    mut number_of_bytes_to_write: usize,
210    number_of_bytes_written: *mut usize,
211) -> NTSTATUS {
212    // Retrieve the address of the ntdll.dll module in memory.
213    let ntdll = get_ntdll_address();
214
215    cfg_if::cfg_if! {
216        if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
217            // Handle debugging breakpoints, if enabled.
218            if is_breakpoint_enabled() {
219                unsafe {
220                    CURRENT_API = Some(WINAPI::NtWriteVirtualMemory {
221                        ProcessHandle: process_handle,
222                        Buffer: buffer,
223                        NumberOfBytesToWrite: number_of_bytes_written
224                    });
225                }
226
227                // Replacing process handle with an arbitrary value.
228                process_handle = -90isize as HANDLE;
229
230                // Modifying buffer and size before syscall execution.
231                let temp = [0u8; 10];
232                buffer = temp.as_ptr().cast_mut().cast();
233                number_of_bytes_to_write = temp.len();
234
235                // Locate and set a breakpoint on the NtWriteVirtualMemory syscall.
236                let addr = crate::GetProcAddress(ntdll, s!("NtWriteVirtualMemory"), None);
237                if let Some(addr) = crate::get_syscall_address(addr) {
238                    set_breakpoint(addr);
239                }
240            }
241        }
242    }
243    
244    dinvoke!(
245        ntdll,
246        s!("NtWriteVirtualMemory"),
247        NtWriteVirtualMemory,
248        process_handle,
249        base_address,
250        buffer,
251        number_of_bytes_to_write,
252        number_of_bytes_written
253    )
254    .unwrap_or(STATUS_UNSUCCESSFUL)
255}
256
257/// Wrapper for the `HeapAlloc` function from `KERNEL32.DLL`.
258pub fn HeapAlloc(
259    hheap: HANDLE, 
260    dwflags: HEAP_FLAGS, 
261    dwbytes: usize
262) -> *mut c_void {
263    let kernel32 = GetModuleHandle(s!("KERNEL32.DLL"), None);
264    dinvoke!(
265        kernel32,
266        s!("HeapAlloc"),
267        HeapAlloc,
268        hheap,
269        dwflags,
270        dwbytes
271    )
272    .unwrap_or(core::ptr::null_mut())
273}
274
275/// Wrapper for the `HeapFree` function from `KERNEL32.DLL`.
276pub fn HeapFree(
277    hheap: HANDLE,
278    dwflags: HEAP_FLAGS,
279    lpmem: *const c_void,
280) -> *mut c_void {
281    let kernel32 = GetModuleHandle(s!("KERNEL32.DLL"), None);
282    dinvoke!(
283        kernel32,
284        s!("HeapFree"),
285        HeapFree,
286        hheap,
287        dwflags,
288        lpmem
289    )
290    .unwrap_or(core::ptr::null_mut())
291}
292
293/// Wrapper for the `HeapCreate` function from `KERNEL32.DLL`.
294pub fn HeapCreate(
295    floptions: HEAP_FLAGS,
296    dwinitialsize: usize,
297    dwmaximumsize: usize,
298) -> *mut c_void {
299    let kernel32 = GetModuleHandle(s!("KERNEL32.DLL"), None);
300    dinvoke!(
301        kernel32,
302        s!("HeapCreate"),
303        HeapCreate,
304        floptions,
305        dwinitialsize,
306        dwmaximumsize
307    )
308    .unwrap_or(core::ptr::null_mut())
309}
310
311/// Wrapper for the `AddVectoredExceptionHandler` function from `KERNEL32.DLL`.
312pub fn AddVectoredExceptionHandler(
313    first: u32,
314    handler: PVECTORED_EXCEPTION_HANDLER,
315) -> *mut c_void {
316    let kernel32 = GetModuleHandle(s!("KERNEL32.DLL"), None);
317    dinvoke!(
318        kernel32,
319        s!("AddVectoredExceptionHandler"),
320        AddVectoredExceptionHandler,
321        first,
322        handler
323    )
324    .unwrap_or(core::ptr::null_mut())
325}
326
327/// Wrapper for the `RemoveVectoredExceptionHandler` function from `KERNEL32.DLL`.
328pub fn RemoveVectoredExceptionHandler(
329    handle: *mut c_void,
330) -> u32 {
331    let kernel32 = GetModuleHandle(s!("KERNEL32.DLL"), None);
332    dinvoke!(
333        kernel32,
334        s!("RemoveVectoredExceptionHandler"),
335        RemoveVectoredExceptionHandler,
336        handle
337    )
338    .unwrap_or(0)
339}
340
341/// Wrapper for the `GetThreadContext` function from `KERNEL32.DLL`.
342pub fn GetThreadContext(
343    hthread: HANDLE,
344    lpcontext: *mut CONTEXT,
345) -> i32 {
346    let kernel32 = GetModuleHandle(s!("KERNEL32.DLL"), None);
347    dinvoke!(
348        kernel32,
349        s!("GetThreadContext"),
350        GetThreadContext,
351        hthread,
352        lpcontext
353    )
354    .unwrap_or(0)
355}
356
357/// Wrapper for the `SetThreadContext` function from `KERNEL32.DLL`.
358pub fn SetThreadContext(
359    hthread: HANDLE,
360    lpcontext: *const CONTEXT,
361) -> i32 {
362    let kernel32 = GetModuleHandle(s!("KERNEL32.DLL"), None);
363    dinvoke!(
364        kernel32,
365        s!("SetThreadContext"),
366        SetThreadContext,
367        hthread,
368        lpcontext
369    )
370    .unwrap_or(0)
371}
372
373/// Wrapper for the `GetStdHandle` function from `KERNEL32.DLL`.
374pub fn GetStdHandle(nStdHandle: u32) -> HANDLE {
375    let kernel32 = GetModuleHandle(s!("KERNEL32.DLL"), None);
376    dinvoke!(
377        kernel32,
378        s!("GetStdHandle"),
379        GetStdHandle,
380        nStdHandle
381    )
382    .unwrap_or(core::ptr::null_mut())
383}