Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 48 additions & 88 deletions crates/unicorn/src/hook.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
#![allow(non_camel_case_types)]

use alloc::rc::Weak;
use core::{cell::UnsafeCell, ffi::c_void};
use core::ffi::c_void;

pub use unicorn_engine_sys::{self as sys, uc_context, uc_engine, uc_hook};

use crate::{Unicorn, UnicornInner};
use crate::HookContext;

pub struct UcHook<'a, D: 'a, F: 'a> {
pub callback: F,
pub uc: Weak<UnsafeCell<UnicornInner<'a, D>>>,
// No value of `D` is stored in the hook. This marker keeps the `D`
// type parameter and callback lifetime visible to the type system
// while hook storage is erased behind `IsUcHook`.
pub marker: core::marker::PhantomData<&'a D>,
}

pub trait IsUcHook<'a> {}
Expand All @@ -27,14 +29,11 @@ pub extern "C" fn mmio_read_callback_proxy<D, F>(
user_data: *mut c_void,
) -> u64
where
F: FnMut(&mut crate::Unicorn<D>, u64, usize) -> u64,
F: FnMut(&mut HookContext, u64, usize) -> u64,
{
let user_data = unsafe { &mut *user_data.cast::<UcHook<D, F>>() };
let mut user_data_uc = Unicorn {
inner: user_data.uc.upgrade().unwrap(),
};
debug_assert_eq!(uc, user_data_uc.get_handle());
(user_data.callback)(&mut user_data_uc, offset, size as usize)
let mut context = HookContext::from_handle(uc);
(user_data.callback)(&mut context, offset, size as usize)
}

/// # Safety
Expand All @@ -47,14 +46,11 @@ pub unsafe extern "C" fn mmio_write_callback_proxy<D, F>(
value: u64,
user_data: *mut c_void,
) where
F: FnMut(&mut crate::Unicorn<D>, u64, usize, u64),
F: FnMut(&mut HookContext, u64, usize, u64),
{
let user_data = unsafe { &mut *user_data.cast::<UcHook<D, F>>() };
let mut user_data_uc = Unicorn {
inner: user_data.uc.upgrade().unwrap(),
};
debug_assert_eq!(uc, user_data_uc.get_handle());
(user_data.callback)(&mut user_data_uc, offset, size as usize, value);
let mut context = HookContext::from_handle(uc);
(user_data.callback)(&mut context, offset, size as usize, value);
}

/// # Safety
Expand All @@ -66,14 +62,11 @@ pub unsafe extern "C" fn code_hook_proxy<D, F>(
size: u32,
user_data: *mut UcHook<D, F>,
) where
F: FnMut(&mut crate::Unicorn<D>, u64, u32),
F: FnMut(&mut HookContext, u64, u32),
{
let user_data = unsafe { &mut *user_data };
let mut user_data_uc = Unicorn {
inner: user_data.uc.upgrade().unwrap(),
};
debug_assert_eq!(uc, user_data_uc.get_handle());
(user_data.callback)(&mut user_data_uc, address, size);
let mut context = HookContext::from_handle(uc);
(user_data.callback)(&mut context, address, size);
}

/// # Safety
Expand All @@ -85,14 +78,11 @@ pub unsafe extern "C" fn block_hook_proxy<D, F>(
size: u32,
user_data: *mut UcHook<D, F>,
) where
F: FnMut(&mut crate::Unicorn<D>, u64, u32),
F: FnMut(&mut HookContext, u64, u32),
{
let user_data = unsafe { &mut *user_data };
let mut user_data_uc = Unicorn {
inner: user_data.uc.upgrade().unwrap(),
};
debug_assert_eq!(uc, user_data_uc.get_handle());
(user_data.callback)(&mut user_data_uc, address, size);
let mut context = HookContext::from_handle(uc);
(user_data.callback)(&mut context, address, size);
}

