diff --git a/src/icicle-emulator/icicle_x64_emulator.cpp b/src/icicle-emulator/icicle_x64_emulator.cpp index ad9321ad..076aed44 100644 --- a/src/icicle-emulator/icicle_x64_emulator.cpp +++ b/src/icicle-emulator/icicle_x64_emulator.cpp @@ -6,13 +6,27 @@ using icicle_emulator = struct icicle_emulator_; extern "C" { 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); 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); void icicle_destroy_emulator(icicle_emulator*); } namespace icicle { + namespace + { + void ice(const bool result, const std::string_view error) + { + if (!result) + { + throw std::runtime_error(std::string(error)); + } + } + } + class icicle_x64_emulator : public x64_emulator { public: @@ -66,42 +80,36 @@ namespace icicle void map_memory(const uint64_t address, const size_t size, memory_permission permissions) override { const auto res = icicle_map_memory(this->emu_, address, size, static_cast(permissions)); - if (!res) - { - throw std::runtime_error("Failed to map memory"); - } + ice(res, "Failed to map memory"); } void unmap_memory(const uint64_t address, const size_t size) override { const auto res = icicle_unmap_memory(this->emu_, address, size); - if (!res) - { - throw std::runtime_error("Failed to map memory"); - } + ice(res, "Failed to unmap memory"); } bool try_read_memory(const uint64_t address, void* data, const size_t size) const override { - throw std::runtime_error("Not implemented"); + return icicle_read_memory(this->emu_, address, data, size); } void read_memory(const uint64_t address, void* data, const size_t size) const override { - if (!this->try_read_memory(address, data, size)) - { - throw std::runtime_error("Failed to read memory"); - } + const auto res = this->try_read_memory(address, data, size); + ice(res, "Failed to read memory"); } void write_memory(const uint64_t address, const void* data, const size_t size) override { - throw std::runtime_error("Not implemented"); + const auto res = icicle_write_memory(this->emu_, address, data, size); + ice(res, "Failed to write memory"); } void apply_memory_protection(const uint64_t address, const size_t size, memory_permission permissions) override { - throw std::runtime_error("Not implemented"); + const auto res = icicle_protect_memory(this->emu_, address, size, static_cast(permissions)); + ice(res, "Failed to apply permissions"); } emulator_hook* hook_instruction(int instruction_type, instruction_hook_callback callback) override diff --git a/src/icicle/.gitignore b/src/icicle/.gitignore new file mode 100644 index 00000000..31aef32c --- /dev/null +++ b/src/icicle/.gitignore @@ -0,0 +1,2 @@ +/target +/Ghidra diff --git a/src/icicle/src/icicle.rs b/src/icicle/src/icicle.rs index b9146cce..f2322da9 100644 --- a/src/icicle/src/icicle.rs +++ b/src/icicle/src/icicle.rs @@ -37,6 +37,10 @@ impl IcicleEmulator { } } + fn get_mem(&mut self) -> &mut icicle_vm::cpu::Mmu { + return &mut self.vm.cpu.mem; + } + pub fn map_memory(&mut self, address: u64, length: u64, permissions: u8) -> bool { const MAPPING_PERMISSIONS: u8 = icicle_vm::cpu::mem::perm::MAP | icicle_vm::cpu::mem::perm::INIT @@ -55,11 +59,27 @@ impl IcicleEmulator { align: 0x1000, }; - let res = self.vm.cpu.mem.alloc_memory(layout, mapping); + let res = self.get_mem().alloc_memory(layout, mapping); return res.is_ok(); } pub fn unmap_memory(&mut self, address: u64, length: u64) -> bool { - return self.vm.cpu.mem.unmap_memory_len(address, length); + return self.get_mem().unmap_memory_len(address, length); + } + + pub fn protect_memory(&mut self, address: u64, length: u64, permissions: u8) -> bool { + let native_permissions = map_permissions(permissions); + let res = self.get_mem().update_perm(address, length, native_permissions); + return res.is_ok(); + } + + pub fn write_memory(&mut self, address: u64, data: &[u8]) -> bool { + let res = self.get_mem().write_bytes(address, data, icicle_vm::cpu::mem::perm::WRITE); + return res.is_ok(); + } + + pub fn read_memory(&mut self, address: u64, data: &mut [u8]) -> bool { + let res = self.get_mem().read_bytes(address, data, icicle_vm::cpu::mem::perm::READ); + return res.is_ok(); } } diff --git a/src/icicle/src/lib.rs b/src/icicle/src/lib.rs index a766834a..0e2ef681 100644 --- a/src/icicle/src/lib.rs +++ b/src/icicle/src/lib.rs @@ -3,6 +3,14 @@ mod icicle; use icicle::IcicleEmulator; use std::os::raw::c_void; +fn to_cbool(value: bool) -> i32 { + if value { + return 1; + } + + return 0; +} + #[unsafe(no_mangle)] pub fn icicle_create_emulator() -> *mut c_void { let emulator = Box::new(IcicleEmulator::new()); @@ -10,21 +18,11 @@ pub fn icicle_create_emulator() -> *mut c_void { } #[unsafe(no_mangle)] -pub fn icicle_map_memory( - ptr: *mut c_void, - address: u64, - length: u64, - permissions: u8, -) -> i32 { +pub fn icicle_map_memory(ptr: *mut c_void, address: u64, length: u64, permissions: u8) -> i32 { unsafe { let emulator = &mut *(ptr as *mut IcicleEmulator); let res = emulator.map_memory(address, length, permissions); - - if res { - return 1; - } - - return 0; + return to_cbool(res); } } @@ -33,12 +31,38 @@ pub fn icicle_unmap_memory(ptr: *mut c_void, address: u64, length: u64) -> i32 { unsafe { let emulator = &mut *(ptr as *mut IcicleEmulator); let res = emulator.unmap_memory(address, length); + return to_cbool(res); + } +} - if res { - return 1; - } +#[unsafe(no_mangle)] +pub fn icicle_protect_memory(ptr: *mut c_void, address: u64, length: u64, permissions: u8) -> i32 { + unsafe { + let emulator = &mut *(ptr as *mut IcicleEmulator); + let res = emulator.protect_memory(address, length, permissions); + return to_cbool(res); + } +} - return 0; +#[unsafe(no_mangle)] +pub fn icicle_write_memory(ptr: *mut c_void, address: u64, data: *const c_void, size: usize) -> i32 { + unsafe { + let emulator = &mut *(ptr as *mut IcicleEmulator); + let u8_ptr = data as *const u8; + let u8_slice = std::slice::from_raw_parts(u8_ptr, size); + let res = emulator.write_memory(address, u8_slice); + return to_cbool(res); + } +} + +#[unsafe(no_mangle)] +pub fn icicle_read_memory(ptr: *mut c_void, address: u64, data: *mut c_void, size: usize) -> i32 { + unsafe { + let emulator = &mut *(ptr as *mut IcicleEmulator); + let u8_ptr = data as *mut u8; + let u8_slice = std::slice::from_raw_parts_mut(u8_ptr, size); + let res = emulator.read_memory(address, u8_slice); + return to_cbool(res); } }