Skip to content

Commit 618bcd6

Browse files
committed
iat binding alternative method, when original first thunk is zero
1 parent f0c39b3 commit 618bcd6

File tree

7 files changed

+174
-45
lines changed

7 files changed

+174
-45
lines changed

Cargo.lock

Lines changed: 2 additions & 21 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

libmwemu/src/emu/fpu.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ pub struct FPU {
2323
pub f_c3: bool, // precission
2424
pub f_c4: bool, // stack fault
2525
pub mxcsr: u32,
26+
pub fpu_control_word: u16,
2627
}
2728

2829
impl Default for FPU {
@@ -55,6 +56,7 @@ impl FPU {
5556
f_c3: false, // precision
5657
f_c4: false, // stack fault
5758
mxcsr: 0,
59+
fpu_control_word: 0,
5860
}
5961
}
6062

@@ -74,6 +76,7 @@ impl FPU {
7476
self.reserved = [0; 14];
7577
self.reserved2 = [0; 96];
7678
self.xmm = [0; 16];
79+
self.fpu_control_word = 0;
7780
}
7881

7982
pub fn set_ctrl(&mut self, ctrl: u16) {

libmwemu/src/emu/mod.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13299,6 +13299,15 @@ impl Emu {
1329913299
self.fpu.mxcsr = value as u32;
1330013300
}
1330113301

13302+
Mnemonic::Fnstcw => {
13303+
self.show_instruction(&self.colors.red, ins);
13304+
13305+
let addr = self.get_operand_value(ins, 0, false).unwrap_or(0);
13306+
if addr > 0 {
13307+
self.maps.write_word(addr, self.fpu.fpu_control_word);
13308+
}
13309+
}
13310+
1330213311
Mnemonic::Prefetchw => {
1330313312
self.show_instruction(&self.colors.red, ins);
1330413313
}

libmwemu/src/emu/pe64.rs

Lines changed: 56 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -513,39 +513,75 @@ impl PE64 {
513513
}
514514

515515
pub fn iat_binding(&mut self, emu: &mut emu::Emu) {
516-
// TODO: refactor this, instead of patching the raw and the loading it, do the iat_binding
517-
// after the loading, in this way its possible to use virtual addreses instad of calculate
518-
// the offset on the raw blob
519-
520516
// https://docs.microsoft.com/en-us/archive/msdn-magazine/2002/march/inside-windows-an-in-depth-look-into-the-win32-portable-executable-file-format-part-2#Binding
521517

522-
log::info!(
523-
"IAT binding started image_import_descriptor.len() = {} ...",
524-
self.image_import_descriptor.len()
525-
);
526-
let mut flipflop;
518+
if emu.cfg.verbose >= 1 {
519+
log::info!(
520+
"IAT binding started image_import_descriptor.len() = {} ...",
521+
self.image_import_descriptor.len()
522+
);
523+
}
527524

528525
for i in 0..self.image_import_descriptor.len() {
529526
let iim = &self.image_import_descriptor[i];
530527

531528
if iim.name.is_empty() {
532529
continue;
533530
}
534-
535531
if emu::winapi64::kernel32::load_library(emu, &iim.name) == 0 {
536532
log::info!("cannot found the library {} on maps64/", &iim.name);
537533
return;
538534
}
539535

540-
// Walking function names.
541-
let mut off_name =
542-
PE32::vaddr_to_off(&self.sect_hdr, iim.original_first_thunk) as usize;
536+
if iim.original_first_thunk == 0 {
537+
self.iat_binding_alternative(emu, iim.first_thunk);
538+
} else {
539+
self.iat_binding_original(emu, iim.original_first_thunk, iim.first_thunk);
540+
}
543541

544-
//log::info!("----> 0x{:x}", iim.first_thunk);
545-
let mut off_addr = PE32::vaddr_to_off(&self.sect_hdr, iim.first_thunk) as usize;
546-
//off_addr += 8;
542+
}
543+
log::info!("IAT Bound.");
544+
}
545+
546+
pub fn iat_binding_alternative(&mut self, emu: &mut emu::Emu, first_thunk: u32) {
547+
// this function is called for every DLL that in iat.
548+
549+
let mut off = PE32::vaddr_to_off(&self.sect_hdr, first_thunk) as usize;
550+
let ordinal:u16;
551+
552+
loop {
553+
let entry = read_u64_le!(self.raw, off);
554+
if entry == 0 {
555+
break;
556+
}
557+
if (entry & 0x80000000_00000000) != 0 {
558+
ordinal = (entry & 0xFFFF) as u16;
559+
println!("---- ordinal: {}", ordinal);
560+
unimplemented!("third variation of iat binding not implemented");
561+
562+
} else {
563+
let name_rva = entry as u32;
564+
let name_off = PE32::vaddr_to_off(&self.sect_hdr, name_rva) as usize;
565+
let api_name = PE32::read_string(&self.raw, name_off+2);
566+
567+
let real_addr = emu::winapi64::kernel32::resolve_api_name(emu, &api_name);
568+
if real_addr > 0 {
569+
write_u64_le!(self.raw, off, real_addr); // patch the IAT to do the binding
570+
}
571+
}
572+
573+
574+
off += 8;
575+
}
576+
}
577+
578+
pub fn iat_binding_original(&mut self, emu: &mut emu::Emu, original_first_thunk: u32, first_thunk: u32) {
579+
// this function is called for every DLL in iat.
547580

548-
flipflop = false;
581+
let mut off_name =
582+
PE32::vaddr_to_off(&self.sect_hdr, original_first_thunk) as usize;
583+
let mut off_addr = PE32::vaddr_to_off(&self.sect_hdr, first_thunk) as usize;
584+
let mut flipflop = false;
549585

550586
loop {
551587
if self.raw.len() <= off_name + 4 || self.raw.len() <= off_addr + 8 {
@@ -555,10 +591,9 @@ impl PE64 {
555591
let hint = pe32::HintNameItem::load(&self.raw, off_name);
556592
let addr = read_u32_le!(self.raw, off_addr); // & 0b01111111_11111111_11111111_11111111;
557593
let off2 = PE32::vaddr_to_off(&self.sect_hdr, hint.func_name_addr) as usize;
594+
558595
if off2 == 0 {
559-
//|| addr < 0x100 {
560596
off_name += pe32::HintNameItem::size();
561-
//off_addr += 8;
562597
if flipflop {
563598
break;
564599
}
@@ -567,6 +602,7 @@ impl PE64 {
567602
}
568603
flipflop = false;
569604
let func_name = PE32::read_string(&self.raw, off2 + 2);
605+
//println!("resolving func_name: {}", func_name);
570606
let real_addr = emu::winapi64::kernel32::resolve_api_name(emu, &func_name);
571607
if real_addr == 0 {
572608
break;
@@ -579,14 +615,12 @@ impl PE64 {
579615
let fake_addr = read_u64_le!(self.raw, off_addr);
580616

581617
//println!("writing real_addr: 0x{:x} {} 0x{:x} -> 0x{:x} ", off_addr, func_name, fake_addr, real_addr);
582-
583618
write_u64_le!(self.raw, off_addr, real_addr);
584619

585620
off_name += pe32::HintNameItem::size();
586621
off_addr += 8;
587622
}
588-
}
589-
log::info!("IAT Bound.");
623+
590624
}
591625

592626
pub fn import_addr_to_name(&self, paddr: u64) -> String {

libmwemu/src/emu/winapi64/kernel32.rs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,8 @@ pub fn gateway(addr: u64, emu: &mut emu::Emu) -> String {
135135
"GetNativeSystemInfo" => GetNativeSystemInfo(emu),
136136
"lstrcpyW" => lstrcpyW(emu),
137137
"lstrcpy" => lstrcpy(emu),
138+
"GetModuleHandleA" => GetModuleHandleA(emu),
139+
"GetModuleHandleW" => GetModuleHandleW(emu),
138140

139141
_ => {
140142
log::info!(
@@ -352,6 +354,35 @@ pub fn load_library(emu: &mut emu::Emu, libname: &str) -> u64 {
352354
}
353355
}
354356

357+
pub fn get_library_handle(emu: &mut emu::Emu, libname: &str) -> u64 {
358+
// log::info!("kern32!load_library: {}", libname);
359+
360+
let mut dll = libname.to_string().to_lowercase();
361+
362+
if dll.is_empty() {
363+
emu.regs.rax = 0;
364+
return 0;
365+
}
366+
367+
if !dll.ends_with(".dll") {
368+
dll.push_str(".dll");
369+
}
370+
371+
let mut dll_path = emu.cfg.maps_folder.clone();
372+
dll_path.push('/');
373+
dll_path.push_str(&dll);
374+
375+
match peb64::get_module_base(&dll, emu) {
376+
Some(base) => {
377+
return base;
378+
}
379+
None => {
380+
// if is not linked, dont link, this is not a load_library
381+
return 0;
382+
}
383+
}
384+
}
385+
355386
fn LoadLibraryA(emu: &mut emu::Emu) {
356387
let dllptr = emu.regs.rcx;
357388
let dll = emu.maps.read_string(dllptr);
@@ -2734,3 +2765,36 @@ pub fn FindActCtxSectionStringW(emu: &mut emu::Emu) {
27342765

27352766
emu.regs.rax = 0;
27362767
}
2768+
2769+
fn GetModuleHandleA(emu: &mut emu::Emu) {
2770+
let module_name = emu.maps.read_string(emu.regs.rcx);
2771+
let handle = get_library_handle(emu, &module_name);
2772+
2773+
log::info!(
2774+
"{}** {} kernel32!GetModuleHandleA module_name: {} handle: 0x{:x} {}",
2775+
emu.colors.light_red,
2776+
emu.pos,
2777+
module_name,
2778+
handle,
2779+
emu.colors.nc
2780+
);
2781+
2782+
emu.regs.rax = handle;
2783+
}
2784+
2785+
fn GetModuleHandleW(emu: &mut emu::Emu) {
2786+
let module_name = emu.maps.read_wide_string(emu.regs.rcx);
2787+
let handle = get_library_handle(emu, &module_name);
2788+
2789+
log::info!(
2790+
"{}** {} kernel32!GetModuleHandleW module_name: {} handle: 0x{:x} {}",
2791+
emu.colors.light_red,
2792+
emu.pos,
2793+
module_name,
2794+
handle,
2795+
emu.colors.nc
2796+
);
2797+
2798+
emu.regs.rax = handle;
2799+
}
2800+

pymwemu/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,5 @@ crate-type = ["cdylib"]
1212
[dependencies]
1313
pyo3 = "0.18.1"
1414
env_logger = "0.11.6"
15-
#libmwemu = { path = "../libmwemu" }
16-
libmwemu = "0.19.4"
15+
libmwemu = { path = "../libmwemu" }
16+
#libmwemu = "0.19.4"

scripts/enigma2.sh

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#!/bin/bash
2+
3+
set -x
4+
5+
export RUST_BACKTRACE=1
6+
export RUST_LOG=info
7+
8+
cargo run --release \
9+
--target x86_64-apple-darwin \
10+
-- \
11+
--filename ~/Downloads/enigma/surprise.dll \
12+
--maps ./maps64 \
13+
--64bits \
14+
--trace_start 0xD950920 \
15+
--trace /tmp/output.csv \
16+
--memory \
17+
--mxcsr 0x1FC00001FA0 \
18+
--stack_address 0x32C6FE000 \
19+
--exit 0xD95092E \
20+
--base 0x7FFBFA260000 \
21+
--entry 0x7FFBFB295FF0 \
22+
--rax 0x7FFBFB295FF0 \
23+
--rbx 0x7FFE0385 \
24+
--rcx 0x7FFBFA260000 \
25+
--rdx 0x1 \
26+
--rsp 0x32C6FE378 \
27+
--rbp 0x32C6FE6B8 \
28+
--rsi 0x1 \
29+
--rdi 0x7FFE0384 \
30+
--r8 0x0 \
31+
--r9 0x0 \
32+
--r10 0xA440AE23305F3A70 \
33+
--r11 0x32C6FE3E8 \
34+
--r12 0x7FFBFB295FF0 \
35+
--r13 0x120136C63F0 \
36+
--r14 0x7FFBFA260000 \
37+
--r15 0x0 \
38+
--rflags 0x344

0 commit comments

Comments
 (0)