1 // 2 // Copyright © 2024 Microsoft 3 // 4 // SPDX-License-Identifier: Apache-2.0 5 // 6 7 #![allow(non_camel_case_types)] 8 9 // 10 // STOS - Store String 11 // 12 13 use crate::arch::x86::emulator::instructions::*; 14 use crate::arch::x86::regs::DF; 15 16 macro_rules! stos { 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 rax = state 33 .read_reg(Register::RAX) 34 .map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?; 35 36 let mut rdi = state 37 .read_reg(Register::RDI) 38 .map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?; 39 40 let df = (state.flags() & DF) != 0; 41 let len = std::mem::size_of::<$bound>(); 42 let rax_bytes = rax.to_le_bytes(); 43 44 while count > 0 { 45 let dst = state 46 .linearize(Register::ES, rdi, true) 47 .map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?; 48 49 platform 50 .write_memory(dst, &rax_bytes[0..len]) 51 .map_err(EmulationError::PlatformEmulationError)?; 52 53 if df { 54 rdi = rdi.wrapping_sub(len as u64); 55 } else { 56 rdi = rdi.wrapping_add(len as u64); 57 } 58 count -= 1; 59 } 60 61 if insn.has_rep_prefix() { 62 state 63 .write_reg(Register::ECX, 0) 64 .map_err(|e| EmulationError::InvalidOperand(anyhow!(e)))?; 65 } 66 67 Ok(()) 68 } 69 }; 70 } 71 72 pub struct Stosq_m64_RAX; 73 impl<T: CpuStateManager> InstructionHandler<T> for Stosq_m64_RAX { 74 stos!(u64); 75 } 76 77 pub struct Stosd_m32_EAX; 78 impl<T: CpuStateManager> InstructionHandler<T> for Stosd_m32_EAX { 79 stos!(u32); 80 } 81 82 pub struct Stosw_m16_AX; 83 impl<T: CpuStateManager> InstructionHandler<T> for Stosw_m16_AX { 84 stos!(u16); 85 } 86 87 pub struct Stosb_m8_AL; 88 impl<T: CpuStateManager> InstructionHandler<T> for Stosb_m8_AL { 89 stos!(u8); 90 } 91 92 #[cfg(test)] 93 mod tests { 94 use super::*; 95 use crate::arch::x86::emulator::mock_vmm::*; 96 97 #[test] 98 fn test_rep_stosb() { 99 let ip: u64 = 0x1000; 100 let memory: [u8; 12] = [ 101 0x78, 0x56, 0x34, 0x12, // 0x12345678 102 0xdd, 0xcc, 0xbb, 0xaa, // 0xaabbccdd 103 0xa5, 0x5a, 0xa5, 0x5a, // 0x5aa55aa5 104 ]; 105 let insn = [0xf3, 0xaa]; // rep stosb 106 let regs = vec![ 107 (Register::ECX, 3), 108 (Register::EDI, 0x0), 109 (Register::RAX, 0x123456ff), 110 ]; 111 let mut data = [0u8; 4]; 112 113 let mut vmm = MockVmm::new(ip, regs, Some((0, &memory))); 114 115 vmm.emulate_first_insn(0, &insn).unwrap(); 116 117 vmm.read_memory(0, &mut data).unwrap(); 118 assert_eq!(0x12ffffff, <u32>::from_le_bytes(data)); 119 vmm.read_memory(4, &mut data).unwrap(); 120 assert_eq!(0xaabbccdd, <u32>::from_le_bytes(data)); 121 vmm.read_memory(8, &mut data).unwrap(); 122 assert_eq!(0x5aa55aa5, <u32>::from_le_bytes(data)); 123 } 124 125 #[test] 126 fn test_stosw() { 127 let ip: u64 = 0x1000; 128 let memory: [u8; 4] = [ 129 0x78, 0x56, 0x34, 0x12, // 0x12345678 130 ]; 131 let insn = [0x66, 0xab]; // stosw 132 let regs = vec![(Register::EDI, 0x1), (Register::AX, 0xaabb)]; 133 let mut data = [0u8; 4]; 134 135 let mut vmm = MockVmm::new(ip, regs, Some((0, &memory))); 136 137 vmm.emulate_first_insn(0, &insn).unwrap(); 138 139 vmm.read_memory(0x0, &mut data).unwrap(); 140 assert_eq!(0x12aabb78, <u32>::from_le_bytes(data)); 141 // The rest should be default value 0 from MockVmm 142 vmm.read_memory(0x4, &mut data).unwrap(); 143 assert_eq!(0x0, <u32>::from_le_bytes(data)); 144 vmm.read_memory(0x8 + 8, &mut data).unwrap(); 145 assert_eq!(0x0, <u32>::from_le_bytes(data)); 146 } 147 148 #[test] 149 fn test_rep_stosw() { 150 let ip: u64 = 0x1000; 151 let memory: [u8; 8] = [ 152 0x78, 0x56, 0x34, 0x12, // 0x12345678 153 0x00, 0x00, 0x00, 0x00, // 0x00000000 154 ]; 155 let insn = [0x66, 0xf3, 0xab]; // rep stosw 156 let regs = vec![ 157 (Register::ECX, 2), 158 (Register::EDI, 0x2), 159 (Register::AX, 0xaabb), 160 ]; 161 let mut data = [0u8; 4]; 162 163 let mut vmm = MockVmm::new(ip, regs, Some((0, &memory))); 164 165 vmm.emulate_first_insn(0, &insn).unwrap(); 166 167 vmm.read_memory(0x0, &mut data).unwrap(); 168 assert_eq!(0xaabb5678, <u32>::from_le_bytes(data)); 169 vmm.read_memory(0x4, &mut data).unwrap(); 170 assert_eq!(0x0000aabb, <u32>::from_le_bytes(data)); 171 vmm.read_memory(0x8, &mut data).unwrap(); 172 assert_eq!(0x0, <u32>::from_le_bytes(data)); 173 } 174 175 #[test] 176 fn test_rep_stosd() { 177 let ip: u64 = 0x1000; 178 let memory: [u8; 12] = [ 179 0x78, 0x56, 0x34, 0x12, // 0x12345678 180 0x00, 0x00, 0x00, 0x00, // 0x00000000 181 0x00, 0x00, 0x00, 0x00, // 0x00000000 182 ]; 183 let insn = [0xf3, 0xab]; // rep stosd 184 let regs = vec![ 185 (Register::ECX, 2), 186 (Register::EDI, 0x8), 187 (Register::EAX, 0xaabbccdd), 188 ]; 189 let mut data = [0u8; 4]; 190 191 let mut vmm = MockVmm::new(ip, regs, Some((0, &memory))); 192 193 // Go backwards this time 194 let mut state = vmm.cpu_state(0).unwrap(); 195 state.set_flags(state.flags() | DF); 196 vmm.set_cpu_state(0, state).unwrap(); 197 198 vmm.emulate_first_insn(0, &insn).unwrap(); 199 200 vmm.read_memory(0x0, &mut data).unwrap(); 201 assert_eq!(0x12345678, <u32>::from_le_bytes(data)); 202 vmm.read_memory(0x4, &mut data).unwrap(); 203 assert_eq!(0xaabbccdd, <u32>::from_le_bytes(data)); 204 vmm.read_memory(0x8, &mut data).unwrap(); 205 assert_eq!(0xaabbccdd, <u32>::from_le_bytes(data)); 206 vmm.read_memory(0xc, &mut data).unwrap(); 207 assert_eq!(0x0, <u32>::from_le_bytes(data)); 208 } 209 210 #[test] 211 fn test_rep_stosq() { 212 let ip: u64 = 0x1000; 213 let memory: [u8; 8] = [ 214 0x78, 0x56, 0x34, 0x12, // 0x12345678 215 0x00, 0x00, 0x00, 0x00, // 0x00000000 216 ]; 217 let insn = [0xf3, 0x48, 0xab]; // rep stosq 218 let regs = vec![ 219 (Register::ECX, 2), 220 (Register::RDI, 0x0), 221 (Register::RAX, 0x11223344aabbccdd), 222 ]; 223 let mut data = [0u8; 8]; 224 225 let mut vmm = MockVmm::new(ip, regs, Some((0, &memory))); 226 227 vmm.emulate_first_insn(0, &insn).unwrap(); 228 229 vmm.read_memory(0x0, &mut data).unwrap(); 230 assert_eq!(0x11223344aabbccdd, <u64>::from_le_bytes(data)); 231 vmm.read_memory(0x8, &mut data).unwrap(); 232 assert_eq!(0x11223344aabbccdd, <u64>::from_le_bytes(data)); 233 vmm.read_memory(0x10, &mut data).unwrap(); 234 assert_eq!(0x0, <u64>::from_le_bytes(data)); 235 } 236 } 237