From 2a74303cdc0824802540335ad392ec63f397e95c Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sat, 29 Mar 2025 10:43:59 +0100 Subject: [PATCH] Support syscall hooks --- src/icicle-emulator/icicle_x64_emulator.cpp | 35 ++++++++++++++++++--- src/icicle/src/icicle.rs | 34 ++++++++++++++++++-- src/icicle/src/lib.rs | 18 +++++++++++ 3 files changed, 80 insertions(+), 7 deletions(-) diff --git a/src/icicle-emulator/icicle_x64_emulator.cpp b/src/icicle-emulator/icicle_x64_emulator.cpp index ce50ca00..48625de4 100644 --- a/src/icicle-emulator/icicle_x64_emulator.cpp +++ b/src/icicle-emulator/icicle_x64_emulator.cpp @@ -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(instruction_type) != x64_hookable_instructions::syscall) + { + return nullptr; + } + + auto callback_store = std::make_unique>([c = std::move(callback)] { + (void)c(); // + }); + + const auto invoker = +[](void* cb) { + (*static_cast*>(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(static_cast(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(reinterpret_cast(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::unordered_map syscall_hooks_{}; icicle_emulator* emu_{}; }; diff --git a/src/icicle/src/icicle.rs b/src/icicle/src/icicle.rs index 95df2ac9..f47c3b94 100644 --- a/src/icicle/src/icicle.rs +++ b/src/icicle/src/icicle.rs @@ -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>, } 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) -> 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 { diff --git a/src/icicle/src/lib.rs b/src/icicle/src/lib.rs index b11b022f..426825b8 100644 --- a/src/icicle/src/lib.rs +++ b/src/icicle/src/lib.rs @@ -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,