1#![no_std]
29#![cfg_attr(docsrs, feature(doc_cfg))]
30extern crate alloc;
31
32#[cfg(not(windows))]
33compile_error!("dyncvoke-core is Windows-only");
34
35use alloc::{
36 collections::BTreeMap,
37 ffi::CString,
38 format,
39 string::{String, ToString},
40 vec,
41 vec::Vec,
42};
43use core::{ffi::c_void, mem::size_of, ptr};
44
45use data::lc;
46use data::LARGE_INTEGER;
47use windows_sys::Win32::Foundation::BOOL;
48use windows_sys::Win32::Security::SECURITY_ATTRIBUTES;
49#[cfg(target_arch = "x86_64")]
50use windows_sys::Win32::System::Diagnostics::Debug::{GetThreadContext, SetThreadContext};
51use windows_sys::Win32::System::Memory::MEMORY_BASIC_INFORMATION;
52use windows_sys::Win32::System::SystemInformation::SYSTEM_INFO;
53use windows_sys::Win32::System::IO::IO_STATUS_BLOCK;
54#[cfg(target_arch = "x86_64")]
55use windows_sys::Win32::System::Threading::GetCurrentProcessId;
56
57pub mod peb;
58
59pub use data::HANDLE;
60pub use data::HINSTANCE;
61pub use data::OBJECT_ATTRIBUTES;
62pub use data::UNICODE_STRING;
63pub use windows_sys::Win32::System::Threading::{GetCurrentProcess, PROCESS_BASIC_INFORMATION};
64
65pub const INVALID_HANDLE_VALUE: HANDLE = -1isize as HANDLE;
66
67pub mod sys;
68pub use sys::{extract_ssn, get_syscall_address, resolve_syscall, SyscallError};
69#[cfg(target_arch = "x86_64")]
70pub use sys::asm::do_syscall;
71
72#[allow(unused_imports)]
73use data::{
74 ApiSetNamespace, ApiSetNamespaceEntry, ApiSetValueEntry, ClientId, EntryPoint,
75 LptopLevelExceptionFilter, PeMetadata, PsAttributeList, PsCreateInfo,
76 DLL_PROCESS_ATTACH, EAT, MAX_PATH,
77 MEM_COMMIT, MEM_RESERVE,
78 PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_READONLY, PAGE_READWRITE,
79 PROCESS_QUERY_LIMITED_INFORMATION, PVOID, TLS_OUT_OF_INDEXES,
80};
81
82#[cfg(target_arch = "x86_64")]
83use data::{
84 ExceptionHandleFunction, ExceptionPointers,
85 NtAllocateVirtualMemoryArgs, NtCreateThreadExArgs, NtOpenProcessArgs,
86 NtProtectVirtualMemoryArgs, NtWriteVirtualMemoryArgs,
87};
88#[cfg(target_arch = "x86_64")]
89use windows_sys::Win32::System::Threading::GetCurrentThread;
90
91#[cfg(target_arch = "x86_64")]
92static mut HARDWARE_BREAKPOINTS: bool = false;
93#[cfg(target_arch = "x86_64")]
94static mut HARDWARE_EXCEPTION_FUNCTION: ExceptionHandleFunction =
95 ExceptionHandleFunction::NtOpenProcess;
96#[cfg(target_arch = "x86_64")]
97static mut NT_ALLOCATE_VIRTUAL_MEMORY_ARGS: NtAllocateVirtualMemoryArgs =
98 NtAllocateVirtualMemoryArgs {
99 handle: INVALID_HANDLE_VALUE,
100 base_address: ptr::null_mut(),
101 };
102#[cfg(target_arch = "x86_64")]
103static mut NT_OPEN_PROCESS_ARGS: NtOpenProcessArgs = NtOpenProcessArgs {
104 handle: ptr::null_mut(),
105 access: 0,
106 attributes: ptr::null_mut(),
107 client_id: ptr::null_mut(),
108};
109#[cfg(target_arch = "x86_64")]
110static mut NT_PROTECT_VIRTUAL_MEMORY_ARGS: NtProtectVirtualMemoryArgs =
111 NtProtectVirtualMemoryArgs {
112 handle: INVALID_HANDLE_VALUE,
113 base_address: ptr::null_mut(),
114 size: ptr::null_mut(),
115 protection: 0,
116 };
117#[cfg(target_arch = "x86_64")]
118static mut NT_WRITE_VIRTUAL_MEMORY_ARGS: NtWriteVirtualMemoryArgs = NtWriteVirtualMemoryArgs {
119 handle: INVALID_HANDLE_VALUE,
120 base_address: ptr::null_mut(),
121 buffer: ptr::null_mut(),
122 size: 0usize,
123};
124#[cfg(target_arch = "x86_64")]
125static mut NT_CREATE_THREAD_EX_ARGS: NtCreateThreadExArgs = NtCreateThreadExArgs {
126 thread: ptr::null_mut(),
127 access: 0,
128 attributes: ptr::null_mut(),
129 process: INVALID_HANDLE_VALUE,
130};
131#[allow(static_mut_refs)]
132static mut HOOKED_FUNCTIONS_INFO: Vec<(usize, Vec<u8>)> = vec![];
133
134#[cfg(target_arch = "x86_64")]
137pub fn use_hardware_breakpoints(value: bool) {
138 unsafe {
139 HARDWARE_BREAKPOINTS = value;
140 }
141}
142
143#[cfg(target_arch = "x86_64")]
153pub fn set_hardware_breakpoint(address: usize) {
154 use windows_sys::Win32::System::Diagnostics::Debug::CONTEXT;
155
156 unsafe {
157 let mut context: CONTEXT = core::mem::zeroed();
158 context.ContextFlags = 0x100000 | 0x10; let _ = GetThreadContext(GetCurrentThread(), &mut context);
160
161 context.Dr0 = address as u64;
162 context.Dr6 = 0;
163 context.Dr7 = context.Dr7 & !(((1 << 2) - 1) << 16); context.Dr7 = context.Dr7 & !(((1 << 2) - 1) << 18); context.Dr7 = (context.Dr7 & !(((1 << 1) - 1) << 0)) | (1 << 0); context.ContextFlags = 0x100000 | 0x10;
168
169 let _ = SetThreadContext(GetCurrentThread(), &context);
170 }
171}
172
173#[cfg(target_arch = "x86_64")]
178pub unsafe extern "system" fn breakpoint_handler(exceptioninfo: *mut ExceptionPointers) -> i32 {
179 if (*(*(exceptioninfo)).exception_record).ExceptionCode as u32 == 0x80000004
180 {
182 if ((*(*exceptioninfo).context_record).Dr7 & 1) == 1 {
183 if (*(*exceptioninfo).context_record).Rip == (*(*exceptioninfo).context_record).Dr0 {
184 (*(*exceptioninfo).context_record).Dr0 = 0; match HARDWARE_EXCEPTION_FUNCTION {
186 ExceptionHandleFunction::NtAllocateVirtualMemory => {
187 (*(*exceptioninfo).context_record).R10 =
188 NT_ALLOCATE_VIRTUAL_MEMORY_ARGS.handle as u64 as u64;
189 (*(*exceptioninfo).context_record).Rdx =
190 core::mem::transmute(NT_ALLOCATE_VIRTUAL_MEMORY_ARGS.base_address);
191 }
192 ExceptionHandleFunction::NtProtectVirtualMemory => {
193 (*(*exceptioninfo).context_record).R10 =
194 NT_PROTECT_VIRTUAL_MEMORY_ARGS.handle as u64 as u64;
195 (*(*exceptioninfo).context_record).Rdx =
196 core::mem::transmute(NT_PROTECT_VIRTUAL_MEMORY_ARGS.base_address);
197 (*(*exceptioninfo).context_record).R8 =
198 core::mem::transmute(NT_PROTECT_VIRTUAL_MEMORY_ARGS.size);
199 (*(*exceptioninfo).context_record).R9 =
200 NT_PROTECT_VIRTUAL_MEMORY_ARGS.protection as u64;
201 }
202 ExceptionHandleFunction::NtOpenProcess => {
203 (*(*exceptioninfo).context_record).R10 =
204 core::mem::transmute(NT_OPEN_PROCESS_ARGS.handle);
205 (*(*exceptioninfo).context_record).Rdx = NT_OPEN_PROCESS_ARGS.access as u64;
206 (*(*exceptioninfo).context_record).R8 =
207 core::mem::transmute(NT_OPEN_PROCESS_ARGS.attributes);
208 (*(*exceptioninfo).context_record).R9 =
209 core::mem::transmute(NT_OPEN_PROCESS_ARGS.client_id);
210 }
211 ExceptionHandleFunction::NtWriteVirtualMemory => {
212 (*(*exceptioninfo).context_record).R10 =
213 NT_WRITE_VIRTUAL_MEMORY_ARGS.handle as u64 as u64;
214 (*(*exceptioninfo).context_record).Rdx =
215 core::mem::transmute(NT_WRITE_VIRTUAL_MEMORY_ARGS.base_address);
216 (*(*exceptioninfo).context_record).R8 =
217 core::mem::transmute(NT_WRITE_VIRTUAL_MEMORY_ARGS.buffer);
218 (*(*exceptioninfo).context_record).R9 =
219 NT_WRITE_VIRTUAL_MEMORY_ARGS.size as u64;
220 }
221 ExceptionHandleFunction::NtCreateThreadEx => {
222 (*(*exceptioninfo).context_record).R10 =
223 core::mem::transmute(NT_CREATE_THREAD_EX_ARGS.thread);
224 (*(*exceptioninfo).context_record).Rdx =
225 NT_CREATE_THREAD_EX_ARGS.access as u64;
226 (*(*exceptioninfo).context_record).R8 =
227 core::mem::transmute(NT_CREATE_THREAD_EX_ARGS.attributes);
228 (*(*exceptioninfo).context_record).R9 =
229 NT_CREATE_THREAD_EX_ARGS.process as u64;
230 }
231 }
232 }
233 }
234 return -1; }
236 0 }
238
239#[allow(static_mut_refs)]
242pub fn hook_function(src_address: usize, dst_address: usize) -> bool {
243 unsafe {
244 let mut original_address = src_address;
245 let handle = INVALID_HANDLE_VALUE;
246 let base_address: *mut PVOID = &mut original_address as *mut usize as *mut PVOID;
247 let mut size: usize = 4096;
248 let mut old_protection: u32 = 0;
249
250 let z = nt_protect_virtual_memory(
251 handle,
252 base_address,
253 &mut size,
254 PAGE_EXECUTE_READWRITE,
255 &mut old_protection,
256 );
257
258 if z != 0 {
259 return false;
260 }
261
262 let ntop_ptr = src_address as *mut u8;
263 let mut original_bytes: Vec<u8> = vec![];
264 if cfg!(target_pointer_width = "64") {
265 for i in 0..=12 {
266 let b = *(ntop_ptr.add(i));
267 original_bytes.push(b);
268 }
269
270 *ntop_ptr = 0x49;
271 *(ntop_ptr.add(1)) = 0xBB;
272 *(ntop_ptr.add(2) as *mut usize) = dst_address;
273 *(ntop_ptr.add(10)) = 0x41;
274 *(ntop_ptr.add(11)) = 0xFF;
275 *(ntop_ptr.add(12)) = 0xE3;
276 } else {
277 for i in 0..=5 {
278 let b = *(ntop_ptr.add(i));
279 original_bytes.push(b);
280 }
281
282 *ntop_ptr = 0x68;
283 *(ntop_ptr.add(1) as *mut usize) = dst_address;
284 *(ntop_ptr.add(5)) = 0xC3
285 }
286
287 HOOKED_FUNCTIONS_INFO.push((src_address, original_bytes));
288
289 let mut unused = 0u32;
290 let z = nt_protect_virtual_memory(
291 handle,
292 base_address,
293 &mut size,
294 old_protection,
295 &mut unused,
296 );
297
298 if z != 0 {
299 return false;
300 }
301
302 true
303 }
304}
305
306#[allow(static_mut_refs)]
308pub fn unhook_function(address: usize) -> bool {
309 unsafe {
310 let mut unhook_info = (0, vec![]);
311 let mut index = 0;
312 for (i, element) in HOOKED_FUNCTIONS_INFO.iter().enumerate() {
313 if element.0 == address {
314 unhook_info = (element.0, element.1.to_vec());
315 index = i;
316 break;
317 }
318 }
319
320 if unhook_info.0 == 0 {
321 return false;
322 }
323
324 let mut original_address = unhook_info.0;
325 let handle = INVALID_HANDLE_VALUE;
326 let base_address: *mut PVOID = &mut original_address as *mut usize as *mut PVOID;
327 let mut size: usize = 4096;
328 let mut old_protection: u32 = 0;
329
330 let z = nt_protect_virtual_memory(
331 handle,
332 base_address,
333 &mut size,
334 PAGE_EXECUTE_READWRITE,
335 &mut old_protection,
336 );
337
338 if z != 0 {
339 return false;
340 }
341
342 let ptr = unhook_info.0 as *mut u8;
343 for i in 0..unhook_info.1.len() {
344 let addr = ptr.add(i);
345 *addr = unhook_info.1[i];
346 }
347
348 let mut unused = 0u32;
349 let z = nt_protect_virtual_memory(
350 handle,
351 base_address,
352 &mut size,
353 old_protection,
354 &mut unused,
355 );
356
357 if z != 0 {
358 return false;
359 }
360
361 HOOKED_FUNCTIONS_INFO.remove(index);
362
363 true
364 }
365}
366
367pub fn get_module_base_address(module_name: &str) -> usize {
383 peb::get_module_by_name(module_name)
384}
385
386pub fn get_module_base_address_h(name_hash: u32) -> usize {
389 peb::get_module_by_hash(name_hash)
390}
391
392pub fn get_function_address(module_base_address: usize, function: &str) -> usize {
412 if module_base_address == 0 {
413 return 0;
414 }
415 unsafe {
416 let mut function_ptr: *mut i32 = ptr::null_mut();
417 let pe_header = *((module_base_address + 0x3C) as *mut i32);
418 let opt_header: usize = module_base_address + (pe_header as usize) + 0x18;
419 let magic = *(opt_header as *mut i16);
420 let p_export: usize;
421
422 if magic == 0x010b {
423 p_export = opt_header + 0x60;
424 } else {
425 p_export = opt_header + 0x70;
426 }
427
428 let export_rva = *(p_export as *mut i32);
429 let export_size = *((p_export + 4) as *mut i32);
435 let export_start = export_rva as usize;
436 let export_end = export_start.wrapping_add(export_size as usize);
437 let ordinal_base = *((module_base_address + export_rva as usize + 0x10) as *mut i32);
438 let number_of_names = *((module_base_address + export_rva as usize + 0x18) as *mut i32);
439 let functions_rva = *((module_base_address + export_rva as usize + 0x1C) as *mut i32);
440 let names_rva = *((module_base_address + export_rva as usize + 0x20) as *mut i32);
441 let ordinals_rva = *((module_base_address + export_rva as usize + 0x24) as *mut i32);
442
443 for x in 0..number_of_names {
444 let address =
445 *((module_base_address + names_rva as usize + x as usize * 4) as *mut i32);
446 let mut function_name_ptr = (module_base_address + address as usize) as *mut u8;
447 let mut function_name: String = "".to_string();
448
449 while *function_name_ptr as char != '\0'
450 {
452 function_name.push(*function_name_ptr as char);
453 function_name_ptr = function_name_ptr.add(1);
454 }
455
456 if function_name.to_lowercase() == function.to_lowercase() {
457 let function_ordinal = *((module_base_address
458 + ordinals_rva as usize
459 + x as usize * 2) as *mut i16) as i32
460 + ordinal_base;
461 let function_rva = *((module_base_address
462 + functions_rva as usize
463 + (4 * (function_ordinal - ordinal_base)) as usize)
464 as *mut i32);
465 function_ptr = (module_base_address + function_rva as usize) as *mut i32;
466
467 let rva = function_rva as usize;
468 if rva >= export_start && rva < export_end {
469 function_ptr = get_forward_address(function_ptr as *mut u8) as *mut i32;
470 }
471
472 break;
473 }
474 }
475
476 let mut ret: usize = 0;
477
478 if function_ptr != ptr::null_mut() {
479 ret = function_ptr as usize;
480 }
481
482 ret
483 }
484}
485
486fn get_forward_address(function_ptr: *mut u8) -> usize {
487 unsafe {
488 let mut c = 100;
489 let mut ptr = function_ptr.clone();
490 let mut forwarded_names = "".to_string();
491
492 loop {
493 if *ptr as char != '\0' {
494 forwarded_names.push(*ptr as char);
495 } else {
496 break;
497 }
498
499 ptr = ptr.add(1);
500 c = c - 1;
501
502 if c == 0 {
503 return function_ptr as usize;
504 }
505 }
506
507 let values: Vec<&str> = forwarded_names.split(".").collect();
508 if values.len() != 2 {
509 return function_ptr as usize;
510 }
511
512 let mut forwarded_module_name = values[0].to_string();
513 let forwarded_export_name = values[1].to_string();
514
515 if forwarded_module_name.len() < 2 || forwarded_export_name.len() == 0 {
516 return function_ptr as usize;
517 }
518
519 let api_set = get_api_mapping();
520
521 if forwarded_module_name.len() < 2
522 || !forwarded_module_name.is_char_boundary(forwarded_module_name.len() - 2)
523 {
524 return function_ptr as usize;
525 }
526
527 let lookup_key = format!(
528 "{}{}",
529 &forwarded_module_name[..forwarded_module_name.len() - 2],
530 ".dll"
531 );
532
533 if api_set.contains_key(&lookup_key) {
534 forwarded_module_name = match api_set.get(&lookup_key) {
535 Some(x) => x.to_string(),
536 None => forwarded_module_name,
537 };
538 } else {
539 forwarded_module_name = forwarded_module_name + ".dll";
540 }
541
542 let mut module = get_module_base_address(&forwarded_module_name);
543
544 if module == 0 {
545 module = load_library_a(&forwarded_module_name);
546 }
547
548 if module != 0 {
549 return get_function_address(module, &forwarded_export_name);
550 }
551
552 function_ptr as usize
553 }
554}
555
556pub fn get_api_mapping() -> BTreeMap<String, String> {
557 unsafe {
558 let handle = INVALID_HANDLE_VALUE;
559 let mut p: PROCESS_BASIC_INFORMATION = core::mem::zeroed();
560 let process_information: *mut c_void = &mut p as *mut PROCESS_BASIC_INFORMATION as *mut c_void;
561 let _ret = nt_query_information_process(
562 handle,
563 0,
564 process_information,
565 size_of::<PROCESS_BASIC_INFORMATION>() as u32,
566 ptr::null_mut(),
567 );
568
569 let process_information_ptr: *mut PROCESS_BASIC_INFORMATION =
570 core::mem::transmute(process_information);
571
572 let api_set_map_offset: usize;
573
574 if size_of::<usize>() == 4 {
575 api_set_map_offset = 0x38;
576 } else {
577 api_set_map_offset = 0x68;
578 }
579
580 let mut api_set_dict: BTreeMap<String, String> = BTreeMap::new();
581
582 let api_set_namespace_ptr = *(((*process_information_ptr).PebBaseAddress as usize
583 + api_set_map_offset) as *mut usize);
584 let api_set_namespace_ptr: *mut ApiSetNamespace =
585 core::ptr::with_exposed_provenance_mut::<ApiSetNamespace>(api_set_namespace_ptr);
586 let namespace = *api_set_namespace_ptr;
587
588 for i in 0..namespace.count {
589 let set_entry_ptr = (api_set_namespace_ptr as usize
590 + namespace.entry_offset as usize
591 + (i * size_of::<ApiSetNamespaceEntry>() as i32) as usize)
592 as *mut ApiSetNamespaceEntry;
593 let set_entry = *set_entry_ptr;
594
595 let mut api_set_entry_name_ptr: *mut u8 =
596 (api_set_namespace_ptr as usize + set_entry.name_offset as usize) as *mut u8;
597 let mut api_set_entry_name: String = "".to_string();
598 let mut j = 0;
599 while j < (set_entry.name_length / 2) {
600 let c = *api_set_entry_name_ptr as char;
601 if c != '\0' {
602 api_set_entry_name.push(c);
603 j = j + 1;
604 }
605
606 api_set_entry_name_ptr = api_set_entry_name_ptr.add(1);
607 }
608
609 if api_set_entry_name.len() < 2 {
610 continue;
611 }
612 let api_set_entry_key = format!(
613 "{}{}",
614 &api_set_entry_name[..api_set_entry_name.len() - 2],
615 ".dll"
616 );
617 let mut set_value_ptr: *mut ApiSetValueEntry = ptr::null_mut();
618
619 if set_entry.value_length == 1 {
620 let value =
621 (api_set_namespace_ptr as usize + set_entry.value_offset as usize) as *mut u8;
622 set_value_ptr = core::mem::transmute(value);
623 } else if set_entry.value_length > 1 {
624 for x in 0..set_entry.value_length {
625 let host_ptr = (api_set_namespace_ptr as usize
626 + set_entry.value_offset as usize
627 + size_of::<ApiSetValueEntry>() as usize * x as usize)
628 as *mut u8;
629 let mut host_walk: *mut u8 = host_ptr;
630 let mut host: String = "".to_string();
631 loop {
632 let c = *host_walk;
633 if c == 0 {
634 break;
635 }
636 host.push(c as char);
637 host_walk = host_walk.add(1);
638 }
639
640 if host != api_set_entry_name {
641 set_value_ptr = (api_set_namespace_ptr as usize
642 + set_entry.value_offset as usize
643 + size_of::<ApiSetValueEntry>() as usize * x as usize)
644 as *mut ApiSetValueEntry;
645 }
646 }
647
648 if set_value_ptr == ptr::null_mut() {
649 set_value_ptr = (api_set_namespace_ptr as usize
650 + set_entry.value_offset as usize)
651 as *mut ApiSetValueEntry;
652 }
653 }
654
655 let set_value = *set_value_ptr;
656 let mut api_set_value: String = "".to_string();
657 if set_value.value_count != 0 {
658 let mut value_ptr =
659 (api_set_namespace_ptr as usize + set_value.value_offset as usize) as *mut u8;
660 let mut r = 0;
661 while r < (set_value.value_count / 2) {
662 let c = *value_ptr as char;
663 if c != '\0' {
664 api_set_value.push(c);
665 r = r + 1;
666 }
667
668 value_ptr = value_ptr.add(1);
669 }
670 }
671
672 api_set_dict.insert(api_set_entry_key, api_set_value);
673 }
674
675 api_set_dict
676 }
677}
678
679
680pub fn call_module_entry_point(
695 pe_info: PeMetadata,
696 module_base_address: usize,
697) -> Result<(), String> {
698 let entry_point;
699 if pe_info.is_32_bit {
700 entry_point = module_base_address + pe_info.opt_header_32.AddressOfEntryPoint as usize;
701 } else {
702 entry_point = module_base_address + pe_info.opt_header_64.address_of_entry_point as usize;
703 }
704
705 unsafe {
706 let main: EntryPoint = core::mem::transmute(entry_point);
707 let module = entry_point as HINSTANCE;
708 let ret = main(module, DLL_PROCESS_ATTACH, ptr::null_mut());
709
710 if ret == 0 {
711 return Err(lc!(
712 "[x] Failed to call module's entry point (DllMain -> DLL_PROCESS_ATTACH)."
713 ));
714 }
715
716 Ok(())
717 }
718}
719
720pub fn get_function_address_by_ordinal(module_base_address: usize, ordinal: u32) -> usize {
742 let ret = ldr_get_procedure_address(module_base_address, "", ordinal);
743 ret
744}
745
746pub fn fork() -> i32 {
751 unsafe {
752 let mut process_handle: HANDLE = ptr::null_mut();
753 let mut thread_handle: HANDLE = ptr::null_mut();
754 let mut create_info: PsCreateInfo = core::mem::zeroed();
755 create_info.size = size_of::<PsCreateInfo>();
756 let ps_create_info: *mut PsCreateInfo = core::mem::transmute(&create_info);
757
758 let ret = nt_create_user_process(
759 &mut process_handle,
760 &mut thread_handle,
761 (0x000F0000) | (0x00100000) | 0xFFFF, (0x000F0000) | (0x00100000) | 0xFFFF, ptr::null_mut(),
764 ptr::null_mut(),
765 0x00000004, 0,
767 ptr::null_mut(),
768 ps_create_info, ptr::null_mut(),
770 );
771
772 ret
773 }
774}
775
776pub fn ldr_get_procedure_address(module_handle: usize, function_name: &str, ordinal: u32) -> usize {
799 unsafe {
800 let ret: Option<i32>;
801 let func_ptr: data::LdrGetProcedureAddress;
802 let hmodule: PVOID = core::ptr::with_exposed_provenance_mut::<c_void>(module_handle);
803 let mut r = usize::default();
804 let return_address: *mut PVOID = &mut r as *mut usize as *mut PVOID;
805
806 let c_name = if function_name.is_empty() {
811 None
812 } else {
813 CString::new(function_name).ok()
814 };
815 let ansi = c_name.as_ref().map(|s| data::ANSI_STRING {
816 Length: s.as_bytes().len() as u16,
817 MaximumLength: (s.as_bytes().len() + 1) as u16,
818 Buffer: s.as_ptr() as *const u8,
819 });
820 let name_ptr: *const data::ANSI_STRING = match ansi.as_ref() {
821 Some(a) => a as *const _,
822 None => ptr::null(),
823 };
824
825 let module_base_address = get_module_base_address(&lc!("ntdll.dll"));
826 dynamic_invoke!(
827 module_base_address,
828 &lc!("LdrGetProcedureAddress"),
829 func_ptr,
830 ret,
831 hmodule,
832 name_ptr,
833 ordinal,
834 return_address
835 );
836
837 match ret {
838 Some(0) => *return_address as usize,
839 _ => 0,
840 }
841 }
842}
843
844pub fn set_unhandled_exception_filter(address: usize) -> LptopLevelExceptionFilter {
846 unsafe {
847 let ret: Option<LptopLevelExceptionFilter>;
848 let func_ptr: data::SetUnhandledExceptionFilter;
849 let module_base_address = get_module_base_address(&lc!("kernel32.dll"));
850 dynamic_invoke!(
851 module_base_address,
852 &lc!("SetUnhandledExceptionFilter"),
853 func_ptr,
854 ret,
855 address
856 );
857
858 match ret {
859 Some(x) => return x,
860 None => return 0,
861 }
862 }
863}
864
865pub fn add_vectored_exception_handler(first: u32, address: usize) -> PVOID {
867 unsafe {
868 let ret: Option<PVOID>;
869 let func_ptr: data::AddVectoredExceptionHandler;
870 let module_base_address = get_module_base_address(&lc!("kernel32.dll"));
871 dynamic_invoke!(
872 module_base_address,
873 &lc!("AddVectoredExceptionHandler"),
874 func_ptr,
875 ret,
876 first,
877 address
878 );
879
880 match ret {
881 Some(x) => return x,
882 None => return ptr::null_mut(),
883 }
884 }
885}
886
887pub fn load_library_a_tp(module: &str) -> usize {
899 unsafe {
900 let ret: Option<i32>;
901 let func_ptr: data::RtlQueueWorkItem;
902 let name = CString::new(module.to_string()).expect("");
903 let module_name: PVOID = core::mem::transmute(name.as_ptr());
904 let k32 = get_module_base_address(&lc!("kernel32.dll"));
905 let ntdll = get_module_base_address(&lc!("ntdll.dll"));
906 let load_library = get_function_address(k32, &lc!("LoadLibraryA"));
907 dynamic_invoke!(
908 ntdll,
909 &lc!("RtlQueueWorkItem"),
910 func_ptr,
911 ret,
912 load_library,
913 module_name,
914 0
915 );
916
917 match ret {
918 Some(x) => {
919 if x != 0 {
920 return 0;
921 } else {
922 nt_sleep_millis(500);
923 return get_module_base_address(module);
924 }
925 }
926 None => {
927 return 0;
928 }
929 }
930 }
931}
932
933pub fn nt_sleep_millis(ms: u64) {
935 type NtDelayExecution = unsafe extern "system" fn(u8, *mut LARGE_INTEGER) -> i32;
936 unsafe {
937 let mut interval = LARGE_INTEGER {
938 QuadPart: -(ms as i64 * 10_000),
939 };
940 let ret: Option<i32>;
941 let func_ptr: NtDelayExecution;
942 let ntdll = get_module_base_address(&lc!("ntdll.dll"));
943 dynamic_invoke!(
944 ntdll,
945 &lc!("NtDelayExecution"),
946 func_ptr,
947 ret,
948 0u8,
949 &mut interval as *mut _
950 );
951 let _ = ret;
952 }
953}
954
955pub fn load_library_a(module: &str) -> usize {
967 unsafe {
968 let ret: Option<usize>;
969 let func_ptr: data::LoadLibraryA;
970 let name = CString::new(module.to_string()).expect("");
971 let module_name: *mut u8 = core::mem::transmute(name.as_ptr());
972 let k32 = get_module_base_address(&lc!("kernel32.dll"));
973 dynamic_invoke!(k32, &lc!("LoadLibraryA"), func_ptr, ret, module_name);
974
975 match ret {
976 Some(x) => {
977 return x;
978 }
979 None => {
980 return 0;
981 }
982 }
983 }
984}
985
986pub fn free_library(module_handle: isize) -> usize {
999 unsafe {
1000 let ret: Option<BOOL>;
1001 let func_ptr: data::FreeLibrary;
1002 let module_base_address = get_module_base_address(&lc!("kernel32.dll"));
1003 dynamic_invoke!(
1004 module_base_address,
1005 &lc!("FreeLibrary"),
1006 func_ptr,
1007 ret,
1008 module_handle as HINSTANCE
1009 );
1010
1011 match ret {
1012 Some(x) => return if x != 0 { 1 } else { 0 },
1013 None => return 0,
1014 }
1015 }
1016}
1017
1018pub fn create_file_a(
1021 name: *mut u8,
1022 access: u32,
1023 mode: u32,
1024 attributes: *const SECURITY_ATTRIBUTES,
1025 disposition: u32,
1026 flags: u32,
1027 template: HANDLE,
1028) -> HANDLE {
1029 unsafe {
1030 let ret: Option<HANDLE>;
1031 let func_ptr: data::CreateFileA;
1032 let kernel32 = get_module_base_address(&lc!("kernel32.dll"));
1033 dynamic_invoke!(
1034 kernel32,
1035 &lc!("CreateFileA"),
1036 func_ptr,
1037 ret,
1038 name,
1039 access,
1040 mode,
1041 attributes,
1042 disposition,
1043 flags,
1044 template
1045 );
1046
1047 match ret {
1048 Some(x) => return x,
1049 None => return core::ptr::null_mut(),
1050 }
1051 }
1052}
1053
1054pub fn get_file_size(handle: HANDLE, size: *mut u32) -> u32 {
1057 unsafe {
1058 let ret: Option<u32>;
1059 let func_ptr: data::GetFileSize;
1060 let kernel32 = get_module_base_address(&lc!("kernel32.dll"));
1061 dynamic_invoke!(kernel32, &lc!("GetFileSize"), func_ptr, ret, handle, size);
1062
1063 match ret {
1064 Some(x) => return x,
1065 None => return 0,
1066 }
1067 }
1068}
1069
1070pub fn create_file_mapping_w(
1073 file: HANDLE,
1074 attributes: *const SECURITY_ATTRIBUTES,
1075 protect: u32,
1076 max_size_high: u32,
1077 max_size_low: u32,
1078 name: *mut u8,
1079) -> HANDLE {
1080 unsafe {
1081 let ret: Option<HANDLE>;
1082 let func_ptr: data::CreateFileMapping;
1083 let kernel32 = get_module_base_address(&lc!("kernel32.dll"));
1084 dynamic_invoke!(
1085 kernel32,
1086 &lc!("CreateFileMappingW"),
1087 func_ptr,
1088 ret,
1089 file,
1090 attributes,
1091 protect,
1092 max_size_high,
1093 max_size_low,
1094 name
1095 );
1096
1097 match ret {
1098 Some(x) => return x,
1099 None => return core::ptr::null_mut(),
1100 }
1101 }
1102}
1103
1104pub fn map_view_of_file(
1107 file: HANDLE,
1108 access: u32,
1109 off_high: u32,
1110 off_low: u32,
1111 bytes: usize,
1112) -> PVOID {
1113 unsafe {
1114 let ret: Option<PVOID>;
1115 let func_ptr: data::MapViewOfFile;
1116 let kernel32 = get_module_base_address(&lc!("kernel32.dll"));
1117 dynamic_invoke!(
1118 kernel32,
1119 &lc!("MapViewOfFile"),
1120 func_ptr,
1121 ret,
1122 file,
1123 access,
1124 off_high,
1125 off_low,
1126 bytes
1127 );
1128
1129 match ret {
1130 Some(x) => return x,
1131 None => return ptr::null_mut(),
1132 }
1133 }
1134}
1135
1136pub fn unmap_view_of_file(base_address: PVOID) -> bool {
1139 unsafe {
1140 let ret: Option<BOOL>;
1141 let func_ptr: data::UnmapViewOfFile;
1142 let kernel32 = get_module_base_address(&lc!("kernel32.dll"));
1143 dynamic_invoke!(
1144 kernel32,
1145 &lc!("UnmapViewOfFile"),
1146 func_ptr,
1147 ret,
1148 base_address
1149 );
1150
1151 match ret {
1152 Some(x) => return x != 0,
1153 None => return false,
1154 }
1155 }
1156}
1157
1158pub fn rollback_transaction(transaction: HANDLE) -> bool {
1161 unsafe {
1162 let ret: Option<BOOL>;
1163 let func_ptr: data::RollbackTransaction;
1164 let ktmv = load_library_a(&lc!("KtmW32.dll"));
1165 dynamic_invoke!(
1166 ktmv,
1167 &lc!("RollbackTransaction"),
1168 func_ptr,
1169 ret,
1170 transaction
1171 );
1172
1173 match ret {
1174 Some(x) => return x != 0,
1175 None => return false,
1176 }
1177 }
1178}
1179
1180pub fn open_process(desired_access: u32, inherit_handle: i32, process_id: u32) -> HANDLE {
1196 unsafe {
1197 let ret: Option<HANDLE>;
1198 let func_ptr: data::OpenProcess;
1199 let module_base_address = get_module_base_address(&lc!("kernel32.dll"));
1200 dynamic_invoke!(
1201 module_base_address,
1202 &lc!("OpenProcess"),
1203 func_ptr,
1204 ret,
1205 desired_access,
1206 inherit_handle,
1207 process_id
1208 );
1209
1210 match ret {
1211 Some(x) => return x,
1212 None => return core::ptr::null_mut(),
1213 }
1214 }
1215}
1216
1217pub fn open_thread(desired_access: u32, inherit_handle: i32, thread_id: u32) -> HANDLE {
1233 unsafe {
1234 let ret: Option<HANDLE>;
1235 let func_ptr: data::OpenThread;
1236 let module_base_address = get_module_base_address(&lc!("kernel32.dll"));
1237 dynamic_invoke!(
1238 module_base_address,
1239 &lc!("OpenThread"),
1240 func_ptr,
1241 ret,
1242 desired_access,
1243 inherit_handle,
1244 thread_id
1245 );
1246
1247 match ret {
1248 Some(x) => return x,
1249 None => return core::ptr::null_mut(),
1250 }
1251 }
1252}
1253
1254pub fn close_handle(handle: HANDLE) -> bool {
1275 unsafe {
1276 let ret: Option<i32>;
1277 let func_ptr: data::CloseHandle;
1278 let kernel32 = get_module_base_address(&lc!("kernel32.dll"));
1279 dynamic_invoke!(kernel32, &lc!("CloseHandle"), func_ptr, ret, handle);
1280
1281 match ret {
1282 Some(x) => {
1283 if x == 0 {
1284 return false;
1285 } else {
1286 return true;
1287 }
1288 }
1289 None => return false,
1290 }
1291 }
1292}
1293
1294pub fn tls_alloc() -> u32 {
1296 unsafe {
1297 let ret: Option<u32>;
1298 let func_ptr: data::TlsAlloc;
1299 let module_base_address = get_module_base_address(&lc!("kernel32.dll"));
1300 dynamic_invoke!(module_base_address, &lc!("TlsAlloc"), func_ptr, ret,);
1301
1302 match ret {
1303 Some(x) => return x,
1304 None => return TLS_OUT_OF_INDEXES,
1305 }
1306 }
1307}
1308
1309pub fn tls_get_value(index: u32) -> PVOID {
1311 unsafe {
1312 let ret: Option<PVOID>;
1313 let func_ptr: data::TlsGetValue;
1314 let module_base_address = get_module_base_address(&lc!("kernel32.dll"));
1315 dynamic_invoke!(
1316 module_base_address,
1317 &lc!("TlsGetValue"),
1318 func_ptr,
1319 ret,
1320 index
1321 );
1322
1323 match ret {
1324 Some(x) => return x,
1325 None => return ptr::null_mut(),
1326 }
1327 }
1328}
1329
1330pub fn tls_set_value(index: u32, data: PVOID) -> bool {
1332 unsafe {
1333 let ret: Option<bool>;
1334 let func_ptr: data::TlsSetValue;
1335 let module_base_address = get_module_base_address(&lc!("kernel32.dll"));
1336 dynamic_invoke!(
1337 module_base_address,
1338 &lc!("TlsSetValue"),
1339 func_ptr,
1340 ret,
1341 index,
1342 data
1343 );
1344
1345 match ret {
1346 Some(x) => return x,
1347 None => return false,
1348 }
1349 }
1350}
1351
1352pub fn enum_process_modules(
1354 process: HANDLE,
1355 module: *mut usize,
1356 cb: u32,
1357 needed: *mut u32,
1358) -> bool {
1359 unsafe {
1360 let ret: Option<bool>;
1361 let func_ptr: data::EnumProcessModules;
1362 let module_base_address = get_module_base_address(&lc!("kernel32.dll"));
1363 dynamic_invoke!(
1364 module_base_address,
1365 &lc!("K32EnumProcessModules"),
1366 func_ptr,
1367 ret,
1368 process,
1369 module,
1370 cb,
1371 needed
1372 );
1373
1374 match ret {
1375 Some(x) => return x,
1376 None => return false,
1377 }
1378 }
1379}
1380
1381pub fn get_module_handle_ex_a(flags: i32, module_name: *const u8, module: *mut usize) -> bool {
1383 unsafe {
1384 let ret: Option<bool>;
1385 let func_ptr: data::GetModuleHandleExA;
1386 let module_base_address = get_module_base_address(&lc!("kernel32.dll"));
1387 dynamic_invoke!(
1388 module_base_address,
1389 &lc!("GetModuleHandleExA"),
1390 func_ptr,
1391 ret,
1392 flags,
1393 module_name,
1394 module
1395 );
1396
1397 match ret {
1398 Some(x) => return x,
1399 None => return false,
1400 }
1401 }
1402}
1403
1404pub fn get_module_base_name_w(
1406 process: HANDLE,
1407 module: usize,
1408 base_name: *mut u16,
1409 size: u32,
1410) -> u32 {
1411 unsafe {
1412 let ret: Option<u32>;
1413 let func_ptr: data::GetModuleBaseNameW;
1414 let module_base_address = get_module_base_address(&lc!("kernel32.dll"));
1415 dynamic_invoke!(
1416 module_base_address,
1417 &lc!("K32GetModuleBaseNameW"),
1418 func_ptr,
1419 ret,
1420 process,
1421 module,
1422 base_name,
1423 size
1424 );
1425
1426 match ret {
1427 Some(x) => return x,
1428 None => return 0,
1429 }
1430 }
1431}
1432
1433pub fn get_module_file_name_ex_w(
1435 process: HANDLE,
1436 module: usize,
1437 base_name: *mut u16,
1438 size: u32,
1439) -> u32 {
1440 unsafe {
1441 let ret: Option<u32>;
1442 let func_ptr: data::GetModuleFileNameExW;
1443 let module_base_address = get_module_base_address(&lc!("kernel32.dll"));
1444 dynamic_invoke!(
1445 module_base_address,
1446 &lc!("K32GetModuleFileNameExW"),
1447 func_ptr,
1448 ret,
1449 process,
1450 module,
1451 base_name,
1452 size
1453 );
1454
1455 match ret {
1456 Some(x) => return x,
1457 None => return 0,
1458 }
1459 }
1460}
1461
1462pub fn get_last_error() -> u32 {
1466 let last_error: u32;
1467 #[cfg(target_arch = "x86_64")]
1468 unsafe {
1469 core::arch::asm!(
1470 "mov {err:e}, gs:[0x68]",
1471 err = out(reg) last_error,
1472 options(nostack, preserves_flags, readonly)
1473 );
1474 }
1475 #[cfg(target_arch = "x86")]
1476 unsafe {
1477 core::arch::asm!(
1478 "mov {err:e}, fs:[0x34]",
1479 err = out(reg) last_error,
1480 options(nostack, preserves_flags, readonly)
1481 );
1482 }
1483 #[cfg(not(any(target_arch = "x86_64", target_arch = "x86")))]
1484 compile_error!("get_last_error only supports x86 / x86_64");
1485 last_error
1486}
1487
1488pub fn local_alloc(flags: u32, size: usize) -> PVOID {
1490 unsafe {
1491 let ret: Option<PVOID>;
1492 let func_ptr: data::LocalAlloc;
1493 let module_base_address = get_module_base_address(&lc!("kernel32.dll"));
1494 dynamic_invoke!(
1495 module_base_address,
1496 &lc!("LocalAlloc"),
1497 func_ptr,
1498 ret,
1499 flags,
1500 size
1501 );
1502
1503 match ret {
1504 Some(x) => return x,
1505 None => return ptr::null_mut(),
1506 }
1507 }
1508}
1509
1510pub fn get_system_info(sysinfo: *mut SYSTEM_INFO) {
1512 unsafe {
1513 let _ret: Option<()>;
1514 let func_ptr: data::GetSystemInfo;
1515 let kernel32 = get_module_base_address(&lc!("kernel32.dll"));
1516 dynamic_invoke!(kernel32, &lc!("GetSystemInfo"), func_ptr, _ret, sysinfo);
1517 }
1518}
1519
1520pub fn virtual_query_ex(
1522 process_handle: HANDLE,
1523 page_address: *const c_void,
1524 buffer: *mut MEMORY_BASIC_INFORMATION,
1525 length: usize,
1526) -> usize {
1527 unsafe {
1528 let ret: Option<usize>;
1529 let func_ptr: data::VirtualQueryEx;
1530 let kernel32 = get_module_base_address(&lc!("kernel32.dll"));
1531 dynamic_invoke!(
1532 kernel32,
1533 &lc!("VirtualQueryEx"),
1534 func_ptr,
1535 ret,
1536 process_handle,
1537 page_address,
1538 buffer,
1539 length
1540 );
1541
1542 match ret {
1543 Some(x) => return x,
1544 None => return 0,
1545 }
1546 }
1547}
1548
1549pub fn virtual_free(address: PVOID, size: usize, free_type: u32) -> bool {
1551 unsafe {
1552 let ret: Option<bool>;
1553 let func_ptr: data::VirtualFree;
1554 let k32 = get_module_base_address(&lc!("kernel32.dll"));
1555 dynamic_invoke!(
1556 k32,
1557 &lc!("VirtualFree"),
1558 func_ptr,
1559 ret,
1560 address,
1561 size,
1562 free_type
1563 );
1564
1565 match ret {
1566 Some(x) => {
1567 return x;
1568 }
1569 None => return false,
1570 }
1571 }
1572}
1573
1574pub fn nt_create_user_process(
1578 process_handle: *mut HANDLE,
1579 thread_handle: *mut HANDLE,
1580 process_access: u32,
1581 thread_access: u32,
1582 object_attributes: *mut OBJECT_ATTRIBUTES,
1583 thread_object_attr: *mut OBJECT_ATTRIBUTES,
1584 process_flags: u32,
1585 thread_flags: u32,
1586 parameters: PVOID,
1587 create_info: *mut PsCreateInfo,
1588 attr_list: *mut PsAttributeList,
1589) -> i32 {
1590 unsafe {
1591 let ret: Option<i32>;
1592 let func_ptr: data::NtCreateUserProcess;
1593 let ntdll = get_module_base_address(&lc!("ntdll.dll"));
1594 dynamic_invoke!(
1595 ntdll,
1596 &lc!("NtCreateUserProcess"),
1597 func_ptr,
1598 ret,
1599 process_handle,
1600 thread_handle,
1601 process_access,
1602 thread_access,
1603 object_attributes,
1604 thread_object_attr,
1605 process_flags,
1606 thread_flags,
1607 parameters,
1608 create_info,
1609 attr_list
1610 );
1611
1612 match ret {
1613 Some(x) => return x,
1614 None => return -1,
1615 }
1616 }
1617}
1618
1619#[cfg(target_arch = "x86_64")]
1623pub fn nt_write_virtual_memory(
1624 mut handle: HANDLE,
1625 base_address: PVOID,
1626 mut buffer: PVOID,
1627 mut size: usize,
1628 bytes_written: *mut usize,
1629) -> i32 {
1630 unsafe {
1631 let ret;
1632 let func_ptr: data::NtWriteVirtualMemory;
1633 let ntdll = get_module_base_address(&lc!("ntdll.dll"));
1634
1635 let _decoy_buf: Vec<u8>;
1636 if HARDWARE_BREAKPOINTS {
1637 let addr = get_function_address(ntdll, &lc!("NtWriteVirtualMemory")) as usize;
1638 HARDWARE_EXCEPTION_FUNCTION = ExceptionHandleFunction::NtWriteVirtualMemory;
1639 NT_WRITE_VIRTUAL_MEMORY_ARGS.handle = handle;
1640 NT_WRITE_VIRTUAL_MEMORY_ARGS.base_address = base_address;
1641 NT_WRITE_VIRTUAL_MEMORY_ARGS.buffer = buffer;
1642 NT_WRITE_VIRTUAL_MEMORY_ARGS.size = size;
1643 set_hardware_breakpoint(sys::get_syscall_address(addr as *mut _).unwrap_or(0));
1644
1645 handle = INVALID_HANDLE_VALUE;
1646 _decoy_buf = vec![20u8];
1647 buffer = _decoy_buf.as_ptr() as PVOID;
1648 size = _decoy_buf.len();
1649 }
1650
1651 dynamic_invoke!(
1652 ntdll,
1653 &lc!("NtWriteVirtualMemory"),
1654 func_ptr,
1655 ret,
1656 handle,
1657 base_address,
1658 buffer,
1659 size,
1660 bytes_written
1661 );
1662
1663 match ret {
1664 Some(x) => return x,
1665 None => return -1,
1666 }
1667 }
1668}
1669
1670#[cfg(target_arch = "x86")]
1674pub fn nt_write_virtual_memory(
1675 handle: HANDLE,
1676 base_address: PVOID,
1677 buffer: PVOID,
1678 size: usize,
1679 bytes_written: *mut usize,
1680) -> i32 {
1681 unsafe {
1682 let ret;
1683 let func_ptr: data::NtWriteVirtualMemory;
1684 let ntdll = get_module_base_address(&lc!("ntdll.dll"));
1685 dynamic_invoke!(
1686 ntdll,
1687 &lc!("NtWriteVirtualMemory"),
1688 func_ptr,
1689 ret,
1690 handle,
1691 base_address,
1692 buffer,
1693 size,
1694 bytes_written
1695 );
1696
1697 match ret {
1698 Some(x) => return x,
1699 None => return -1,
1700 }
1701 }
1702}
1703
1704#[cfg(target_arch = "x86_64")]
1708pub fn nt_allocate_virtual_memory(
1709 mut handle: HANDLE,
1710 mut base_address: *mut PVOID,
1711 zero_bits: usize,
1712 size: *mut usize,
1713 allocation_type: u32,
1714 protection: u32,
1715) -> i32 {
1716 unsafe {
1717 let ret;
1718 let func_ptr: data::NtAllocateVirtualMemory;
1719 let ntdll = get_module_base_address(&lc!("ntdll.dll"));
1720
1721 if HARDWARE_BREAKPOINTS {
1722 let addr = get_function_address(ntdll, &lc!("NtAllocateVirtualMemory")) as usize;
1723 HARDWARE_EXCEPTION_FUNCTION = ExceptionHandleFunction::NtAllocateVirtualMemory;
1724 NT_ALLOCATE_VIRTUAL_MEMORY_ARGS.handle = handle;
1725 NT_ALLOCATE_VIRTUAL_MEMORY_ARGS.base_address = base_address;
1726 set_hardware_breakpoint(sys::get_syscall_address(addr as *mut _).unwrap_or(0));
1727
1728 handle = INVALID_HANDLE_VALUE;
1729 base_address = ptr::null_mut();
1730 }
1731
1732 dynamic_invoke!(
1733 ntdll,
1734 &lc!("NtAllocateVirtualMemory"),
1735 func_ptr,
1736 ret,
1737 handle,
1738 base_address,
1739 zero_bits,
1740 size,
1741 allocation_type,
1742 protection
1743 );
1744
1745 match ret {
1746 Some(x) => return x,
1747 None => return -1,
1748 }
1749 }
1750}
1751
1752#[cfg(target_arch = "x86")]
1756pub fn nt_allocate_virtual_memory(
1757 handle: HANDLE,
1758 base_address: *mut PVOID,
1759 zero_bits: usize,
1760 size: *mut usize,
1761 allocation_type: u32,
1762 protection: u32,
1763) -> i32 {
1764 unsafe {
1765 let ret;
1766 let func_ptr: data::NtAllocateVirtualMemory;
1767 let ntdll = get_module_base_address(&lc!("ntdll.dll"));
1768 dynamic_invoke!(
1769 ntdll,
1770 &lc!("NtAllocateVirtualMemory"),
1771 func_ptr,
1772 ret,
1773 handle,
1774 base_address,
1775 zero_bits,
1776 size,
1777 allocation_type,
1778 protection
1779 );
1780
1781 match ret {
1782 Some(x) => return x,
1783 None => return -1,
1784 }
1785 }
1786}
1787
1788#[cfg(target_arch = "x86_64")]
1792pub fn nt_protect_virtual_memory(
1793 mut handle: HANDLE,
1794 mut base_address: *mut PVOID,
1795 mut size: *mut usize,
1796 mut new_protection: u32,
1797 old_protection: *mut u32,
1798) -> i32 {
1799 unsafe {
1800 let ret;
1801 let func_ptr: data::NtProtectVirtualMemory;
1802 let ntdll = get_module_base_address(&lc!("ntdll.dll"));
1803
1804 if HARDWARE_BREAKPOINTS {
1805 let addr = get_function_address(ntdll, &lc!("NtProtectVirtualMemory")) as usize;
1806 HARDWARE_EXCEPTION_FUNCTION = ExceptionHandleFunction::NtProtectVirtualMemory;
1807 NT_PROTECT_VIRTUAL_MEMORY_ARGS.handle = handle;
1808 NT_PROTECT_VIRTUAL_MEMORY_ARGS.base_address = base_address;
1809 NT_PROTECT_VIRTUAL_MEMORY_ARGS.size = size;
1810 NT_PROTECT_VIRTUAL_MEMORY_ARGS.protection = new_protection;
1811 set_hardware_breakpoint(sys::get_syscall_address(addr as *mut _).unwrap_or(0));
1812
1813 handle = INVALID_HANDLE_VALUE;
1814 base_address = ptr::null_mut();
1815 let s = 10usize;
1816 size = core::mem::transmute(&s);
1817 new_protection = PAGE_READONLY;
1818 }
1819
1820 dynamic_invoke!(
1821 ntdll,
1822 &lc!("NtProtectVirtualMemory"),
1823 func_ptr,
1824 ret,
1825 handle,
1826 base_address,
1827 size,
1828 new_protection,
1829 old_protection
1830 );
1831
1832 match ret {
1833 Some(x) => return x,
1834 None => return -1,
1835 }
1836 }
1837}
1838
1839#[cfg(target_arch = "x86")]
1843pub fn nt_protect_virtual_memory(
1844 handle: HANDLE,
1845 base_address: *mut PVOID,
1846 size: *mut usize,
1847 new_protection: u32,
1848 old_protection: *mut u32,
1849) -> i32 {
1850 unsafe {
1851 let ret;
1852 let func_ptr: data::NtProtectVirtualMemory;
1853 let ntdll = get_module_base_address(&lc!("ntdll.dll"));
1854 dynamic_invoke!(
1855 ntdll,
1856 &lc!("NtProtectVirtualMemory"),
1857 func_ptr,
1858 ret,
1859 handle,
1860 base_address,
1861 size,
1862 new_protection,
1863 old_protection
1864 );
1865
1866 match ret {
1867 Some(x) => return x,
1868 None => return -1,
1869 }
1870 }
1871}
1872
1873#[cfg(target_arch = "x86_64")]
1877pub fn nt_open_process(
1878 mut handle: *mut HANDLE,
1879 mut access: u32,
1880 mut attributes: *mut OBJECT_ATTRIBUTES,
1881 mut client_id: *mut ClientId,
1882) -> i32 {
1883 unsafe {
1884 let ret;
1885 let func_ptr: data::NtOpenProcess;
1886 let ntdll = get_module_base_address(&lc!("ntdll.dll"));
1887
1888 if HARDWARE_BREAKPOINTS {
1889 let addr = get_function_address(ntdll, &lc!("NtOpenProcess")) as usize;
1890 HARDWARE_EXCEPTION_FUNCTION = ExceptionHandleFunction::NtOpenProcess;
1891 NT_OPEN_PROCESS_ARGS.handle = handle;
1892 NT_OPEN_PROCESS_ARGS.access = access;
1893 NT_OPEN_PROCESS_ARGS.attributes = attributes;
1894 NT_OPEN_PROCESS_ARGS.client_id = client_id;
1895 set_hardware_breakpoint(sys::get_syscall_address(addr as *mut _).unwrap_or(0));
1896
1897 let h = INVALID_HANDLE_VALUE;
1898 handle = core::mem::transmute(&h);
1899 access = PROCESS_QUERY_LIMITED_INFORMATION;
1900 let a: OBJECT_ATTRIBUTES = core::mem::zeroed();
1901 attributes = core::mem::transmute(&a);
1902 let c = ClientId {
1903 unique_process: GetCurrentProcessId() as *mut core::ffi::c_void,
1904 unique_thread: core::ptr::null_mut(),
1905 };
1906 client_id = core::mem::transmute(&c);
1907 }
1908
1909 dynamic_invoke!(
1910 ntdll,
1911 &lc!("NtOpenProcess"),
1912 func_ptr,
1913 ret,
1914 handle,
1915 access,
1916 attributes,
1917 client_id
1918 );
1919
1920 match ret {
1921 Some(x) => return x,
1922 None => return -1,
1923 }
1924 }
1925}
1926
1927#[cfg(target_arch = "x86")]
1931pub fn nt_open_process(
1932 handle: *mut HANDLE,
1933 access: u32,
1934 attributes: *mut OBJECT_ATTRIBUTES,
1935 client_id: *mut ClientId,
1936) -> i32 {
1937 unsafe {
1938 let ret;
1939 let func_ptr: data::NtOpenProcess;
1940 let ntdll = get_module_base_address(&lc!("ntdll.dll"));
1941 dynamic_invoke!(
1942 ntdll,
1943 &lc!("NtOpenProcess"),
1944 func_ptr,
1945 ret,
1946 handle,
1947 access,
1948 attributes,
1949 client_id
1950 );
1951
1952 match ret {
1953 Some(x) => return x,
1954 None => return -1,
1955 }
1956 }
1957}
1958
1959pub fn nt_query_information_process(
1963 handle: HANDLE,
1964 process_information_class: u32,
1965 process_information: PVOID,
1966 length: u32,
1967 return_length: *mut u32,
1968) -> i32 {
1969 unsafe {
1970 let ret;
1971 let func_ptr: data::NtQueryInformationProcess;
1972 let ntdll = get_module_base_address(&lc!("ntdll.dll"));
1973 dynamic_invoke!(
1974 ntdll,
1975 &lc!("NtQueryInformationProcess"),
1976 func_ptr,
1977 ret,
1978 handle,
1979 process_information_class,
1980 process_information,
1981 length,
1982 return_length
1983 );
1984
1985 match ret {
1986 Some(x) => return x,
1987 None => return -1,
1988 }
1989 }
1990}
1991
1992pub fn nt_query_information_thread(
1996 handle: HANDLE,
1997 thread_information_class: u32,
1998 thread_information: PVOID,
1999 length: u32,
2000 return_length: *mut u32,
2001) -> i32 {
2002 unsafe {
2003 let ret;
2004 let func_ptr: data::NtQueryInformationThread;
2005 let ntdll = get_module_base_address(&lc!("ntdll.dll"));
2006 dynamic_invoke!(
2007 ntdll,
2008 &lc!("NtQueryInformationThread"),
2009 func_ptr,
2010 ret,
2011 handle,
2012 thread_information_class,
2013 thread_information,
2014 length,
2015 return_length
2016 );
2017
2018 match ret {
2019 Some(x) => return x,
2020 None => return -1,
2021 }
2022 }
2023}
2024
2025pub fn nt_query_information_file(
2029 handle: HANDLE,
2030 io: *mut IO_STATUS_BLOCK,
2031 file_information: PVOID,
2032 length: u32,
2033 file_information_class: u32,
2034) -> i32 {
2035 unsafe {
2036 let ret;
2037 let func_ptr: data::NtQueryInformationFile;
2038 let ntdll = get_module_base_address(&lc!("ntdll.dll"));
2039 dynamic_invoke!(
2040 ntdll,
2041 &lc!("NtQueryInformationFile"),
2042 func_ptr,
2043 ret,
2044 handle,
2045 io,
2046 file_information,
2047 length,
2048 file_information_class
2049 );
2050
2051 match ret {
2052 Some(x) => return x,
2053 None => return -1,
2054 }
2055 }
2056}
2057
2058pub fn rtl_adjust_privilege(
2062 privilege: u32,
2063 enable: u8,
2064 current_thread: u8,
2065 enabled: *mut u8,
2066) -> i32 {
2067 unsafe {
2068 let ret;
2069 let func_ptr: data::RtlAdjustPrivilege;
2070 let ntdll = get_module_base_address(&lc!("ntdll.dll"));
2071 dynamic_invoke!(
2072 ntdll,
2073 &lc!("RtlAdjustPrivilege"),
2074 func_ptr,
2075 ret,
2076 privilege,
2077 enable,
2078 current_thread,
2079 enabled
2080 );
2081
2082 match ret {
2083 Some(x) => return x,
2084 None => return -1,
2085 }
2086 }
2087}
2088
2089pub fn rtl_init_unicode_string(
2093 destination_string: *mut UNICODE_STRING,
2094 source_string: *const u16,
2095) -> () {
2096 unsafe {
2097 let _ret: Option<()>;
2098 let func_ptr: data::RtlInitUnicodeString;
2099 let ntdll = get_module_base_address(&lc!("ntdll.dll"));
2100 dynamic_invoke!(
2101 ntdll,
2102 &lc!("RtlInitUnicodeString"),
2103 func_ptr,
2104 _ret,
2105 destination_string,
2106 source_string
2107 );
2108 }
2109}
2110
2111pub fn rtl_zero_memory(address: PVOID, length: usize) -> () {
2115 unsafe {
2116 let _ret: Option<()>;
2117 let func_ptr: data::RtlZeroMemory;
2118 let ntdll = get_module_base_address(&lc!("ntdll.dll"));
2119 dynamic_invoke!(
2120 ntdll,
2121 &lc!("RtlZeroMemory"),
2122 func_ptr,
2123 _ret,
2124 address,
2125 length
2126 );
2127 }
2128}
2129
2130pub fn nt_open_file(
2134 file_handle: *mut HANDLE,
2135 desired_access: u32,
2136 object_attributes: *mut OBJECT_ATTRIBUTES,
2137 io: *mut IO_STATUS_BLOCK,
2138 share_access: u32,
2139 options: u32,
2140) -> i32 {
2141 unsafe {
2142 let ret: Option<i32>;
2143 let func_ptr: data::NtOpenFile;
2144 let ntdll = get_module_base_address(&lc!("ntdll.dll"));
2145 dynamic_invoke!(
2146 ntdll,
2147 &lc!("NtOpenFile"),
2148 func_ptr,
2149 ret,
2150 file_handle,
2151 desired_access,
2152 object_attributes,
2153 io,
2154 share_access,
2155 options
2156 );
2157
2158 match ret {
2159 Some(x) => return x,
2160 None => return -1,
2161 }
2162 }
2163}
2164
2165pub fn nt_create_section(
2169 section_handle: *mut HANDLE,
2170 desired_access: u32,
2171 object_attributes: *mut OBJECT_ATTRIBUTES,
2172 size: *mut LARGE_INTEGER,
2173 page_protection: u32,
2174 allocation_attributes: u32,
2175 file_handle: HANDLE,
2176) -> i32 {
2177 unsafe {
2178 let ret: Option<i32>;
2179 let func_ptr: data::NtCreateSection;
2180 let ntdll = get_module_base_address(&lc!("ntdll.dll"));
2181 dynamic_invoke!(
2182 ntdll,
2183 &lc!("NtCreateSection"),
2184 func_ptr,
2185 ret,
2186 section_handle,
2187 desired_access,
2188 object_attributes,
2189 size,
2190 page_protection,
2191 allocation_attributes,
2192 file_handle
2193 );
2194
2195 match ret {
2196 Some(x) => return x,
2197 None => return -1,
2198 }
2199 }
2200}
2201
2202pub fn nt_map_view_of_section(
2206 section_handle: HANDLE,
2207 process_handle: HANDLE,
2208 base_address: *mut PVOID,
2209 zero: usize,
2210 commit_size: usize,
2211 offset: *mut LARGE_INTEGER,
2212 view_size: *mut usize,
2213 disposition: u32,
2214 allocation_type: u32,
2215 protection: u32,
2216) -> i32 {
2217 unsafe {
2218 let ret: Option<i32>;
2219 let func_ptr: data::NtMapViewOfSection;
2220 let ntdll = get_module_base_address(&lc!("ntdll.dll"));
2221 dynamic_invoke!(
2222 ntdll,
2223 &lc!("NtMapViewOfSection"),
2224 func_ptr,
2225 ret,
2226 section_handle,
2227 process_handle,
2228 base_address,
2229 zero,
2230 commit_size,
2231 offset,
2232 view_size,
2233 disposition,
2234 allocation_type,
2235 protection
2236 );
2237
2238 match ret {
2239 Some(x) => return x,
2240 None => return -1,
2241 }
2242 }
2243}
2244
2245#[cfg(target_arch = "x86_64")]
2249pub fn nt_create_thread_ex(
2250 mut thread: *mut HANDLE,
2251 mut access: u32,
2252 mut attributes: *mut OBJECT_ATTRIBUTES,
2253 mut process: HANDLE,
2254 function: PVOID,
2255 args: PVOID,
2256 flags: u32,
2257 zero: usize,
2258 stack: usize,
2259 reserve: usize,
2260 buffer: *mut PsAttributeList,
2261) -> i32 {
2262 unsafe {
2263 let ret: Option<i32>;
2264 let func_ptr: data::NtCreateThreadEx;
2265 let ntdll = get_module_base_address(&lc!("ntdll.dll"));
2266
2267 if HARDWARE_BREAKPOINTS {
2268 let addr = get_function_address(ntdll, &lc!("NtCreateThreadEx")) as usize;
2269 HARDWARE_EXCEPTION_FUNCTION = ExceptionHandleFunction::NtCreateThreadEx;
2270 NT_CREATE_THREAD_EX_ARGS.thread = thread;
2271 NT_CREATE_THREAD_EX_ARGS.access = access;
2272 NT_CREATE_THREAD_EX_ARGS.attributes = attributes;
2273 NT_CREATE_THREAD_EX_ARGS.process = process;
2274 set_hardware_breakpoint(sys::get_syscall_address(addr as *mut _).unwrap_or(0));
2275
2276 let h = INVALID_HANDLE_VALUE;
2277 thread = core::mem::transmute(&h);
2278 access = PROCESS_QUERY_LIMITED_INFORMATION;
2279 let a: OBJECT_ATTRIBUTES = core::mem::zeroed();
2280 attributes = core::mem::transmute(&a);
2281 process = INVALID_HANDLE_VALUE;
2282 }
2283
2284 dynamic_invoke!(
2285 ntdll,
2286 &lc!("NtCreateThreadEx"),
2287 func_ptr,
2288 ret,
2289 thread,
2290 access,
2291 attributes,
2292 process,
2293 function,
2294 args,
2295 flags,
2296 zero,
2297 stack,
2298 reserve,
2299 buffer
2300 );
2301
2302 match ret {
2303 Some(x) => return x,
2304 None => return -1,
2305 }
2306 }
2307}
2308
2309#[cfg(target_arch = "x86")]
2313pub fn nt_create_thread_ex(
2314 thread: *mut HANDLE,
2315 access: u32,
2316 attributes: *mut OBJECT_ATTRIBUTES,
2317 process: HANDLE,
2318 function: PVOID,
2319 args: PVOID,
2320 flags: u32,
2321 zero: usize,
2322 stack: usize,
2323 reserve: usize,
2324 buffer: *mut PsAttributeList,
2325) -> i32 {
2326 unsafe {
2327 let ret: Option<i32>;
2328 let func_ptr: data::NtCreateThreadEx;
2329 let ntdll = get_module_base_address(&lc!("ntdll.dll"));
2330 dynamic_invoke!(
2331 ntdll,
2332 &lc!("NtCreateThreadEx"),
2333 func_ptr,
2334 ret,
2335 thread,
2336 access,
2337 attributes,
2338 process,
2339 function,
2340 args,
2341 flags,
2342 zero,
2343 stack,
2344 reserve,
2345 buffer
2346 );
2347
2348 match ret {
2349 Some(x) => return x,
2350 None => return -1,
2351 }
2352 }
2353}
2354
2355pub fn nt_read_virtual_memory(
2359 handle: HANDLE,
2360 base_address: PVOID,
2361 buffer: PVOID,
2362 size: usize,
2363 bytes_written: *mut usize,
2364) -> i32 {
2365 unsafe {
2366 let ret;
2367 let func_ptr: data::NtReadVirtualMemory;
2368 let ntdll = get_module_base_address(&lc!("ntdll.dll"));
2369 dynamic_invoke!(
2370 ntdll,
2371 &lc!("NtReadVirtualMemory"),
2372 func_ptr,
2373 ret,
2374 handle,
2375 base_address,
2376 buffer,
2377 size,
2378 bytes_written
2379 );
2380
2381 match ret {
2382 Some(x) => return x,
2383 None => return -1,
2384 }
2385 }
2386}
2387
2388#[macro_export]
2443macro_rules! dynamic_invoke {
2444
2445 ($a:expr, $b:expr, $c:expr) => {
2446
2447 let ret = $crate::call_module_entry_point($a,$b);
2448
2449 match ret {
2450 Ok(_) => $c = true,
2451 Err(_) => $c = false,
2452 }
2453
2454 };
2455
2456 ($a:expr, $b:expr, $c:expr, $d:expr, $($e:tt)*) => {
2457
2458 let function_ptr = $crate::get_function_address($a, $b);
2459 if function_ptr != 0
2460 {
2461 $c = core::mem::transmute(function_ptr);
2462 $d = Some($c($($e)*));
2463 }
2464 else
2465 {
2466 $d = None;
2467 }
2468
2469 };
2470}
2471
2472#[cfg(target_arch = "x86_64")]
2521#[macro_export]
2522macro_rules! syscall {
2523 ($name:expr $(, $arg:expr)* $(,)?) => {{
2524 $crate::resolve_syscall($name).map(|(ssn, addr)| {
2525 let argc = 0u32 $(+ { let _ = &$arg; 1u32 })*;
2526 unsafe {
2527 $crate::do_syscall(
2528 ssn,
2529 addr,
2530 argc
2531 $(, ::core::mem::transmute::<usize, *mut ::core::ffi::c_void>($arg as usize))*
2532 )
2533 }
2534 })
2535 }};
2536}
2537
2538#[cfg(target_arch = "x86_64")]
2559#[macro_export]
2560macro_rules! do_syscall {
2561 ($ssn:expr, $addr:expr $(, $arg:expr)* $(,)?) => {{
2562 let argc = 0u32 $(+ { let _ = &$arg; 1u32 })*;
2563 unsafe {
2564 $crate::do_syscall(
2565 $ssn,
2566 $addr,
2567 argc
2568 $(, ::core::mem::transmute::<usize, *mut ::core::ffi::c_void>($arg as usize))*
2569 )
2570 }
2571 }};
2572}
2573
2574
2575#[cfg(test)]
2576extern crate std;
2577
2578#[cfg(test)]
2579mod tests {
2580 use super::*;
2581
2582 #[test]
2583 fn test_invalid_handle_value() {
2584 assert_eq!(INVALID_HANDLE_VALUE as isize, -1);
2585 }
2586
2587 #[test]
2588 fn test_constants_exist() {
2589 assert_eq!(PAGE_EXECUTE_READ, 0x20);
2591 assert_eq!(PAGE_EXECUTE_READWRITE, 0x40);
2592 assert_eq!(PAGE_READONLY, 0x2);
2593 assert_eq!(PAGE_READWRITE, 0x4);
2594 assert_eq!(MEM_COMMIT, 0x1000);
2595 assert_eq!(MEM_RESERVE, 0x2000);
2596 assert_eq!(PROCESS_QUERY_LIMITED_INFORMATION, 0x1000);
2597 assert_eq!(TLS_OUT_OF_INDEXES, 0xFFFFFFFF);
2598 }
2599
2600 #[test]
2601 fn test_eat_type() {
2602 let mut eat: EAT = std::collections::BTreeMap::new();
2603 eat.insert(0, "NtOpenProcess".to_string());
2604 eat.insert(1, "NtAllocateVirtualMemory".to_string());
2605
2606 assert_eq!(eat.len(), 2);
2607 assert_eq!(eat.get(&0), Some(&"NtOpenProcess".to_string()));
2608 assert_eq!(eat.get(&1), Some(&"NtAllocateVirtualMemory".to_string()));
2609 }
2610
2611 #[test]
2612 fn test_rtl_zero_memory() {
2613 let mut buffer = vec![0xFFu8; 64];
2614 let ptr = buffer.as_mut_ptr() as PVOID;
2615 rtl_zero_memory(ptr, 64);
2616 for byte in &buffer {
2617 assert_eq!(*byte, 0);
2618 }
2619 }
2620
2621 #[test]
2622 fn test_large_integer_creation() {
2623 let li = LARGE_INTEGER { QuadPart: 12345 };
2624 assert_eq!(li.QuadPart, 12345);
2625
2626 let li_default = LARGE_INTEGER::default();
2627 assert_eq!(li_default.QuadPart, 0);
2628 }
2629
2630 #[test]
2631 fn test_object_attributes_creation() {
2632 let oa = OBJECT_ATTRIBUTES::default();
2633 assert_eq!(oa.Length, 0);
2634 assert!(oa.RootDirectory.is_null());
2635 assert!(oa.ObjectName.is_null());
2636 }
2637
2638 #[test]
2639 fn test_client_id_creation() {
2640 let cid = ClientId {
2641 unique_process: 0x1234 as HANDLE,
2642 unique_thread: 0x5678 as HANDLE,
2643 };
2644 assert_eq!(cid.unique_process as usize, 0x1234);
2645 assert_eq!(cid.unique_thread as usize, 0x5678);
2646
2647 let cid_default = ClientId::default();
2648 assert!(cid_default.unique_process.is_null());
2649 assert!(cid_default.unique_thread.is_null());
2650 }
2651
2652 #[test]
2653 fn test_nt_allocate_virtual_memory_args() {
2654 let args = NtAllocateVirtualMemoryArgs {
2655 handle: INVALID_HANDLE_VALUE,
2656 base_address: core::ptr::null_mut(),
2657 };
2658 assert_eq!(args.handle as isize, -1);
2659 assert!(args.base_address.is_null());
2660 }
2661
2662 #[test]
2663 fn test_nt_open_process_args() {
2664 let args = NtOpenProcessArgs {
2665 handle: core::ptr::null_mut(),
2666 access: 0x1000,
2667 attributes: core::ptr::null_mut(),
2668 client_id: core::ptr::null_mut(),
2669 };
2670 assert!(args.handle.is_null());
2671 assert_eq!(args.access, 0x1000);
2672 }
2673
2674 #[test]
2675 fn test_nt_protect_virtual_memory_args() {
2676 let args = NtProtectVirtualMemoryArgs {
2677 handle: INVALID_HANDLE_VALUE,
2678 base_address: core::ptr::null_mut(),
2679 size: core::ptr::null_mut(),
2680 protection: PAGE_EXECUTE_READWRITE,
2681 };
2682 assert_eq!(args.handle as isize, -1);
2683 assert_eq!(args.protection, PAGE_EXECUTE_READWRITE);
2684 }
2685
2686 #[test]
2687 fn test_nt_write_virtual_memory_args() {
2688 let args = NtWriteVirtualMemoryArgs {
2689 handle: INVALID_HANDLE_VALUE,
2690 base_address: core::ptr::null_mut(),
2691 buffer: core::ptr::null_mut(),
2692 size: 0,
2693 };
2694 assert_eq!(args.handle as isize, -1);
2695 }
2696
2697 #[test]
2698 fn test_nt_create_thread_ex_args() {
2699 let args = NtCreateThreadExArgs {
2700 thread: core::ptr::null_mut(),
2701 access: 0x1F03FF,
2702 attributes: core::ptr::null_mut(),
2703 process: INVALID_HANDLE_VALUE,
2704 };
2705 assert!(args.thread.is_null());
2706 assert_eq!(args.process as isize, -1);
2707 }
2708
2709 #[cfg(target_arch = "x86_64")]
2710 #[test]
2711 fn test_use_hardware_breakpoints() {
2712 use_hardware_breakpoints(true);
2713 use_hardware_breakpoints(false);
2714 }
2715
2716 #[test]
2717 fn test_type_sizes() {
2718 assert_eq!(core::mem::size_of::<HANDLE>(), core::mem::size_of::<*mut core::ffi::c_void>());
2719 assert_eq!(core::mem::size_of::<PVOID>(), core::mem::size_of::<*mut core::ffi::c_void>());
2720 }
2721}