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 #![allow(unused_mut)] 104 use super::*; 105 use crate::arch::x86::emulator::mock_vmm::*; 106 107 #[test] 108 fn test_rep_movsd_m32_m32() { 109 let ip: u64 = 0x1000; 110 let memory: [u8; 24] = [ 111 0x78, 0x56, 0x34, 0x12, // 0x12345678 112 0xdd, 0xcc, 0xbb, 0xaa, // 0xaabbccdd 113 0xa5, 0x5a, 0xa5, 0x5a, // 0x5aa55aa5 114 0x00, 0x00, 0x00, 0x00, // 0x00000000 115 0x00, 0x00, 0x00, 0x00, // 0x00000000 116 0x00, 0x00, 0x00, 0x00, // 0x00000000 117 ]; 118 let insn = [0xf3, 0xa5]; // rep movsd 119 let regs = vec![(Register::ECX, 3), (Register::ESI, 0), (Register::EDI, 0xc)]; 120 let mut data = [0u8; 4]; 121 122 let mut vmm = MockVmm::new(ip, regs, Some((0, &memory))); 123 124 assert!(vmm.emulate_first_insn(0, &insn).is_ok()); 125 126 vmm.read_memory(0xc, &mut data).unwrap(); 127 assert_eq!(0x12345678, <u32>::from_le_bytes(data)); 128 vmm.read_memory(0xc + 4, &mut data).unwrap(); 129 assert_eq!(0xaabbccdd, <u32>::from_le_bytes(data)); 130 vmm.read_memory(0xc + 8, &mut data).unwrap(); 131 assert_eq!(0x5aa55aa5, <u32>::from_le_bytes(data)); 132 // The rest should be default value 0 from MockVmm 133 vmm.read_memory(0xc + 12, &mut data).unwrap(); 134 assert_eq!(0x0, <u32>::from_le_bytes(data)); 135 } 136 137 #[test] 138 fn test_movsd_m32_m32() { 139 let ip: u64 = 0x1000; 140 let memory: [u8; 4] = [ 141 0x78, 0x56, 0x34, 0x12, // 0x12345678 142 ]; 143 let insn = [0xa5]; // movsd 144 let regs = vec![(Register::ESI, 0), (Register::EDI, 0x8)]; 145 let mut data = [0u8; 4]; 146 147 let mut vmm = MockVmm::new(ip, regs, Some((0, &memory))); 148 149 assert!(vmm.emulate_first_insn(0, &insn).is_ok()); 150 151 vmm.read_memory(0x8, &mut data).unwrap(); 152 assert_eq!(0x12345678, <u32>::from_le_bytes(data)); 153 // The rest should be default value 0 from MockVmm 154 vmm.read_memory(0x4, &mut data).unwrap(); 155 assert_eq!(0x0, <u32>::from_le_bytes(data)); 156 vmm.read_memory(0x8 + 8, &mut data).unwrap(); 157 assert_eq!(0x0, <u32>::from_le_bytes(data)); 158 } 159 160 #[test] 161 fn test_rep_movsw_m16_m16() { 162 let ip: u64 = 0x1000; 163 let memory: [u8; 24] = [ 164 0x78, 0x56, 0x34, 0x12, // 0x12345678 165 0xdd, 0xcc, 0xbb, 0xaa, // 0xaabbccdd 166 0xa5, 0x5a, 0xa5, 0x5a, // 0x5aa55aa5 167 0x00, 0x00, 0x00, 0x00, // 0x00000000 168 0x00, 0x00, 0x00, 0x00, // 0x00000000 169 0x00, 0x00, 0x00, 0x00, // 0x00000000 170 ]; 171 let insn = [0x66, 0xf3, 0xa5]; // rep movsw 172 let regs = vec![(Register::ECX, 6), (Register::ESI, 0), (Register::EDI, 0xc)]; 173 let mut data = [0u8; 2]; 174 175 let mut vmm = MockVmm::new(ip, regs, Some((0, &memory))); 176 177 assert!(vmm.emulate_first_insn(0, &insn).is_ok()); 178 179 vmm.read_memory(0xc, &mut data).unwrap(); 180 assert_eq!(0x5678, <u16>::from_le_bytes(data)); 181 vmm.read_memory(0xc + 2, &mut data).unwrap(); 182 assert_eq!(0x1234, <u16>::from_le_bytes(data)); 183 vmm.read_memory(0xc + 4, &mut data).unwrap(); 184 assert_eq!(0xccdd, <u16>::from_le_bytes(data)); 185 vmm.read_memory(0xc + 6, &mut data).unwrap(); 186 assert_eq!(0xaabb, <u16>::from_le_bytes(data)); 187 vmm.read_memory(0xc + 8, &mut data).unwrap(); 188 assert_eq!(0x5aa5, <u16>::from_le_bytes(data)); 189 vmm.read_memory(0xc + 10, &mut data).unwrap(); 190 assert_eq!(0x5aa5, <u16>::from_le_bytes(data)); 191 // The rest should be default value 0 from MockVmm 192 vmm.read_memory(0xc + 12, &mut data).unwrap(); 193 assert_eq!(0x0, <u16>::from_le_bytes(data)); 194 } 195 196 #[test] 197 fn test_movsw_m16_m16() { 198 let ip: u64 = 0x1000; 199 let memory: [u8; 4] = [ 200 0x78, 0x56, 0x34, 0x12, // 0x12345678 201 ]; 202 let insn = [0x66, 0xa5]; // movsw 203 let regs = vec![(Register::ESI, 0), (Register::EDI, 0x8)]; 204 let mut data = [0u8; 2]; 205 206 let mut vmm = MockVmm::new(ip, regs, Some((0, &memory))); 207 208 assert!(vmm.emulate_first_insn(0, &insn).is_ok()); 209 210 vmm.read_memory(0x8, &mut data).unwrap(); 211 assert_eq!(0x5678, <u16>::from_le_bytes(data)); 212 // Only two bytes were copied, so the value at 0xa should be zero 213 vmm.read_memory(0xa, &mut data).unwrap(); 214 assert_eq!(0x0, <u16>::from_le_bytes(data)); 215 // The rest should be default value 0 from MockVmm 216 vmm.read_memory(0x4, &mut data).unwrap(); 217 assert_eq!(0x0, <u16>::from_le_bytes(data)); 218 vmm.read_memory(0x8 + 8, &mut data).unwrap(); 219 assert_eq!(0x0, <u16>::from_le_bytes(data)); 220 } 221 222 #[test] 223 fn test_movsb_m8_m8() { 224 let ip: u64 = 0x1000; 225 let memory: [u8; 4] = [ 226 0x78, 0x56, 0x34, 0x12, // 0x12345678 227 ]; 228 let insn = [0x66, 0xa4]; // movsb 229 let regs = vec![(Register::ESI, 0), (Register::EDI, 0x8)]; 230 let mut data = [0u8; 1]; 231 232 let mut vmm = MockVmm::new(ip, regs, Some((0, &memory))); 233 234 assert!(vmm.emulate_first_insn(0, &insn).is_ok()); 235 236 vmm.read_memory(0x8, &mut data).unwrap(); 237 assert_eq!(0x78, data[0]); 238 // Only one byte was copied, so the value at 0x9 should be zero 239 vmm.read_memory(0x9, &mut data).unwrap(); 240 assert_eq!(0x0, data[0]); 241 // The rest should be default value 0 from MockVmm 242 vmm.read_memory(0x4, &mut data).unwrap(); 243 assert_eq!(0x0, data[0]); 244 // the src value is left as is after movb 245 vmm.read_memory(0x0, &mut data).unwrap(); 246 assert_eq!(0x78, data[0]); 247 } 248 249 #[test] 250 fn test_rep_movsb_m8_m8() { 251 let ip: u64 = 0x1000; 252 let memory: [u8; 16] = [ 253 0x78, 0x56, 0x34, 0x12, // 0x12345678 254 0xbb, 0xaa, 0x00, 0x00, // 0x0000aabb 255 0x00, 0x00, 0x00, 0x00, // 0x00000000 256 0x00, 0x00, 0x00, 0x00, // 0x00000000 257 ]; 258 let insn = [0x66, 0xf3, 0xa4]; // rep movsw 259 let regs = vec![(Register::ECX, 6), (Register::ESI, 0), (Register::EDI, 0x8)]; 260 let mut data = [0u8; 1]; 261 262 let mut vmm = MockVmm::new(ip, regs, Some((0, &memory))); 263 264 assert!(vmm.emulate_first_insn(0, &insn).is_ok()); 265 266 vmm.read_memory(0x8, &mut data).unwrap(); 267 assert_eq!(0x78, data[0]); 268 vmm.read_memory(0x8 + 1, &mut data).unwrap(); 269 assert_eq!(0x56, data[0]); 270 vmm.read_memory(0x8 + 2, &mut data).unwrap(); 271 assert_eq!(0x34, data[0]); 272 vmm.read_memory(0x8 + 3, &mut data).unwrap(); 273 assert_eq!(0x12, data[0]); 274 vmm.read_memory(0x8 + 4, &mut data).unwrap(); 275 assert_eq!(0xbb, data[0]); 276 vmm.read_memory(0x8 + 5, &mut data).unwrap(); 277 assert_eq!(0xaa, data[0]); 278 // The rest should be default value 0 from MockVmm 279 vmm.read_memory(0x8 + 6, &mut data).unwrap(); 280 assert_eq!(0x0, data[0]); 281 } 282 } 283