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