1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
use crate::color;
use crate::emu::Emu;
use crate::winapi::{winapi32, winapi64};
use crate::windows::constants::{LIBS64_MAX, LIBS64_MIN};
use iced_x86::Instruction;
pub fn execute(emu: &mut Emu, ins: &Instruction, instruction_sz: usize, _rep_step: bool) -> bool {
emu.show_instruction(
color!("Yellow"),
&crate::emu::decoded_instruction::DecodedInstruction::X86(*ins),
);
if ins.op_count() != 1 {
unimplemented!("weird variant of call");
}
let addr = match emu.get_jump_value(ins, 0) {
Some(a) => a,
None => return false,
};
if emu.cfg.trace_calls {
let callee_sym = if emu.cfg.is_x64() {
winapi64::kernel32::guess_api_name(emu, addr)
} else {
winapi32::kernel32::guess_api_name(emu, addr as u32)
};
let callee_note = if callee_sym.is_empty() {
String::new()
} else {
format!(" {}", callee_sym)
};
log::trace!(
"{} 0x{:x} CALL 0x{:x}{} (0x{:x}, 0x{:x}, 0x{:x})",
emu.pos,
emu.regs().rip,
addr,
callee_note,
emu.regs().rcx,
emu.regs().rdx,
emu.regs().r8
);
}
/*
if emu.regs_mut().rip == addr - 5 && emu.cfg.verbose >= 1 {
log::trace!("call next instruction, prolly call/pop");
}
*/
//emu.stack_lvl[emu.stack_lvl_idx] -= 1;
/*else {
emu.stack_lvl.push(0);
emu.stack_lvl_idx += 1;
}*/
let rip = emu.regs().rip;
emu.call_stack_mut().push((rip, addr));
if emu.cfg.is_x64() {
// SSDT shadow-space padding: real-Windows DLLs use the caller's 32-byte
// home space (`[rsp+0x00..rsp+0x20]`) as scratch (e.g. KernelBase spills
// `rsi` to `[rsp+0x10]`). Hand-written PE x64 binaries that store data
// inside what would be their *callee's* home — like exe64win_msgbox,
// which keeps a saved RSP at `[rbp-0x48]` directly overlapping the R8
// home — get those locals trashed by the very first DLL call. Shift
// the home-space window down by 0x20 only on PE→real-DLL transitions;
// a matching RET (back to PE) unwinds the pad in `ret.rs`.
let pad_call = emu.cfg.emulate_winapi
&& rip < LIBS64_MIN
&& (LIBS64_MIN..=LIBS64_MAX).contains(&addr)
&& emu.maps.is_mapped(addr);
if pad_call {
emu.regs_mut().rsp = emu.regs().rsp.wrapping_sub(0x20);
let expected_ra = rip + instruction_sz as u64;
emu.ssdt_pad_stack.push(expected_ra);
}
if !emu.stack_push64(emu.regs().rip + instruction_sz as u64) {
return false;
}
emu.set_rip(addr, false)
} else {
if !emu.stack_push32(emu.regs().get_eip() as u32 + instruction_sz as u32) {
return false;
}
emu.set_eip(addr, false)
}
//true
}