aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoriximeow <me@iximeow.net>2020-05-23 21:02:32 -0700
committeriximeow <me@iximeow.net>2020-05-23 21:02:32 -0700
commit79cd0c80a858448713aedd3d607dc363be891d8c (patch)
tree8767f8c59c11c47a7f6996d0655206fa6917b2ba
parent9b965525afced37e99543e3a412218207a41e793 (diff)
fix important memory decode error in long mode
add tests for modrm/sib decoding, xsave extensions
-rw-r--r--CHANGELOG12
-rw-r--r--src/long_mode/mod.rs50
-rw-r--r--test/long_mode/mod.rs70
-rw-r--r--test/protected_mode/mod.rs5
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<T: Iterator<Item=u8>>(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<T: Iterator<Item=u8>>(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]");