From 1b5461036e5debedb3cde34f18ddca1cba4f5a25 Mon Sep 17 00:00:00 2001 From: Alexis Engelke Date: Thu, 25 Jun 2020 16:51:21 +0200 Subject: [PATCH] decode: Don't walk escape opcodes in tables --- decode.c | 34 +++++++++++++++++++--------------- parseinstrs.py | 13 ++++--------- 2 files changed, 23 insertions(+), 24 deletions(-) diff --git a/decode.c b/decode.c index 13819af..4e53fa3 100644 --- a/decode.c +++ b/decode.c @@ -83,7 +83,7 @@ decode_prefixes(const uint8_t* buffer, int len, DecodeMode mode, uint8_t rep = 0; *out_mandatory = 0; *out_segment = FD_REG_NONE; - *out_opcode_escape = -1; + *out_opcode_escape = 0; while (LIKELY(off < len)) { @@ -373,24 +373,28 @@ fd_decode(const uint8_t* buffer, size_t len_sz, int mode_int, uintptr_t address, uint32_t kind = ENTRY_TABLE_ROOT; - if (LIKELY(!(prefixes & PREFIX_VEX))) + if (UNLIKELY(prefixes & PREFIX_VEX)) { - // "Legacy" walk through table and escape opcodes - ENTRY_UNPACK(table, kind, table[0]); - if (kind == ENTRY_TABLE256 && LIKELY(off < len)) - ENTRY_UNPACK(table, kind, table[buffer[off++]]); - if (UNLIKELY(kind == ENTRY_TABLE256) && LIKELY(off < len)) - ENTRY_UNPACK(table, kind, table[buffer[off++]]); - } - else - { - // VEX/EVEX compact escapes; the prefix precedes the single opcode byte if (opcode_escape < 0 || opcode_escape > 3) return FD_ERR_UD; - ENTRY_UNPACK(table, kind, table[4 | opcode_escape]); - if (LIKELY(off < len)) - ENTRY_UNPACK(table, kind, table[buffer[off++]]); + opcode_escape |= 4; } + else if (buffer[off] == 0x0f) + { + if (UNLIKELY(off + 1 >= len)) + return FD_ERR_PARTIAL; + if (buffer[off + 1] == 0x38) + opcode_escape = 2; + else if (buffer[off + 1] == 0x3a) + opcode_escape = 3; + else + opcode_escape = 1; + off += opcode_escape >= 2 ? 2 : 1; + } + + ENTRY_UNPACK(table, kind, table[opcode_escape]); + if (LIKELY(off < len)) + ENTRY_UNPACK(table, kind, table[buffer[off++]]); // Then, walk through ModR/M-encoded opcode extensions. if ((kind == ENTRY_TABLE8 || kind == ENTRY_TABLE72) && LIKELY(off < len)) diff --git a/parseinstrs.py b/parseinstrs.py index e9676f4..1b154ba 100644 --- a/parseinstrs.py +++ b/parseinstrs.py @@ -214,16 +214,11 @@ def parse_opcode(opcode_string): opcode = [] opcode_bytes = unhexlify(match.group("opcode")) - # root table, VEX prefix already consumes escape opcode bytes + idx = [b"", b"\x0f", b"\x0f\x38", b"\x0f\x3a"].index(opcode_bytes[:-1]) if match.group("vex"): - idx = [b"", b"\x0f", b"\x0f\x38", b"\x0f\x3a"].index(opcode_bytes[:-1]) - opcode.append((EntryKind.TABLE_ROOT, [4 | idx])) - opcode_bytes = opcode_bytes[-1:] - else: - opcode.append((EntryKind.TABLE_ROOT, [0])) - - # normal opcode bytes - opcode += [(EntryKind.TABLE256, [x]) for x in opcode_bytes] + idx |= 4 + opcode.append((EntryKind.TABLE_ROOT, [idx])) + opcode.append((EntryKind.TABLE256, [opcode_bytes[-1]])) opcext = match.group("modrm") if opcext: