From 84268bc7e392a2bf011b9c2eadeea6198e4a1463 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Wed, 2 Apr 2025 06:28:01 +0200 Subject: [PATCH] More icicle progress --- src/icicle-emulator/icicle_x64_emulator.cpp | 66 +++++++++++++++++---- src/icicle/src/icicle.rs | 24 +++++++- src/icicle/src/lib.rs | 17 ++++++ 3 files changed, 94 insertions(+), 13 deletions(-) diff --git a/src/icicle-emulator/icicle_x64_emulator.cpp b/src/icicle-emulator/icicle_x64_emulator.cpp index 3947e9bd..b202472d 100644 --- a/src/icicle-emulator/icicle_x64_emulator.cpp +++ b/src/icicle-emulator/icicle_x64_emulator.cpp @@ -7,11 +7,13 @@ using icicle_emulator = struct icicle_emulator_; extern "C" { + using raw_func = void(void*); + using ptr_func = void(void*, uint64_t); + using data_accessor_func = void(void* user, const void* data, size_t length); + using icicle_mmio_read_func = void(void* user, uint64_t address, size_t length, void* data); using icicle_mmio_write_func = void(void* user, uint64_t address, size_t length, const void* data); - using data_accessor_func = void(void* user, const void* data, size_t length); - icicle_emulator* icicle_create_emulator(); int32_t icicle_protect_memory(icicle_emulator*, uint64_t address, uint64_t length, uint8_t permissions); int32_t icicle_map_memory(icicle_emulator*, uint64_t address, uint64_t length, uint8_t permissions); @@ -22,11 +24,13 @@ extern "C" int32_t icicle_write_memory(icicle_emulator*, uint64_t address, const void* data, size_t length); int32_t icicle_save_registers(icicle_emulator*, data_accessor_func* accessor, void* accessor_data); int32_t icicle_restore_registers(icicle_emulator*, const void* data, size_t length); - uint32_t icicle_add_syscall_hook(icicle_emulator*, void (*callback)(void*), void* data); + uint32_t icicle_add_syscall_hook(icicle_emulator*, raw_func* callback, void* data); + uint32_t icicle_add_execution_hook(icicle_emulator*, ptr_func* callback, 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*); + void icicle_stop(icicle_emulator*); void icicle_destroy_emulator(icicle_emulator*); } @@ -48,6 +52,21 @@ namespace icicle using std::function::function; ~function_object() override = default; }; + + template + std::unique_ptr wrap_shared(std::shared_ptr shared_ptr) + { + struct shard_wrapper : utils::object + { + std::shared_ptr ptr{}; + ~shard_wrapper() override = default; + }; + + auto wrapper = std::make_unique(); + wrapper->ptr = std::move(shared_ptr); + + return wrapper; + } } class icicle_x64_emulator : public x64_emulator @@ -87,6 +106,7 @@ namespace icicle void stop() override { + icicle_stop(this->emu_); } void load_gdt(const pointer_type address, const uint32_t limit) override @@ -149,28 +169,30 @@ namespace icicle auto* ptr = wrapper.get(); this->storage_.push_back(std::move(wrapper)); - auto* read_wrapper = +[](void* user, const uint64_t address, const size_t length, void* data) { + auto* read_wrapper = +[](void* user, const uint64_t addr, const size_t length, void* data) { constexpr auto limit = sizeof(uint64_t); const auto* w = static_cast(user); + // TODO: Change interface to get rid of loop for (size_t offset = 0; offset < length; offset += limit) { const auto max_read = std::min(limit, length - offset); - const auto value = w->read_cb(address + offset - w->base, max_read); + const auto value = w->read_cb(addr + offset - w->base, max_read); memcpy(static_cast(data) + offset, &value, max_read); } }; - auto* write_wrapper = +[](void* user, const uint64_t address, const size_t length, const void* data) { + auto* write_wrapper = +[](void* user, const uint64_t addr, const size_t length, const void* data) { constexpr auto limit = sizeof(uint64_t); const auto* w = static_cast(user); + // TODO: Change interface to get rid of loop for (size_t offset = 0; offset < length; offset += limit) { uint64_t value{}; const auto max_read = std::min(limit, length - offset); memcpy(&value, static_cast(data) + offset, max_read); - w->write_cb(address + offset - w->base, max_read, value); + w->write_cb(addr + offset - w->base, max_read, value); } }; @@ -216,6 +238,7 @@ namespace icicle { if (static_cast(instruction_type) != x64_hookable_instructions::syscall) { + // TODO return nullptr; } @@ -235,18 +258,21 @@ namespace icicle emulator_hook* hook_basic_block(basic_block_hook_callback callback) override { + // TODO (void)callback; throw std::runtime_error("Not implemented"); } emulator_hook* hook_edge_generation(edge_generation_hook_callback callback) override { + // TODO (void)callback; throw std::runtime_error("Not implemented"); } emulator_hook* hook_interrupt(interrupt_hook_callback callback) override { + // TODO (void)callback; return nullptr; // throw std::runtime_error("Not implemented"); @@ -255,6 +281,7 @@ namespace icicle emulator_hook* hook_memory_violation(uint64_t address, size_t size, memory_violation_hook_callback callback) override { + // TODO (void)address; (void)size; (void)callback; @@ -270,11 +297,28 @@ namespace icicle return nullptr; } - (void)address; - (void)size; - (void)callback; + auto shared_callback = std::make_shared(std::move(callback)); + + if ((filter & memory_permission::exec) == memory_permission::exec) + { + if (address != 0 || size != std::numeric_limits::max()) + { + throw std::runtime_error("Not supported!"); + } + + auto* ptr = shared_callback.get(); + auto wrapper = wrap_shared(shared_callback); + auto* func = +[](void* user, const uint64_t ptr) { + (*static_cast(user))(ptr, 0, 0, memory_permission::exec); + }; + + const auto id = icicle_add_execution_hook(this->emu_, func, ptr); + this->hooks_[id] = std::move(wrapper); + + return reinterpret_cast(static_cast(id)); + } + return nullptr; - // throw std::runtime_error("Not implemented"); } void delete_hook(emulator_hook* hook) override diff --git a/src/icicle/src/icicle.rs b/src/icicle/src/icicle.rs index b1b3d9c4..c0b7a7ad 100644 --- a/src/icicle/src/icicle.rs +++ b/src/icicle/src/icicle.rs @@ -1,5 +1,5 @@ use icicle_cpu::ValueSource; -use std::collections::HashMap; +use std::{cell::RefCell, collections::HashMap, rc::Rc}; use crate::registers; @@ -133,6 +133,7 @@ pub struct IcicleEmulator { vm: icicle_vm::Vm, reg: registers::X64RegisterNodes, syscall_hooks: HookContainer, + execution_hooks: Rc>>, } pub struct MmioHandler { @@ -167,8 +168,14 @@ impl icicle_cpu::mem::IoMemory for MmioHandler { impl IcicleEmulator { pub fn new() -> Self { let mut virtual_machine = create_x64_vm(); + let exec_hooks: Rc>> = Rc::new(RefCell::new(HookContainer::new())); + + let exec_hooks_clone = Rc::clone(&exec_hooks); + let hook = icicle_cpu::InstHook::new(move |_: &mut icicle_cpu::Cpu, addr: u64| { - println!("TEST hook: {:#x}", addr); + for (_key, func) in exec_hooks_clone.borrow().get_hooks() { + func(addr); + } }); let hook = virtual_machine.cpu.add_hook(hook); @@ -178,6 +185,7 @@ impl IcicleEmulator { reg: registers::X64RegisterNodes::new(&virtual_machine.cpu.arch), vm: virtual_machine, syscall_hooks: HookContainer::new(), + execution_hooks: exec_hooks, } } @@ -186,6 +194,8 @@ impl IcicleEmulator { } pub fn start(&mut self) { + self.vm.icount_limit = u64::MAX; + loop { let reason = self.vm.run(); @@ -208,6 +218,15 @@ impl IcicleEmulator { } } + pub fn stop(&mut self) { + self.vm.icount_limit = self.vm.cpu.icount + 1; + } + + pub fn add_execution_hook(&mut self, callback: Box) -> u32 { + let hook_id = self.execution_hooks.borrow_mut().add_hook(callback); + return qualify_hook_id(hook_id, HookType::Execute); + } + pub fn add_syscall_hook(&mut self, callback: Box) -> u32 { let hook_id = self.syscall_hooks.add_hook(callback); return qualify_hook_id(hook_id, HookType::Syscall); @@ -218,6 +237,7 @@ impl IcicleEmulator { match hook_type { HookType::Syscall => self.syscall_hooks.remove_hook(hook_id), + HookType::Execute => self.execution_hooks.borrow_mut().remove_hook(hook_id), _ => {} } } diff --git a/src/icicle/src/lib.rs b/src/icicle/src/lib.rs index d12b64d5..183c2a45 100644 --- a/src/icicle/src/lib.rs +++ b/src/icicle/src/lib.rs @@ -27,7 +27,16 @@ pub fn icicle_start(ptr: *mut c_void) { } } +#[unsafe(no_mangle)] +pub fn icicle_stop(ptr: *mut c_void) { + unsafe { + let emulator = &mut *(ptr as *mut IcicleEmulator); + emulator.stop(); + } +} + type RawFunction = extern "C" fn(*mut c_void); +type PtrFunction = extern "C" fn(*mut c_void, u64); type DataFunction = extern "C" fn(*mut c_void, *const c_void, usize); type MmioReadFunction = extern "C" fn(*mut c_void, u64, usize, *mut c_void); type MmioWriteFunction = extern "C" fn(*mut c_void, u64, usize, *const c_void); @@ -138,6 +147,14 @@ pub fn icicle_add_syscall_hook(ptr: *mut c_void, callback: RawFunction, data: *m } } +#[unsafe(no_mangle)] +pub fn icicle_add_execution_hook(ptr: *mut c_void, callback: PtrFunction, data: *mut c_void) { + unsafe { + let emulator = &mut *(ptr as *mut IcicleEmulator); + emulator.add_execution_hook(Box::new(move |ptr: u64| callback(data, ptr))); + } +} + #[unsafe(no_mangle)] pub fn icicle_remove_syscall_hook(ptr: *mut c_void, id: u32) { unsafe {