1#![cfg(windows)]
19#![cfg_attr(docsrs, feature(doc_cfg))]
20
21use data::lc;
22use data::LARGE_INTEGER;
23use std::ffi::c_void;
24use std::mem::size_of;
25use std::path::Path;
26use std::{fs, ptr};
27
28use data::{section_ascii_name, RuntimeFunction, OBJECT_ATTRIBUTES, UNICODE_STRING};
29use windows_sys::Win32::System::SystemServices::{IMAGE_BASE_RELOCATION, IMAGE_IMPORT_DESCRIPTOR};
30use windows_sys::Win32::System::WindowsProgramming::{IMAGE_THUNK_DATA32, IMAGE_THUNK_DATA64};
31use windows_sys::Win32::{
32 Foundation::HANDLE,
33 System::{
34 Diagnostics::Debug::{IMAGE_OPTIONAL_HEADER32, IMAGE_SECTION_HEADER},
35 IO::IO_STATUS_BLOCK,
36 },
37};
38
39use data::{
40 ImageFileHeader, ImageOptionalHeader64, PeManualMap, PeMetadata, FILE_EXECUTE,
41 FILE_NON_DIRECTORY_FILE, FILE_READ_ATTRIBUTES, FILE_READ_DATA, FILE_SHARE_DELETE,
42 FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT, MEM_COMMIT, MEM_RESERVE, PAGE_EXECUTE,
43 PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_READONLY, PAGE_READWRITE, PVOID,
44 SECTION_ALL_ACCESS, SECTION_MEM_EXECUTE, SECTION_MEM_READ, SECTION_MEM_WRITE, SEC_IMAGE,
45 SYNCHRONIZE,
46};
47
48pub fn read_and_map_module(
69 filepath: &str,
70 clean_dos_header: bool,
71 run_callbacks: bool,
72) -> Result<(PeMetadata, usize), String> {
73 let file_content = fs::read(filepath).expect(&lc!("[x] Error opening the specified file."));
74 let file_content_ptr = file_content.as_ptr() as *mut _;
75
76 let result = manually_map_module(file_content_ptr, clean_dos_header, run_callbacks)?;
77
78 unsafe {
79 for i in 0..file_content.len() {
80 *(file_content_ptr.add(i)) = 0u8;
81 }
82
83 Ok(result)
84 }
85}
86
87pub fn manually_map_module(
107 file_ptr: *const u8,
108 clean_dos_headers: bool,
109 run_callbacks: bool,
110) -> Result<(PeMetadata, usize), String> {
111 let pe_info = get_pe_metadata(file_ptr, false)?;
112 if (pe_info.is_32_bit && (size_of::<usize>() == 8))
113 || (!pe_info.is_32_bit && (size_of::<usize>() == 4))
114 {
115 return Err(lc!(
116 "[x] The module architecture does not match the process architecture."
117 ));
118 }
119
120 let dwsize;
121 if pe_info.is_32_bit {
122 dwsize = pe_info.opt_header_32.SizeOfImage as usize;
123 } else {
124 dwsize = pe_info.opt_header_64.size_of_image as usize;
125 }
126
127 unsafe {
128 let handle = dyncvoke_core::INVALID_HANDLE_VALUE;
129 let mut a = usize::default();
130 let base_address: *mut PVOID = &mut a as *mut usize as *mut PVOID;
131 let zero_bits = 0 as usize;
132 let size: *mut usize = std::mem::transmute(&dwsize);
133
134 let ret = dyncvoke_core::nt_allocate_virtual_memory(
135 handle,
136 base_address,
137 zero_bits,
138 size,
139 MEM_COMMIT | MEM_RESERVE,
140 PAGE_READWRITE,
141 );
142
143 if ret != 0 {
144 return Err(lc!("[x] Error allocating memory."));
145 }
146
147 let image_ptr = *base_address;
148
149 map_module_to_memory(file_ptr, image_ptr, &pe_info)?;
150
151 relocate_module(&pe_info, image_ptr);
152
153 rewrite_module_iat(&pe_info, image_ptr)?;
154
155 if clean_dos_headers {
156 clean_dos_header(image_ptr);
157 }
158
159 set_module_section_permissions(&pe_info, image_ptr)?;
160
161 add_runtime_table(&pe_info, image_ptr);
162
163 if run_callbacks {
164 run_tls_callbacks(&pe_info, image_ptr);
165 }
166
167 Ok((pe_info, image_ptr as usize))
168 }
169}
170
171pub fn get_runtime_table(image_ptr: *mut c_void) -> (*mut data::RuntimeFunction, u32) {
175 let mut size: u32 = 0;
176 let module_metadata = get_pe_metadata(image_ptr as *const u8, false);
177 if !module_metadata.is_ok() {
178 return (ptr::null_mut(), size);
179 }
180
181 let metadata = module_metadata.unwrap();
182
183 let mut runtime: *mut data::RuntimeFunction = ptr::null_mut();
184 for section in &metadata.sections {
185 if section_ascii_name(§ion.Name) == b".pdata" {
186 let base = image_ptr as usize;
187 let addr = base + section.VirtualAddress as usize;
188 runtime = std::ptr::with_exposed_provenance_mut::<RuntimeFunction>(addr);
189 size = section.SizeOfRawData;
190 break;
191 }
192 }
193
194 return (runtime, size);
195}
196
197pub fn get_pe_metadata(module_ptr: *const u8, check_signature: bool) -> Result<PeMetadata, String> {
212 if module_ptr.is_null() {
213 return Err(lc!("[x] Null module pointer."));
214 }
215 let mut pe_metadata = PeMetadata::default();
216
217 unsafe {
218 let e_lfanew = *((module_ptr as usize + 0x3C) as *const u32);
219 pe_metadata.pe = *((module_ptr as usize + e_lfanew as usize) as *const u32);
220
221 if pe_metadata.pe != 0x4550 && check_signature {
222 return Err(lc!("[x] Invalid PE signature."));
223 }
224
225 pe_metadata.image_file_header =
226 *((module_ptr as usize + e_lfanew as usize + 0x4) as *mut ImageFileHeader);
227
228 let opt_header: *const u16 = (module_ptr as usize + e_lfanew as usize + 0x18) as *const u16;
229 let pe_arch = *(opt_header);
230
231 if pe_arch == 0x010B {
232 pe_metadata.is_32_bit = true;
233 let opt_header_content: *const IMAGE_OPTIONAL_HEADER32 =
234 std::mem::transmute(opt_header);
235 pe_metadata.opt_header_32 = *opt_header_content;
236 } else if pe_arch == 0x020B {
237 pe_metadata.is_32_bit = false;
238 let opt_header_content: *const ImageOptionalHeader64 = std::mem::transmute(opt_header);
239 pe_metadata.opt_header_64 = *opt_header_content;
240 } else {
241 return Err(lc!("[x] Invalid magic value."));
242 }
243
244 let mut sections: Vec<IMAGE_SECTION_HEADER> = vec![];
245
246 for i in 0..pe_metadata.image_file_header.number_of_sections {
247 let section_ptr = (opt_header as usize
248 + pe_metadata.image_file_header.size_of_optional_header as usize
249 + (i * 0x28) as usize) as *const u8;
250 let section_ptr: *const IMAGE_SECTION_HEADER = std::mem::transmute(section_ptr);
251 sections.push(*section_ptr);
252 }
253
254 pe_metadata.sections = sections;
255
256 Ok(pe_metadata)
257 }
258}
259
260pub fn map_module_to_memory(
265 module_ptr: *const u8,
266 image_ptr: *mut c_void,
267 pe_info: &PeMetadata,
268) -> Result<(), String> {
269 if (pe_info.is_32_bit && (size_of::<usize>() == 8))
270 || (!pe_info.is_32_bit && (size_of::<usize>() == 4))
271 {
272 return Err(lc!(
273 "[x] The module architecture does not match the process architecture."
274 ));
275 }
276
277 let nsize;
278 if pe_info.is_32_bit {
279 nsize = pe_info.opt_header_32.SizeOfHeaders as usize;
280 } else {
281 nsize = pe_info.opt_header_64.size_of_headers as usize;
282 }
283
284 unsafe {
285 let handle = dyncvoke_core::INVALID_HANDLE_VALUE;
286 let base_address: *mut c_void = std::mem::transmute(image_ptr);
287 let buffer: *mut c_void = std::mem::transmute(module_ptr);
288 let mut written: usize = 0;
289 let bytes_written: *mut usize = &mut written;
290 let ret = dyncvoke_core::nt_write_virtual_memory(
291 handle,
292 base_address,
293 buffer,
294 nsize,
295 bytes_written,
296 );
297
298 if ret != 0 {
299 return Err(lc!("[x] Error writing PE headers to the allocated memory."));
300 }
301
302 for section in &pe_info.sections {
303 let section_base_ptr =
304 (image_ptr as usize + section.VirtualAddress as usize) as *mut u8;
305 let section_content_ptr =
306 (module_ptr as usize + section.PointerToRawData as usize) as *mut u8;
307
308 let base_address: *mut c_void = std::mem::transmute(section_base_ptr);
309 let buffer: *mut c_void = std::mem::transmute(section_content_ptr);
310 let nsize = section.SizeOfRawData as usize;
311 let bytes_written: *mut usize = std::mem::transmute(&written);
312 let ret = dyncvoke_core::nt_write_virtual_memory(
313 handle,
314 base_address,
315 buffer,
316 nsize,
317 bytes_written,
318 );
319
320 if ret != 0 || *bytes_written != nsize {
321 return Err(lc!(
322 "[x] Failed to write PE sections to the allocated memory."
323 ));
324 }
325 }
326
327 Ok(())
328 }
329}
330
331pub fn relocate_module(pe_info: &PeMetadata, image_ptr: *mut c_void) {
336 unsafe {
337 let module_memory_base: *mut usize = std::mem::transmute(image_ptr);
338 let image_data_directory;
339 let image_delta: isize;
340 if pe_info.is_32_bit {
341 image_data_directory = pe_info.opt_header_32.DataDirectory[5]; image_delta = module_memory_base as isize - pe_info.opt_header_32.ImageBase as isize;
343 } else {
344 image_data_directory = pe_info.opt_header_64.datas_directory[5]; image_delta = module_memory_base as isize - pe_info.opt_header_64.image_base as isize;
346 }
347
348 if image_data_directory.VirtualAddress == 0 || image_data_directory.Size == 0 {
349 return;
350 }
351
352 let reloc_table_start = module_memory_base as usize
353 + image_data_directory.VirtualAddress as usize;
354 let reloc_table_end = reloc_table_start + image_data_directory.Size as usize;
355
356 let mut reloc_table_ptr = reloc_table_start as *mut i32;
357
358 while (reloc_table_ptr as usize) + size_of::<IMAGE_BASE_RELOCATION>()
359 <= reloc_table_end
360 {
361 let ibr: *mut IMAGE_BASE_RELOCATION = std::mem::transmute(reloc_table_ptr);
362 let image_base_relocation = *ibr;
363
364 if image_base_relocation.VirtualAddress == 0
365 || (image_base_relocation.SizeOfBlock as usize)
366 < size_of::<IMAGE_BASE_RELOCATION>()
367 {
368 break;
369 }
370
371 let reloc_count: isize = (image_base_relocation.SizeOfBlock as isize
372 - size_of::<IMAGE_BASE_RELOCATION>() as isize)
373 / 2;
374
375 for i in 0..reloc_count {
376 let reloc_entry_ptr = (reloc_table_ptr as usize
377 + size_of::<IMAGE_BASE_RELOCATION>() as usize
378 + (i * 2) as usize) as *mut u16;
379 let reloc_value = *reloc_entry_ptr;
380
381 let reloc_type = reloc_value >> 12;
382 let reloc_patch = reloc_value & 0xfff;
383
384 if reloc_type != 0 {
385 let patch_addr = module_memory_base as usize
386 + image_base_relocation.VirtualAddress as usize
387 + reloc_patch as usize;
388
389 if reloc_type == 0x3 {
390 if patch_addr % 4 == 0 {
392 let patch_ptr = patch_addr as *mut i32;
393 let original_ptr = *patch_ptr;
394 let patch = original_ptr + image_delta as i32;
395 *patch_ptr = patch;
396 }
397 } else {
398 if patch_addr % 8 == 0 {
401 let patch_ptr = patch_addr as *mut isize;
402 let original_ptr = *patch_ptr;
403 let patch = original_ptr + image_delta as isize;
404 *patch_ptr = patch;
405 }
406 }
407 }
408 }
409
410 reloc_table_ptr = (reloc_table_ptr as usize
411 + image_base_relocation.SizeOfBlock as usize)
412 as *mut i32;
413 }
414 }
415}
416
417pub fn rewrite_module_iat(pe_info: &PeMetadata, image_ptr: *mut c_void) -> Result<(), String> {
422 unsafe {
423 let module_memory_base: *mut usize = std::mem::transmute(image_ptr);
424 let image_data_directory;
425 if pe_info.is_32_bit {
426 image_data_directory = pe_info.opt_header_32.DataDirectory[1]; } else {
428 image_data_directory = pe_info.opt_header_64.datas_directory[1]; }
430
431 if image_data_directory.VirtualAddress == 0 {
432 return Ok(());
433 }
434
435 let import_table_ptr = (module_memory_base as usize
436 + image_data_directory.VirtualAddress as usize)
437 as *mut usize;
438
439 let api_set_dict = dyncvoke_core::get_api_mapping();
440
441 let mut counter = 0;
442 let mut image_import_descriptor_ptr = (import_table_ptr as usize
443 + size_of::<IMAGE_IMPORT_DESCRIPTOR>() as usize * counter)
444 as *mut IMAGE_IMPORT_DESCRIPTOR;
445 let mut image_import_descriptor = *image_import_descriptor_ptr;
446
447 while image_import_descriptor.Name != 0 {
448 let mut dll_name = "".to_string();
449 let mut c: char = ' ';
450 let mut ptr =
451 (module_memory_base as usize + image_import_descriptor.Name as usize) as *mut u8;
452 while c != '\0' {
453 c = *ptr as char;
454 if c != '\0' {
455 dll_name.push(c);
456 ptr = ptr.add(1);
457 }
458 }
459
460 if dll_name == "" {
461 return Ok(());
462 } else {
463 let lookup_key = if dll_name.len() >= 6 {
464 format!("{}{}", &dll_name[..dll_name.len() - 6], ".dll")
465 } else {
466 dll_name.clone()
467 };
468
469 if (dll_name.starts_with("api-") || dll_name.starts_with("ext-"))
470 && api_set_dict.contains_key(&lookup_key)
471 {
472 let key = match api_set_dict.get(&lookup_key) {
473 Some(x) => x.to_string(),
474 None => "".to_string(),
475 };
476
477 if key.len() > 0 {
478 dll_name = key.to_string();
479 }
480 }
481
482 let mut module_handle = dyncvoke_core::get_module_base_address(&dll_name) as usize;
483
484 if module_handle == 0 {
485 module_handle = dyncvoke_core::load_library_a(&dll_name) as usize;
486
487 if module_handle == 0 {
488 return Err(format!(
489 "{}{}",
490 lc!("[x] Unable to find the specified module: "),
491 dll_name
492 ));
493 }
494 }
495
496 if pe_info.is_32_bit {
497 let mut i: isize = 0;
498
499 loop {
500 let image_thunk_data = (module_memory_base as usize
501 + image_import_descriptor.Anonymous.OriginalFirstThunk as usize
502 + i as usize * size_of::<u32>() as usize)
503 as *mut IMAGE_THUNK_DATA32;
504 let image_thunk_data = *image_thunk_data;
505 let ft_itd = (module_memory_base as usize
506 + image_import_descriptor.FirstThunk as usize
507 + i as usize * size_of::<u32>() as usize)
508 as *mut i32;
509 if image_thunk_data.u1.AddressOfData == 0 {
510 break;
511 }
512
513 if image_thunk_data.u1.AddressOfData < 0x80000000 {
514 let mut imp_by_name_ptr = (module_memory_base as usize
515 + image_thunk_data.u1.AddressOfData as usize
516 + size_of::<u16>() as usize)
517 as *mut u8;
518 let mut import_name: String = "".to_string();
519 let mut c: char = ' ';
520 while c != '\0' {
521 c = *imp_by_name_ptr as char;
522 if c != '\0' {
523 import_name.push(c);
524 }
525
526 imp_by_name_ptr = imp_by_name_ptr.add(1);
527 }
528
529 let func_ptr =
530 dyncvoke_core::get_function_address(module_handle, &import_name);
531 *ft_itd = func_ptr as i32;
532 } else {
533 let f_ordinal = (image_thunk_data.u1.AddressOfData & 0xFFFF) as u32;
534 let func_ptr = dyncvoke_core::get_function_address_by_ordinal(
535 module_handle,
536 f_ordinal,
537 );
538 let func_ptr = func_ptr as *mut i32;
539 *ft_itd = func_ptr as i32;
540 }
541
542 i = i + 1;
543 }
544 } else {
545 let mut i: isize = 0;
546
547 loop {
548 let image_thunk_data = (module_memory_base as u64
549 + image_import_descriptor.Anonymous.OriginalFirstThunk as u64
550 + i as u64 * size_of::<u64>() as u64)
551 as *mut IMAGE_THUNK_DATA64;
552 let image_thunk_data = *image_thunk_data;
553 let ft_itd = (module_memory_base as u64
554 + image_import_descriptor.FirstThunk as u64
555 + i as u64 * size_of::<u64>() as u64)
556 as *mut isize;
557
558 if image_thunk_data.u1.AddressOfData == 0 {
559 break;
560 }
561
562 if image_thunk_data.u1.AddressOfData < 0x8000000000000000 {
563 let mut imp_by_name_ptr = (module_memory_base as u64
564 + image_thunk_data.u1.AddressOfData as u64
565 + size_of::<u16>() as u64)
566 as *mut u8;
567 let mut import_name: String = "".to_string();
568 let mut c: char = ' ';
569 while c != '\0' {
570 c = *imp_by_name_ptr as char;
571 if c != '\0' {
572 import_name.push(c);
573 }
574
575 imp_by_name_ptr = imp_by_name_ptr.add(1);
576 }
577
578 let func_ptr =
579 dyncvoke_core::get_function_address(module_handle, &import_name)
580 as *mut isize;
581 *ft_itd = func_ptr as isize;
582 } else {
583 let f_ordinal = (image_thunk_data.u1.AddressOfData & 0xFFFF) as u32;
584 let func_ptr = dyncvoke_core::get_function_address_by_ordinal(
585 module_handle,
586 f_ordinal,
587 );
588 *ft_itd = func_ptr as isize;
589 }
590
591 i = i + 1;
592 }
593 }
594 }
595
596 counter = counter + 1;
597 image_import_descriptor_ptr = (import_table_ptr as usize
598 + size_of::<IMAGE_IMPORT_DESCRIPTOR>() as usize * counter)
599 as *mut IMAGE_IMPORT_DESCRIPTOR;
600 image_import_descriptor = *image_import_descriptor_ptr;
601 }
602
603 Ok(())
604 }
605}
606
607fn clean_dos_header(image_ptr: *mut c_void) {
608 unsafe {
609 let mut base_addr = image_ptr as *mut u8;
610 let pe_header = image_ptr as isize + 0x3C;
611 while (base_addr as isize) < pe_header {
612 *base_addr = 0;
613 base_addr = base_addr.add(1);
614 }
615 base_addr = base_addr.add(4);
616
617 let e_lfanew = *((image_ptr as usize + 0x3C) as *const u32);
618 let pe = image_ptr as isize + e_lfanew as isize;
619
620 while (base_addr as isize) < pe {
621 *base_addr = 0;
622 base_addr = base_addr.add(1);
623 }
624
625 let pe = pe as *mut u16;
626 *pe = 0;
627 }
628}
629
630pub fn add_runtime_table(pe_info: &PeMetadata, image_ptr: *mut c_void) {
631 unsafe {
632 for section in &pe_info.sections {
633 if section_ascii_name(§ion.Name) == b".pdata" {
634 let entry_count = (section.SizeOfRawData / 12) as i32; let func: data::RtlAddFunctionTable;
637 let _ret: Option<bool>;
638 let k32 = dyncvoke_core::get_module_base_address(&lc!("kernel32.dll"));
639 let function_table_addr: usize =
640 image_ptr as usize + section.VirtualAddress as usize;
641 dyncvoke_core::dynamic_invoke!(
642 k32,
643 &lc!("RtlAddFunctionTable"),
644 func,
645 _ret,
646 function_table_addr,
647 entry_count,
648 image_ptr as usize
649 );
650 }
651 }
652 }
653}
654
655pub fn set_module_section_permissions(
660 pe_info: &PeMetadata,
661 image_ptr: *mut c_void,
662) -> Result<(), String> {
663 unsafe {
664 let base_of_code;
665
666 if pe_info.is_32_bit {
667 base_of_code = pe_info.opt_header_32.BaseOfCode as usize;
668 } else {
669 base_of_code = pe_info.opt_header_64.base_of_code as usize;
670 }
671
672 let handle = dyncvoke_core::INVALID_HANDLE_VALUE;
673 let mut image_ptr = image_ptr;
674 let base_address: *mut PVOID = &mut image_ptr as *mut *mut c_void as *mut PVOID;
675 let mut size: usize = base_of_code;
676 let mut old_protection: u32 = 0;
677 let _ret = dyncvoke_core::nt_protect_virtual_memory(
678 handle,
679 base_address,
680 &mut size,
681 PAGE_READONLY,
682 &mut old_protection,
683 );
684
685 for section in &pe_info.sections {
686 let is_read = (section.Characteristics & SECTION_MEM_READ) != 0;
687 let is_write = (section.Characteristics & SECTION_MEM_WRITE) != 0;
688 let is_execute = (section.Characteristics & SECTION_MEM_EXECUTE) != 0;
689 let new_protect: u32;
690
691 if is_read & !is_write & !is_execute {
692 new_protect = PAGE_READONLY;
693 } else if is_read & is_write & !is_execute {
694 new_protect = PAGE_READWRITE;
695 } else if is_read & is_write & is_execute {
696 new_protect = PAGE_EXECUTE_READWRITE;
697 } else if is_read & !is_write & is_execute {
698 new_protect = PAGE_EXECUTE_READ;
699 } else if !is_read & !is_write & is_execute {
700 new_protect = PAGE_EXECUTE;
701 } else {
702 return Err(lc!("[x] Unknown section permission."));
703 }
704
705 let mut address: *mut c_void =
706 (image_ptr as usize + section.VirtualAddress as usize) as *mut c_void;
707 let base_address: *mut PVOID = &mut address as *mut *mut c_void as *mut PVOID;
708 size = section.Misc.VirtualSize as usize;
709 let mut old_protection: u32 = 0;
710 let ret = dyncvoke_core::nt_protect_virtual_memory(
711 handle,
712 base_address,
713 &mut size,
714 new_protect,
715 &mut old_protection,
716 );
717
718 if ret != 0 {
719 return Err(lc!("[x] Error changing section permission."));
720 }
721 }
722
723 Ok(())
724 }
725}
726
727pub fn run_tls_callbacks(pe_info: &PeMetadata, image_ptr: *mut c_void) {
732 unsafe {
733 let entry_point;
734 if pe_info.is_32_bit {
735 entry_point = image_ptr as isize + pe_info.opt_header_32.AddressOfEntryPoint as isize;
736 } else {
737 entry_point =
738 image_ptr as isize + pe_info.opt_header_64.address_of_entry_point as isize;
739 }
740
741 let (tls_dir_rva, tls_cb_off) = if pe_info.is_32_bit {
742 (
743 pe_info.opt_header_32.NumberOfRvaAndSizes >= 10,
744 pe_info.opt_header_32.DataDirectory[9].VirtualAddress as usize,
745 )
746 } else {
747 (
748 pe_info.opt_header_64.number_of_rva_and_sizes >= 10,
749 pe_info.opt_header_64.datas_directory[9].VirtualAddress as usize,
750 )
751 };
752 if tls_dir_rva && tls_cb_off != 0 {
753 let address: *mut u8 = (image_ptr as usize + tls_cb_off) as *mut u8;
754 let cb_off = if pe_info.is_32_bit { 12 } else { 24 };
758 let address_of_tls_callback = address.add(cb_off) as *mut usize;
759 let mut address_of_tls_callback_array: *mut usize =
760 std::ptr::with_exposed_provenance_mut::<usize>(*address_of_tls_callback);
761
762 while *address_of_tls_callback_array != 0 {
763 let tls_callback: extern "system" fn(isize, u32, PVOID) =
764 std::mem::transmute(*address_of_tls_callback_array);
765 tls_callback(entry_point, 1, ptr::null_mut());
766 address_of_tls_callback_array = address_of_tls_callback_array.add(1);
767 }
768 }
769 }
770}
771
772pub fn map_to_section(module_path: &str) -> Result<(PeManualMap, HANDLE), String> {
776 unsafe {
777 if !Path::new(&module_path).is_file() {
778 return Err(lc!("[x] Filepath not found."));
779 }
780
781 let module_path = format!("{}{}", "\\??\\", module_path);
782 let mut module_path_utf16: Vec<u16> = module_path.encode_utf16().collect();
783 module_path_utf16.push(0);
784
785 let mut o_name: UNICODE_STRING = std::mem::zeroed();
786 dyncvoke_core::rtl_init_unicode_string(&mut o_name, module_path_utf16.as_ptr());
787
788 let mut object_attributes: OBJECT_ATTRIBUTES = std::mem::zeroed();
789 object_attributes.Length = size_of::<OBJECT_ATTRIBUTES>() as u32;
790 object_attributes.ObjectName = &mut o_name;
791 object_attributes.Attributes = 0x40; let mut io: IO_STATUS_BLOCK = std::mem::zeroed();
794 let mut hfile: HANDLE = std::ptr::null_mut();
795 let r = dyncvoke_core::nt_open_file(
796 &mut hfile,
797 FILE_READ_DATA | FILE_EXECUTE | FILE_READ_ATTRIBUTES | SYNCHRONIZE,
798 &mut object_attributes,
799 &mut io,
800 FILE_SHARE_READ | FILE_SHARE_DELETE,
801 FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE,
802 );
803
804 if r != 0 {
805 return Err(lc!("[x] Error opening file."));
806 }
807
808 let mut max_size: LARGE_INTEGER = LARGE_INTEGER::default();
809 let mut hsection: HANDLE = std::ptr::null_mut();
810 let r = dyncvoke_core::nt_create_section(
811 &mut hsection,
812 SECTION_ALL_ACCESS,
813 ptr::null_mut(),
814 &mut max_size,
815 PAGE_READONLY,
816 SEC_IMAGE,
817 hfile,
818 );
819
820 if r != 0 {
821 return Err(lc!("[x] Error creating file section in memory."));
822 }
823
824 let mut offset: LARGE_INTEGER = LARGE_INTEGER::default();
825 let mut b = usize::default();
826 let base_address: *mut PVOID = &mut b as *mut usize as *mut PVOID;
827 let mut v = usize::default();
828 let r = dyncvoke_core::nt_map_view_of_section(
829 hsection,
830 dyncvoke_core::INVALID_HANDLE_VALUE,
831 base_address,
832 0,
833 0,
834 &mut offset,
835 &mut v,
836 0x2,
837 0x0,
838 PAGE_READWRITE,
839 );
840
841 if r != 0 {
842 return Err(lc!("[x] Error mapping file section."));
843 }
844
845 let base_address: *const u8 = std::mem::transmute(*base_address);
846 let sec_object: PeManualMap = PeManualMap {
847 pe_info: get_pe_metadata(base_address, false).unwrap(),
848 base_address: base_address as usize,
849 decoy_module: module_path,
850 };
851
852 let _r = dyncvoke_core::close_handle(hfile);
853
854 Ok((sec_object, hsection))
855 }
856}
857
858pub fn map_to_allocated_memory(
859 module_ptr: *const u8,
860 image_ptr: *mut c_void,
861 pe_info: &PeMetadata,
862) -> Result<(), String> {
863 map_module_to_memory(module_ptr, image_ptr, &pe_info)?;
864
865 relocate_module(&pe_info, image_ptr);
866
867 rewrite_module_iat(&pe_info, image_ptr)?;
868
869 clean_dos_header(image_ptr);
870
871 set_module_section_permissions(&pe_info, image_ptr)?;
872
873 add_runtime_table(&pe_info, image_ptr);
874
875 Ok(())
876}
877
878#[cfg(test)]
883mod tests {
884 use super::*;
885 use data::{PeMetadata, ImageOptionalHeader64, ImageFileHeader};
886 use windows_sys::Win32::System::Diagnostics::Debug::IMAGE_SECTION_HEADER;
887 use std::collections::BTreeMap;
888
889 #[test]
891 fn test_pe_metadata_creation() {
892 let pe = PeMetadata {
893 pe: 0x4550, is_32_bit: false,
895 image_file_header: ImageFileHeader {
896 machine: 0x8664, number_of_sections: 3,
898 time_data_stamp: 1234567890,
899 pointer_to_symbol_table: 0,
900 number_of_symbols: 0,
901 size_of_optional_header: 0xF0,
902 characteristics: 0x2002, },
904 opt_header_32: unsafe { std::mem::zeroed() },
905 opt_header_64: ImageOptionalHeader64 {
906 magic: 0x20B, major_linker_version: 14,
908 minor_linker_version: 0,
909 size_of_code: 0x1000,
910 size_of_initialized_data: 0,
911 size_of_unitialized_data: 0,
912 address_of_entry_point: 0x1000,
913 base_of_code: 0x1000,
914 image_base: 0x140000000,
915 section_alignment: 0x1000,
916 file_alignment: 0x200,
917 major_operating_system_version: 10,
918 minor_operating_system_version: 0,
919 major_image_version: 0,
920 minor_image_version: 0,
921 major_subsystem_version: 10,
922 minor_subsystem_version: 0,
923 win32_version_value: 0,
924 size_of_image: 0x7000,
925 size_of_headers: 0x400,
926 checksum: 0,
927 subsystem: 3, dll_characteristics: 0x8160,
929 size_of_stack_reserve: 0x40000,
930 size_of_stack_commit: 0x1000,
931 size_of_heap_reserve: 0x100000,
932 size_of_heap_commit: 0x1000,
933 loader_flags: 0,
934 number_of_rva_and_sizes: 16,
935 datas_directory: [unsafe { std::mem::zeroed() }; 16],
936 },
937 sections: Vec::new(),
938 };
939
940 assert_eq!(pe.pe, 0x4550);
941 assert!(!pe.is_32_bit);
942 assert_eq!(pe.image_file_header.machine, 0x8664);
943 assert_eq!(pe.image_file_header.number_of_sections, 3);
944 }
945
946 #[test]
948 fn test_pe_metadata_default() {
949 let pe = PeMetadata::default();
950 assert_eq!(pe.pe, 0);
951 assert!(!pe.is_32_bit);
952 }
953
954
955 #[test]
956 fn test_image_section_header_size() {
957 assert_eq!(std::mem::size_of::<IMAGE_SECTION_HEADER>(), 40);
958 }
959
960 #[test]
962 fn test_pe_manual_map_creation() {
963 let pmm = PeManualMap {
964 decoy_module: "kernel32.dll".to_string(),
965 base_address: 0x12340000,
966 pe_info: PeMetadata::default(),
967 };
968
969 assert_eq!(pmm.decoy_module, "kernel32.dll");
970 assert_eq!(pmm.base_address, 0x12340000);
971 }
972
973 #[test]
975 fn test_pe_header_validation() {
976 let valid_pe: [u8; 2] = [0x50, 0x45]; assert_eq!(valid_pe[0], 0x50);
979 assert_eq!(valid_pe[1], 0x45);
980
981 let invalid_pe: [u8; 2] = [0x00, 0x00];
982 assert_ne!(invalid_pe[0], 0x50);
983 }
984
985 #[test]
987 fn test_dos_header_magic() {
988 let dos_magic: [u8; 2] = [0x5A, 0x4D]; assert_eq!(dos_magic[0], 0x5A); assert_eq!(dos_magic[1], 0x4D); }
992
993 #[test]
995 fn test_section_characteristics() {
996 const IMAGE_SCN_CNT_CODE: u32 = 0x20000000;
998 const IMAGE_SCN_MEM_EXECUTE: u32 = 0x20000000;
999 const IMAGE_SCN_MEM_READ: u32 = 0x40000000;
1000 const IMAGE_SCN_MEM_WRITE: u32 = 0x80000000;
1001
1002 let code_section = IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ;
1003 assert!(code_section & IMAGE_SCN_CNT_CODE != 0);
1004 assert!(code_section & IMAGE_SCN_MEM_EXECUTE != 0);
1005 assert!(code_section & IMAGE_SCN_MEM_READ != 0);
1006
1007 let data_section = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
1008 assert!(data_section & IMAGE_SCN_MEM_READ != 0);
1009 assert!(data_section & IMAGE_SCN_MEM_WRITE != 0);
1010 assert!(data_section & IMAGE_SCN_MEM_EXECUTE == 0);
1011 }
1012
1013 #[test]
1015 fn test_optional_header_magic() {
1016 const PE32_MAGIC: u16 = 0x10B;
1017 const PE32_PLUS_MAGIC: u16 = 0x20B;
1018
1019 assert_eq!(PE32_MAGIC, 0x10B);
1020 assert_eq!(PE32_PLUS_MAGIC, 0x20B);
1021 }
1022
1023 #[test]
1025 fn test_subsystem_values() {
1026 const IMAGE_SUBSYSTEM_UNKNOWN: u16 = 0;
1027 const IMAGE_SUBSYSTEM_NATIVE: u16 = 1;
1028 const IMAGE_SUBSYSTEM_WINDOWS_GUI: u16 = 2;
1029 const IMAGE_SUBSYSTEM_WINDOWS_CUI: u16 = 3;
1030
1031 assert_eq!(IMAGE_SUBSYSTEM_UNKNOWN, 0);
1032 assert_eq!(IMAGE_SUBSYSTEM_NATIVE, 1);
1033 assert_eq!(IMAGE_SUBSYSTEM_WINDOWS_GUI, 2);
1034 assert_eq!(IMAGE_SUBSYSTEM_WINDOWS_CUI, 3);
1035 }
1036
1037 #[test]
1039 fn test_dll_characteristics() {
1040 const IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE: u16 = 0x0040;
1041 const IMAGE_DLL_CHARACTERISTICS_NX_COMPAT: u16 = 0x0100;
1042 const IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION: u16 = 0x0200;
1043 const IMAGE_DLL_CHARACTERISTICS_NO_SEH: u16 = 0x0400;
1044
1045 let chars = IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE | IMAGE_DLL_CHARACTERISTICS_NX_COMPAT;
1046 assert!(chars & IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE != 0);
1047 assert!(chars & IMAGE_DLL_CHARACTERISTICS_NX_COMPAT != 0);
1048 assert!(chars & IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION == 0);
1049 assert!(chars & IMAGE_DLL_CHARACTERISTICS_NO_SEH == 0);
1050 }
1051
1052 #[test]
1054 fn test_machine_types() {
1055 const IMAGE_FILE_MACHINE_I386: u16 = 0x014C;
1056 const IMAGE_FILE_MACHINE_AMD64: u16 = 0x8664;
1057 const IMAGE_FILE_MACHINE_ARM: u16 = 0x01C0;
1058 const IMAGE_FILE_MACHINE_ARM64: u16 = 0xAA64;
1059
1060 assert_eq!(IMAGE_FILE_MACHINE_I386, 0x014C);
1061 assert_eq!(IMAGE_FILE_MACHINE_AMD64, 0x8664);
1062 assert_eq!(IMAGE_FILE_MACHINE_ARM, 0x01C0);
1063 assert_eq!(IMAGE_FILE_MACHINE_ARM64, 0xAA64);
1064 }
1065
1066 #[test]
1068 fn test_data_directories() {
1069 const IMAGE_DIRECTORY_ENTRY_EXPORT: usize = 0;
1070 const IMAGE_DIRECTORY_ENTRY_IMPORT: usize = 1;
1071 const IMAGE_DIRECTORY_ENTRY_RESOURCE: usize = 2;
1072 const IMAGE_DIRECTORY_ENTRY_EXCEPTION: usize = 3;
1073 const IMAGE_DIRECTORY_ENTRY_TLS: usize = 9;
1074
1075 assert_eq!(IMAGE_DIRECTORY_ENTRY_EXPORT, 0);
1076 assert_eq!(IMAGE_DIRECTORY_ENTRY_IMPORT, 1);
1077 assert_eq!(IMAGE_DIRECTORY_ENTRY_RESOURCE, 2);
1078 assert_eq!(IMAGE_DIRECTORY_ENTRY_EXCEPTION, 3);
1079 assert_eq!(IMAGE_DIRECTORY_ENTRY_TLS, 9);
1080 }
1081
1082 #[test]
1084 fn test_runtime_function_structure() {
1085 use data::RuntimeFunction;
1086
1087 let rf = RuntimeFunction {
1088 begin_addr: 0x1000,
1089 end_addr: 0x2000,
1090 unwind_addr: 0x1500,
1091 };
1092
1093 assert_eq!(rf.begin_addr, 0x1000);
1094 assert_eq!(rf.end_addr, 0x2000);
1095 assert_eq!(rf.unwind_addr, 0x1500);
1096 }
1097
1098 #[test]
1100 fn test_module_size_calculations() {
1101 let section_alignment = 0x1000u32;
1102 let file_alignment = 0x200u32;
1103 let raw_size = 0x1800u32;
1104
1105 let aligned_size = ((raw_size + section_alignment - 1) / section_alignment) * section_alignment;
1107 assert_eq!(aligned_size, 0x2000);
1108
1109 let file_aligned = ((raw_size + file_alignment - 1) / file_alignment) * file_alignment;
1111 assert_eq!(file_aligned, 0x1800);
1112 }
1113
1114 #[test]
1116 fn test_rva_to_offset() {
1117 struct SectionInfo {
1119 virtual_address: u32,
1120 pointer_to_raw_data: u32,
1121 virtual_size: u32,
1122 }
1123
1124 let sections = vec![
1125 SectionInfo { virtual_address: 0x1000, pointer_to_raw_data: 0x400, virtual_size: 0x1000 },
1126 SectionInfo { virtual_address: 0x2000, pointer_to_raw_data: 0x1400, virtual_size: 0x800 },
1127 ];
1128
1129 let rva = 0x1500u32;
1133 let offset = sections.iter().find(|s| rva >= s.virtual_address && rva < s.virtual_address + s.virtual_size)
1134 .map(|s| s.pointer_to_raw_data + (rva - s.virtual_address));
1135
1136 assert_eq!(offset, Some(0x900));
1137 }
1138
1139 #[test]
1141 fn test_import_lookup() {
1142 let mut imports: BTreeMap<String, usize> = BTreeMap::new();
1143 imports.insert("kernel32.dll".to_string(), 0x1000);
1144 imports.insert("ntdll.dll".to_string(), 0x2000);
1145 imports.insert("user32.dll".to_string(), 0x3000);
1146
1147 assert_eq!(imports.len(), 3);
1148 assert_eq!(imports.get("kernel32.dll"), Some(&0x1000));
1149 assert!(imports.get("nonexistent.dll").is_none());
1150 }
1151}