/// # Safety
Expand All @@ -107,14 +97,11 @@ pub unsafe extern "C" fn mem_hook_proxy<D, F>(
user_data: *mut UcHook<D, F>,
) -> bool
where
F: FnMut(&mut crate::Unicorn<D>, sys::MemType, u64, usize, i64) -> bool,
F: FnMut(&mut HookContext, sys::MemType, u64, usize, i64) -> bool,
{
let user_data = unsafe { &mut *user_data };
let mut user_data_uc = Unicorn {
inner: user_data.uc.upgrade().unwrap(),
};
debug_assert_eq!(uc, user_data_uc.get_handle());
(user_data.callback)(&mut user_data_uc, mem_type, address, size as usize, value)
let mut context = HookContext::from_handle(uc);
(user_data.callback)(&mut context, mem_type, address, size as usize, value)
}

/// # Safety
Expand All @@ -125,14 +112,11 @@ pub unsafe extern "C" fn intr_hook_proxy<D, F>(
value: u32,
user_data: *mut UcHook<D, F>,
) where
F: FnMut(&mut crate::Unicorn<D>, u32),
F: FnMut(&mut HookContext, u32),
{
let user_data = unsafe { &mut *user_data };
let mut user_data_uc = Unicorn {
inner: user_data.uc.upgrade().unwrap(),
};
debug_assert_eq!(uc, user_data_uc.get_handle());
(user_data.callback)(&mut user_data_uc, value);
let mut context = HookContext::from_handle(uc);
(user_data.callback)(&mut context, value);
}

/// # Safety
Expand All @@ -145,14 +129,11 @@ pub unsafe extern "C" fn insn_in_hook_proxy<D, F>(
user_data: *mut UcHook<D, F>,
) -> u32
where
F: FnMut(&mut crate::Unicorn<D>, u32, usize) -> u32,
F: FnMut(&mut HookContext, u32, usize) -> u32,
{
let user_data = unsafe { &mut *user_data };
let mut user_data_uc = Unicorn {
inner: user_data.uc.upgrade().unwrap(),
};
debug_assert_eq!(uc, user_data_uc.get_handle());
(user_data.callback)(&mut user_data_uc, port, size)
let mut context = HookContext::from_handle(uc);
(user_data.callback)(&mut context, port, size)
}

/// # Safety
Expand All @@ -163,14 +144,11 @@ pub unsafe extern "C" fn insn_invalid_hook_proxy<D, F>(
user_data: *mut UcHook<D, F>,
) -> bool
where
F: FnMut(&mut crate::Unicorn<D>) -> bool,
F: FnMut(&mut HookContext) -> bool,
{
let user_data = unsafe { &mut *user_data };
let mut user_data_uc = Unicorn {
inner: user_data.uc.upgrade().unwrap(),
};
debug_assert_eq!(uc, user_data_uc.get_handle());
(user_data.callback)(&mut user_data_uc)
let mut context = HookContext::from_handle(uc);
(user_data.callback)(&mut context)
}

/// # Safety
Expand All @@ -183,29 +161,23 @@ pub unsafe extern "C" fn insn_out_hook_proxy<D, F>(
value: u32,
user_data: *mut UcHook<D, F>,
) where
F: FnMut(&mut crate::Unicorn<D>, u32, usize, u32),
F: FnMut(&mut HookContext, u32, usize, u32),
{
let user_data = unsafe { &mut *user_data };
let mut user_data_uc = Unicorn {
inner: user_data.uc.upgrade().unwrap(),
};
debug_assert_eq!(uc, user_data_uc.get_handle());
(user_data.callback)(&mut user_data_uc, port, size, value);
let mut context = HookContext::from_handle(uc);
(user_data.callback)(&mut context, port, size, value);
}

/// # Safety
///
/// This function is unsafe because it dereferences the `user_data` pointer.
pub unsafe extern "C" fn insn_sys_hook_proxy<D, F>(uc: *mut uc_engine, user_data: *mut UcHook<D, F>)
where
F: FnMut(&mut crate::Unicorn<D>),
F: FnMut(&mut HookContext),
{
let user_data = unsafe { &mut *user_data };
let mut user_data_uc = Unicorn {
inner: user_data.uc.upgrade().unwrap(),
};
debug_assert_eq!(uc, user_data_uc.get_handle());
(user_data.callback)(&mut user_data_uc);
let mut context = HookContext::from_handle(uc);
(user_data.callback)(&mut context);
}

