From dde61f76f6fa80555fc0e867695302ffa90dbc39 Mon Sep 17 00:00:00 2001 From: mappzor <34216645+mappzor@users.noreply.github.com> Date: Wed, 6 Nov 2024 01:01:29 +0100 Subject: [PATCH 1/3] Fixed `movdiri` (APX) and compressed disp8 handling --- src/Encoder.c | 13 +++++++++++-- src/Generated/EncoderTables.inc | 1 - tests/crash_tool.py | 13 +++++++++---- tests/re_enc_test_cases.json | 25 +++++++++++++++++++++++++ tests/zydis_encoder_types.py | 16 ---------------- 5 files changed, 45 insertions(+), 23 deletions(-) diff --git a/src/Encoder.c b/src/Encoder.c index c114aa26..4778ac2e 100644 --- a/src/Encoder.c +++ b/src/Encoder.c @@ -1729,7 +1729,16 @@ static ZyanBool ZydisCheckVectorMemorySize(ZydisEncoderInstructionMatch *match, ZyanU16 allowed_mem_size = def_op->size[eosz_index]; if (allowed_mem_size || (match->definition->encoding == ZYDIS_INSTRUCTION_ENCODING_VEX)) { - return user_op->mem.size == allowed_mem_size; + if (user_op->mem.size == allowed_mem_size) + { + return ZYAN_TRUE; + } + if (!match->eosz64_forbidden && (eosz_index == 2)) + { + ZYAN_ASSERT(def_op->size[0] == def_op->size[1]); + return user_op->mem.size == def_op->size[1]; + } + return ZYAN_FALSE; } ZYAN_ASSERT((match->definition->encoding == ZYDIS_INSTRUCTION_ENCODING_EVEX) || (match->definition->encoding == ZYDIS_INSTRUCTION_ENCODING_MVEX)); @@ -2123,7 +2132,7 @@ static ZyanBool ZydisIsMemoryOperandCompatible(ZydisEncoderInstructionMatch *mat reg_index_class); } } - else if (disp_size != 8 || !match->cd8_scale) + else { const ZyanU8 addr_size = ZydisGetMaxAddressSize(match->request); if (disp_size > addr_size) diff --git a/src/Generated/EncoderTables.inc b/src/Generated/EncoderTables.inc index a5ec6868..8c5cf814 100644 --- a/src/Generated/EncoderTables.inc +++ b/src/Generated/EncoderTables.inc @@ -11746,4 +11746,3 @@ const ZydisEncodableInstruction encoder_instructions[] = { 0x07A3, 0x0000, 0x01, 0xE8, ZYDIS_INSTRUCTION_ENCODING_LEGACY, ZYDIS_OPCODE_MAP_0F, ZYDIS_WIDTH_16 | ZYDIS_WIDTH_32 | ZYDIS_WIDTH_64, ZYDIS_WIDTH_16 | ZYDIS_WIDTH_32 | ZYDIS_WIDTH_64, ZYDIS_WIDTH_16 | ZYDIS_WIDTH_32 | ZYDIS_WIDTH_64, ZYDIS_MANDATORY_PREFIX_F2, ZYAN_FALSE, ZYAN_FALSE, ZYAN_FALSE, ZYAN_FALSE, ZYAN_FALSE, ZYDIS_VECTOR_LENGTH_INVALID, ZYDIS_SIZE_HINT_NONE, ZYAN_FALSE }, { 0x07A4, 0x0000, 0x01, 0xD6, ZYDIS_INSTRUCTION_ENCODING_LEGACY, ZYDIS_OPCODE_MAP_0F, ZYDIS_WIDTH_16 | ZYDIS_WIDTH_32 | ZYDIS_WIDTH_64, ZYDIS_WIDTH_16 | ZYDIS_WIDTH_32 | ZYDIS_WIDTH_64, ZYDIS_WIDTH_16 | ZYDIS_WIDTH_32 | ZYDIS_WIDTH_64, ZYDIS_MANDATORY_PREFIX_NONE, ZYAN_FALSE, ZYAN_FALSE, ZYAN_FALSE, ZYAN_FALSE, ZYAN_FALSE, ZYDIS_VECTOR_LENGTH_INVALID, ZYDIS_SIZE_HINT_NONE, ZYAN_FALSE }, }; - diff --git a/tests/crash_tool.py b/tests/crash_tool.py index 6e340a20..c718258b 100644 --- a/tests/crash_tool.py +++ b/tests/crash_tool.py @@ -50,12 +50,16 @@ def get_combined_flags(flag_str, enum_class): return functools.reduce(lambda x, y: x | y, [enum_class[v] for v in flag_str.split('|')]) -def get_disasm(zydis_info, machine_mode, stack_width, payload): +def get_disasm(zydis_info, machine_mode, stack_width, payload, knc=False): if not zydis_info: return '' arg_machine_mode = '-' + get_width_from_enum(machine_mode) arg_stack_width = '-' + get_width_from_enum(stack_width) - proc = Popen([zydis_info, arg_machine_mode, arg_stack_width, payload[:30]], stdout=PIPE, stderr=PIPE) + args = [zydis_info, arg_machine_mode, arg_stack_width] + if knc: + args.append('-knc') + args.append(payload[:30]) + proc = Popen(args, stdout=PIPE, stderr=PIPE) out = proc.communicate()[0].decode('utf-8') if proc.returncode != 0: return '' @@ -176,13 +180,14 @@ def convert_re_enc_crash_to_json(crash, zydis_info, return_dict=False): stack_width = ZydisStackWidth(reader.read_uint32()) decoder_mode = reader.read_uint32() payload = reader.read_bytes().hex().upper() + is_knc = (decoder_mode & ZYDIS_DECODER_MODE_KNC) != 0 test_case = { 'machine_mode': machine_mode.name, 'stack_width': stack_width.name, 'payload': payload, - 'description': get_disasm(zydis_info, machine_mode, stack_width, payload), + 'description': get_disasm(zydis_info, machine_mode, stack_width, payload, is_knc), } - if decoder_mode & ZYDIS_DECODER_MODE_KNC: + if is_knc: test_case['knc'] = True if return_dict: return test_case diff --git a/tests/re_enc_test_cases.json b/tests/re_enc_test_cases.json index 55acd690..f5f856cc 100644 --- a/tests/re_enc_test_cases.json +++ b/tests/re_enc_test_cases.json @@ -913,5 +913,30 @@ "stack_width": "ZYDIS_STACK_WIDTH_64", "payload": "D51087C02300", "description": "xchg r16d, eax" + }, + { + "machine_mode": "ZYDIS_MACHINE_MODE_LONG_64", + "stack_width": "ZYDIS_STACK_WIDTH_64", + "payload": "676262794BBE0C6500FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00006F", + "description": "vfnmsub231ps zmm25 {k3}, zmm0, xmmword ptr ds:[0xFFFFFF00] {uint8}", + "knc": true + }, + { + "machine_mode": "ZYDIS_MACHINE_MODE_LONG_64", + "stack_width": "ZYDIS_STACK_WIDTH_64", + "payload": "62DC7C08F90500000002", + "description": "movdiri dword ptr ds:[0x000000000200000A], eax" + }, + { + "machine_mode": "ZYDIS_MACHINE_MODE_LONG_COMPAT_16", + "stack_width": "ZYDIS_STACK_WIDTH_16", + "payload": "C4C3F961E1C4", + "description": "vpcmpestri xmm4, xmm1, 0xC4" + }, + { + "machine_mode": "ZYDIS_MACHINE_MODE_LONG_64", + "stack_width": "ZYDIS_STACK_WIDTH_64", + "payload": "F3660FA7C86239F6", + "description": "rep xcrypt_ecb <- TODO: Remove 0x66 byte after fixing OSIZE handling for XCRYPT" } ] \ No newline at end of file diff --git a/tests/zydis_encoder_types.py b/tests/zydis_encoder_types.py index 3b286eef..176d7bd9 100644 --- a/tests/zydis_encoder_types.py +++ b/tests/zydis_encoder_types.py @@ -2430,22 +2430,6 @@ 'ZYDIS_REGISTER_BND3', 'ZYDIS_REGISTER_BNDCFG', 'ZYDIS_REGISTER_BNDSTATUS', - 'ZYDIS_REGISTER_DFV0', - 'ZYDIS_REGISTER_DFV1', - 'ZYDIS_REGISTER_DFV2', - 'ZYDIS_REGISTER_DFV3', - 'ZYDIS_REGISTER_DFV4', - 'ZYDIS_REGISTER_DFV5', - 'ZYDIS_REGISTER_DFV6', - 'ZYDIS_REGISTER_DFV7', - 'ZYDIS_REGISTER_DFV8', - 'ZYDIS_REGISTER_DFV9', - 'ZYDIS_REGISTER_DFV10', - 'ZYDIS_REGISTER_DFV11', - 'ZYDIS_REGISTER_DFV12', - 'ZYDIS_REGISTER_DFV13', - 'ZYDIS_REGISTER_DFV14', - 'ZYDIS_REGISTER_DFV15', 'ZYDIS_REGISTER_MXCSR', 'ZYDIS_REGISTER_PKRU', 'ZYDIS_REGISTER_XCR0', From 47b92fd8688b72d85de171da8dcc0677797f737a Mon Sep 17 00:00:00 2001 From: mappzor <34216645+mappzor@users.noreply.github.com> Date: Wed, 6 Nov 2024 01:50:55 +0100 Subject: [PATCH 2/3] Fixed VSIB encoding in 16-bit mode --- src/Encoder.c | 8 ++++++-- tests/re_enc_test_cases.json | 6 ++++++ tools/ZydisFuzzShared.c | 4 ++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/Encoder.c b/src/Encoder.c index 4778ac2e..a9dd7cbc 100644 --- a/src/Encoder.c +++ b/src/Encoder.c @@ -2177,9 +2177,13 @@ static ZyanBool ZydisIsMemoryOperandCompatible(ZydisEncoderInstructionMatch *mat return ZYAN_FALSE; } } - else + else if (candidate_easz == 16) { - if (candidate_easz == 16 && !disp_only) + if (is_vsib) + { + candidate_easz = 32; + } + else if (!disp_only) { if (disp_size > 16) { diff --git a/tests/re_enc_test_cases.json b/tests/re_enc_test_cases.json index f5f856cc..907bbd1a 100644 --- a/tests/re_enc_test_cases.json +++ b/tests/re_enc_test_cases.json @@ -938,5 +938,11 @@ "stack_width": "ZYDIS_STACK_WIDTH_64", "payload": "F3660FA7C86239F6", "description": "rep xcrypt_ecb <- TODO: Remove 0x66 byte after fixing OSIZE handling for XCRYPT" + }, + { + "machine_mode": "ZYDIS_MACHINE_MODE_LONG_COMPAT_16", + "stack_width": "ZYDIS_STACK_WIDTH_16", + "payload": "6762C27D2DA00C150000000000000000", + "description": "vpscatterdd dword ptr ds:[ymm2*1] {k5}, ymm1" } ] \ No newline at end of file diff --git a/tools/ZydisFuzzShared.c b/tools/ZydisFuzzShared.c index 64a28270..7ec305ba 100644 --- a/tools/ZydisFuzzShared.c +++ b/tools/ZydisFuzzShared.c @@ -111,6 +111,10 @@ void ZydisPrintInstruction(const ZydisDecodedInstruction* instruction, ZYAN_UNREACHABLE; } printf("-%u ", instruction->stack_width); + if (instruction->encoding == ZYDIS_INSTRUCTION_ENCODING_MVEX) + { + printf("-knc "); + } for (ZyanU8 i = 0; i < instruction->length; ++i) { From e1b47b2a23c4edd48f8b267a6d76bf8ee61a7454 Mon Sep 17 00:00:00 2001 From: mappzor <34216645+mappzor@users.noreply.github.com> Date: Wed, 6 Nov 2024 02:16:32 +0100 Subject: [PATCH 3/3] Workaround for `xsha1`/`xsha256` --- tools/ZydisFuzzReEncoding.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tools/ZydisFuzzReEncoding.c b/tools/ZydisFuzzReEncoding.c index e0c59247..1f891536 100644 --- a/tools/ZydisFuzzReEncoding.c +++ b/tools/ZydisFuzzReEncoding.c @@ -89,6 +89,14 @@ int ZydisFuzzTarget(ZydisStreamRead read_fn, void *stream_ctx) { return EXIT_FAILURE; } + // TODO: Temporary workaround for `xsha1` and `xsha256` with OSIZE prefix + if (insn1.mnemonic == ZYDIS_MNEMONIC_XSHA1 || insn1.mnemonic == ZYDIS_MNEMONIC_XSHA256) + { + if (insn1.attributes & ZYDIS_ATTRIB_HAS_OPERANDSIZE) + { + return EXIT_SUCCESS; + } + } ZydisReEncodeInstruction(&decoder, &insn1, operands1, insn1.operand_count_visible, buffer);