use crate::emu::Emu;
use crate::err::MwemuError;
const MAX_CALL_DEPTH: u32 = 32;
impl Emu {
pub fn call32(&mut self, addr: u64, args: &[u32]) -> Result<u32, MwemuError> {
if addr == self.regs().get_eip() {
if addr == 0 {
return Err(MwemuError::new(
"return address reached after starting the call32, change eip.",
));
} else {
self.regs_mut().rip = 0;
}
}
let orig_stack = self.regs().get_esp();
for arg in args.iter().rev() {
self.stack_push32(*arg);
}
let ret_addr = self.regs().get_eip();
self.stack_push32(ret_addr as u32);
self.regs_mut().set_eip(addr);
if self.call_depth >= MAX_CALL_DEPTH {
return Err(MwemuError::new("call depth limit reached"));
}
self.call_depth += 1;
let result = self.run(Some(ret_addr));
self.call_depth -= 1;
result?;
self.regs_mut().set_esp(orig_stack);
Ok(self.regs().get_eax() as u32)
}
pub fn call64(&mut self, addr: u64, args: &[u64]) -> Result<u64, MwemuError> {
if addr == self.regs().rip {
if addr == 0 {
return Err(MwemuError::new(
"return address reached after starting the call64, change rip.",
));
} else {
self.regs_mut().rip = 0;
}
}
let n = args.len();
if n >= 1 {
self.regs_mut().rcx = args[0];
}
if n >= 2 {
self.regs_mut().rdx = args[1];
}
if n >= 3 {
self.regs_mut().r8 = args[2];
}
if n >= 4 {
self.regs_mut().r9 = args[3];
}
let orig_stack = self.regs().rsp;
let extra_args = if n > 4 { (n - 4) * 8 } else { 0 };
let total = extra_args + 32 + 8;
let padding = (16 - (self.regs().rsp as usize + total) % 16) % 16;
self.regs_mut().rsp -= padding as u64;
for _ in 0..4 {
self.stack_push64(0);
}
if n > 4 {
for arg in args.iter().skip(4).rev() {
self.stack_push64(*arg);
}
}
let ret_addr = self.regs().rip;
self.stack_push64(ret_addr);
self.regs_mut().rip = addr;
if self.call_depth >= MAX_CALL_DEPTH {
return Err(MwemuError::new("call depth limit reached"));
}
self.call_depth += 1;
let result = self.run(Some(ret_addr));
self.call_depth -= 1;
result?;
self.regs_mut().rsp = orig_stack;
Ok(self.regs().rax)
}
pub fn linux_call64(&mut self, addr: u64, args: &[u64]) -> Result<u64, MwemuError> {
if addr == self.regs().rip {
if addr == 0 {
return Err(MwemuError::new(
"return address reached after starting the call64, change rip.",
));
} else {
self.regs_mut().rip = 0;
}
}
let n = args.len();
if n >= 1 {
self.regs_mut().rdi = args[0];
}
if n >= 2 {
self.regs_mut().rsi = args[1];
}
if n >= 3 {
self.regs_mut().rdx = args[2];
}
if n >= 4 {
self.regs_mut().rcx = args[3];
}
if n >= 5 {
self.regs_mut().r8 = args[4];
}
if n >= 6 {
self.regs_mut().r9 = args[5];
}
let orig_stack = self.regs().rsp;
let extra_args = if n > 6 { (n - 6) * 8 } else { 0 };
let total = extra_args + 8;
let padding = (16 - (self.regs().rsp as usize + total) % 16) % 16;
self.regs_mut().rsp -= padding as u64;
if n > 6 {
for arg in args.iter().skip(6).rev() {
self.stack_push64(*arg);
}
}
let ret_addr = self.regs().rip;
self.stack_push64(ret_addr);
self.regs_mut().rip = addr;
if self.call_depth >= MAX_CALL_DEPTH {
return Err(MwemuError::new("call depth limit reached"));
}
self.call_depth += 1;
let result = self.run(Some(ret_addr));
self.call_depth -= 1;
result?;
self.regs_mut().rsp = orig_stack;
Ok(self.regs().rax)
}
}