1 // 2 // Copyright © 2021 Microsoft 3 // 4 // SPDX-License-Identifier: Apache-2.0 5 // 6 7 #![allow(non_camel_case_types)] 8 9 // 10 // MOVS - Move Data from String to String 11 // 12 13 use crate::arch::emulator::{EmulationError, PlatformEmulator}; 14 use crate::arch::x86::emulator::instructions::*; 15 use crate::arch::x86::regs::DF; 16 use crate::arch::x86::Exception; 17 18 pub struct Movsd_m32_m32; 19 impl<T: CpuStateManager> InstructionHandler<T> for Movsd_m32_m32 { 20 fn emulate( 21 &self, 22 insn: &Instruction, 23 state: &mut T, 24 platform: &mut dyn PlatformEmulator<CpuState = T>, 25 ) -> Result<(), EmulationError<Exception>> { 26 let mut count: u64 = if insn.has_rep_prefix() { 27 state 28 .read_reg(Register::ECX) 29 .map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))? 30 } else { 31 1 32 }; 33 34 let mut rsi = state 35 .read_reg(Register::RSI) 36 .map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?; 37 let mut rdi = state 38 .read_reg(Register::RDI) 39 .map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?; 40 41 let df = (state.flags() & DF) != 0; 42 let len = std::mem::size_of::<u32>(); 43 44 while count > 0 { 45 let mut memory: [u8; 4] = [0; 4]; 46 47 let src = state 48 .linearize(Register::DS, rsi, false) 49 .map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?; 50 let dst = state 51 .linearize(Register::ES, rdi, true) 52 .map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?; 53 54 platform 55 .read_memory(src, &mut memory[0..len]) 56 .map_err(EmulationError::PlatformEmulationError)?; 57 platform 58 .write_memory(dst, &memory[0..len]) 59 .map_err(EmulationError::PlatformEmulationError)?; 60 61 if df { 62 rsi = rsi.wrapping_sub(len as u64); 63 rdi = rdi.wrapping_sub(len as u64); 64 } else { 65 rsi = rsi.wrapping_add(len as u64); 66 rdi = rdi.wrapping_add(len as u64); 67 } 68 count -= 1; 69 } 70 71 state 72 .write_reg(Register::RSI, rsi) 73 .map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?; 74 state 75 .write_reg(Register::RDI, rdi) 76 .map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?; 77 if insn.has_rep_prefix() { 78 state 79 .write_reg(Register::ECX, 0) 80 .map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?; 81 } 82 83 Ok(()) 84 } 85 } 86 87 #[cfg(test)] 88 mod tests { 89 #![allow(unused_mut)] 90 use super::*; 91 use crate::arch::x86::emulator::mock_vmm::*; 92 93 #[test] 94 fn test_rep_movsd_m32_m32() { 95 let ip: u64 = 0x1000; 96 let memory: [u8; 24] = [ 97 0x78, 0x56, 0x34, 0x12, // 0x12345678 98 0xdd, 0xcc, 0xbb, 0xaa, // 0xaabbccdd 99 0xa5, 0x5a, 0xa5, 0x5a, // 0x5aa55aa5 100 0x00, 0x00, 0x00, 0x00, // 0x00000000 101 0x00, 0x00, 0x00, 0x00, // 0x00000000 102 0x00, 0x00, 0x00, 0x00, // 0x00000000 103 ]; 104 let insn = [0xf3, 0xa5]; // rep movsd 105 let regs = vec![(Register::ECX, 3), (Register::ESI, 0), (Register::EDI, 0xc)]; 106 let mut data = [0u8; 4]; 107 108 let mut vmm = MockVmm::new(ip, regs, Some((0, &memory))); 109 110 assert!(vmm.emulate_first_insn(0, &insn).is_ok()); 111 112 vmm.read_memory(0xc, &mut data).unwrap(); 113 assert_eq!(0x12345678, <u32>::from_le_bytes(data)); 114 vmm.read_memory(0xc + 4, &mut data).unwrap(); 115 assert_eq!(0xaabbccdd, <u32>::from_le_bytes(data)); 116 vmm.read_memory(0xc + 8, &mut data).unwrap(); 117 assert_eq!(0x5aa55aa5, <u32>::from_le_bytes(data)); 118 // The rest should be default value 0 from MockVmm 119 vmm.read_memory(0xc + 12, &mut data).unwrap(); 120 assert_eq!(0x0, <u32>::from_le_bytes(data)); 121 } 122 123 #[test] 124 fn test_movsd_m32_m32() { 125 let ip: u64 = 0x1000; 126 let memory: [u8; 4] = [ 127 0x78, 0x56, 0x34, 0x12, // 0x12345678 128 ]; 129 let insn = [0xa5]; // movsd 130 let regs = vec![(Register::ESI, 0), (Register::EDI, 0x8)]; 131 let mut data = [0u8; 4]; 132 133 let mut vmm = MockVmm::new(ip, regs, Some((0, &memory))); 134 135 assert!(vmm.emulate_first_insn(0, &insn).is_ok()); 136 137 vmm.read_memory(0x8, &mut data).unwrap(); 138 assert_eq!(0x12345678, <u32>::from_le_bytes(data)); 139 // The rest should be default value 0 from MockVmm 140 vmm.read_memory(0x4, &mut data).unwrap(); 141 assert_eq!(0x0, <u32>::from_le_bytes(data)); 142 vmm.read_memory(0x8 + 8, &mut data).unwrap(); 143 assert_eq!(0x0, <u32>::from_le_bytes(data)); 144 } 145 } 146