From 79cd0c80a858448713aedd3d607dc363be891d8c Mon Sep 17 00:00:00 2001 From: iximeow Date: Sat, 23 May 2020 21:02:32 -0700 Subject: fix important memory decode error in long mode add tests for modrm/sib decoding, xsave extensions --- CHANGELOG | 12 ++++++++ src/long_mode/mod.rs | 50 +++++++++++++++++++++++++-------- test/long_mode/mod.rs | 70 ++++++++++++++++++++++++++++++++++++++++++++++ test/protected_mode/mod.rs | 5 ++++ 4 files changed, 126 insertions(+), 11 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index e8e35da..24290ab 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,15 @@ +## 0.0.12 + +* fix improper decode of `sib` memory operand when `rex.x` is set and index is `0b100` + - functionally: instructions which should have had a memory operand like + `[rax + r12 + disp]` were missing `r12` +* add instruction set extensions: `SHA`, `BMI1`, `BMI2`, `XSAVE`, `RDRAND`, + `RDSEED`, `CMPXCHG{8,16}B` `ADX`, `SVM`, `MOVBE`, `PREFETCHW`, `TSX`, and + `F16C` +* add `RDFSBASE`, `RDGSBASE`, `WRFSBASE`, `WRGSBASE` +* builders for per-uarch x86_64 instruction decoders, see `yaxpeax_x86::long_mode::uarch::{intel, amd}` +* builders for per-uarch x86_32 instruction decoders, see `yaxpeax_x86::protected_mode::uarch::{intel, amd}` + ## 0.0.11 * fix mis-named 'cbd' instruction, which should be 'cwd' diff --git a/src/long_mode/mod.rs b/src/long_mode/mod.rs index 58d4c57..146a535 100644 --- a/src/long_mode/mod.rs +++ b/src/long_mode/mod.rs @@ -4906,14 +4906,28 @@ fn read_sib>(bytes_iter: &mut T, instr: &mut Instruction, m OperandSpec::DispU32 } else { - let reg = RegSpec::from_parts(0b100, instr.prefixes.rex().x(), addr_width); - instr.modrm_mmm = reg; - - if disp == 0 { - OperandSpec::Deref + if instr.prefixes.rex().x() { + let reg = RegSpec::from_parts(0b100, true, addr_width); + instr.sib_index = reg; + let scale = 1u8 << (sibbyte >> 6); + instr.scale = scale; + + if disp == 0 { + OperandSpec::RegIndexBaseScale + } else { + instr.disp = disp as i64 as u64; + OperandSpec::RegIndexBaseScaleDisp + } } else { - instr.disp = disp as i64 as u64; - OperandSpec::RegDisp + let reg = RegSpec::from_parts(0b101, instr.prefixes.rex().b(), addr_width); + instr.modrm_mmm = reg; + + if disp == 0 { + OperandSpec::Deref + } else { + instr.disp = disp as i64 as u64; + OperandSpec::RegDisp + } } } } else { @@ -4952,11 +4966,25 @@ fn read_sib>(bytes_iter: &mut T, instr: &mut Instruction, m }; if ((sibbyte >> 3) & 7) == 0b100 { - if disp == 0 { - OperandSpec::Deref + if instr.prefixes.rex().x() { + let reg = RegSpec::from_parts(0b100, true, addr_width); + instr.sib_index = reg; + let scale = 1u8 << (sibbyte >> 6); + instr.scale = scale; + + if disp == 0 { + OperandSpec::RegIndexBaseScale + } else { + instr.disp = disp as i64 as u64; + OperandSpec::RegIndexBaseScaleDisp + } } else { - instr.disp = disp as i64 as u64; - OperandSpec::RegDisp + if disp == 0 { + OperandSpec::Deref + } else { + instr.disp = disp as i64 as u64; + OperandSpec::RegDisp + } } } else { instr.sib_index = RegSpec::from_parts((sibbyte >> 3) & 7, instr.prefixes.rex().x(), addr_width); diff --git a/test/long_mode/mod.rs b/test/long_mode/mod.rs index f6f02a1..97f0bd5 100644 --- a/test/long_mode/mod.rs +++ b/test/long_mode/mod.rs @@ -50,6 +50,68 @@ fn test_display_under(decoder: &InstDecoder, data: &[u8], expected: &'static str } #[test] +fn test_modrm_decode() { + // just modrm + test_display(&[0x33, 0x08], "xor ecx, [rax]"); + test_display(&[0x33, 0x20], "xor esp, [rax]"); + test_display(&[0x33, 0x05, 0x78, 0x56, 0x34, 0x12], "xor eax, [rip + 0x12345678]"); + test_display(&[0x33, 0x41, 0x23], "xor eax, [rcx + 0x23]"); + test_display(&[0x33, 0x81, 0x23, 0x01, 0x65, 0x43], "xor eax, [rcx + 0x43650123]"); + test_display(&[0x33, 0xc1], "xor eax, ecx"); + + // modrm + rex.w + test_display(&[0x48, 0x33, 0x08], "xor rcx, [rax]"); + test_display(&[0x48, 0x33, 0x20], "xor rsp, [rax]"); + test_display(&[0x48, 0x33, 0x05, 0x78, 0x56, 0x34, 0x12], "xor rax, [rip + 0x12345678]"); + test_display(&[0x48, 0x33, 0x41, 0x23], "xor rax, [rcx + 0x23]"); + test_display(&[0x48, 0x33, 0x81, 0x23, 0x01, 0x65, 0x43], "xor rax, [rcx + 0x43650123]"); + test_display(&[0x48, 0x33, 0xc1], "xor rax, rcx"); + + // modrm + rex.r + test_display(&[0x44, 0x33, 0x08], "xor r9d, [rax]"); + test_display(&[0x44, 0x33, 0x20], "xor r12d, [rax]"); + test_display(&[0x44, 0x33, 0x05, 0x78, 0x56, 0x34, 0x12], "xor r8d, [rip + 0x12345678]"); + test_display(&[0x44, 0x33, 0x41, 0x23], "xor r8d, [rcx + 0x23]"); + test_display(&[0x44, 0x33, 0x81, 0x23, 0x01, 0x65, 0x43], "xor r8d, [rcx + 0x43650123]"); + test_display(&[0x44, 0x33, 0xc1], "xor r8d, ecx"); + + // modrm + rex.rb + test_display(&[0x45, 0x33, 0x08], "xor r9d, [r8]"); + test_display(&[0x45, 0x33, 0x20], "xor r12d, [r8]"); + test_display(&[0x45, 0x33, 0x05, 0x78, 0x56, 0x34, 0x12], "xor r8d, [rip + 0x12345678]"); + test_display(&[0x45, 0x33, 0x41, 0x23], "xor r8d, [r9 + 0x23]"); + test_display(&[0x45, 0x33, 0x81, 0x23, 0x01, 0x65, 0x43], "xor r8d, [r9 + 0x43650123]"); + test_display(&[0x45, 0x33, 0xc1], "xor r8d, r9d"); + + // sib + test_display(&[0x33, 0x04, 0x0a], "xor eax, [rdx + rcx * 1]"); + test_display(&[0x33, 0x04, 0x4a], "xor eax, [rdx + rcx * 2]"); + test_display(&[0x33, 0x04, 0x8a], "xor eax, [rdx + rcx * 4]"); + test_display(&[0x33, 0x04, 0xca], "xor eax, [rdx + rcx * 8]"); + test_display(&[0x33, 0x04, 0x20], "xor eax, [rax]"); + test_display(&[0x33, 0x04, 0x60], "xor eax, [rax]"); + test_display(&[0x33, 0x04, 0xa0], "xor eax, [rax]"); + test_display(&[0x33, 0x04, 0xe0], "xor eax, [rax]"); + test_display(&[0x42, 0x33, 0x04, 0x20], "xor eax, [rax + r12 * 1]"); + test_display(&[0x42, 0x33, 0x04, 0x60], "xor eax, [rax + r12 * 2]"); + test_display(&[0x42, 0x33, 0x04, 0xa0], "xor eax, [rax + r12 * 4]"); + test_display(&[0x42, 0x33, 0x04, 0xe0], "xor eax, [rax + r12 * 8]"); + test_display(&[0x43, 0x33, 0x04, 0x20], "xor eax, [r8 + r12 * 1]"); + test_display(&[0x43, 0x33, 0x04, 0x60], "xor eax, [r8 + r12 * 2]"); + test_display(&[0x43, 0x33, 0x04, 0xa0], "xor eax, [r8 + r12 * 4]"); + test_display(&[0x43, 0x33, 0x04, 0xe0], "xor eax, [r8 + r12 * 8]"); + test_display(&[0x33, 0x04, 0x25, 0x11, 0x22, 0x33, 0x44], "xor eax, [0x44332211]"); + test_display(&[0x41, 0x33, 0x04, 0x25, 0x11, 0x22, 0x33, 0x44], "xor eax, [0x44332211]"); + + test_display(&[0x33, 0x44, 0x65, 0x11], "xor eax, [rbp + 0x11]"); + test_display(&[0x41, 0x33, 0x44, 0x65, 0x11], "xor eax, [r13 + 0x11]"); + test_display(&[0x33, 0x84, 0xa5, 0x11, 0x22, 0x33, 0x44], "xor eax, [rbp + 0x44332211]"); + test_display(&[0x41, 0x33, 0x84, 0xa5, 0x11, 0x22, 0x33, 0x44], "xor eax, [r13 + 0x44332211]"); + test_display(&[0x33, 0x04, 0xe5, 0x11, 0x22, 0x33, 0x44], "xor eax, [0x44332211]"); + test_display(&[0x41, 0x33, 0x04, 0xe5, 0x11, 0x22, 0x33, 0x44], "xor eax, [0x44332211]"); +} + +#[test] fn test_mmx() { test_display(&[0x4f, 0x0f, 0x7e, 0xcf], "movd r15, mm1"); test_display(&[0x41, 0x0f, 0x7e, 0xcf], "movd r15d, mm1"); @@ -538,6 +600,14 @@ fn test_0fae() { test_display(&[0x0f, 0xae, 0x14, 0x4f], "ldmxcsr [rdi + rcx * 2]"); test_display(&[0x0f, 0xae, 0x1c, 0x4f], "stmxcsr [rdi + rcx * 2]"); test_display(&[0x0f, 0xae, 0x24, 0x4f], "xsave [rdi + rcx * 2]"); + test_display(&[0x0f, 0xc7, 0x5c, 0x24, 0x40], "xrstors [rsp + 0x40]"); + test_display(&[0x0f, 0xc7, 0x64, 0x24, 0x40], "xsavec [rsp + 0x40]"); + test_display(&[0x0f, 0xc7, 0x6c, 0x24, 0x40], "xsaves [rsp + 0x40]"); + test_display(&[0x4f, 0x0f, 0xc7, 0x5c, 0x24, 0x40], "xrstors64 [r12 + r12 * 1 + 0x40]"); + test_display(&[0x4f, 0x0f, 0xc7, 0x64, 0x24, 0x40], "xsavec64 [r12 + r12 * 1 + 0x40]"); + test_display(&[0x4f, 0x0f, 0xc7, 0x6c, 0x24, 0x40], "xsaves64 [r12 + r12 * 1 + 0x40]"); + test_display(&[0x0f, 0xc7, 0x74, 0x24, 0x40], "vmptrld [rsp + 0x40]"); + test_display(&[0x0f, 0xc7, 0x7c, 0x24, 0x40], "vmptrst [rsp + 0x40]"); test_display(&[0x0f, 0xae, 0x2c, 0x4f], "xrstor [rdi + rcx * 2]"); test_display(&[0x0f, 0xae, 0x34, 0x4f], "xsaveopt [rdi + rcx * 2]"); test_display(&[0x0f, 0xae, 0x3c, 0x4f], "clflush [rdi + rcx * 2]"); diff --git a/test/protected_mode/mod.rs b/test/protected_mode/mod.rs index fc1db2d..3443565 100644 --- a/test/protected_mode/mod.rs +++ b/test/protected_mode/mod.rs @@ -509,6 +509,11 @@ fn test_0fae() { test_display(&[0x0f, 0xae, 0x14, 0x4f], "ldmxcsr [edi + ecx * 2]"); test_display(&[0x0f, 0xae, 0x1c, 0x4f], "stmxcsr [edi + ecx * 2]"); test_display(&[0x0f, 0xae, 0x24, 0x4f], "xsave [edi + ecx * 2]"); + test_display(&[0x0f, 0xc7, 0x5c, 0x24, 0x40], "xrstors [esp + 0x40]"); + test_display(&[0x0f, 0xc7, 0x64, 0x24, 0x40], "xsavec [esp + 0x40]"); + test_display(&[0x0f, 0xc7, 0x6c, 0x24, 0x40], "xsaves [esp + 0x40]"); + test_display(&[0x0f, 0xc7, 0x74, 0x24, 0x40], "vmptrld [esp + 0x40]"); + test_display(&[0x0f, 0xc7, 0x7c, 0x24, 0x40], "vmptrst [esp + 0x40]"); test_display(&[0x0f, 0xae, 0x2c, 0x4f], "xrstor [edi + ecx * 2]"); test_display(&[0x0f, 0xae, 0x34, 0x4f], "xsaveopt [edi + ecx * 2]"); test_display(&[0x0f, 0xae, 0x3c, 0x4f], "clflush [edi + ecx * 2]"); -- cgit v1.1