diff --git a/Cargo.toml b/Cargo.toml index 4aec13d..6fffa74 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,3 +9,6 @@ edition = "2021" iced-x86 = { version = "1.19.0", default-features = false, features = ["decoder", "fast_fmt", "intel", "instr_info", "lazy_static", "std", "nasm"] } elf = { version = "0.7.2", default-features = false } # bddisasm = "0.2.1" + +[features] +raw_tracking = [] diff --git a/src/emu.rs b/src/emu.rs index 3f2cc1f..0ee6361 100644 --- a/src/emu.rs +++ b/src/emu.rs @@ -330,13 +330,13 @@ impl Emu { } macro_rules! jmp { - () => { + () => {{ // get the new ip let new_ip: u64 = self.get_val::(instruction, 0)?; self.set_reg(new_ip, Register::RIP); // and jump to it continue 'next_instr; - }; + }}; } macro_rules! sized_mov { @@ -346,6 +346,72 @@ impl Emu { }}; } + macro_rules! cc { + (be,$code:expr) => { + if self.get_reg::(Register::RFLAGS) & (1 << 6) != 0 + || self.get_reg::(Register::RFLAGS) & (1 << 0) != 0 + { + $code; + } + }; + (ne,$code:expr) => { + if self.get_reg::(Register::RFLAGS) & (1 << 6) == 0 { + $code; + } + }; + (e,$code:expr) => { + if self.get_reg::(Register::RFLAGS) & (1 << 6) != 0 { + $code; + } + }; + (b,$code:expr) => { + if self.get_reg::(Register::RFLAGS) & (1 << 0) != 0 { + $code; + } + }; + (le,$code:expr) => { + // if the ZF==1 + if self.get_reg::(Register::RFLAGS) & (1 << 6) != 0 + // or SF!=OF + || (self.get_reg::(Register::RFLAGS) & (1 << 11)).count_ones() + != (self.get_reg::(Register::RFLAGS) & (1 << 7)).count_ones() + { + $code; + } + }; + (g,$code:expr) => { + // if ZF==0 + if self.get_reg::(Register::RFLAGS) & (1 << 6) == 0 + // and SF==OF + && (self.get_reg::(Register::RFLAGS) & (1 << 11)).count_ones() + == (self.get_reg::(Register::RFLAGS) & (1 << 7)).count_ones() + { + $code; + } + }; + (a,$code:expr) => { + // if ZF==0 + if self.get_reg::(Register::RFLAGS) & (1 << 6) == 0 + // and CF==0 + && self.get_reg::(Register::RFLAGS) & (1 << 0) == 0 + { + $code; + } + }; + (ae,$code:expr) => { + // if CF==0 + if self.get_reg::(Register::RFLAGS) & (1 << 0) == 0 { + $code; + } + }; + (s,$code:expr) => { + // if CF==0 + if self.get_reg::(Register::RFLAGS) & (1 << 7) != 0 { + $code; + } + } + } + // set the instruction pointer to the next instruction inc_reg!(instruction.len(), Register::RIP); // TODO: get rid of boilerplate code @@ -627,66 +693,48 @@ impl Emu { // | jump instructions | Mnemonic::Jne => { - if self.get_reg::(Register::RFLAGS) & (1 << 6) == 0 { - jmp!(); + cc! {ne, + jmp!() } } Mnemonic::Jbe => { - if self.get_reg::(Register::RFLAGS) & (1 << 6) != 0 - || self.get_reg::(Register::RFLAGS) & (1 << 0) != 0 - { - jmp!(); + cc! {be, + jmp!() } } Mnemonic::Je => { - if self.get_reg::(Register::RFLAGS) & (1 << 6) != 0 { - jmp!(); + cc! {e, + jmp!() } } Mnemonic::Jb => { - if self.get_reg::(Register::RFLAGS) & (1 << 0) != 0 { - jmp!(); + cc! { b, + jmp!() } } Mnemonic::Jle => { - // if the ZF==1 - if self.get_reg::(Register::RFLAGS) & (1 << 6) != 0 - // or SF!=OF - || (self.get_reg::(Register::RFLAGS) & (1 << 11)).count_ones() - != (self.get_reg::(Register::RFLAGS) & (1 << 7)).count_ones() - { - jmp!(); + cc! { le, + jmp!() } } Mnemonic::Jg => { - // if ZF==0 - if self.get_reg::(Register::RFLAGS) & (1 << 6) == 0 - // and SF==OF - && (self.get_reg::(Register::RFLAGS) & (1 << 11)).count_ones() - == (self.get_reg::(Register::RFLAGS) & (1 << 7)).count_ones() - { - jmp!(); + cc! {g, + jmp!() } } Mnemonic::Ja => { - // if ZF==0 - if self.get_reg::(Register::RFLAGS) & (1 << 6) == 0 - // and CF==0 - && self.get_reg::(Register::RFLAGS) & (1 << 0) == 0 - { - jmp!(); + cc! {a, + jmp!() } } Mnemonic::Jae => { - // if CF==0 - if self.get_reg::(Register::RFLAGS) & (1 << 0) == 0 { - jmp!(); + cc! { ae, + jmp!() } } Mnemonic::Js => { - // if CF==0 - if self.get_reg::(Register::RFLAGS) & (1 << 7) != 0 { - jmp!(); + cc! { s, + jmp!() } } Mnemonic::Jmp => { @@ -743,41 +791,34 @@ impl Emu { +----------------------+ */ Mnemonic::Cmovne => { - if self.get_reg::(Register::RFLAGS) & (1 << 6) == 0 { + cc! {ne, { match_bitness_typ!(sized_mov) - } + }} } Mnemonic::Cmove => { - if self.get_reg::(Register::RFLAGS) & (1 << 6) != 0 { + cc! {e, { match_bitness_typ!(sized_mov) - } + }} } Mnemonic::Cmova => { - if self.get_reg::(Register::RFLAGS) & (1 << 6) == 0 - // and CF==0 - && self.get_reg::(Register::RFLAGS) & (1 << 0) == 0 - { + cc! {a, match_bitness_typ!(sized_mov) } } Mnemonic::Cmovae => { - if self.get_reg::(Register::RFLAGS) & (1 << 0) == 0 { + cc! {ae, match_bitness_typ!(sized_mov) } } Mnemonic::Cmovg => { - if self.get_reg::(Register::RFLAGS) & (1 << 6) == 0 - // and SF==OF - && (self.get_reg::(Register::RFLAGS) & (1 << 11)).count_ones() - == (self.get_reg::(Register::RFLAGS) & (1 << 7)).count_ones() - { + cc! {g, match_bitness_typ!(sized_mov) } } Mnemonic::Cmovb => { - if self.get_reg::(Register::RFLAGS) & (1 << 0) != 0 { + cc! {b, { match_bitness_typ!(sized_mov) - } + }} } Mnemonic::Mov => { // mov, as documented by https://www.felixcloutier.com/x86/mov @@ -1045,10 +1086,23 @@ impl Emu { _ => self.set_reg(u64::MAX, Register::RAX), } } + 218 => { + // do nothing for now + self.set_reg(0u64, Register::RAX) + } + 273 => { + // do nothing for now + self.set_reg(0u64, Register::RAX) + } // exit 231 => { return Err(ExecErr::Exit { ip: unsafe { IP } }); } + // rseq + 334 => { + // do nothing for now + self.set_reg(0u64, Register::RAX) + } x => todo!("syscall # {x}"), }; Ok(()) diff --git a/src/mmu.rs b/src/mmu.rs index 38ba511..6d96ea9 100644 --- a/src/mmu.rs +++ b/src/mmu.rs @@ -102,6 +102,7 @@ impl MMU { /// write a buffer to a virtual adress, checking if we have the given permissions pub fn write_from_perms(&mut self, addr: Virtaddr, buf: &[u8], exp_perm: Perm) -> Result<()> { + #[cfg(raw_tracking)] let mut has_raw = false; // check if we're not writing past the memory buffer @@ -113,6 +114,7 @@ impl MMU { // dbg!("checking permissions"); // check if we have the permission, paying extra attention to if we have RAW // memory, to update the permissions later + #[cfg(raw_tracking)] if !self.permissions[addr.0..addr.0 + buf.len()] .iter() .all(|&x| { @@ -124,12 +126,22 @@ impl MMU { println!("perm check failed"); return Err(AccessError::PermErr(addr, self.permissions[addr.0])); } + #[cfg(not(raw_tracking))] + if !self.permissions[addr.0..addr.0 + buf.len()] + .iter() + .all(|&x| (x & exp_perm).0 != 0) + { + println!("expected permission: {:#b}", exp_perm.0); + println!("perm check failed"); + return Err(AccessError::PermErr(addr, self.permissions[addr.0])); + } // dbg!("after checking permissions"); self.memory[addr.0..addr.0 + buf.len()].copy_from_slice(buf); // dbg!("after writing memory"); // if the read after write flag is up, update the Permission of the memory + #[cfg(raw_tracking)] if has_raw { self.permissions.iter_mut().for_each(|x| { if (*x & PERM_RAW).0 != 0 { @@ -240,12 +252,20 @@ impl MMU { } // Mark the memory as un-initialized and writable + #[cfg(raw_tracking)] if self .set_permissions(base, align_size, PERM_RAW | PERM_WRITE) .is_err() { return None; } + #[cfg(not(raw_tracking))] + if self + .set_permissions(base, align_size, PERM_WRITE | PERM_READ) + .is_err() + { + return None; + } Some(self.cur_alc) } @@ -460,6 +480,7 @@ pub const PERM_READ: Perm = Perm(1 << 2); pub const PERM_WRITE: Perm = Perm(1 << 1); /// permission to read a byte in memory after writing to it /// this can be useful for detecting unintialized reads +#[cfg(raw_tracking)] pub const PERM_RAW: Perm = Perm(1 << 3); /// permission to execute a byte in memory pub const PERM_EXEC: Perm = Perm(1 << 0);