diff --git a/src/emu.rs b/src/emu.rs index 0ee6361..1b12b8b 100644 --- a/src/emu.rs +++ b/src/emu.rs @@ -171,10 +171,7 @@ impl Emu { } OpKind::Memory => { let address: usize = self.calc_addr(instruction); - Ok(self - .memory - .read_primitive(Virtaddr(address)) - .map(T::from_ne_bytes)?) + Ok(self.memory.read_primitive(Virtaddr(address))?) } x => todo!("{x:?}"), } @@ -196,9 +193,9 @@ impl Emu { let mut depth = 0; 'recursive_memory_lookup: while let Ok(new_val) = self .memory - .read_primitive::(Virtaddr(usize::try_from(val).unwrap())) + .read_primitive(Virtaddr(usize::try_from(val).unwrap())) { - val = T::from_ne_bytes(new_val); + val = new_val; let val_addr = usize::try_from(val).unwrap(); print!("\x1b[0m -> "); @@ -268,7 +265,7 @@ impl Emu { self.memory.read_to( // we currently only support running this on x86 hosts // so it is fine to assume that a usize has size 8 bytes here - Virtaddr(self.get_reg::(Register::RIP)), + Virtaddr(self.get_reg(Register::RIP)), &mut inst_buf, )?; unsafe { IP = self.get_reg(Register::RIP) }; @@ -293,7 +290,7 @@ impl Emu { } macro_rules! push { ($expr:expr) => { - let sp = self.get_reg::(Register::RSP) as usize + let sp = self.get_reg::(Register::RSP) - core::mem::size_of_val(&$expr) as usize; self.memory.write_primitive(Virtaddr(sp), $expr)?; self.set_reg(sp, Register::RSP); @@ -301,7 +298,7 @@ impl Emu { } macro_rules! pop { ($exp:expr) => {{ - let sp = self.get_reg::(Register::RSP) as usize; + let sp: usize = self.get_reg::(Register::RSP); self.set_reg(sp + $exp as usize, Register::RSP); self.memory.read_primitive(Virtaddr(sp))? }}; @@ -433,7 +430,7 @@ impl Emu { })? }; } - self.set_reg::( + self.set_reg( overflowing as u8 | self.get_reg::(Register::RFLAGS), Register::RFLAGS, ); @@ -453,7 +450,7 @@ impl Emu { }; } - self.set_reg::( + self.set_reg( overflowing as u8 | self.get_reg::(Register::RFLAGS), Register::RFLAGS, ); @@ -601,28 +598,28 @@ impl Emu { } Mnemonic::Not => { macro_rules! sized_not { - ($typ:ty,$size:literal) => {{ + ($typ:ty) => {{ let val: $typ = self.get_val(instruction, 0)?; - self.set_val::<$typ, $size>(instruction, 0, !val)?; + self.set_val(instruction, 0, !val)?; }}; } - match_bitness_ts!(sized_not) + match_bitness_typ!(sized_not) } Mnemonic::Neg => { macro_rules! sized_neg { - ($typ:ty,$size:literal) => {{ + ($typ:ty) => {{ let val: $typ = self.get_val(instruction, 0)?; - self.set_val::<$typ, $size>(instruction, 0, -val)?; + self.set_val(instruction, 0, -val)?; }}; } match bitness(instruction) { - Bitness::Eight => sized_neg!(i8, 1), - Bitness::Sixteen => sized_neg!(i16, 2), - Bitness::ThirtyTwo => sized_neg!(i32, 4), - Bitness::SixtyFour => sized_neg!(i64, 8), - Bitness::HundredTwentyEigth => sized_neg!(i128, 16), + Bitness::Eight => sized_neg!(i8), + Bitness::Sixteen => sized_neg!(i16), + Bitness::ThirtyTwo => sized_neg!(i32), + Bitness::SixtyFour => sized_neg!(i64), + Bitness::HundredTwentyEigth => sized_neg!(i128), } } Mnemonic::Or => { @@ -675,7 +672,7 @@ impl Emu { } Mnemonic::Ret => { // get the new ip - let new_ip: u64 = u64::from_ne_bytes(pop!(8)); + let new_ip: u64 = pop!(8); #[cfg(debug_assertions)] { // println!("{:\t<1$}ret to: {new_ip:#x}", "", call_depth); @@ -791,14 +788,14 @@ impl Emu { +----------------------+ */ Mnemonic::Cmovne => { - cc! {ne, { + cc! {ne, match_bitness_typ!(sized_mov) - }} + } } Mnemonic::Cmove => { - cc! {e, { + cc! {e, match_bitness_typ!(sized_mov) - }} + } } Mnemonic::Cmova => { cc! {a, @@ -816,9 +813,9 @@ impl Emu { } } Mnemonic::Cmovb => { - cc! {b, { + cc! {b, match_bitness_typ!(sized_mov) - }} + } } Mnemonic::Mov => { // mov, as documented by https://www.felixcloutier.com/x86/mov @@ -852,7 +849,7 @@ impl Emu { Mnemonic::Pop => { macro_rules! pop_sized { ($typ:ty, $size:literal) => {{ - let val = <$typ>::from_ne_bytes(pop!($size)); + let val: $typ = pop!($size); self.set_val(instruction, 0, val)?; }}; } @@ -1178,7 +1175,9 @@ impl Emu { // get the displacement first, since any memory acces will have one (even if it's 0) let mut addr = mem.memory_displacement64() as usize; // check if there is a memory indexing register like in + // ```x86asm // call QWORD PTR [r12+r14*8] + // ``` // if that is the case, then multiply the value stored in the register (r14 in the above) // with its scale (8 in the above case) // and add the resulting value to the displacement @@ -1190,7 +1189,9 @@ impl Emu { // check if we are indexin a segment register // if so, add it to the addres // example: + // ```x86asm // mov rbx,QWORD PTR fs:0x10 + // ``` // here fs is the segment register if let Some(seg_reg) = seg_from_iced_seg(mem.memory_segment()) { addr = addr.wrapping_add(self.get_seg(seg_reg) as usize); @@ -1199,11 +1200,15 @@ impl Emu { // check if there is a base register indexing the memory // if that is the case, add the value stored in the register to the current address // example: + // ```x86asm // call QWORD PTR [r12+r14*8] + // ``` // here r12 is the base register if let Some(base_reg) = reg_from_iced_reg(mem.memory_base()) { // this can be wrapping, for example you can have + // ```x86asm // cmp QWORD PTR [rdi-0x8],0x0 + // ``` // substracting some displacement (i.e. doing a wrapping add (I could be wrong here)) addr = addr.wrapping_add(self.get_reg::(base_reg)); } @@ -1251,9 +1256,9 @@ impl Emu { let mut depth = 0; while let Ok(new_val) = self .memory - .read_primitive::<8>(Virtaddr(usize::try_from(val).unwrap())) + .read_primitive(Virtaddr(usize::try_from(val).unwrap())) { - val = u64::from_ne_bytes(new_val); + val = new_val; print!("\x1b[0m -> \x1b[;96m{val:#x?}"); depth += 1; if depth > 5 { diff --git a/src/mmu.rs b/src/mmu.rs index d51d331..58b5e65 100644 --- a/src/mmu.rs +++ b/src/mmu.rs @@ -6,7 +6,7 @@ use std::path::Path; use elf::{endian::AnyEndian, ElfBytes}; -use crate::symbol_table::SymbolTable; +use crate::{primitive::Primitive, symbol_table::SymbolTable}; pub struct MMU { memory: Vec, @@ -197,7 +197,11 @@ impl MMU { } /// write a primitive type to memory - pub fn write_primitive(&mut self, addr: Virtaddr, value: T) -> Result<()> { + pub fn write_primitive, const BYTES: usize>( + &mut self, + addr: Virtaddr, + value: T, + ) -> Result<()> { // check if we are not writing past the memory buffer if addr.0 + std::mem::size_of::() > self.memory.len() { return Err(AccessError::AddrOOB); @@ -215,9 +219,8 @@ impl MMU { // the pointer casting here is needed, // since rust places an restriction of using `std::mem::sizeof::()` // in the construction of arrays - self.memory[addr.0..addr.0 + std::mem::size_of::()].copy_from_slice(unsafe { - core::slice::from_raw_parts(&value as *const T as *const u8, core::mem::size_of::()) - }); + self.memory[addr.0..addr.0 + std::mem::size_of::()] + .copy_from_slice(&value.to_ne_bytes()); // self.memory[addr.0..addr.0 + std::mem::size_of::()] // .copy_from_slice(&value.to_ne_bytes()); @@ -267,7 +270,7 @@ impl MMU { } /// this function reads primitives as [u8; N], /// this is to circumvent the restriction of using generic const expressions - pub fn read_primitive(&self, addr: Virtaddr) -> Result<[u8; N]> { + pub fn read_primitive>(&self, addr: Virtaddr) -> Result { // check if we are not writing past the memory buffer let Some(last_addr) = addr.0.checked_add(N) else { return Err(AccessError::AddrOverflow); @@ -287,7 +290,7 @@ impl MMU { // copy the requested memory let mut buf = [0u8; N]; buf.copy_from_slice(&self.memory[addr.0..last_addr]); - Ok(buf) + Ok(T::from_ne_bytes(buf)) } /// get acces to a mutable slice of memory diff --git a/src/primitive.rs b/src/primitive.rs index afba751..0c9c8e2 100644 --- a/src/primitive.rs +++ b/src/primitive.rs @@ -20,6 +20,8 @@ pub trait Primitive: fn to_u64(self) -> u64; fn from_ne_bytes(bytes: [u8; SIZE]) -> Self; + + fn to_ne_bytes(self) -> [u8; SIZE]; } macro_rules! impl_primitive { @@ -29,12 +31,20 @@ macro_rules! impl_primitive { fn to_u64(self) -> u64 { self as u64 } + #[inline(always)] fn from_ne_bytes(bytes: [u8; $bytes]) -> Self { // assert!(size == $bytes); // let bytes = unsafe { core::mem::transmute::<[u8; size], [u8; $bytes]>(bytes) }; Self::from_ne_bytes(bytes) } + + #[inline(always)] + fn to_ne_bytes(self) -> [u8; $bytes] { + // assert!(size == $bytes); + // let bytes = unsafe { core::mem::transmute::<[u8; size], [u8; $bytes]>(bytes) }; + <$type>::to_ne_bytes(self) + } } }; }