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; 8] = [0; 8]; 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 Movsq_m64_m64; 87 impl<T: CpuStateManager> InstructionHandler<T> for Movsq_m64_m64 { 88 movs!(u64); 89 } 90 91 pub struct Movsd_m32_m32; 92 impl<T: CpuStateManager> InstructionHandler<T> for Movsd_m32_m32 { 93 movs!(u32); 94 } 95 96 pub struct Movsw_m16_m16; 97 impl<T: CpuStateManager> InstructionHandler<T> for Movsw_m16_m16 { 98 movs!(u16); 99 } 100 101 pub struct Movsb_m8_m8; 102 impl<T: CpuStateManager> InstructionHandler<T> for Movsb_m8_m8 { 103 movs!(u8); 104 } 105 106 #[cfg(test)] 107 mod tests { 108 use super::*; 109 use crate::arch::x86::emulator::mock_vmm::*; 110 111 #[test] 112 fn test_rep_movsq_m64_m64() { 113 let ip: u64 = 0x1000; 114 let memory: [u8; 32] = [ 115 0x78, 0x56, 0x34, 0x12, // 0x12345678 116 0xdd, 0xcc, 0xbb, 0xaa, // 0xaabbccdd 117 0xa5, 0x5a, 0xa5, 0x5a, // 0x5aa55aa5 118 0xcd, 0xcd, 0xcd, 0xcd, // 0xcdcdcdcd 119 0x00, 0x00, 0x00, 0x00, // 0x00000000 120 0x00, 0x00, 0x00, 0x00, // 0x00000000 121 0x00, 0x00, 0x00, 0x00, // 0x00000000 122 0x00, 0x00, 0x00, 0x00, // 0x00000000 123 ]; 124 let insn = [0xf3, 0x48, 0xa5]; // rep movsq 125 let regs = vec![ 126 (Register::ECX, 2), 127 (Register::ESI, 0), 128 (Register::EDI, 0x10), 129 ]; 130 let mut data = [0u8; 8]; 131 132 let mut vmm = MockVmm::new(ip, regs, Some((0, &memory))); 133 134 assert!(vmm.emulate_first_insn(0, &insn).is_ok()); 135 136 vmm.read_memory(0x10, &mut data).unwrap(); 137 assert_eq!(0xaabbccdd12345678, <u64>::from_le_bytes(data)); 138 vmm.read_memory(0x18, &mut data).unwrap(); 139 assert_eq!(0xcdcdcdcd5aa55aa5, <u64>::from_le_bytes(data)); 140 // The rest should be default value 0 from MockVmm 141 vmm.read_memory(0x20, &mut data).unwrap(); 142 assert_eq!(0x0, <u64>::from_le_bytes(data)); 143 } 144 145 #[test] 146 fn test_rep_movsd_m32_m32() { 147 let ip: u64 = 0x1000; 148 let memory: [u8; 24] = [ 149 0x78, 0x56, 0x34, 0x12, // 0x12345678 150 0xdd, 0xcc, 0xbb, 0xaa, // 0xaabbccdd 151 0xa5, 0x5a, 0xa5, 0x5a, // 0x5aa55aa5 152 0x00, 0x00, 0x00, 0x00, // 0x00000000 153 0x00, 0x00, 0x00, 0x00, // 0x00000000 154 0x00, 0x00, 0x00, 0x00, // 0x00000000 155 ]; 156 let insn = [0xf3, 0xa5]; // rep movsd 157 let regs = vec![(Register::ECX, 3), (Register::ESI, 0), (Register::EDI, 0xc)]; 158 let mut data = [0u8; 4]; 159 160 let mut vmm = MockVmm::new(ip, regs, Some((0, &memory))); 161 162 assert!(vmm.emulate_first_insn(0, &insn).is_ok()); 163 164 vmm.read_memory(0xc, &mut data).unwrap(); 165 assert_eq!(0x12345678, <u32>::from_le_bytes(data)); 166 vmm.read_memory(0xc + 4, &mut data).unwrap(); 167 assert_eq!(0xaabbccdd, <u32>::from_le_bytes(data)); 168 vmm.read_memory(0xc + 8, &mut data).unwrap(); 169 assert_eq!(0x5aa55aa5, <u32>::from_le_bytes(data)); 170 // The rest should be default value 0 from MockVmm 171 vmm.read_memory(0xc + 12, &mut data).unwrap(); 172 assert_eq!(0x0, <u32>::from_le_bytes(data)); 173 } 174 175 #[test] 176 fn test_movsd_m32_m32() { 177 let ip: u64 = 0x1000; 178 let memory: [u8; 4] = [ 179 0x78, 0x56, 0x34, 0x12, // 0x12345678 180 ]; 181 let insn = [0xa5]; // movsd 182 let regs = vec![(Register::ESI, 0), (Register::EDI, 0x8)]; 183 let mut data = [0u8; 4]; 184 185 let mut vmm = MockVmm::new(ip, regs, Some((0, &memory))); 186 187 assert!(vmm.emulate_first_insn(0, &insn).is_ok()); 188 189 vmm.read_memory(0x8, &mut data).unwrap(); 190 assert_eq!(0x12345678, <u32>::from_le_bytes(data)); 191 // The rest should be default value 0 from MockVmm 192 vmm.read_memory(0x4, &mut data).unwrap(); 193 assert_eq!(0x0, <u32>::from_le_bytes(data)); 194 vmm.read_memory(0x8 + 8, &mut data).unwrap(); 195 assert_eq!(0x0, <u32>::from_le_bytes(data)); 196 } 197 198 #[test] 199 fn test_rep_movsw_m16_m16() { 200 let ip: u64 = 0x1000; 201 let memory: [u8; 24] = [ 202 0x78, 0x56, 0x34, 0x12, // 0x12345678 203 0xdd, 0xcc, 0xbb, 0xaa, // 0xaabbccdd 204 0xa5, 0x5a, 0xa5, 0x5a, // 0x5aa55aa5 205 0x00, 0x00, 0x00, 0x00, // 0x00000000 206 0x00, 0x00, 0x00, 0x00, // 0x00000000 207 0x00, 0x00, 0x00, 0x00, // 0x00000000 208 ]; 209 let insn = [0x66, 0xf3, 0xa5]; // rep movsw 210 let regs = vec![(Register::ECX, 6), (Register::ESI, 0), (Register::EDI, 0xc)]; 211 let mut data = [0u8; 2]; 212 213 let mut vmm = MockVmm::new(ip, regs, Some((0, &memory))); 214 215 assert!(vmm.emulate_first_insn(0, &insn).is_ok()); 216 217 vmm.read_memory(0xc, &mut data).unwrap(); 218 assert_eq!(0x5678, <u16>::from_le_bytes(data)); 219 vmm.read_memory(0xc + 2, &mut data).unwrap(); 220 assert_eq!(0x1234, <u16>::from_le_bytes(data)); 221 vmm.read_memory(0xc + 4, &mut data).unwrap(); 222 assert_eq!(0xccdd, <u16>::from_le_bytes(data)); 223 vmm.read_memory(0xc + 6, &mut data).unwrap(); 224 assert_eq!(0xaabb, <u16>::from_le_bytes(data)); 225 vmm.read_memory(0xc + 8, &mut data).unwrap(); 226 assert_eq!(0x5aa5, <u16>::from_le_bytes(data)); 227 vmm.read_memory(0xc + 10, &mut data).unwrap(); 228 assert_eq!(0x5aa5, <u16>::from_le_bytes(data)); 229 // The rest should be default value 0 from MockVmm 230 vmm.read_memory(0xc + 12, &mut data).unwrap(); 231 assert_eq!(0x0, <u16>::from_le_bytes(data)); 232 } 233 234 #[test] 235 fn test_movsw_m16_m16() { 236 let ip: u64 = 0x1000; 237 let memory: [u8; 4] = [ 238 0x78, 0x56, 0x34, 0x12, // 0x12345678 239 ]; 240 let insn = [0x66, 0xa5]; // movsw 241 let regs = vec![(Register::ESI, 0), (Register::EDI, 0x8)]; 242 let mut data = [0u8; 2]; 243 244 let mut vmm = MockVmm::new(ip, regs, Some((0, &memory))); 245 246 assert!(vmm.emulate_first_insn(0, &insn).is_ok()); 247 248 vmm.read_memory(0x8, &mut data).unwrap(); 249 assert_eq!(0x5678, <u16>::from_le_bytes(data)); 250 // Only two bytes were copied, so the value at 0xa should be zero 251 vmm.read_memory(0xa, &mut data).unwrap(); 252 assert_eq!(0x0, <u16>::from_le_bytes(data)); 253 // The rest should be default value 0 from MockVmm 254 vmm.read_memory(0x4, &mut data).unwrap(); 255 assert_eq!(0x0, <u16>::from_le_bytes(data)); 256 vmm.read_memory(0x8 + 8, &mut data).unwrap(); 257 assert_eq!(0x0, <u16>::from_le_bytes(data)); 258 } 259 260 #[test] 261 fn test_movsb_m8_m8() { 262 let ip: u64 = 0x1000; 263 let memory: [u8; 4] = [ 264 0x78, 0x56, 0x34, 0x12, // 0x12345678 265 ]; 266 let insn = [0x66, 0xa4]; // movsb 267 let regs = vec![(Register::ESI, 0), (Register::EDI, 0x8)]; 268 let mut data = [0u8; 1]; 269 270 let mut vmm = MockVmm::new(ip, regs, Some((0, &memory))); 271 272 assert!(vmm.emulate_first_insn(0, &insn).is_ok()); 273 274 vmm.read_memory(0x8, &mut data).unwrap(); 275 assert_eq!(0x78, data[0]); 276 // Only one byte was copied, so the value at 0x9 should be zero 277 vmm.read_memory(0x9, &mut data).unwrap(); 278 assert_eq!(0x0, data[0]); 279 // The rest should be default value 0 from MockVmm 280 vmm.read_memory(0x4, &mut data).unwrap(); 281 assert_eq!(0x0, data[0]); 282 // the src value is left as is after movb 283 vmm.read_memory(0x0, &mut data).unwrap(); 284 assert_eq!(0x78, data[0]); 285 } 286 287 #[test] 288 fn test_rep_movsb_m8_m8() { 289 let ip: u64 = 0x1000; 290 let memory: [u8; 16] = [ 291 0x78, 0x56, 0x34, 0x12, // 0x12345678 292 0xbb, 0xaa, 0x00, 0x00, // 0x0000aabb 293 0x00, 0x00, 0x00, 0x00, // 0x00000000 294 0x00, 0x00, 0x00, 0x00, // 0x00000000 295 ]; 296 let insn = [0x66, 0xf3, 0xa4]; // rep movsw 297 let regs = vec![(Register::ECX, 6), (Register::ESI, 0), (Register::EDI, 0x8)]; 298 let mut data = [0u8; 1]; 299 300 let mut vmm = MockVmm::new(ip, regs, Some((0, &memory))); 301 302 assert!(vmm.emulate_first_insn(0, &insn).is_ok()); 303 304 vmm.read_memory(0x8, &mut data).unwrap(); 305 assert_eq!(0x78, data[0]); 306 vmm.read_memory(0x8 + 1, &mut data).unwrap(); 307 assert_eq!(0x56, data[0]); 308 vmm.read_memory(0x8 + 2, &mut data).unwrap(); 309 assert_eq!(0x34, data[0]); 310 vmm.read_memory(0x8 + 3, &mut data).unwrap(); 311 assert_eq!(0x12, data[0]); 312 vmm.read_memory(0x8 + 4, &mut data).unwrap(); 313 assert_eq!(0xbb, data[0]); 314 vmm.read_memory(0x8 + 5, &mut data).unwrap(); 315 assert_eq!(0xaa, data[0]); 316 // The rest should be default value 0 from MockVmm 317 vmm.read_memory(0x8 + 6, &mut data).unwrap(); 318 assert_eq!(0x0, data[0]); 319 } 320 } 321