From 1ad8a1591b0f3886bcd28f4e8708ca938a99fe26 Mon Sep 17 00:00:00 2001 From: naci Date: Fri, 15 Mar 2024 20:27:31 +0300 Subject: [PATCH] Add size and offset to immediate and memory operand structs (#489) --- assets/porting-guide-v4-v5.md | 19 +++++++++++++++++-- include/Zydis/DecoderTypes.h | 22 ++++++++++++++++++---- src/Decoder.c | 8 ++++++-- src/Encoder.c | 2 +- src/FormatterATT.c | 4 ++-- src/FormatterIntel.c | 4 ++-- src/Utils.c | 2 +- tools/ZydisFuzzEncoder.c | 2 +- tools/ZydisFuzzShared.c | 21 ++++++++++++++++++++- 9 files changed, 68 insertions(+), 16 deletions(-) diff --git a/assets/porting-guide-v4-v5.md b/assets/porting-guide-v4-v5.md index 6bb4aab3..a1dd029e 100644 --- a/assets/porting-guide-v4-v5.md +++ b/assets/porting-guide-v4-v5.md @@ -1,9 +1,24 @@ # Porting Guide v4 -> v5 -# Encoder +### Encoder - `ZydisRegisterGetLargestEnclosing` will now return the given register itself for registers that don't have an enclosing register. Previously it would return `ZYDIS_REGISTER_NONE` in these cases. - `ZydisEncoderDecodedInstructionToEncoderRequest` now expects exactly `instruction->operand_count_visible` to be passed, not `operand_count_visible` at maximum. Passing a lower value was previously allowed but didn't really - make much sense at all. \ No newline at end of file + make much sense at all. + +### Decoder + +- `ZydisDecodedOperandImm` struct was changed + - Added field `offset` + - Contains the offset of the immediate data, relative to the beginning of the instruction, in bytes. + - Added field `size` + - Contains the physical immediate size, in bits. +- `ZydisDecodedOperandMemDisp_` struct was changed + - Added field `offset` + - Contains the offset of the immediate data, relative to the beginning of the instruction, in bytes. + - Added field `size` + - Contains the physical displacement size, in bits. + - Removed field `has_displacement` + - A `size` of 0 indicates that there is no displacement, effectively replacing the need for `has_displacement`. \ No newline at end of file diff --git a/include/Zydis/DecoderTypes.h b/include/Zydis/DecoderTypes.h index 7142abe8..4ea3bf7a 100644 --- a/include/Zydis/DecoderTypes.h +++ b/include/Zydis/DecoderTypes.h @@ -149,14 +149,19 @@ typedef struct ZydisDecodedOperandMem_ */ struct ZydisDecodedOperandMemDisp_ { - /** - * Signals, if the displacement value is used. - */ - ZyanBool has_displacement; /** * The displacement value */ ZyanI64 value; + /** + * The offset of the displacement data, relative to the beginning of the + * instruction, in bytes. + */ + ZyanU8 offset; + /** + * The physical displacement size, in bits. + */ + ZyanU8 size; } disp; } ZydisDecodedOperandMem; @@ -191,6 +196,15 @@ typedef struct ZydisDecodedOperandImm_ ZyanU64 u; ZyanI64 s; } value; + /** + * The offset of the immediate data, relative to the beginning of the + * instruction, in bytes. + */ + ZyanU8 offset; + /** + * The physical immediate size, in bits. + */ + ZyanU8 size; } ZydisDecodedOperandImm; /** diff --git a/src/Decoder.c b/src/Decoder.c index 2d73c554..3c02e6ee 100644 --- a/src/Decoder.c +++ b/src/Decoder.c @@ -1433,8 +1433,9 @@ static ZyanStatus ZydisDecodeOperandMemory(const ZydisDecoderContext* context, if (displacement_size) { ZYAN_ASSERT(instruction->raw.disp.size == displacement_size); - operand->mem.disp.has_displacement = ZYAN_TRUE; operand->mem.disp.value = instruction->raw.disp.value; + operand->mem.disp.size = displacement_size; + operand->mem.disp.offset = instruction->raw.disp.offset; } return ZYAN_STATUS_SUCCESS; } @@ -1829,7 +1830,8 @@ static ZyanStatus ZydisDecodeOperands(const ZydisDecoder* decoder, const ZydisDe ZYAN_ASSERT(instruction->raw.disp.size); operands[i].type = ZYDIS_OPERAND_TYPE_MEMORY; operands[i].mem.type = ZYDIS_MEMOP_TYPE_MEM; - operands[i].mem.disp.has_displacement = ZYAN_TRUE; + operands[i].mem.disp.size = instruction->raw.disp.size; + operands[i].mem.disp.offset = instruction->raw.disp.offset; operands[i].mem.disp.value = instruction->raw.disp.value; break; case ZYDIS_SEMANTIC_OPTYPE_MIB: @@ -1877,6 +1879,8 @@ static ZyanStatus ZydisDecodeOperands(const ZydisDecoder* decoder, const ZydisDe { operands[i].imm.value.u = instruction->raw.imm[imm_id].value.u; } + operands[i].imm.offset = instruction->raw.imm->offset; + operands[i].imm.size = instruction->raw.imm->size; operands[i].imm.is_signed = instruction->raw.imm[imm_id].is_signed; operands[i].imm.is_relative = instruction->raw.imm[imm_id].is_relative; ++imm_id; diff --git a/src/Encoder.c b/src/Encoder.c index 49f7e303..1b92fe2e 100644 --- a/src/Encoder.c +++ b/src/Encoder.c @@ -4705,7 +4705,7 @@ ZYDIS_EXPORT ZyanStatus ZydisEncoderDecodedInstructionToEncoderRequest( enc_op->mem.base = dec_op->mem.base; enc_op->mem.index = dec_op->mem.index; enc_op->mem.scale = dec_op->mem.type != ZYDIS_MEMOP_TYPE_MIB ? dec_op->mem.scale : 0; - if (dec_op->mem.disp.has_displacement) + if (dec_op->mem.disp.size) { enc_op->mem.displacement = dec_op->mem.disp.value; } diff --git a/src/FormatterATT.c b/src/FormatterATT.c index bb183bdc..462ba449 100644 --- a/src/FormatterATT.c +++ b/src/FormatterATT.c @@ -208,7 +208,7 @@ ZyanStatus ZydisFormatterATTFormatOperandMEM(const ZydisFormatter* formatter, const ZyanBool absolute = !formatter->force_relative_riprel && (context->runtime_address != ZYDIS_RUNTIME_ADDRESS_NONE); - if (absolute && context->operand->mem.disp.has_displacement && + if (absolute && context->operand->mem.disp.size && (context->operand->mem.index == ZYDIS_REGISTER_NONE) && ((context->operand->mem.base == ZYDIS_REGISTER_NONE) || (context->operand->mem.base == ZYDIS_REGISTER_EIP ) || @@ -226,7 +226,7 @@ ZyanStatus ZydisFormatterATTFormatOperandMEM(const ZydisFormatter* formatter, if (neither_reg_nor_idx) { ZYAN_CHECK(formatter->func_print_address_abs(formatter, buffer, context)); - } else if (context->operand->mem.disp.has_displacement && context->operand->mem.disp.value) + } else if (context->operand->mem.disp.size && context->operand->mem.disp.value) { ZYAN_CHECK(formatter->func_print_disp(formatter, buffer, context)); } diff --git a/src/FormatterIntel.c b/src/FormatterIntel.c index 5e01e858..77144e82 100644 --- a/src/FormatterIntel.c +++ b/src/FormatterIntel.c @@ -212,7 +212,7 @@ ZyanStatus ZydisFormatterIntelFormatOperandMEM(const ZydisFormatter* formatter, const ZyanBool absolute = !formatter->force_relative_riprel && (context->runtime_address != ZYDIS_RUNTIME_ADDRESS_NONE); - if (absolute && context->operand->mem.disp.has_displacement && + if (absolute && context->operand->mem.disp.size && (context->operand->mem.index == ZYDIS_REGISTER_NONE) && ((context->operand->mem.base == ZYDIS_REGISTER_NONE) || (context->operand->mem.base == ZYDIS_REGISTER_EIP ) || @@ -253,7 +253,7 @@ ZyanStatus ZydisFormatterIntelFormatOperandMEM(const ZydisFormatter* formatter, if (neither_reg_nor_idx) { ZYAN_CHECK(formatter->func_print_address_abs(formatter, buffer, context)); - } else if (context->operand->mem.disp.has_displacement && context->operand->mem.disp.value) + } else if (context->operand->mem.disp.size && context->operand->mem.disp.value) { ZYAN_CHECK(formatter->func_print_disp(formatter, buffer, context)); } diff --git a/src/Utils.c b/src/Utils.c index 6fd86a98..c3a5b0f9 100644 --- a/src/Utils.c +++ b/src/Utils.c @@ -49,7 +49,7 @@ ZyanStatus ZydisCalcAbsoluteAddress(const ZydisDecodedInstruction* instruction, switch (operand->type) { case ZYDIS_OPERAND_TYPE_MEMORY: - if (!operand->mem.disp.has_displacement) + if (!operand->mem.disp.size) { return ZYAN_STATUS_INVALID_ARGUMENT; } diff --git a/tools/ZydisFuzzEncoder.c b/tools/ZydisFuzzEncoder.c index bc062bef..550d533c 100644 --- a/tools/ZydisFuzzEncoder.c +++ b/tools/ZydisFuzzEncoder.c @@ -132,7 +132,7 @@ void ZydisCompareRequestToInstruction(const ZydisEncoderRequest *request, ZyanBool acceptable_mismatch = ZYAN_FALSE; if (op1->mem.displacement != op2->mem.disp.value) { - if ((op2->mem.disp.has_displacement) && + if ((op2->mem.disp.size) && (op1->mem.index == ZYDIS_REGISTER_NONE) && ((op1->mem.base == ZYDIS_REGISTER_NONE) || (op1->mem.base == ZYDIS_REGISTER_EIP) || diff --git a/tools/ZydisFuzzShared.c b/tools/ZydisFuzzShared.c index 3e352d5d..d02c9f8d 100644 --- a/tools/ZydisFuzzShared.c +++ b/tools/ZydisFuzzShared.c @@ -136,6 +136,20 @@ void ZydisPrintInstruction(const ZydisDecodedInstruction* instruction, #endif +void ZydisValidateImmediateSize(ZyanU64 value) +{ + if ((value != 0) && + (value != 8) && + (value != 16) && + (value != 32) && + (value != 64)) + { + fprintf(stderr, "Value 0x%016" PRIX64 " does not match any of the expected " + "values (0, 8, 16, 32, 64).\n", value); + abort(); + } +} + // NOTE: This function doesn't validate flag values, yet. void ZydisValidateEnumRanges(const ZydisDecodedInstruction* insn, const ZydisDecodedOperand* operands, ZyanU8 operand_count) @@ -147,6 +161,7 @@ void ZydisValidateEnumRanges(const ZydisDecodedInstruction* insn, " = 0x%016" PRIX64 "\n", (ZyanU64)(value), (ZyanU64)(max)); \ abort(); \ } +# define ZYDIS_CHECK_MAX ZYDIS_CHECK_ENUM ZYDIS_CHECK_ENUM(insn->length, ZYDIS_MAX_INSTRUCTION_LENGTH); @@ -175,11 +190,14 @@ void ZydisValidateEnumRanges(const ZydisDecodedInstruction* insn, ZYDIS_CHECK_ENUM(op->mem.segment, ZYDIS_REGISTER_MAX_VALUE); ZYDIS_CHECK_ENUM(op->mem.base, ZYDIS_REGISTER_MAX_VALUE); ZYDIS_CHECK_ENUM(op->mem.index, ZYDIS_REGISTER_MAX_VALUE); - ZYDIS_CHECK_ENUM(op->mem.disp.has_displacement, ZYAN_TRUE); + ZydisValidateImmediateSize(op->mem.disp.size); + ZYDIS_CHECK_MAX(op->mem.disp.offset + (op->mem.disp.size / 8), insn->length); break; case ZYDIS_OPERAND_TYPE_IMMEDIATE: ZYDIS_CHECK_ENUM(op->imm.is_signed, ZYAN_TRUE); ZYDIS_CHECK_ENUM(op->imm.is_relative, ZYAN_TRUE); + ZydisValidateImmediateSize(op->imm.size); + ZYDIS_CHECK_MAX(op->imm.offset + (op->imm.size / 8), insn->length); break; default: break; @@ -216,6 +234,7 @@ void ZydisValidateEnumRanges(const ZydisDecodedInstruction* insn, } # undef ZYDIS_CHECK_ENUM +# undef ZYDIS_CHECK_MAX } void ZydisValidateInstructionIdentity(const ZydisDecodedInstruction* insn1,