diff --git a/Cargo.toml b/Cargo.toml index 33e767f..99e0a7c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,6 @@ documentation = "https://docs.rs/libscemu/0.4.15/libscemu/" repository = "https://github.com/sha0coder/libscemu" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] iced-x86 = "1.19.0" uint = "0.9.5" diff --git a/src/config.rs b/src/config.rs index cf98027..6f048f0 100644 --- a/src/config.rs +++ b/src/config.rs @@ -18,6 +18,7 @@ pub struct Config { pub console2: bool, pub console_addr: u64, pub entry_point: u64, + pub exit_position: u64, pub code_base_addr: u64, pub is_64bits: bool, // 64bits mode pub stack_trace: bool, @@ -50,6 +51,7 @@ impl Config { console2: false, console_addr: 0, entry_point: 0x3c0000, + exit_position: 0, code_base_addr: 0x3c0000, is_64bits: false, stack_trace: false, diff --git a/src/emu/constants.rs b/src/emu/constants.rs index d9d2a17..6eff7a4 100644 --- a/src/emu/constants.rs +++ b/src/emu/constants.rs @@ -12,7 +12,6 @@ pub const LIBS32_MAX: u64 = 0x7FFFFFFF; pub const LIBS64_MIN: u64 = 0x7FF000000000; pub const LIBS64_MAX: u64 = 0x7FFFFFFFFFFF; - pub const STATUS_SUCCESS: u64 = 0x00000000; pub const STATUS_ACCESS_DENIED: u64 = 0xC0000022; pub const STATUS_INVALID_HANDLE: u64 = 0xC0000008; diff --git a/src/emu/flags.rs b/src/emu/flags.rs index 1239ccc..42aeac2 100644 --- a/src/emu/flags.rs +++ b/src/emu/flags.rs @@ -86,14 +86,6 @@ impl Flags { } } - pub fn diff(rip: u64, pos: u64, a: Flags, b: Flags) -> String { - let mut output = String::new(); - if a.dump() != b.dump() { - output = format!("rflags: {:x} -> {:x}; ", a.dump(), b.dump()); - } - output - } - pub fn clear(&mut self) { self.f_cf = false; self.f_pf = false; @@ -139,6 +131,83 @@ impl Flags { log::info!("---"); } + pub fn diff(a: Flags, b: Flags) -> String { + let mut output = String::new(); + // f_cf + if a.f_cf != b.f_cf { + output = format!("{}{}: {} -> {} ", output, "cf", a.f_cf, b.f_cf); + } + // f_pf + if a.f_pf != b.f_pf { + output = format!("{}{}: {} -> {} ", output, "pf", a.f_pf, b.f_pf); + } + // f_af + if a.f_af != b.f_af { + output = format!("{}{}: {} -> {} ", output, "af", a.f_af, b.f_af); + } + // f_zf + if a.f_zf != b.f_zf { + output = format!("{}{}: {} -> {} ", output, "zf", a.f_zf, b.f_zf); + } + // f_sf + if a.f_sf != b.f_sf { + output = format!("{}{}: {} -> {} ", output, "sf", a.f_sf, b.f_sf); + } + // f_tf + if a.f_tf != b.f_tf { + output = format!("{}{}: {} -> {} ", output, "tf", a.f_tf, b.f_tf); + } + // f_if + if a.f_if != b.f_if { + output = format!("{}{}: {} -> {} ", output, "if", a.f_if, b.f_if); + } + // f_df + if a.f_df != b.f_df { + output = format!("{}{}: {} -> {} ", output, "df", a.f_df, b.f_df); + } + // f_of + if a.f_of != b.f_of { + output = format!("{}{}: {} -> {} ", output, "of", a.f_of, b.f_of); + } + // f_iopl1 + if a.f_iopl1 != b.f_iopl1 { + output = format!("{}{}: {} -> {} ", output, "iopl1", a.f_iopl1, b.f_iopl1); + } + // f_iopl2 + if a.f_iopl2 != b.f_iopl2 { + output = format!("{}{}: {} -> {} ", output, "iopl2", a.f_iopl2, b.f_iopl2); + } + // f_nt + if a.f_nt != b.f_nt { + output = format!("{}{}: {} -> {} ", output, "nt", a.f_nt, b.f_nt); + } + // f_rf + if a.f_rf != b.f_rf { + output = format!("{}{}: {} -> {} ", output, "rf", a.f_rf, b.f_rf); + } + // f_vm + if a.f_vm != b.f_vm { + output = format!("{}{}: {} -> {} ", output, "vm", a.f_vm, b.f_vm); + } + // f_ac + if a.f_ac != b.f_ac { + output = format!("{}{}: {} -> {} ", output, "ac", a.f_ac, b.f_ac); + } + // f_vif + if a.f_vif != b.f_vif { + output = format!("{}{}: {} -> {} ", output, "vif", a.f_vif, b.f_vif); + } + // f_vip + if a.f_vip != b.f_vip { + output = format!("{}{}: {} -> {} ", output, "vip", a.f_vip, b.f_vip); + } + // f_id + if a.f_id != b.f_id { + output = format!("{}{}: {} -> {} ", output, "id", a.f_id, b.f_id); + } + output + } + pub fn dump(&self) -> u32 { let mut flags: u32 = 0; @@ -336,77 +405,106 @@ impl Flags { //self.f_af = (value1 & 0x0f) + (value2 & 0x0f) > 0x09; } - - - pub fn add64(&mut self, value1: u64, value2: u64) -> u64 { - let unsigned: u128 = value1 as u128 + value2 as u128; - - self.f_sf = (unsigned as i64) < 0; - self.f_zf = (unsigned & 0xffffffff_ffffffff) == 0; - //self.f_pf = (unsigned & 0xff) % 2 == 0; - self.calc_pf(unsigned as u8); - let (result, carry) = (value2).overflowing_add(value1); - let (_, overflow) = (value2 as i64).overflowing_add(value1 as i64); - self.f_of = overflow; - self.f_cf = carry; - self.calc_af(value1, value2, result, 64); + pub fn add64(&mut self, value1: u64, value2: u64, cf: bool, include_carry: bool) -> u64 { + let v1 = value1; + let v2 = value2; + let c = if include_carry { cf as u64 } else { 0 }; - /* - let low_nibble_value1 = value1 & 0xf; - let low_nibble_value2 = value2 & 0xf; - self.f_af = (low_nibble_value1 > 0x7) && (low_nibble_value2 > 0x7); - */ - + let result = v1.wrapping_add(v2).wrapping_add(c); + let sum = v1 as u128 + v2 as u128 + c as u128; + + self.f_cf = sum > 0xFFFFFFFFFFFFFFFF; + self.f_sf = (result as i64) < 0; + self.f_zf = result == 0; + self.calc_pf(result as u8); + + let sign1 = (v1 >> 63) & 1; + let sign2 = (v2 >> 63) & 1; + let signr = (result >> 63) & 1; + self.f_of = (sign1 == sign2) && (sign1 != signr); + + self.calc_af(v1, v2, result, 64); result } - - pub fn add32(&mut self, value1: u64, value2: u64) -> u64 { - let unsigned: u64 = value1 + value2; - - self.f_sf = (unsigned as i32) < 0; - self.f_zf = (unsigned & 0xffffffff) == 0; - //self.f_pf = (unsigned & 0xff) % 2 == 0; - self.calc_pf(unsigned as u8); - let (result, carry) = (value2 as u32).overflowing_add(value1 as u32); - let (_, overflow) = (value2 as u32 as i32).overflowing_add(value1 as u32 as i32); - self.f_of = overflow; - self.f_cf = carry; - self.calc_af(value1, value2, result as u64, 32); - + + pub fn add32(&mut self, value1: u32, value2: u32, cf: bool, include_carry: bool) -> u64 { + let result = if include_carry { + value1.wrapping_add(value2).wrapping_add(cf as u32) + } else { + value1.wrapping_add(value2) + }; + + let sum = if include_carry { + value1 as u64 + value2 as u64 + cf as u64 + } else { + value1 as u64 + value2 as u64 + }; + + self.f_cf = sum > 0xFFFFFFFF; + self.f_sf = (result as i32) < 0; + self.f_zf = result == 0; + self.calc_pf(result as u8); + + let sign1 = (value1 >> 31) & 1; + let sign2 = (value2 >> 31) & 1; + let signr = (result >> 31) & 1; + self.f_of = (sign1 == sign2) && (sign1 != signr); + + self.calc_af(value1 as u64, value2 as u64, result as u64, 32); result as u64 - } - - pub fn add16(&mut self, value1: u64, value2: u64) -> u64 { - if value1 > 0xffff || value2 > 0xffff { - panic!("add16 with a bigger precision"); - } - - let unsigned: u32 = value1 as u32 + value2 as u32; - - self.f_sf = (unsigned as i16) < 0; - self.f_zf = (unsigned & 0xffff) == 0; - self.calc_pf(unsigned as u8); - let (result, carry) = (value2 as u16).overflowing_add(value1 as u16); - let (_, overflow) = (value2 as u16 as i16).overflowing_add(value1 as u16 as i16); - self.f_of = overflow; - self.f_cf = carry; - self.calc_af(value1, value2, result as u64, 16); - + } + + pub fn add16(&mut self, value1: u16, value2: u16, cf: bool, include_carry: bool) -> u64 { + let result = if include_carry { + value1.wrapping_add(value2).wrapping_add(cf as u16) + } else { + value1.wrapping_add(value2) + }; + + let sum = if include_carry { + value1 as u32 + value2 as u32 + cf as u32 + } else { + value1 as u32 + value2 as u32 + }; + + self.f_cf = sum > 0xFFFF; + self.f_sf = (result as i16) < 0; + self.f_zf = result == 0; + self.calc_pf(result as u8); + + let sign1 = (value1 >> 15) & 1; + let sign2 = (value2 >> 15) & 1; + let signr = (result >> 15) & 1; + self.f_of = (sign1 == sign2) && (sign1 != signr); + + self.calc_af(value1 as u64, value2 as u64, result as u64, 16); result as u64 - } - - pub fn add8(&mut self, value1: u64, value2: u64) -> u64 { - let unsigned: u16 = value1 as u8 as u16 + value2 as u8 as u16; - - self.f_sf = (unsigned as i8) < 0; - self.f_zf = (unsigned & 0xff) == 0; - self.calc_pf(unsigned as u8); - let (result, carry) = (value2 as u8).overflowing_add(value1 as u8); - let (_, overflow) = (value2 as u8 as i8).overflowing_add(value1 as u8 as i8); - self.f_of = overflow; - self.f_cf = carry; - self.calc_af(value1, value2, result as u64, 8); - + } + + pub fn add8(&mut self, value1: u8, value2: u8, cf: bool, include_carry: bool) -> u64 { + let result = if include_carry { + value1.wrapping_add(value2).wrapping_add(cf as u8) + } else { + value1.wrapping_add(value2) + }; + + let sum = if include_carry { + value1 as u16 + value2 as u16 + cf as u16 + } else { + value1 as u16 + value2 as u16 + }; + + self.f_cf = sum > 0xFF; + self.f_sf = (result as i8) < 0; + self.f_zf = result == 0; + self.calc_pf(result as u8); + + let sign1 = (value1 >> 7) & 1; + let sign2 = (value2 >> 7) & 1; + let signr = (result >> 7) & 1; + self.f_of = (sign1 == sign2) && (sign1 != signr); + + self.calc_af(value1 as u64, value2 as u64, result as u64, 8); result as u64 } diff --git a/src/emu.rs b/src/emu/mod.rs similarity index 99% rename from src/emu.rs rename to src/emu/mod.rs index ed0afe1..30540d6 100644 --- a/src/emu.rs +++ b/src/emu/mod.rs @@ -417,7 +417,6 @@ impl Emu { pub fn init(&mut self, clear_registers: bool, clear_flags: bool) { self.pos = 0; - if !atty::is(Stream::Stdout) { self.cfg.nocolors = true; self.colors.disable(); @@ -819,7 +818,6 @@ impl Emu { // base is setted by image base (if overlapps, alloc) } else { - // user's program if set_entry { if pe64.opt.image_base >= constants::LIBS64_MIN as u64 { @@ -3313,7 +3311,7 @@ impl Emu { } } else { if self.seh == 0 { - log::info!("exception without any SEH handler nor vector configured."); + log::info!("exception without any SEH handler nor vector configured. pos = {}", self.pos); if self.cfg.console_enabled { self.spawn_console(); } @@ -4265,35 +4263,16 @@ impl Emu { } pub fn write_to_trace_file(&mut self) { - // 00,00007FFBEF4E5FF0,EB 08,jmp 7FFBEF4E5FFA,rax: 7FFBEF4E5FF0-> 7FFBEF4E5FF0 rbx: 7FFE0385-> 7FFE0385 rcx: 7FFBEE4B0000-> 7FFBEE4B0000 rdx: 1-> 1 rsp: 98EB5DDFF8-> 98EB5DDFF8 rbp: 98EB5DE338-> 98EB5DE338 rsi: 1-> 1 rdi: 7FFE0384-> 7FFE0384 r8: 0-> 0 r9: 0-> 0 r10: A440AE23305F3A70-> A440AE23305F3A70 r11: 98EB5DE068-> 98EB5DE068 r12: 7FFBEF4E5FF0-> 7FFBEF4E5FF0 r13: 1FC18C72DC0-> 1FC18C72DC0 r14: 7FFBEE4B0000-> 7FFBEE4B0000 r15: 0-> 0 rflags: 344-> 246,,OptionalHeader.AddressOfEntryPoint - // 01,00007FFBEF4E5FFA,50,push rax,rsp: 98EB5DDFF8-> 98EB5DDFF0,00000098EB5DDFF0: 7FFC65FF8B8F-> 7FFBEF4E5FF0,rax:GetMsgProc+102D07D let index = self.pos - 1; let instruction = self.instruction.unwrap(); let instruction_bytes = &self.instruction_bytes; + let mut comments = String::new(); + // dump all registers on first, only differences on next let mut registers = String::new(); if index == 0 { - /* - rax: 7FFBEF4E5FF0->7FFBEF4E5FF0 - rbx: 7FFE0385->7FFE0385 - rcx: 7FFBEE4B0000->7FFBEE4B0000 - rdx: 1->1 - rsp: 98EB5DDFF8->98EB5DDFF8 - rbp: 98EB5DE338->98EB5DE338 - rsi: 1->1 - rdi: 7FFE0384->7FFE0384 - r8: 0->0 - r9: 0->0 - r10: A440AE23305F3A70->A440AE23305F3A70 - r11: 98EB5DE068->98EB5DE068 - r12: 7FFBEF4E5FF0->7FFBEF4E5FF0 - r13: 1FC18C72DC0->1FC18C72DC0 - r14: 7FFBEE4B0000->7FFBEE4B0000 - r15: 0->0 - rflags: 344->246 - */ registers = format!("{} rax: {:x}-> {:x}", registers, self.pre_op_regs.rax, self.post_op_regs.rax); registers = format!("{} rbx: {:x}-> {:x}", registers, self.pre_op_regs.rbx, self.post_op_regs.rbx); registers = format!("{} rcx: {:x}-> {:x}", registers, self.pre_op_regs.rcx, self.post_op_regs.rcx); @@ -4312,28 +4291,28 @@ impl Emu { registers = format!("{} r15: {:x}-> {:x}", registers, self.pre_op_regs.r15, self.post_op_regs.r15); } else { registers = Regs64::diff( - self.pre_op_regs.rip, - self.pos - 1, self.pre_op_regs, self.post_op_regs, ); } let mut flags = String::new(); + // dump all flags on first, only differences on next if index == 0 { flags = format!("rflags: {:x}-> {:x}", self.pre_op_flags.dump(), self.post_op_flags.dump()); } else { if self.pre_op_flags.dump() != self.post_op_flags.dump() { flags = format!("rflags: {:x}-> {:x}", self.pre_op_flags.dump(), self.post_op_flags.dump()); + comments = format!("{} {}", comments, Flags::diff(self.pre_op_flags, self.post_op_flags)); } } + // dump all write memory operations let mut memory = String::new(); for memory_op in self.memory_operations.iter() { if memory_op.op == "read" { continue; } - // 00000098EB5DDFF0: 7FFC65FF8B8F-> 7FFBEF4E5FF0 memory = format!("{} {:016X}: {:X}-> {:X}", memory, memory_op.address, memory_op.old_value, memory_op.new_value); } @@ -4347,7 +4326,7 @@ impl Emu { disassembly = self.out, registers = format!("{} {}", registers, flags), memory = memory, - comments = "" + comments = comments ).expect("failed to write to trace file"); } @@ -4422,6 +4401,12 @@ impl Emu { pub fn step(&mut self) -> bool { self.pos += 1; + // exit + if self.cfg.exit_position != 0 && self.pos == self.cfg.exit_position { + log::info!("exit position reached"); + std::process::exit(0); + } + // code let code = match self.maps.get_mem_by_addr(self.regs.rip) { Some(c) => c, @@ -4437,8 +4422,8 @@ impl Emu { // block let block = code.read_from(self.regs.rip).to_vec(); // reduce code block for more speed - // - // decoder + + // decoder let mut decoder; if self.cfg.is_64bits { decoder = Decoder::with_ip(64, &block, self.regs.rip, DecoderOptions::NONE); @@ -4545,7 +4530,6 @@ impl Emu { //let mut position:usize = 0; //let mut instruction_bytes:Vec = Vec::new(); - self.rep = None; while decoder.can_decode() { if self.rep.is_none() { @@ -4567,6 +4551,11 @@ impl Emu { self.memory_operations.clear(); self.pos += 1; + if self.cfg.exit_position != 0 && self.pos == self.cfg.exit_position { + log::info!("exit position reached"); + std::process::exit(0); + } + if self.exp == self.pos || self.pos == self.bp.get_instruction() || self.bp.get_bp() == addr @@ -4671,11 +4660,30 @@ impl Emu { self.rep = Some(rep_count + 1); } } - if ins.has_repe_prefix() && !self.flags.f_zf { - self.rep = None; - } - if ins.has_repne_prefix() && self.flags.f_zf { - self.rep = None; + + // repe and repe are the same on x86 (0xf3) so you have to check if it is movement or comparison + let is_string_movement = matches!( + ins.mnemonic(), + Mnemonic::Movsb | Mnemonic::Movsw | Mnemonic::Movsd | Mnemonic::Movsq | + Mnemonic::Stosb | Mnemonic::Stosw | Mnemonic::Stosd | Mnemonic::Stosq | + Mnemonic::Lodsb | Mnemonic::Lodsw | Mnemonic::Lodsd | Mnemonic::Lodsq + ); + let is_string_comparison = matches!( + ins.mnemonic(), + Mnemonic::Cmpsb | Mnemonic::Cmpsw | Mnemonic::Cmpsd | Mnemonic::Cmpsq | + Mnemonic::Scasb | Mnemonic::Scasw | Mnemonic::Scasd | Mnemonic::Scasq + ); + if is_string_movement { + // do not clear rep if it is a string movement + } else if is_string_comparison { + if ins.has_repe_prefix() && !self.flags.f_zf { + self.rep = None; + } + if ins.has_repne_prefix() && self.flags.f_zf { + self.rep = None; + } + } else { + unimplemented!("string instruction not supported"); } } @@ -5100,10 +5108,10 @@ impl Emu { }; let res: u64 = match self.get_operand_sz(&ins, 1) { - 64 => self.flags.add64(value0, value1), - 32 => self.flags.add32(value0, value1), - 16 => self.flags.add16(value0, value1), - 8 => self.flags.add8(value0, value1), + 64 => self.flags.add64(value0, value1, self.flags.f_cf, false), + 32 => self.flags.add32((value0 & 0xffffffff) as u32, (value1 & 0xffffffff) as u32, self.flags.f_cf, false), + 16 => self.flags.add16((value0 & 0xffff) as u16, (value1 & 0xffff) as u16, self.flags.f_cf, false), + 8 => self.flags.add8((value0 & 0xff) as u8, (value1 & 0xff) as u8, self.flags.f_cf, false), _ => unreachable!("weird size"), }; @@ -5117,12 +5125,7 @@ impl Emu { assert!(ins.op_count() == 2); - let cf: u64; - if self.flags.f_cf { - cf = 1 - } else { - cf = 0; - } + let cf = self.flags.f_cf as u64; let value0 = match self.get_operand_value(&ins, 0, true) { Some(v) => v, @@ -5134,14 +5137,13 @@ impl Emu { None => return false, }; - let res: u64; - match self.get_operand_sz(&ins, 1) { - 64 => res = self.flags.add64(value0, value1 + cf), - 32 => res = self.flags.add32(value0, value1 + cf), - 16 => res = self.flags.add16(value0, value1 + cf), - 8 => res = self.flags.add8(value0, value1 + cf), + let res = match self.get_operand_sz(&ins, 1) { + 64 => self.flags.add64(value0, value1, self.flags.f_cf, true), + 32 => self.flags.add32((value0 & 0xffffffff) as u32, (value1 & 0xffffffff) as u32, self.flags.f_cf, true), + 16 => self.flags.add16((value0 & 0xffff) as u16, (value1 & 0xffff) as u16, self.flags.f_cf, true), + 8 => self.flags.add8((value0 & 0xff) as u8, (value1 & 0xff) as u8, self.flags.f_cf, true), _ => unreachable!("weird size"), - } + }; if !self.set_operand_value(&ins, 0, res) { return false; @@ -5169,9 +5171,9 @@ impl Emu { let sz = self.get_operand_sz(&ins, 1); match sz { 64 => res = self.flags.sub64(value0, value1.wrapping_add(cf)), - 32 => res = self.flags.sub32(value0, value1.wrapping_add(cf)), - 16 => res = self.flags.sub16(value0, value1.wrapping_add(cf)), - 8 => res = self.flags.sub8(value0, value1.wrapping_add(cf)), + 32 => res = self.flags.sub32(value0, (value1 & 0xffffffff).wrapping_add(cf)), + 16 => res = self.flags.sub16(value0, (value1 & 0xffff).wrapping_add(cf)), + 8 => res = self.flags.sub8(value0, (value1 & 0xff).wrapping_add(cf)), _ => panic!("weird size"), } @@ -6558,10 +6560,10 @@ impl Emu { } let res: u64 = match self.get_operand_sz(&ins, 1) { - 64 => self.flags.add64(value0, value1), - 32 => self.flags.add32(value0, value1), - 16 => self.flags.add16(value0, value1), - 8 => self.flags.add8(value0, value1), + 64 => self.flags.add64(value0, value1, self.flags.f_cf, false), + 32 => self.flags.add32((value0 & 0xffffffff) as u32, (value1 & 0xffffffff) as u32, self.flags.f_cf, false), + 16 => self.flags.add16((value0 & 0xffff) as u16, (value1 & 0xffff) as u16, self.flags.f_cf, false), + 8 => self.flags.add8((value0 & 0xff) as u8, (value1 & 0xff) as u8, self.flags.f_cf, false), _ => unreachable!("weird size"), }; diff --git a/src/emu/regs64.rs b/src/emu/regs64.rs index 495e0f5..4bc2e30 100644 --- a/src/emu/regs64.rs +++ b/src/emu/regs64.rs @@ -268,7 +268,7 @@ impl Regs64 { } } - pub fn diff(rip: u64, pos: u64, a: Regs64, b: Regs64) -> String { + pub fn diff(a: Regs64, b: Regs64) -> String { let mut output = String::new(); if a.dr0 != b.dr0 { output = format!("{}{}: {:x} -> {:x} ", output, "dr0", a.dr0, b.dr0); diff --git a/src/emu/winapi32.rs b/src/emu/winapi32.rs index f0e21c4..500f056 100644 --- a/src/emu/winapi32.rs +++ b/src/emu/winapi32.rs @@ -19,6 +19,8 @@ mod wincrt; use crate::emu; pub fn gateway(addr: u32, name: String, emu: &mut emu::Emu) { + log::info!("winapi32::gateway called with addr: 0x{:x}, name: {}", addr, name); + emu.regs.sanitize32(); let unimplemented_api = match name.as_str() { "kernel32.text" => kernel32::gateway(addr, emu), diff --git a/src/emu/winapi64.rs b/src/emu/winapi64.rs index f99f582..31e24f1 100644 --- a/src/emu/winapi64.rs +++ b/src/emu/winapi64.rs @@ -14,6 +14,8 @@ mod kernelbase; use crate::emu; pub fn gateway(addr: u64, name: String, emu: &mut emu::Emu) { + log::info!("winapi64::gateway called with addr: 0x{:x}, name: {}", addr, name); + let unimplemented_api = match name.as_str() { "kernel32.text" => kernel32::gateway(addr, emu), "kernel32.rdata" => kernel32::gateway(addr, emu),