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::x86::emulator::instructions::*; 14 use crate::arch::x86::regs::DF; 15 16 macro_rules! movs { 17 ($bound:ty) => { 18 fn emulate( 19 &self, 20 insn: &Instruction, 21 state: &mut T, 22 platform: &mut dyn PlatformEmulator<CpuState = T>, 23 ) -> Result<(), EmulationError<Exception>> { 24 let mut count: u64 = if insn.has_rep_prefix() { 25 state 26 .read_reg(Register::ECX) 27 .map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))? 28 } else { 29 1 30 }; 31 32 let mut rsi = state 33 .read_reg(Register::RSI) 34 .map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?; 35 let mut rdi = state 36 .read_reg(Register::RDI) 37 .map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?; 38 39 let df = (state.flags() & DF) != 0; 40 let len = std::mem::size_of::<$bound>(); 41 42 while count > 0 { 43 let mut memory: [u8; 4] = [0; 4]; 44 45 let src = state 46 .linearize(Register::DS, rsi, false) 47 .map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?; 48 let dst = state 49 .linearize(Register::ES, rdi, true) 50 .map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?; 51 52 platform 53 .read_memory(src, &mut memory[0..len]) 54 .map_err(EmulationError::PlatformEmulationError)?; 55 platform 56 .write_memory(dst, &memory[0..len]) 57 .map_err(EmulationError::PlatformEmulationError)?; 58 59 if df { 60 rsi = rsi.wrapping_sub(len as u64); 61 rdi = rdi.wrapping_sub(len as u64); 62 } else { 63 rsi = rsi.wrapping_add(len as u64); 64 rdi = rdi.wrapping_add(len as u64); 65 } 66 count -= 1; 67 } 68 69 state 70 .write_reg(Register::RSI, rsi) 71 .map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?; 72 state 73 .write_reg(Register::RDI, rdi) 74 .map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?; 75 if insn.has_rep_prefix() { 76 state 77 .write_reg(Register::ECX, 0) 78 .map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?; 79 } 80 81 Ok(()) 82 } 83 }; 84 } 85 86 pub struct Movsd_m32_m32; 87 impl<T: CpuStateManager> InstructionHandler<T> for Movsd_m32_m32 { 88 movs!(u32); 89 } 90 91 pub struct Movsw_m16_m16; 92 impl<T: CpuStateManager> InstructionHandler<T> for Movsw_m16_m16 { 93 movs!(u16); 94 } 95 96 pub struct Movsb_m8_m8; 97 impl<T: CpuStateManager> InstructionHandler<T> for Movsb_m8_m8 { 98 movs!(u8); 99 } 100 101 #[cfg(test)] 102 mod tests { 103 use super::*; 104 use crate::arch::x86::emulator::mock_vmm::*; 105 106 #[test] 107 fn test_rep_movsd_m32_m32() { 108 let ip: u64 = 0x1000; 109 let memory: [u8; 24] = [ 110 0x78, 0x56, 0x34, 0x12, // 0x12345678 111 0xdd, 0xcc, 0xbb, 0xaa, // 0xaabbccdd 112 0xa5, 0x5a, 0xa5, 0x5a, // 0x5aa55aa5 113 0x00, 0x00, 0x00, 0x00, // 0x00000000 114 0x00, 0x00, 0x00, 0x00, // 0x00000000 115 0x00, 0x00, 0x00, 0x00, // 0x00000000 116 ]; 117 let insn = [0xf3, 0xa5]; // rep movsd 118 let regs = vec![(Register::ECX, 3), (Register::ESI, 0), (Register::EDI, 0xc)]; 119 let mut data = [0u8; 4]; 120 121 let mut vmm = MockVmm::new(ip, regs, Some((0, &memory))); 122 123 assert!(vmm.emulate_first_insn(0, &insn).is_ok()); 124 125 vmm.read_memory(0xc, &mut data).unwrap(); 126 assert_eq!(0x12345678, <u32>::from_le_bytes(data)); 127 vmm.read_memory(0xc + 4, &mut data).unwrap(); 128 assert_eq!(0xaabbccdd, <u32>::from_le_bytes(data)); 129 vmm.read_memory(0xc + 8, &mut data).unwrap(); 130 assert_eq!(0x5aa55aa5, <u32>::from_le_bytes(data)); 131 // The rest should be default value 0 from MockVmm 132 vmm.read_memory(0xc + 12, &mut data).unwrap(); 133 assert_eq!(0x0, <u32>::from_le_bytes(data)); 134 } 135 136 #[test] 137 fn test_movsd_m32_m32() { 138 let ip: u64 = 0x1000; 139 let memory: [u8; 4] = [ 140 0x78, 0x56, 0x34, 0x12, // 0x12345678 141 ]; 142 let insn = [0xa5]; // movsd 143 let regs = vec![(Register::ESI, 0), (Register::EDI, 0x8)]; 144 let mut data = [0u8; 4]; 145 146 let mut vmm = MockVmm::new(ip, regs, Some((0, &memory))); 147 148 assert!(vmm.emulate_first_insn(0, &insn).is_ok()); 149 150 vmm.read_memory(0x8, &mut data).unwrap(); 151 assert_eq!(0x12345678, <u32>::from_le_bytes(data)); 152 // The rest should be default value 0 from MockVmm 153 vmm.read_memory(0x4, &mut data).unwrap(); 154 assert_eq!(0x0, <u32>::from_le_bytes(data)); 155 vmm.read_memory(0x8 + 8, &mut data).unwrap(); 156 assert_eq!(0x0, <u32>::from_le_bytes(data)); 157 } 158 159 #[test] 160 fn test_rep_movsw_m16_m16() { 161 let ip: u64 = 0x1000; 162 let memory: [u8; 24] = [ 163 0x78, 0x56, 0x34, 0x12, // 0x12345678 164 0xdd, 0xcc, 0xbb, 0xaa, // 0xaabbccdd 165 0xa5, 0x5a, 0xa5, 0x5a, // 0x5aa55aa5 166 0x00, 0x00, 0x00, 0x00, // 0x00000000 167 0x00, 0x00, 0x00, 0x00, // 0x00000000 168 0x00, 0x00, 0x00, 0x00, // 0x00000000 169 ]; 170 let insn = [0x66, 0xf3, 0xa5]; // rep movsw 171 let regs = vec![(Register::ECX, 6), (Register::ESI, 0), (Register::EDI, 0xc)]; 172 let mut data = [0u8; 2]; 173 174 let mut vmm = MockVmm::new(ip, regs, Some((0, &memory))); 175 176 assert!(vmm.emulate_first_insn(0, &insn).is_ok()); 177 178 vmm.read_memory(0xc, &mut data).unwrap(); 179 assert_eq!(0x5678, <u16>::from_le_bytes(data)); 180 vmm.read_memory(0xc + 2, &mut data).unwrap(); 181 assert_eq!(0x1234, <u16>::from_le_bytes(data)); 182 vmm.read_memory(0xc + 4, &mut data).unwrap(); 183 assert_eq!(0xccdd, <u16>::from_le_bytes(data)); 184 vmm.read_memory(0xc + 6, &mut data).unwrap(); 185 assert_eq!(0xaabb, <u16>::from_le_bytes(data)); 186 vmm.read_memory(0xc + 8, &mut data).unwrap(); 187 assert_eq!(0x5aa5, <u16>::from_le_bytes(data)); 188 vmm.read_memory(0xc + 10, &mut data).unwrap(); 189 assert_eq!(0x5aa5, <u16>::from_le_bytes(data)); 190 // The rest should be default value 0 from MockVmm 191 vmm.read_memory(0xc + 12, &mut data).unwrap(); 192 assert_eq!(0x0, <u16>::from_le_bytes(data)); 193 } 194 195 #[test] 196 fn test_movsw_m16_m16() { 197 let ip: u64 = 0x1000; 198 let memory: [u8; 4] = [ 199 0x78, 0x56, 0x34, 0x12, // 0x12345678 200 ]; 201 let insn = [0x66, 0xa5]; // movsw 202 let regs = vec![(Register::ESI, 0), (Register::EDI, 0x8)]; 203 let mut data = [0u8; 2]; 204 205 let mut vmm = MockVmm::new(ip, regs, Some((0, &memory))); 206 207 assert!(vmm.emulate_first_insn(0, &insn).is_ok()); 208 209 vmm.read_memory(0x8, &mut data).unwrap(); 210 assert_eq!(0x5678, <u16>::from_le_bytes(data)); 211 // Only two bytes were copied, so the value at 0xa should be zero 212 vmm.read_memory(0xa, &mut data).unwrap(); 213 assert_eq!(0x0, <u16>::from_le_bytes(data)); 214 // The rest should be default value 0 from MockVmm 215 vmm.read_memory(0x4, &mut data).unwrap(); 216 assert_eq!(0x0, <u16>::from_le_bytes(data)); 217 vmm.read_memory(0x8 + 8, &mut data).unwrap(); 218 assert_eq!(0x0, <u16>::from_le_bytes(data)); 219 } 220 221 #[test] 222 fn test_movsb_m8_m8() { 223 let ip: u64 = 0x1000; 224 let memory: [u8; 4] = [ 225 0x78, 0x56, 0x34, 0x12, // 0x12345678 226 ]; 227 let insn = [0x66, 0xa4]; // movsb 228 let regs = vec![(Register::ESI, 0), (Register::EDI, 0x8)]; 229 let mut data = [0u8; 1]; 230 231 let mut vmm = MockVmm::new(ip, regs, Some((0, &memory))); 232 233 assert!(vmm.emulate_first_insn(0, &insn).is_ok()); 234 235 vmm.read_memory(0x8, &mut data).unwrap(); 236 assert_eq!(0x78, data[0]); 237 // Only one byte was copied, so the value at 0x9 should be zero 238 vmm.read_memory(0x9, &mut data).unwrap(); 239 assert_eq!(0x0, data[0]); 240 // The rest should be default value 0 from MockVmm 241 vmm.read_memory(0x4, &mut data).unwrap(); 242 assert_eq!(0x0, data[0]); 243 // the src value is left as is after movb 244 vmm.read_memory(0x0, &mut data).unwrap(); 245 assert_eq!(0x78, data[0]); 246 } 247 248 #[test] 249 fn test_rep_movsb_m8_m8() { 250 let ip: u64 = 0x1000; 251 let memory: [u8; 16] = [ 252 0x78, 0x56, 0x34, 0x12, // 0x12345678 253 0xbb, 0xaa, 0x00, 0x00, // 0x0000aabb 254 0x00, 0x00, 0x00, 0x00, // 0x00000000 255 0x00, 0x00, 0x00, 0x00, // 0x00000000 256 ]; 257 let insn = [0x66, 0xf3, 0xa4]; // rep movsw 258 let regs = vec![(Register::ECX, 6), (Register::ESI, 0), (Register::EDI, 0x8)]; 259 let mut data = [0u8; 1]; 260 261 let mut vmm = MockVmm::new(ip, regs, Some((0, &memory))); 262 263 assert!(vmm.emulate_first_insn(0, &insn).is_ok()); 264 265 vmm.read_memory(0x8, &mut data).unwrap(); 266 assert_eq!(0x78, data[0]); 267 vmm.read_memory(0x8 + 1, &mut data).unwrap(); 268 assert_eq!(0x56, data[0]); 269 vmm.read_memory(0x8 + 2, &mut data).unwrap(); 270 assert_eq!(0x34, data[0]); 271 vmm.read_memory(0x8 + 3, &mut data).unwrap(); 272 assert_eq!(0x12, data[0]); 273 vmm.read_memory(0x8 + 4, &mut data).unwrap(); 274 assert_eq!(0xbb, data[0]); 275 vmm.read_memory(0x8 + 5, &mut data).unwrap(); 276 assert_eq!(0xaa, data[0]); 277 // The rest should be default value 0 from MockVmm 278 vmm.read_memory(0x8 + 6, &mut data).unwrap(); 279 assert_eq!(0x0, data[0]); 280 } 281 } 282