1 use crate::{KprobeBasic, KprobeBuilder, KprobeOps}; 2 use alloc::string::ToString; 3 use alloc::sync::Arc; 4 use core::{ 5 fmt::Debug, 6 ops::{Deref, DerefMut}, 7 }; 8 use yaxpeax_arch::LengthedInstruction; 9 10 const EBREAK_INST: u8 = 0xcc; // x86_64: 0xcc 11 const MAX_INSTRUCTION_SIZE: usize = 15; // x86_64 max instruction length 12 13 pub struct Kprobe { 14 basic: KprobeBasic, 15 point: Arc<X86KprobePoint>, 16 } 17 18 #[derive(Debug)] 19 pub struct X86KprobePoint { 20 addr: usize, 21 old_instruction: [u8; MAX_INSTRUCTION_SIZE], 22 old_instruction_len: usize, 23 } 24 25 impl Drop for X86KprobePoint { drop(&mut self)26 fn drop(&mut self) { 27 let address = self.addr; 28 unsafe { 29 core::ptr::copy( 30 self.old_instruction.as_ptr(), 31 address as *mut u8, 32 self.old_instruction_len, 33 ); 34 core::arch::x86_64::_mm_mfence(); 35 } 36 let decoder = yaxpeax_x86::amd64::InstDecoder::default(); 37 let inst = decoder.decode_slice(&self.old_instruction).unwrap(); 38 log::trace!( 39 "Kprobe::uninstall: address: {:#x}, old_instruction: {:?}", 40 address, 41 inst.to_string() 42 ); 43 } 44 } 45 46 impl Debug for Kprobe { fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result47 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 48 f.debug_struct("Kprobe") 49 .field("basic", &self.basic) 50 .field("point", &self.point) 51 .finish() 52 } 53 } 54 55 impl Deref for Kprobe { 56 type Target = KprobeBasic; 57 deref(&self) -> &Self::Target58 fn deref(&self) -> &Self::Target { 59 &self.basic 60 } 61 } 62 63 impl DerefMut for Kprobe { deref_mut(&mut self) -> &mut Self::Target64 fn deref_mut(&mut self) -> &mut Self::Target { 65 &mut self.basic 66 } 67 } 68 69 impl KprobeBuilder { install(self) -> (Kprobe, Arc<X86KprobePoint>)70 pub fn install(self) -> (Kprobe, Arc<X86KprobePoint>) { 71 let probe_point = match &self.probe_point { 72 Some(point) => point.clone(), 73 None => self.replace_inst(), 74 }; 75 let kprobe = Kprobe { 76 basic: KprobeBasic::from(self), 77 point: probe_point.clone(), 78 }; 79 (kprobe, probe_point) 80 } 81 /// # 安装kprobe 82 /// 83 /// 不同的架构下需要保存原指令,然后替换为断点指令 replace_inst(&self) -> Arc<X86KprobePoint>84 fn replace_inst(&self) -> Arc<X86KprobePoint> { 85 let address = self.symbol_addr + self.offset; 86 let mut inst_tmp = [0u8; MAX_INSTRUCTION_SIZE]; 87 unsafe { 88 core::ptr::copy( 89 address as *const u8, 90 inst_tmp.as_mut_ptr(), 91 MAX_INSTRUCTION_SIZE, 92 ); 93 } 94 let decoder = yaxpeax_x86::amd64::InstDecoder::default(); 95 let inst = decoder.decode_slice(&inst_tmp).unwrap(); 96 let len = inst.len().to_const(); 97 log::trace!("inst: {:?}, len: {:?}", inst.to_string(), len); 98 let point = Arc::new(X86KprobePoint { 99 addr: address, 100 old_instruction: inst_tmp, 101 old_instruction_len: len as usize, 102 }); 103 unsafe { 104 core::ptr::write_volatile(address as *mut u8, EBREAK_INST); 105 core::arch::x86_64::_mm_mfence(); 106 } 107 log::trace!( 108 "Kprobe::install: address: {:#x}, func_name: {:?}", 109 address, 110 self.symbol 111 ); 112 point 113 } 114 } 115 116 impl Kprobe { probe_point(&self) -> &Arc<X86KprobePoint>117 pub fn probe_point(&self) -> &Arc<X86KprobePoint> { 118 &self.point 119 } 120 } 121 122 impl KprobeOps for X86KprobePoint { return_address(&self) -> usize123 fn return_address(&self) -> usize { 124 self.addr + self.old_instruction_len 125 } single_step_address(&self) -> usize126 fn single_step_address(&self) -> usize { 127 self.old_instruction.as_ptr() as usize 128 } debug_address(&self) -> usize129 fn debug_address(&self) -> usize { 130 self.old_instruction.as_ptr() as usize + self.old_instruction_len 131 } break_address(&self) -> usize132 fn break_address(&self) -> usize { 133 self.addr 134 } 135 } 136