mirror of
https://github.com/momo5502/emulator.git
synced 2026-01-18 19:23:56 +00:00
Icicle progress
This commit is contained in:
committed by
momo5502
parent
985dd49059
commit
63f54df78c
@@ -1,14 +1,182 @@
|
||||
#define ICICLE_EMULATOR_IMPL
|
||||
#include "icicle_x64_emulator.hpp"
|
||||
|
||||
extern "C" void test_rust();
|
||||
using icicle_emulator = struct icicle_emulator_;
|
||||
|
||||
extern "C"
|
||||
{
|
||||
icicle_emulator* icicle_create_emulator();
|
||||
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);
|
||||
void icicle_destroy_emulator(icicle_emulator*);
|
||||
}
|
||||
|
||||
namespace icicle
|
||||
{
|
||||
class icicle_x64_emulator : public x64_emulator
|
||||
{
|
||||
public:
|
||||
icicle_x64_emulator()
|
||||
: emu_(icicle_create_emulator())
|
||||
{
|
||||
if (!this->emu_)
|
||||
{
|
||||
throw std::runtime_error("Failed to create icicle emulator instance");
|
||||
}
|
||||
}
|
||||
|
||||
~icicle_x64_emulator() override
|
||||
{
|
||||
if (this->emu_)
|
||||
{
|
||||
icicle_destroy_emulator(this->emu_);
|
||||
this->emu_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void start(const uint64_t start, const uint64_t end, std::chrono::nanoseconds timeout,
|
||||
const size_t count) override
|
||||
{
|
||||
if (timeout.count() < 0)
|
||||
{
|
||||
timeout = {};
|
||||
}
|
||||
}
|
||||
|
||||
void stop() override
|
||||
{
|
||||
}
|
||||
|
||||
size_t write_raw_register(const int reg, const void* value, const size_t size) override
|
||||
{
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
|
||||
size_t read_raw_register(const int reg, void* value, const size_t size) override
|
||||
{
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
|
||||
void map_mmio(const uint64_t address, const size_t size, mmio_read_callback read_cb,
|
||||
mmio_write_callback write_cb) override
|
||||
{
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
|
||||
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<uint8_t>(permissions));
|
||||
if (!res)
|
||||
{
|
||||
throw std::runtime_error("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");
|
||||
}
|
||||
}
|
||||
|
||||
bool try_read_memory(const uint64_t address, void* data, const size_t size) const override
|
||||
{
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
void write_memory(const uint64_t address, const void* data, const size_t size) override
|
||||
{
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
|
||||
void apply_memory_protection(const uint64_t address, const size_t size, memory_permission permissions) override
|
||||
{
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
|
||||
emulator_hook* hook_instruction(int instruction_type, instruction_hook_callback callback) override
|
||||
{
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
|
||||
emulator_hook* hook_basic_block(basic_block_hook_callback callback) override
|
||||
{
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
|
||||
emulator_hook* hook_edge_generation(edge_generation_hook_callback callback) override
|
||||
{
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
|
||||
emulator_hook* hook_interrupt(interrupt_hook_callback callback) override
|
||||
{
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
|
||||
emulator_hook* hook_memory_violation(uint64_t address, size_t size,
|
||||
memory_violation_hook_callback callback) override
|
||||
{
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
|
||||
emulator_hook* hook_memory_access(const uint64_t address, const size_t size, const memory_operation filter,
|
||||
complex_memory_hook_callback callback) override
|
||||
{
|
||||
if (filter == memory_permission::none)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
|
||||
void delete_hook(emulator_hook* hook) override
|
||||
{
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
|
||||
void serialize_state(utils::buffer_serializer& buffer, const bool is_snapshot) const override
|
||||
{
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
|
||||
void deserialize_state(utils::buffer_deserializer& buffer, const bool is_snapshot) override
|
||||
{
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
|
||||
std::vector<std::byte> save_registers() override
|
||||
{
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
|
||||
void restore_registers(const std::vector<std::byte>& register_data) override
|
||||
{
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
|
||||
bool has_violation() const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
icicle_emulator* emu_{};
|
||||
};
|
||||
|
||||
std::unique_ptr<x64_emulator> create_x64_emulator()
|
||||
{
|
||||
test_rust();
|
||||
|
||||
return {};
|
||||
return std::make_unique<icicle_x64_emulator>();
|
||||
}
|
||||
}
|
||||
|
||||
65
src/icicle/src/icicle.rs
Normal file
65
src/icicle/src/icicle.rs
Normal file
@@ -0,0 +1,65 @@
|
||||
fn create_x64_vm() -> icicle_vm::Vm {
|
||||
let cpu_config = icicle_vm::cpu::Config::from_target_triple("x86_64-none");
|
||||
let vm = icicle_vm::build(&cpu_config).unwrap();
|
||||
return vm;
|
||||
}
|
||||
|
||||
fn map_permissions(foreign_permissions: u8) -> u8 {
|
||||
const FOREIGN_READ: u8 = 1 << 0;
|
||||
const FOREIGN_WRITE: u8 = 1 << 1;
|
||||
const FOREIGN_EXEC: u8 = 1 << 2;
|
||||
|
||||
let mut permissions: u8 = 0;
|
||||
|
||||
if (foreign_permissions & FOREIGN_READ) != 0 {
|
||||
permissions |= icicle_vm::cpu::mem::perm::READ;
|
||||
}
|
||||
|
||||
if (foreign_permissions & FOREIGN_WRITE) != 0 {
|
||||
permissions |= icicle_vm::cpu::mem::perm::WRITE;
|
||||
}
|
||||
|
||||
if (foreign_permissions & FOREIGN_EXEC) != 0 {
|
||||
permissions |= icicle_vm::cpu::mem::perm::EXEC;
|
||||
}
|
||||
|
||||
return permissions;
|
||||
}
|
||||
|
||||
pub struct IcicleEmulator {
|
||||
vm: icicle_vm::Vm,
|
||||
}
|
||||
|
||||
impl IcicleEmulator {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
vm: create_x64_vm(),
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
| icicle_vm::cpu::mem::perm::IN_CODE_CACHE;
|
||||
|
||||
let native_permissions = map_permissions(permissions);
|
||||
|
||||
let mapping = icicle_vm::cpu::mem::Mapping {
|
||||
perm: native_permissions | MAPPING_PERMISSIONS,
|
||||
value: 0x0,
|
||||
};
|
||||
|
||||
let layout = icicle_vm::cpu::mem::AllocLayout {
|
||||
addr: Some(address),
|
||||
size: length,
|
||||
align: 0x1000,
|
||||
};
|
||||
|
||||
let res = self.vm.cpu.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);
|
||||
}
|
||||
}
|
||||
@@ -1,58 +1,54 @@
|
||||
mod icicle;
|
||||
|
||||
use icicle::IcicleEmulator;
|
||||
use std::os::raw::c_void;
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub fn test_rust() {
|
||||
// Setup the CPU state for the target triple
|
||||
let cpu_config = icicle_vm::cpu::Config::from_target_triple("x86_64-none");
|
||||
let mut vm = icicle_vm::build(&cpu_config).unwrap();
|
||||
|
||||
// Setup an environment to run inside of.
|
||||
//let mut env = icicle_vm::env::build_auto(&mut vm).unwrap();
|
||||
// Load a binary into the environment.
|
||||
//env.load(&mut vm.cpu, b"./test.elf").unwrap();
|
||||
//vm.env = env;
|
||||
|
||||
let mapping = icicle_vm::cpu::mem::Mapping { perm: icicle_vm::cpu::mem::perm::ALL, value: 0x0 };
|
||||
|
||||
let alloc1 =
|
||||
vm.cpu.mem.alloc_memory(icicle_vm::cpu::mem::AllocLayout { addr: Some(0x10000), size: 0x100, align: 0x100 }, mapping).unwrap();
|
||||
|
||||
// Add instrumentation
|
||||
let counter = vm.cpu.trace.register_store(vec![0_u64]);
|
||||
vm.add_injector(BlockCounter { counter });
|
||||
|
||||
// Run until the VM exits.
|
||||
let exit = vm.run();
|
||||
println!("{exit:?}\n{}", icicle_vm::debug::current_disasm(&mut vm));
|
||||
|
||||
|
||||
// Read instrumentation data.
|
||||
let blocks_hit = vm.cpu.trace[counter].as_any().downcast_ref::<Vec<u64>>().unwrap()[0];
|
||||
let blocks_executed = blocks_hit.saturating_sub(1);
|
||||
println!("{blocks_executed} blocks were executed");
|
||||
pub fn icicle_create_emulator() -> *mut c_void {
|
||||
let emulator = Box::new(IcicleEmulator::new());
|
||||
return Box::into_raw(emulator) as *mut c_void;
|
||||
}
|
||||
|
||||
struct BlockCounter {
|
||||
counter: icicle_vm::cpu::StoreRef,
|
||||
#[unsafe(no_mangle)]
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
impl icicle_vm::CodeInjector for BlockCounter {
|
||||
fn inject(
|
||||
&mut self,
|
||||
_cpu: &mut icicle_vm::cpu::Cpu,
|
||||
group: &icicle_vm::cpu::BlockGroup,
|
||||
code: &mut icicle_vm::BlockTable,
|
||||
) {
|
||||
let store_id = self.counter.get_store_id();
|
||||
for block in &mut code.blocks[group.range()] {
|
||||
// counter += 1
|
||||
let counter = block.pcode.alloc_tmp(8);
|
||||
let instrumentation = [
|
||||
(counter, pcode::Op::Load(store_id), 0_u64).into(),
|
||||
(counter, pcode::Op::IntAdd, (counter, 1_u64)).into(),
|
||||
(pcode::Op::Store(store_id), (0_u64, counter)).into(),
|
||||
];
|
||||
#[unsafe(no_mangle)]
|
||||
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);
|
||||
|
||||
// Inject the instrumentation at the start of the block.
|
||||
block.pcode.instructions.splice(..0, instrumentation);
|
||||
}
|
||||
}
|
||||
}
|
||||
if res {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub fn icicle_destroy_emulator(ptr: *mut c_void) {
|
||||
if ptr.is_null() {
|
||||
return;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let _ = Box::from_raw(ptr as *mut IcicleEmulator);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ endif()
|
||||
|
||||
target_link_libraries(windows-emulator PRIVATE
|
||||
unicorn-emulator
|
||||
icicle-emulator
|
||||
)
|
||||
|
||||
target_link_libraries(windows-emulator PUBLIC emulator)
|
||||
|
||||
Reference in New Issue
Block a user