use crate::{
console::Console, emu::Emu, exception::types::ExceptionType, winapi::winapi32,
winapi::winapi64, windows::constants,
};
impl Emu {
fn resolve_unix_x64_symbol(&self, addr: u64) -> String {
let symbol = if self.os.is_macos() {
self.macho64
.as_ref()
.and_then(|m| m.addr_to_symbol.get(&addr).cloned())
} else if self.os.is_linux() {
self.elf64
.as_ref()
.and_then(|elf| elf.addr_to_symbol.get(&addr).cloned())
.or_else(|| {
self.elf64
.as_ref()
.map(|elf| elf.sym_get_name_from_addr(addr))
.filter(|name| !name.is_empty())
})
} else {
None
};
symbol.unwrap_or_else(|| format!("unknown_0x{:x}", addr))
}
fn intercept_unix_x64_api_call(&mut self, addr: u64, section_name: &str) -> bool {
if self.skip_apicall {
self.its_apicall = Some(addr);
return false;
}
let symbol = self.resolve_unix_x64_symbol(addr);
log::info!(
"{}** {} API call: {} (in {}) at 0x{:x} {}",
self.colors.light_red,
self.pos,
symbol,
section_name,
addr,
self.colors.nc
);
self.gateway_return = self.stack_pop64(false).unwrap_or(0);
self.regs_mut().rip = self.gateway_return;
if self.os.is_macos() {
crate::macosapi::gateway(addr, section_name, &symbol, self);
} else if self.os.is_linux() {
crate::linuxapi::gateway(addr, section_name, &symbol, self);
}
self.force_break = true;
true
}
pub fn set_rip(&mut self, addr: u64, is_branch: bool) -> bool {
self.force_reload = true;
if addr == constants::RETURN_THREAD as u64 {
log::trace!("/!\\ Thread returned, continuing the main thread");
self.regs_mut().rip = self.main_thread_cont;
Console::spawn_console(self);
self.force_break = true;
return true;
}
let name = match self.maps.get_addr_name(addr) {
Some(n) => n.to_string(),
None => {
if self.os.is_linux() {
return false;
}
let import = self
.pe64
.as_ref()
.unwrap()
.import_addr_to_dll_and_name(addr);
if !import.is_empty() {
let (dll, api) = import.split_once('!').unwrap_or(("", ""));
if self.cfg.emulate_winapi {
self.gateway_return = self.stack_pop64(false).unwrap_or(0);
self.regs_mut().rip = self.gateway_return;
winapi64::gateway_by_import(dll, api, self);
self.force_break = true;
self.is_api_run = true;
return true;
}
self.gateway_return = self.stack_pop64(false).unwrap_or(0);
self.regs_mut().rip = self.gateway_return;
winapi64::gateway(addr, "not_loaded", self);
self.force_break = true;
self.is_api_run = true;
return true;
} else {
log::error!(
"/!\\ set_rip setting rip to non mapped addr 0x{:x} {}",
addr,
self.filename
);
self.exception(ExceptionType::SettingRipToNonMappedAddr);
return false;
}
}
};
let map_name = self.filename.as_str();
if addr < constants::LIBS64_MIN {
if self.cfg.verbose > 0 {
let rip = self.regs().rip;
let prev = self.maps.get_addr_name(rip).unwrap_or("??");
if prev != name {
log::trace!("{}:0x{:x} map change {} -> {}", self.pos, rip, prev, name);
}
}
self.regs_mut().rip = addr;
} else if self.os.is_linux() || self.os.is_macos() {
let section_name = name.to_string();
return self.intercept_unix_x64_api_call(addr, §ion_name);
} else {
if self.cfg.verbose >= 1 && !self.cfg.emulate_winapi {
log::trace!("/!\\ changing RIP to {} ", name);
}
if self.cfg.emulate_winapi {
let api_name = winapi64::kernel32::guess_api_name(self, addr);
if !api_name.is_empty() {
if self.cfg.verbose >= 1 {
log_red!(self, "emulating {}", api_name);
}
}
self.regs_mut().rip = addr;
return true;
}
if self.skip_apicall {
self.its_apicall = Some(addr);
return false;
}
self.gateway_return = self.stack_pop64(false).unwrap_or(0);
self.regs_mut().rip = self.gateway_return;
let handle_winapi: bool =
if let Some(mut hook_fn) = self.hooks.hook_on_winapi_call.take() {
let rip = self.regs().rip;
let result = hook_fn(self, rip, addr);
self.hooks.hook_on_winapi_call = Some(hook_fn);
result
} else {
true
};
if handle_winapi {
let name = self
.maps
.get_addr_name(addr)
.expect("/!\\ changing RIP to non mapped addr 0x");
winapi64::gateway(addr, name.to_string().as_str(), self);
}
self.force_break = true;
}
true
}
pub fn set_pc_aarch64(&mut self, addr: u64) -> bool {
if addr < constants::LIBS64_MIN {
self.regs_aarch64_mut().pc = addr;
return true;
}
let name = match self.maps.get_addr_name(addr) {
Some(n) => n.to_string(),
None => {
log::error!("set_pc_aarch64: addr 0x{:x} not in any mapped region", addr);
self.regs_aarch64_mut().pc = addr;
return false;
}
};
let symbol = self
.macho64
.as_ref()
.and_then(|m| m.addr_to_symbol.get(&addr).cloned())
.or_else(|| {
self.elf64
.as_ref()
.and_then(|e| e.addr_to_symbol.get(&addr).cloned())
})
.unwrap_or_else(|| format!("unknown_0x{:x}", addr));
log::info!(
"{}** {} API call: {} (in {}) at 0x{:x} {}",
self.colors.light_red,
self.pos,
symbol,
name,
addr,
self.colors.nc
);
if self.os.is_macos() {
self.regs_aarch64_mut().pc = self.regs_aarch64().x[30];
crate::macosapi::gateway(addr, &name, &symbol, self);
} else if self.os.is_linux() {
self.regs_aarch64_mut().pc = self.regs_aarch64().x[30];
crate::linuxapi::gateway(addr, &name, &symbol, self);
} else if self.os.is_windows() {
if self.cfg.emulate_winapi {
let api_name = winapi64::kernel32::guess_api_name(self, addr);
if !api_name.is_empty() {
if self.cfg.verbose >= 1 {
log_red!(self, "emulating {}", api_name);
}
}
self.regs_aarch64_mut().pc = addr;
return true;
}
if self.skip_apicall {
self.its_apicall = Some(addr);
return false;
}
self.regs_aarch64_mut().pc = self.regs_aarch64().x[30];
self.gateway_return = self.regs_aarch64().x[30];
let handle_winapi: bool =
if let Some(mut hook_fn) = self.hooks.hook_on_winapi_call.take() {
let pc = self.regs_aarch64().pc;
let result = hook_fn(self, pc, addr);
self.hooks.hook_on_winapi_call = Some(hook_fn);
result
} else {
true
};
if handle_winapi {
winapi64::gateway(addr, &name, self);
}
}
self.force_break = true;
true
}
pub fn set_eip(&mut self, addr: u64, is_branch: bool) -> bool {
self.force_reload = true;
if addr == constants::RETURN_THREAD as u64 {
log::trace!("/!\\ Thread returned, continuing the main thread");
self.regs_mut().rip = self.main_thread_cont;
Console::spawn_console(self);
self.force_break = true;
return true;
}
let name = match self.maps.get_addr_name(addr) {
Some(n) => n,
None => {
if self.os.is_linux() {
return false;
}
let api_name = self.pe32.as_ref().unwrap().import_addr_to_name(addr as u32);
if !api_name.is_empty() {
if self.cfg.emulate_winapi {
let api_name = winapi32::kernel32::guess_api_name(self, addr as u32);
if self.cfg.verbose >= 1 {
log_red!(self, "emulating {}", api_name);
}
self.regs_mut().set_eip(addr);
return true;
}
self.gateway_return = self.stack_pop32(false).unwrap_or(0) as u64;
self.regs_mut().rip = self.gateway_return;
winapi32::gateway(addr as u32, "not_loaded", self);
self.force_break = true;
self.is_api_run = true;
return true;
} else {
log::error!("/!\\ setting eip to non mapped addr 0x{:x}", addr);
self.exception(ExceptionType::SettingRipToNonMappedAddr);
return false;
}
}
};
let map_name = self.filename_to_mapname(&self.filename);
if addr < constants::LIBS32_MIN {
if self.cfg.verbose > 0 {
let eip = self.regs().get_eip();
let prev = self.maps.get_addr_name(eip).unwrap_or("??");
if prev != name {
log::trace!("{}:0x{:x} map change {} -> {}", self.pos, eip, prev, name);
}
}
self.regs_mut().set_eip(addr);
} else {
if self.cfg.verbose >= 1 && !self.cfg.emulate_winapi {
log::trace!("/!\\ changing EIP to {} 0x{:x}", name, addr);
}
if self.cfg.emulate_winapi {
let api_name = winapi32::kernel32::guess_api_name(self, addr as u32);
if !api_name.is_empty() {
if self.cfg.verbose >= 1 {
log_red!(self, "emulating {}", api_name);
}
}
self.regs_mut().set_eip(addr);
return true;
}
if self.skip_apicall {
self.its_apicall = Some(addr);
return false;
}
self.gateway_return = self.stack_pop32(false).unwrap_or(0).into();
let gateway_return = self.gateway_return;
self.regs_mut().set_eip(gateway_return);
let handle_winapi: bool =
if let Some(mut hook_fn) = self.hooks.hook_on_winapi_call.take() {
let rip = self.regs().rip;
let result = hook_fn(self, rip, addr);
self.hooks.hook_on_winapi_call = Some(hook_fn);
result
} else {
true
};
if handle_winapi {
let name = self.maps.get_addr_name(addr).unwrap();
winapi32::gateway(to32!(addr), name.to_string().as_str(), self);
}
self.force_break = true;
}
true
}
}