/// # Safety
Expand All @@ -219,15 +191,12 @@ pub unsafe extern "C" fn insn_sys_hook_proxy_arm64<D, F>(
user_data: *mut UcHook<D, F>,
) -> bool
where
F: FnMut(&mut crate::Unicorn<D>, sys::RegisterARM64, &sys::RegisterARM64CP) -> bool,
F: FnMut(&mut HookContext, sys::RegisterARM64, &sys::RegisterARM64CP) -> bool,
{
let user_data = unsafe { &mut *user_data };
let mut user_data_uc = Unicorn {
inner: user_data.uc.upgrade().unwrap(),
};
debug_assert_eq!(uc, user_data_uc.get_handle());
let mut context = HookContext::from_handle(uc);
let cp_reg = unsafe { cp_reg.as_ref() }.unwrap();
(user_data.callback)(&mut user_data_uc, reg, cp_reg)
(user_data.callback)(&mut context, reg, cp_reg)
}

/// # Safety
Expand All @@ -241,14 +210,11 @@ pub unsafe extern "C" fn tlb_lookup_hook_proxy<D, F>(
user_data: *mut UcHook<D, F>,
) -> bool
where
F: FnMut(&mut crate::Unicorn<D>, u64, sys::MemType) -> Option<sys::TlbEntry>,
F: FnMut(&mut HookContext, u64, sys::MemType) -> Option<sys::TlbEntry>,
{
let user_data = unsafe { &mut *user_data };
let mut user_data_uc = Unicorn {
inner: user_data.uc.upgrade().unwrap(),
};
debug_assert_eq!(uc, user_data_uc.get_handle());
let r = (user_data.callback)(&mut user_data_uc, vaddr, mem_type);
let mut context = HookContext::from_handle(uc);
let r = (user_data.callback)(&mut context, vaddr, mem_type);
if let Some(ref e) = r {
let ref_result: &mut sys::TlbEntry = unsafe { &mut *result };
*ref_result = *e;
Expand All @@ -267,14 +233,11 @@ pub unsafe extern "C" fn tcg_proxy<D, F>(
size: u32,
user_data: *mut UcHook<D, F>,
) where
F: FnMut(&mut Unicorn<D>, u64, u64, u64, usize),
F: FnMut(&mut HookContext, u64, u64, u64, usize),
{
let user_data = unsafe { &mut *user_data };
let mut user_data_uc = Unicorn {
inner: user_data.uc.upgrade().unwrap(),
};
debug_assert_eq!(uc, user_data_uc.get_handle());
(user_data.callback)(&mut user_data_uc, addr, arg1, arg2, size as usize);
let mut context = HookContext::from_handle(uc);
(user_data.callback)(&mut context, addr, arg1, arg2, size as usize);
}

/// # Safety
Expand All @@ -286,14 +249,11 @@ pub unsafe extern "C" fn edge_gen_hook_proxy<D, F>(
prev_tb: *mut sys::TranslationBlock,
user_data: *mut UcHook<D, F>,
) where
F: FnMut(&mut Unicorn<D>, &mut sys::TranslationBlock, &mut sys::TranslationBlock),
F: FnMut(&mut HookContext, &mut sys::TranslationBlock, &mut sys::TranslationBlock),
{
let user_data = unsafe { &mut *user_data };
let mut user_data_uc = Unicorn {
inner: user_data.uc.upgrade().unwrap(),
};
debug_assert_eq!(uc, user_data_uc.get_handle());
(user_data.callback)(&mut user_data_uc, unsafe { &mut *cur_tb }, unsafe {
let mut context = HookContext::from_handle(uc);
(user_data.callback)(&mut context, unsafe { &mut *cur_tb }, unsafe {
&mut *prev_tb
});
}
Loading
Loading