1use std::ffi::c_void;
36
37use crate::plugin_import;
38use crate::prelude::*;
39use crate::sys::{self, panda_cb_type};
40
41plugin_import! {
42 static HOOKS: Hooks = extern "hooks" {
43 fn add_hook(hook: &Hook);
44 fn enable_hooking();
45 fn disable_hooking();
46 fn add_symbol_hook(hook: &SymbolHook);
47 };
48}
49
50#[repr(C)]
51#[derive(Copy, Clone, Debug)]
52pub struct Symbol {
53 pub address: target_ulong,
54 pub name: [u8; 256usize],
55 pub section: [u8; 256usize],
56}
57
58#[repr(C)]
59#[derive(Copy, Clone, Debug)]
60pub struct HooksPandaCallback(panda_cb_type, *const ());
61
62type NormalHookType = extern "C" fn(env: &mut CPUState, tb: &mut TranslationBlock, hook: &mut Hook);
63type BeforeTranslateHook = extern "C" fn(env: &mut CPUState, pc: target_ptr_t, hook: &mut Hook);
64type AfterBlockHook =
65 extern "C" fn(env: &mut CPUState, tb: &mut TranslationBlock, exitCode: u8, hook: &mut Hook);
66type InvalidateOpHook =
67 extern "C" fn(env: &mut CPUState, tb: &mut TranslationBlock, hook: &mut Hook) -> bool;
68
69impl HooksPandaCallback {
70 pub fn from_before_tcg_codegen(cb: NormalHookType) -> Self {
71 Self(sys::panda_cb_type_PANDA_CB_BEFORE_TCG_CODEGEN, cb as _)
72 }
73
74 pub fn from_after_block_translate(cb: NormalHookType) -> Self {
75 Self(sys::panda_cb_type_PANDA_CB_AFTER_BLOCK_TRANSLATE, cb as _)
76 }
77
78 pub fn from_before_block_exec(cb: NormalHookType) -> Self {
79 Self(sys::panda_cb_type_PANDA_CB_BEFORE_BLOCK_EXEC, cb as _)
80 }
81
82 pub fn from_start_block_exec(cb: NormalHookType) -> Self {
83 Self(sys::panda_cb_type_PANDA_CB_START_BLOCK_EXEC, cb as _)
84 }
85
86 pub fn from_end_block_exec(cb: NormalHookType) -> Self {
87 Self(sys::panda_cb_type_PANDA_CB_END_BLOCK_EXEC, cb as _)
88 }
89
90 pub fn from_before_block_exec_invalidate_opt(cb: InvalidateOpHook) -> Self {
91 Self(
92 sys::panda_cb_type_PANDA_CB_BEFORE_BLOCK_EXEC_INVALIDATE_OPT,
93 cb as _,
94 )
95 }
96
97 pub fn from_before_block_translate(cb: BeforeTranslateHook) -> Self {
98 Self(sys::panda_cb_type_PANDA_CB_BEFORE_BLOCK_TRANSLATE, cb as _)
99 }
100
101 pub fn from_after_block_exec(cb: AfterBlockHook) -> Self {
102 Self(sys::panda_cb_type_PANDA_CB_AFTER_BLOCK_EXEC, cb as _)
103 }
104}
105
106pub mod hook {
122 use super::*;
123
124 macro_rules! define_hook_builders {
125 ($(
126 fn $name:ident ( $($arg:ident : $arg_ty:ty ),* ) $(-> $ret_ty:ty)?;
127 )*) => {
128 $(
129 pub fn $name<CallbackFn>(
130 callback: CallbackFn
131 ) -> HookBuilder<extern "C" fn(
132 $( $arg : $arg_ty, )*
133 hook: &mut Hook,
134 ) $( -> $ret_ty )?>
135 where CallbackFn: FnMut($($arg_ty,)* &mut Hook) $( -> $ret_ty )? + 'static,
136 {
137 extern "C" fn trampoline(
138 $( $arg : $arg_ty, )*
139 hook: &mut Hook,
140 ) $( -> $ret_ty )? {
141 let callback: &mut &mut dyn FnMut(
142 $($arg_ty,)*
143 &mut Hook,
144 ) $( -> $ret_ty )? = unsafe {
145 std::mem::transmute(hook.context)
146 };
147
148 callback($($arg, )* hook)
149 }
150
151 let cb: &mut &mut dyn FnMut(
152 $($arg_ty,)* &mut Hook
153 ) $( -> $ret_ty )? = Box::leak(Box::new(
154 Box::leak(Box::new(callback) as _)
155 ));
156
157 $crate::paste::paste! {
158 HookBuilder {
159 hook: trampoline,
160 callback: HooksPandaCallback::[< from_ $name >](trampoline),
161 only_kernel: None,
162 enabled: true,
163 asid: None,
164 context: cb as *mut _ as *mut _,
165 }
166 }
167 }
168 )*
169 };
170 }
171
172 define_hook_builders! {
173 fn before_block_exec(env: &mut CPUState, tb: &mut TranslationBlock);
174 fn before_tcg_codegen(env: &mut CPUState, tb: &mut TranslationBlock);
175 fn after_block_translate(env: &mut CPUState, tb: &mut TranslationBlock);
176 fn start_block_exec(env: &mut CPUState, tb: &mut TranslationBlock);
177 fn end_block_exec(env: &mut CPUState, tb: &mut TranslationBlock);
178
179 fn after_block_exec(env: &mut CPUState, tb: &mut TranslationBlock, exit_code: u8);
180 fn before_block_translate(env: &mut CPUState, pc: target_ptr_t);
181 fn before_block_exec_invalidate_opt(env: &mut CPUState, tb: &mut TranslationBlock) -> bool;
182 }
183}
184
185#[repr(u32)]
186#[derive(Copy, Clone, Debug)]
187pub enum KernelMode {
188 Any = 0,
189 KernelOnly = 1,
190 UserOnly = 2,
191}
192
193#[repr(C)]
196#[derive(Copy, Clone, Debug)]
197pub struct Hook {
198 pub addr: target_ulong,
200
201 pub asid: target_ulong,
204
205 pub cb: HooksPandaCallback,
207
208 pub km: KernelMode,
211
212 pub enabled: bool,
214
215 pub sym: Symbol,
217
218 pub context: *mut c_void,
220}
221
222#[repr(C)]
223#[derive(Copy, Clone)]
224pub struct SymbolHook {
225 pub name: [u8; 256usize],
226 pub offset: target_ulong,
227 pub hook_offset: bool,
228 pub section: [u8; 256usize],
229 pub cb: HooksPandaCallback,
230}
231
232pub trait IntoHookBuilder {
233 type BuilderType;
234
235 fn hook(self) -> Self::BuilderType;
236}
237
238impl IntoHookBuilder for NormalHookType {
239 type BuilderType = HookBuilder<NormalHookType>;
240
241 fn hook(self) -> Self::BuilderType {
242 HookBuilder {
243 hook: self,
244 callback: HooksPandaCallback::from_start_block_exec(self),
245 only_kernel: None,
246 enabled: true,
247 asid: None,
248 context: std::ptr::null_mut(),
249 }
250 }
251}
252
253impl IntoHookBuilder for BeforeTranslateHook {
254 type BuilderType = HookBuilderCallbackTypeNeeded<Self>;
255
256 fn hook(self) -> Self::BuilderType {
257 HookBuilderCallbackTypeNeeded(self)
258 }
259}
260
261impl IntoHookBuilder for AfterBlockHook {
262 type BuilderType = HookBuilderCallbackTypeNeeded<Self>;
263
264 fn hook(self) -> Self::BuilderType {
265 HookBuilderCallbackTypeNeeded(self)
266 }
267}
268
269impl IntoHookBuilder for InvalidateOpHook {
270 type BuilderType = HookBuilderCallbackTypeNeeded<Self>;
271
272 fn hook(self) -> Self::BuilderType {
273 HookBuilderCallbackTypeNeeded(self)
274 }
275}
276
277pub struct HookBuilder<T> {
279 hook: T,
280 callback: HooksPandaCallback,
281 only_kernel: Option<bool>,
282 enabled: bool,
283 asid: Option<target_ulong>,
284 context: *mut c_void,
285}
286
287impl<T> HookBuilder<T> {
288 pub fn kernel(mut self, only_kernel: bool) -> Self {
291 self.only_kernel = Some(only_kernel);
292 self
293 }
294
295 pub fn enabled(mut self, enabled: bool) -> Self {
297 self.enabled = enabled;
298 self
299 }
300
301 pub fn asid(mut self, asid: target_ulong) -> Self {
303 self.asid = Some(asid);
304 self
305 }
306
307 pub fn at_addr(self, addr: target_ulong) {
309 HOOKS.add_hook(&Hook {
310 addr,
311 asid: self.asid.unwrap_or(0),
312 enabled: self.enabled,
313 km: match self.only_kernel {
314 Some(true) => KernelMode::KernelOnly,
315 Some(false) => KernelMode::UserOnly,
316 None => KernelMode::Any,
317 },
318 cb: self.callback,
319 sym: unsafe { std::mem::zeroed() },
320 context: self.context,
321 });
322 }
323}
324
325impl HookBuilder<NormalHookType> {
326 pub fn before_tcg_codegen(mut self) -> Self {
327 self.callback = HooksPandaCallback::from_before_tcg_codegen(self.hook);
328 self
329 }
330
331 pub fn after_block_translate(mut self) -> Self {
332 self.callback = HooksPandaCallback::from_after_block_translate(self.hook);
333 self
334 }
335
336 pub fn before_block_exec(mut self) -> Self {
337 self.callback = HooksPandaCallback::from_before_block_exec(self.hook);
338 self
339 }
340
341 pub fn start_block_exec(mut self) -> Self {
342 self.callback = HooksPandaCallback::from_start_block_exec(self.hook);
343 self
344 }
345
346 pub fn end_block_exec(mut self) -> Self {
347 self.callback = HooksPandaCallback::from_end_block_exec(self.hook);
348 self
349 }
350}
351
352pub struct HookBuilderCallbackTypeNeeded<T>(T);
353
354impl HookBuilderCallbackTypeNeeded<BeforeTranslateHook> {
355 pub fn before_block_translate(self) -> HookBuilder<BeforeTranslateHook> {
356 HookBuilder {
357 hook: self.0,
358 callback: HooksPandaCallback::from_before_block_translate(self.0),
359 only_kernel: None,
360 enabled: true,
361 asid: None,
362 context: std::ptr::null_mut(),
363 }
364 }
365}
366
367impl HookBuilderCallbackTypeNeeded<AfterBlockHook> {
368 pub fn after_block_exec(self) -> HookBuilder<AfterBlockHook> {
369 HookBuilder {
370 hook: self.0,
371 callback: HooksPandaCallback::from_after_block_exec(self.0),
372 only_kernel: None,
373 enabled: true,
374 asid: None,
375 context: std::ptr::null_mut(),
376 }
377 }
378}
379
380impl HookBuilderCallbackTypeNeeded<InvalidateOpHook> {
381 pub fn before_block_exec_invalidate_opt(self) -> HookBuilder<InvalidateOpHook> {
382 HookBuilder {
383 hook: self.0,
384 callback: HooksPandaCallback::from_before_block_exec_invalidate_opt(self.0),
385 only_kernel: None,
386 enabled: true,
387 asid: None,
388 context: std::ptr::null_mut(),
389 }
390 }
391}