Support syscall hooks

This commit is contained in:
momo5502
2025-03-29 10:43:59 +01:00
parent 637ed75b8c
commit 2a74303cdc
3 changed files with 80 additions and 7 deletions

View File

@@ -11,6 +11,8 @@ extern "C"
int32_t icicle_unmap_memory(icicle_emulator*, uint64_t address, uint64_t length);
int32_t icicle_read_memory(icicle_emulator*, uint64_t address, void* data, size_t length);
int32_t icicle_write_memory(icicle_emulator*, uint64_t address, const void* data, size_t length);
uint32_t icicle_add_syscall_hook(icicle_emulator*, void (*callback)(void*), void* data);
void icicle_remove_syscall_hook(icicle_emulator*, uint32_t id);
size_t icicle_read_register(icicle_emulator*, int reg, void* data, size_t length);
size_t icicle_write_register(icicle_emulator*, int reg, const void* data, size_t length);
void icicle_start(icicle_emulator*);
@@ -111,7 +113,7 @@ namespace icicle
void map_mmio(const uint64_t address, const size_t size, mmio_read_callback read_cb,
mmio_write_callback write_cb) override
{
return;
this->map_memory(address, size, memory_permission::read_write);
// throw std::runtime_error("Not implemented");
}
@@ -152,8 +154,23 @@ namespace icicle
emulator_hook* hook_instruction(int instruction_type, instruction_hook_callback callback) override
{
return nullptr;
// throw std::runtime_error("Not implemented");
if (static_cast<x64_hookable_instructions>(instruction_type) != x64_hookable_instructions::syscall)
{
return nullptr;
}
auto callback_store = std::make_unique<std::function<void()>>([c = std::move(callback)] {
(void)c(); //
});
const auto invoker = +[](void* cb) {
(*static_cast<std::function<void()>*>(cb))(); //
};
const auto id = icicle_add_syscall_hook(this->emu_, invoker, callback_store.get());
this->syscall_hooks_[id] = std::move(callback_store);
return reinterpret_cast<emulator_hook*>(static_cast<size_t>(id));
}
emulator_hook* hook_basic_block(basic_block_hook_callback callback) override
@@ -195,7 +212,15 @@ namespace icicle
void delete_hook(emulator_hook* hook) override
{
// throw std::runtime_error("Not implemented");
const auto id = static_cast<uint32_t>(reinterpret_cast<size_t>(hook));
const auto entry = this->syscall_hooks_.find(id);
if (entry == this->syscall_hooks_.end())
{
return;
}
icicle_remove_syscall_hook(this->emu_, id);
this->syscall_hooks_.erase(entry);
}
void serialize_state(utils::buffer_serializer& buffer, const bool is_snapshot) const override
@@ -225,6 +250,8 @@ namespace icicle
}
private:
using syscall_hook_storage = std::unique_ptr<std::function<void()>>;
std::unordered_map<uint32_t, syscall_hook_storage> syscall_hooks_{};
icicle_emulator* emu_{};
};

View File

@@ -1,4 +1,5 @@
use icicle_cpu::ValueSource;
use std::collections::HashMap;
fn create_x64_vm() -> icicle_vm::Vm {
let cpu_config = icicle_vm::cpu::Config::from_target_triple("x86_64-none");
@@ -31,6 +32,9 @@ fn map_permissions(foreign_permissions: u8) -> u8 {
pub struct IcicleEmulator {
vm: icicle_vm::Vm,
reg: X64RegisterNodes,
syscall_hook_id: u32,
syscall_hooks: HashMap<u32, Box<dyn Fn()>>,
}
impl IcicleEmulator {
@@ -39,6 +43,8 @@ impl IcicleEmulator {
Self {
reg: X64RegisterNodes::new(&vm_i.cpu.arch),
vm: vm_i,
syscall_hook_id: 0,
syscall_hooks: HashMap::new(),
}
}
@@ -47,11 +53,33 @@ impl IcicleEmulator {
}
pub fn start(&mut self) {
self.vm.run();
loop {
let reason = self.vm.run();
let invoke_syscall = match reason {
icicle_vm::VmExit::UnhandledException((code, _)) => code == icicle_cpu::ExceptionCode::Syscall,
_ => false,
};
if !invoke_syscall {
break;
}
for (_key, func) in &self.syscall_hooks {
func();
}
}
}
pub fn stop(&mut self) {
//self.vm.stop();
pub fn add_syscall_hook(&mut self, callback: Box<dyn Fn()>) -> u32 {
self.syscall_hook_id += 1;
let id = self.syscall_hook_id;
self.syscall_hooks.insert(id, callback);
return id;
}
pub fn remove_syscall_hook(&mut self, id: u32) {
self.syscall_hooks.remove(&id);
}
pub fn map_memory(&mut self, address: u64, length: u64, permissions: u8) -> bool {

View File

@@ -77,6 +77,24 @@ pub fn icicle_read_memory(ptr: *mut c_void, address: u64, data: *mut c_void, siz
}
}
type CFunctionPointer = extern "C" fn(*mut c_void);
#[unsafe(no_mangle)]
pub fn icicle_add_syscall_hook(ptr: *mut c_void, callback: CFunctionPointer, data: *mut c_void) {
unsafe {
let emulator = &mut *(ptr as *mut IcicleEmulator);
emulator.add_syscall_hook(Box::new(move || callback(data)));
}
}
#[unsafe(no_mangle)]
pub fn icicle_remove_syscall_hook(ptr: *mut c_void, id: u32) {
unsafe {
let emulator = &mut *(ptr as *mut IcicleEmulator);
emulator.remove_syscall_hook(id);
}
}
#[unsafe(no_mangle)]
pub fn icicle_read_register(
ptr: *mut c_void,