Skip to content

Commit 30dfaa2

Browse files
committed
more content
1 parent 9cacd1e commit 30dfaa2

File tree

6 files changed

+115
-7
lines changed

6 files changed

+115
-7
lines changed

crates/libmwemu/src/emu/execution.rs

Lines changed: 93 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,7 @@ impl Emu {
2424

2525
/// Call a 32bits function at addr, passing argument in an array of u64 but will cast to u32.
2626
/// The calling convention is stack, like winapi32.
27-
pub fn call32(&mut self, addr: u64, args: &[u64]) -> Result<u32, MwemuError> {
28-
//TODO: why this was u64?
27+
pub fn call32(&mut self, addr: u64, args: &[u32]) -> Result<u32, MwemuError> {
2928
if addr == self.regs().get_eip() {
3029
if addr == 0 {
3130
return Err(MwemuError::new(
@@ -37,7 +36,7 @@ impl Emu {
3736
}
3837
let orig_stack = self.regs().get_esp();
3938
for arg in args.iter().rev() {
40-
self.stack_push32(*arg as u32);
39+
self.stack_push32(*arg);
4140
}
4241
let ret_addr = self.regs().get_eip();
4342
self.stack_push32(ret_addr as u32);
@@ -47,9 +46,9 @@ impl Emu {
4746
Ok(self.regs().get_eax() as u32)
4847
}
4948

50-
/// Call a 64bits function at addr, passing argument in an array of u64.
51-
/// The calling convention is registers rcx/rdx/48/r9 and then stack. Like windows64.
52-
/// Dont use for linux64 syscall like convention, on those cases craft stack/register manually.
49+
/// Call 64bits function at addr using Microsoft x64 ABI, passing argument in an array of u64.
50+
/// The calling convention is registers rcx/rdx/r8/r9 and then stack. Like windows64.
51+
/// Dont use for linux64 syscall like convention, for this is linux_call64()
5352
pub fn call64(&mut self, addr: u64, args: &[u64]) -> Result<u64, MwemuError> {
5453
if addr == self.regs().rip {
5554
if addr == 0 {
@@ -74,21 +73,109 @@ impl Emu {
7473
if n >= 4 {
7574
self.regs_mut().r9 = args[3];
7675
}
76+
77+
// stack pointer backup, for restoring when function returns.
7778
let orig_stack = self.regs().rsp;
79+
80+
// padding
81+
let extra_args = if n > 4 { (n - 4) * 8 } else { 0 };
82+
let total = extra_args + 32 + 8;
83+
let padding = (16 - (self.regs().rsp as usize + total) % 16) % 16;
84+
self.regs_mut().rsp -= padding as u64;
85+
86+
// shadow space (32bits)
87+
for _ in 0..4 {
88+
self.stack_push64(0);
89+
}
90+
91+
// stack parameters
7892
if n > 4 {
7993
for arg in args.iter().skip(4).rev() {
8094
self.stack_push64(*arg);
8195
}
8296
}
8397

98+
// return address
99+
let ret_addr = self.regs().rip;
100+
self.stack_push64(ret_addr);
101+
102+
// trigger function
103+
self.regs_mut().rip = addr;
104+
105+
// emulate the function until return address is reached
106+
self.run(Some(ret_addr))?;
107+
108+
// recover stack and return rax
109+
self.regs_mut().rsp = orig_stack;
110+
Ok(self.regs().rax)
111+
}
112+
113+
114+
/// Call a 64bits function at addr, passing arguments in an array of u64.
115+
/// The calling convention is registers RDI, RSI, RDX, RCX, R8, R9 and then stack. Like linux64.
116+
pub fn linux_call64(&mut self, addr: u64, args: &[u64]) -> Result<u64, MwemuError> {
117+
if addr == self.regs().rip {
118+
if addr == 0 {
119+
return Err(MwemuError::new(
120+
"return address reached after starting the call64, change rip.",
121+
));
122+
} else {
123+
self.regs_mut().rip = 0;
124+
}
125+
}
126+
127+
let n = args.len();
128+
if n >= 1 {
129+
self.regs_mut().rdi = args[0];
130+
}
131+
if n >= 2 {
132+
self.regs_mut().rsi = args[1];
133+
}
134+
if n >= 3 {
135+
self.regs_mut().rdx = args[2];
136+
}
137+
if n >= 4 {
138+
self.regs_mut().rcx = args[3];
139+
}
140+
if n >= 5 {
141+
self.regs_mut().r8 = args[4];
142+
}
143+
if n >= 6 {
144+
self.regs_mut().r9 = args[5];
145+
}
146+
147+
// stack pointer backup, for restoring when function returns.
148+
let orig_stack = self.regs().rsp;
149+
150+
// padding
151+
let extra_args = if n > 6 { (n - 6) * 8 } else { 0 };
152+
let total = extra_args + 8;
153+
let padding = (16 - (self.regs().rsp as usize + total) % 16) % 16;
154+
self.regs_mut().rsp -= padding as u64;
155+
156+
// stack parameters
157+
if n > 6 {
158+
for arg in args.iter().skip(6).rev() {
159+
self.stack_push64(*arg);
160+
}
161+
}
162+
163+
// return address
84164
let ret_addr = self.regs().rip;
85165
self.stack_push64(ret_addr);
166+
167+
// trigger function
86168
self.regs_mut().rip = addr;
169+
170+
// emulate the function until return address is reached
87171
self.run(Some(ret_addr))?;
172+
173+
// recover stack and return rax
88174
self.regs_mut().rsp = orig_stack;
89175
Ok(self.regs().rax)
90176
}
91177

178+
92179
/// Start emulation until a ret instruction is found.
93180
/// It will return the address or MwemuError.
94181
#[inline]
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
use crate::tests::helpers;
2+
use crate::*;
3+
4+
#[test]
5+
// this tests a linux 64bits flags
6+
pub fn call32() {
7+
helpers::setup();
8+
9+
let mut emu = emu32();
10+
let opcodes: Vec<u8> = vec![
11+
0x55, 0x48, 0x89, 0xe5, 0x89, 0x7d, 0xfc, 0x89,
12+
0x75, 0xf8, 0x8b, 0x55, 0xfc, 0x8b, 0x45, 0xf8,
13+
0x01, 0xd0, 0x5d, 0xc3,
14+
];
15+
E emu.load_bytes(opcodes);
16+
17+
18+
}

crates/libmwemu/src/tests/call64.rs

Whitespace-only changes.

crates/libmwemu/src/tests/linux_call64.rs

Whitespace-only changes.

crates/libmwemu/src/tests/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,6 @@ mod stress_shl2p_all;
4545
mod stress_shl2p_trigger;
4646
mod stress_shr2p_all;
4747
mod test_unified_step_and_run_methods;
48+
mod call32;
49+
mod call64;
50+
mod linux_call64;

crates/pymwemu/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,7 @@ impl Emu {
409409
}
410410

411411
/// call a 32bits function, internally pushes params in reverse order.
412-
fn call32(&mut self, address: u64, params: Vec<u64>) -> PyResult<u32> {
412+
fn call32(&mut self, address: u64, params: Vec<u32>) -> PyResult<u32> {
413413
match self.emu.call32(address, &params) {
414414
Ok(pc) => Ok(pc),
415415
Err(e) => Err(PyValueError::new_err(e.message)),

0 commit comments

Comments
 (0)