Skip to content

Commit

Permalink
add some macro, put raw tracking behind a feature
Browse files Browse the repository at this point in the history
  • Loading branch information
lenawanel committed Sep 8, 2023
1 parent 02f2a15 commit 3acb5de
Show file tree
Hide file tree
Showing 3 changed files with 132 additions and 54 deletions.
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 = []
162 changes: 108 additions & 54 deletions src/emu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -330,13 +330,13 @@ impl Emu {
}

macro_rules! jmp {
() => {
() => {{
// get the new ip
let new_ip: u64 = self.get_val::<u64, 8>(instruction, 0)?;
self.set_reg(new_ip, Register::RIP);
// and jump to it
continue 'next_instr;
};
}};
}

macro_rules! sized_mov {
Expand All @@ -346,6 +346,72 @@ impl Emu {
}};
}

macro_rules! cc {
(be,$code:expr) => {
if self.get_reg::<u8, 1>(Register::RFLAGS) & (1 << 6) != 0
|| self.get_reg::<u8, 1>(Register::RFLAGS) & (1 << 0) != 0
{
$code;
}
};
(ne,$code:expr) => {
if self.get_reg::<u8, 1>(Register::RFLAGS) & (1 << 6) == 0 {
$code;
}
};
(e,$code:expr) => {
if self.get_reg::<u8, 1>(Register::RFLAGS) & (1 << 6) != 0 {
$code;
}
};
(b,$code:expr) => {
if self.get_reg::<u8, 1>(Register::RFLAGS) & (1 << 0) != 0 {
$code;
}
};
(le,$code:expr) => {
// if the ZF==1
if self.get_reg::<u8, 1>(Register::RFLAGS) & (1 << 6) != 0
// or SF!=OF
|| (self.get_reg::<u16, 2>(Register::RFLAGS) & (1 << 11)).count_ones()
!= (self.get_reg::<u16, 2>(Register::RFLAGS) & (1 << 7)).count_ones()
{
$code;
}
};
(g,$code:expr) => {
// if ZF==0
if self.get_reg::<u64, 8>(Register::RFLAGS) & (1 << 6) == 0
// and SF==OF
&& (self.get_reg::<u16, 2>(Register::RFLAGS) & (1 << 11)).count_ones()
== (self.get_reg::<u16, 2>(Register::RFLAGS) & (1 << 7)).count_ones()
{
$code;
}
};
(a,$code:expr) => {
// if ZF==0
if self.get_reg::<u8, 1>(Register::RFLAGS) & (1 << 6) == 0
// and CF==0
&& self.get_reg::<u8, 1>(Register::RFLAGS) & (1 << 0) == 0
{
$code;
}
};
(ae,$code:expr) => {
// if CF==0
if self.get_reg::<u8, 1>(Register::RFLAGS) & (1 << 0) == 0 {
$code;
}
};
(s,$code:expr) => {
// if CF==0
if self.get_reg::<u8, 1>(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
Expand Down Expand Up @@ -627,66 +693,48 @@ impl Emu {

// | jump instructions |
Mnemonic::Jne => {
if self.get_reg::<u8, 1>(Register::RFLAGS) & (1 << 6) == 0 {
jmp!();
cc! {ne,
jmp!()
}
}
Mnemonic::Jbe => {
if self.get_reg::<u8, 1>(Register::RFLAGS) & (1 << 6) != 0
|| self.get_reg::<u8, 1>(Register::RFLAGS) & (1 << 0) != 0
{
jmp!();
cc! {be,
jmp!()
}
}
Mnemonic::Je => {
if self.get_reg::<u64, 8>(Register::RFLAGS) & (1 << 6) != 0 {
jmp!();
cc! {e,
jmp!()
}
}
Mnemonic::Jb => {
if self.get_reg::<u64, 8>(Register::RFLAGS) & (1 << 0) != 0 {
jmp!();
cc! { b,
jmp!()
}
}
Mnemonic::Jle => {
// if the ZF==1
if self.get_reg::<u8, 1>(Register::RFLAGS) & (1 << 6) != 0
// or SF!=OF
|| (self.get_reg::<u16, 2>(Register::RFLAGS) & (1 << 11)).count_ones()
!= (self.get_reg::<u16, 2>(Register::RFLAGS) & (1 << 7)).count_ones()
{
jmp!();
cc! { le,
jmp!()
}
}
Mnemonic::Jg => {
// if ZF==0
if self.get_reg::<u64, 8>(Register::RFLAGS) & (1 << 6) == 0
// and SF==OF
&& (self.get_reg::<u16, 2>(Register::RFLAGS) & (1 << 11)).count_ones()
== (self.get_reg::<u16, 2>(Register::RFLAGS) & (1 << 7)).count_ones()
{
jmp!();
cc! {g,
jmp!()
}
}
Mnemonic::Ja => {
// if ZF==0
if self.get_reg::<u8, 1>(Register::RFLAGS) & (1 << 6) == 0
// and CF==0
&& self.get_reg::<u8, 1>(Register::RFLAGS) & (1 << 0) == 0
{
jmp!();
cc! {a,
jmp!()
}
}
Mnemonic::Jae => {
// if CF==0
if self.get_reg::<u8, 1>(Register::RFLAGS) & (1 << 0) == 0 {
jmp!();
cc! { ae,
jmp!()
}
}
Mnemonic::Js => {
// if CF==0
if self.get_reg::<u8, 1>(Register::RFLAGS) & (1 << 7) != 0 {
jmp!();
cc! { s,
jmp!()
}
}
Mnemonic::Jmp => {
Expand Down Expand Up @@ -743,41 +791,34 @@ impl Emu {
+----------------------+
*/
Mnemonic::Cmovne => {
if self.get_reg::<u8, 1>(Register::RFLAGS) & (1 << 6) == 0 {
cc! {ne, {
match_bitness_typ!(sized_mov)
}
}}
}
Mnemonic::Cmove => {
if self.get_reg::<u8, 1>(Register::RFLAGS) & (1 << 6) != 0 {
cc! {e, {
match_bitness_typ!(sized_mov)
}
}}
}
Mnemonic::Cmova => {
if self.get_reg::<u8, 1>(Register::RFLAGS) & (1 << 6) == 0
// and CF==0
&& self.get_reg::<u8, 1>(Register::RFLAGS) & (1 << 0) == 0
{
cc! {a,
match_bitness_typ!(sized_mov)
}
}
Mnemonic::Cmovae => {
if self.get_reg::<u8, 1>(Register::RFLAGS) & (1 << 0) == 0 {
cc! {ae,
match_bitness_typ!(sized_mov)
}
}
Mnemonic::Cmovg => {
if self.get_reg::<u64, 8>(Register::RFLAGS) & (1 << 6) == 0
// and SF==OF
&& (self.get_reg::<u16, 2>(Register::RFLAGS) & (1 << 11)).count_ones()
== (self.get_reg::<u16, 2>(Register::RFLAGS) & (1 << 7)).count_ones()
{
cc! {g,
match_bitness_typ!(sized_mov)
}
}
Mnemonic::Cmovb => {
if self.get_reg::<u64, 8>(Register::RFLAGS) & (1 << 0) != 0 {
cc! {b, {
match_bitness_typ!(sized_mov)
}
}}
}
Mnemonic::Mov => {
// mov, as documented by https://www.felixcloutier.com/x86/mov
Expand Down Expand Up @@ -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(())
Expand Down
21 changes: 21 additions & 0 deletions src/mmu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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| {
Expand All @@ -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 {
Expand Down Expand Up @@ -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)
}
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 3acb5de

Please sign in to comment.