From eb64a23231b059b87cffc813512316f6bc14f58c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20H=C3=B6ner?= Date: Sun, 22 Jan 2017 22:12:06 +0100 Subject: [PATCH 1/7] Added encoding of opcode bits into ModRM --- src/Encoder.c | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/Encoder.c b/src/Encoder.c index 36f1dec..cbba330 100644 --- a/src/Encoder.c +++ b/src/Encoder.c @@ -78,10 +78,11 @@ typedef struct ZydisEncoderTableEntry_ ZydisEncoderTableOperand operands[5]; ZydisOpcodeMap map; ZydisInstructionAttributes attribs; - ZydisModRMMod modRmMod; + ZydisModRMMod modRmReg; ZydisModeConstraint modeConstraint; ZydisPrefixBit prefixBits; uint8_t mandatoryPrefix; // 0x00 = None + uint8_t modrmReg; // 0xFF = None } ZydisEncoderTableEntry; struct ZydisPrefixAcceptMapping @@ -419,6 +420,8 @@ static ZydisStatus ZydisPrepareOpcode(ZydisEncoderContext* ctx) static ZydisStatus ZydisSimplifyOperandType(ZydisSemanticOperandType semType, ZydisOperandType* simpleType) { + ZYDIS_ASSERT(simpleType); + // TODO: Better mapping, this is just for testing. switch (semType) { @@ -454,6 +457,8 @@ static ZydisStatus ZydisSimplifyOperandType(ZydisSemanticOperandType semType, static ZydisStatus ZydisPrepareRegOperand(ZydisEncoderContext* ctx, ZydisRegister reg, char topBitLoc) { + ZYDIS_ASSERT(ctx); + int16_t regID = ZydisRegisterGetId(reg); if (regID == -1) return ZYDIS_STATUS_INVALID_PARAMETER; @@ -539,6 +544,10 @@ static ZydisBool ZydisIsStackReg(ZydisRegister reg) static ZydisStatus ZydisPrepareMemoryOperand(ZydisEncoderContext* ctx, ZydisOperandInfo* operand, const ZydisEncoderTableOperand* tableEntry) { + ZYDIS_ASSERT(ctx); + ZYDIS_ASSERT(operand); + ZYDIS_ASSERT(tableEntry); + // TODO: RIP relative addressing // Absolute memory access? @@ -727,12 +736,17 @@ static ZydisStatus ZydisPrepareMemoryOperand(ZydisEncoderContext* ctx, static ZydisStatus ZydisPrepareOperand(ZydisEncoderContext* ctx, ZydisOperandInfo* operand, const ZydisEncoderTableOperand* tableEntry) { + ZYDIS_ASSERT(ctx); + ZYDIS_ASSERT(operand); + ZYDIS_ASSERT(tableEntry); + switch (tableEntry->encoding) { case ZYDIS_OPERAND_ENCODING_NONE: break; // Nothing to do. case ZYDIS_OPERAND_ENCODING_REG: { + ZYDIS_ASSERT(!ctx->info->details.modrm.reg); ZYDIS_CHECK(ZydisPrepareRegOperand(ctx, operand->reg, 'R')); } break; case ZYDIS_OPERAND_ENCODING_RM: @@ -743,6 +757,12 @@ static ZydisStatus ZydisPrepareOperand(ZydisEncoderContext* ctx, case ZYDIS_OPERAND_ENCODING_RM_CD32: case ZYDIS_OPERAND_ENCODING_RM_CD64: { + ZYDIS_ASSERT(!ctx->info->details.modrm.mod); + ZYDIS_ASSERT(!ctx->info->details.modrm.rm); + ZYDIS_ASSERT(!ctx->info->details.sib.base); + ZYDIS_ASSERT(!ctx->info->details.sib.index); + ZYDIS_ASSERT(!ctx->info->details.sib.scale); + // Memory operand? if (operand->type == ZYDIS_OPERAND_TYPE_MEMORY) { @@ -811,6 +831,8 @@ static ZydisStatus ZydisPrepareOperand(ZydisEncoderContext* ctx, static ZydisStatus ZydisPrepareMandatoryPrefixes(ZydisEncoderContext* ctx) { + ZYDIS_ASSERT(ctx); + // Is a prefix mandatory? 0x00 is a sentinel value for `None` in the table. if (ctx->matchingEntry->mandatoryPrefix != 0x00) { @@ -847,6 +869,8 @@ static ZydisStatus ZydisPrepareMandatoryPrefixes(ZydisEncoderContext* ctx) static ZydisStatus ZydisDeriveEncodingForOp(ZydisOperandDefinition* operand) { + ZYDIS_ASSERT(operand); + switch (operand->type) { default: @@ -969,6 +993,12 @@ ZydisStatus ZydisEncoderEncodeInstruction(void* buffer, size_t* bufferLen, // Prepare opcode. ZYDIS_CHECK(ZydisPrepareOpcode(&ctx)); + // Some instructions have additional opcode bits encoded in ModRM.reg. + if (ctx.matchingEntry->modRmReg != 0xFF) + { + ctx.info->details.modrm.reg = ctx.matchingEntry->modRmReg; + } + // Analyze and prepare operands. if (info->operandCount > ZYDIS_ARRAY_SIZE(info->operands)) { From 08623989403769a5724cbd4f9ad61cf3aa5bf6b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20H=C3=B6ner?= Date: Mon, 23 Jan 2017 18:31:50 +0100 Subject: [PATCH 2/7] Various encoder bug-fixes --- src/Encoder.c | 101 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 71 insertions(+), 30 deletions(-) diff --git a/src/Encoder.c b/src/Encoder.c index cbba330..2562c38 100644 --- a/src/Encoder.c +++ b/src/Encoder.c @@ -78,7 +78,6 @@ typedef struct ZydisEncoderTableEntry_ ZydisEncoderTableOperand operands[5]; ZydisOpcodeMap map; ZydisInstructionAttributes attribs; - ZydisModRMMod modRmReg; ZydisModeConstraint modeConstraint; ZydisPrefixBit prefixBits; uint8_t mandatoryPrefix; // 0x00 = None @@ -251,8 +250,8 @@ static ZydisStatus ZydisEmitVEX(ZydisEncoderContext* ctx) ZYDIS_ASSERT(ctx); // Can we use short 2-byte VEX encoding? - if (ctx->info->details.vex.X == 1 && - ctx->info->details.vex.B == 1 && + if (ctx->info->details.vex.X == 0 && + ctx->info->details.vex.B == 0 && ctx->info->details.vex.W == 0 && ctx->info->details.vex.m_mmmm == 1) { @@ -472,9 +471,11 @@ static ZydisStatus ZydisPrepareRegOperand(ZydisEncoderContext* ctx, case 'X': ctx->info->details.sib.index = lowerBits; break; default: ZYDIS_UNREACHABLE; } + + // No top bit? Quick exit. + if (!topBit) return ZYDIS_STATUS_SUCCESS; uint8_t* topBitDst = NULL; - switch (ctx->info->encoding) { case ZYDIS_INSTRUCTION_ENCODING_DEFAULT: @@ -532,13 +533,36 @@ static ZydisBool ZydisIsBPReg(ZydisRegister reg) reg == ZYDIS_REGISTER_RBP; } -static ZydisBool ZydisIsStackReg(ZydisRegister reg) +static ZydisBool ZydisIsSPReg(ZydisRegister reg) { return reg == ZYDIS_REGISTER_SPL || reg == ZYDIS_REGISTER_SP || reg == ZYDIS_REGISTER_ESP || - reg == ZYDIS_REGISTER_RSP || - ZydisIsBPReg(reg); + reg == ZYDIS_REGISTER_RSP; +} + +static ZydisBool ZydisIsStackReg(ZydisRegister reg) +{ + return ZydisIsSPReg(reg) || ZydisIsBPReg(reg); +} + +static ZydisStatus ZydisSetREXWIfRequired(ZydisEncoderContext* ctx, ZydisRegister reg) +{ + ZydisRegisterClass regClass = ZydisRegisterGetClass(reg); + if (regClass == ZYDIS_REGCLASS_GPR64) + { + if (ctx->info->mode == ZYDIS_DISASSEMBLER_MODE_64BIT) + { + ctx->info->details.rex.W = 0x01; + ctx->info->attributes |= ZYDIS_ATTRIB_HAS_REX; + } + else + { + return ZYDIS_STATUS_IMPOSSIBLE_INSTRUCTION; // TODO + } + } + + return ZYDIS_STATUS_SUCCESS; } static ZydisStatus ZydisPrepareMemoryOperand(ZydisEncoderContext* ctx, @@ -628,14 +652,14 @@ static ZydisStatus ZydisPrepareMemoryOperand(ZydisEncoderContext* ctx, ctx->info->attributes |= ZYDIS_ATTRIB_HAS_SEGMENT_ES; break; case ZYDIS_REGISTER_SS: - ctx->info->attributes |= ZYDIS_ATTRIB_HAS_SEGMENT_SS; - break; - case ZYDIS_REGISTER_CS: if (!ZydisIsStackReg(operand->mem.base)) { - ctx->info->attributes |= ZYDIS_ATTRIB_HAS_SEGMENT_CS; + ctx->info->attributes |= ZYDIS_ATTRIB_HAS_SEGMENT_SS; } break; + case ZYDIS_REGISTER_CS: + ctx->info->attributes |= ZYDIS_ATTRIB_HAS_SEGMENT_CS; + break; case ZYDIS_REGISTER_DS: if (ZydisIsStackReg(operand->mem.base)) { @@ -652,18 +676,13 @@ static ZydisStatus ZydisPrepareMemoryOperand(ZydisEncoderContext* ctx, return ZYDIS_STATUS_IMPOSSIBLE_INSTRUCTION; // TODO: Better status. } - // SIB byte required? - if (operand->mem.index || operand->mem.scale) + // SIB byte required? rSP can only be encoded with SIB. + if (operand->mem.index || operand->mem.scale || ZydisIsSPReg(operand->mem.base)) { - // Base and index register must be of same register class, verify. - if (ZydisRegisterGetClass(operand->mem.index) != baseRegClass) - { - return ZYDIS_STATUS_IMPOSSIBLE_INSTRUCTION; // TODO - } - // Translate scale to SIB format. switch (operand->mem.scale) { + case 0: // We take 0 (uninitialized, 0 from memset) as * 1. case 1: ctx->info->details.sib.scale = 0x00; break; case 2: ctx->info->details.sib.scale = 0x01; break; case 4: ctx->info->details.sib.scale = 0x02; break; @@ -671,11 +690,25 @@ static ZydisStatus ZydisPrepareMemoryOperand(ZydisEncoderContext* ctx, default: return ZYDIS_STATUS_IMPOSSIBLE_INSTRUCTION; // TODO } - // Base & index register. + // Move base register info to SIB. ctx->info->details.sib.base = ctx->info->details.modrm.rm; - ZYDIS_CHECK(ZydisPrepareRegOperand(ctx, operand->mem.index, 'X')); - ctx->info->details.modrm.rm = 0x04 /* SIB */; + + // Process index register. + if (operand->mem.index != ZYDIS_REGISTER_NONE) + { + // Base and index register must be of same register class, verify. + if (ZydisRegisterGetClass(operand->mem.index) != baseRegClass) + { + return ZYDIS_STATUS_IMPOSSIBLE_INSTRUCTION; // TODO + } + ZYDIS_CHECK(ZydisPrepareRegOperand(ctx, operand->mem.index, 'X')); + } + else + { + ctx->info->details.sib.index = 0x04 /* no index */; + } + ctx->info->attributes |= ZYDIS_ATTRIB_HAS_SIB; } @@ -748,6 +781,7 @@ static ZydisStatus ZydisPrepareOperand(ZydisEncoderContext* ctx, { ZYDIS_ASSERT(!ctx->info->details.modrm.reg); ZYDIS_CHECK(ZydisPrepareRegOperand(ctx, operand->reg, 'R')); + ZYDIS_CHECK(ZydisSetREXWIfRequired(ctx, operand->reg)); } break; case ZYDIS_OPERAND_ENCODING_RM: case ZYDIS_OPERAND_ENCODING_RM_CD2: @@ -772,6 +806,7 @@ static ZydisStatus ZydisPrepareOperand(ZydisEncoderContext* ctx, else if (operand->type == ZYDIS_OPERAND_TYPE_REGISTER) { ZYDIS_CHECK(ZydisPrepareRegOperand(ctx, operand->reg, 'B')); + ZYDIS_CHECK(ZydisSetREXWIfRequired(ctx, operand->reg)); ctx->info->details.modrm.mod = 0x03 /* reg */; } @@ -782,9 +817,10 @@ static ZydisStatus ZydisPrepareOperand(ZydisEncoderContext* ctx, { int16_t reg = ZydisRegisterGetId(operand->reg); if (reg == -1) return ZYDIS_STATUS_INVALID_PARAMETER; - ctx->info->opcode += reg & 0x0F; - ctx->info->details.rex.R = (reg & 0x08) >> 3; + ctx->info->opcode += reg & 0x07; + ctx->info->details.rex.B = (reg & 0x08) >> 3; if (ctx->info->details.rex.B) ctx->info->attributes |= ZYDIS_ATTRIB_HAS_REX; + //ZYDIS_CHECK(ZydisSetREXWIfRequired(ctx, operand->reg)); break; } case ZYDIS_OPERAND_ENCODING_VVVV: @@ -909,9 +945,10 @@ static ZydisStatus ZydisFindMatchingDef(const ZydisInstructionInfo* info, const ZydisEncoderTableOperand* curEncoderOp = &curEntry->operands[k]; const ZydisOperandInfo* curReqOp = &info->operands[k]; if (curReqOp->encoding != curEncoderOp->encoding) goto continueTopLevel; - ZydisOperandType simpleType; - ZYDIS_CHECK(ZydisSimplifyOperandType(curEncoderOp->type, &simpleType)); - if (curReqOp->type != simpleType) goto continueTopLevel; + //ZydisOperandType simpleType; + //ZYDIS_CHECK(ZydisSimplifyOperandType(curEncoderOp->type, &simpleType)); + //if (curReqOp->type != simpleType) goto continueTopLevel; + if (curReqOp->temp != curEncoderOp->type) goto continueTopLevel; } // Still here? We found our entry! @@ -987,16 +1024,20 @@ ZydisStatus ZydisEncoderEncodeInstruction(void* buffer, size_t* bufferLen, info->details.evex.B = (pb & ZYDIS_PREFBIT_EVEX_B ) ? 1 : 0; info->details.evex.L2 = (pb & ZYDIS_PREFBIT_EVEX_L2) ? 1 : 0; info->details.vex.L = (pb & ZYDIS_PREFBIT_VEX_L ) ? 1 : 0; - info->details.rex.W = (pb & ZYDIS_PREFBIT_REX_W ) ? 1 : 0; + if (info->details.rex.W) + { + info->details.rex.W = 1; + info->attributes |= ZYDIS_ATTRIB_HAS_REX; + } ZYDIS_CHECK(ZydisPrepareMandatoryPrefixes(&ctx)); // Prepare opcode. ZYDIS_CHECK(ZydisPrepareOpcode(&ctx)); // Some instructions have additional opcode bits encoded in ModRM.reg. - if (ctx.matchingEntry->modRmReg != 0xFF) + if (ctx.matchingEntry->modrmReg != 0xFF) { - ctx.info->details.modrm.reg = ctx.matchingEntry->modRmReg; + ctx.info->details.modrm.reg = ctx.matchingEntry->modrmReg; } // Analyze and prepare operands. From 616cd00ec80d904f06463fe113c01a4020820571 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20H=C3=B6ner?= Date: Mon, 23 Jan 2017 19:21:15 +0100 Subject: [PATCH 3/7] Encoder support for rIP relative addressing --- src/Encoder.c | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/src/Encoder.c b/src/Encoder.c index 2562c38..48e58f1 100644 --- a/src/Encoder.c +++ b/src/Encoder.c @@ -541,6 +541,13 @@ static ZydisBool ZydisIsSPReg(ZydisRegister reg) reg == ZYDIS_REGISTER_RSP; } +static ZydisBool ZydisIsIPReg(ZydisRegister reg) +{ + return reg == ZYDIS_REGISTER_IP || + reg == ZYDIS_REGISTER_EIP || + reg == ZYDIS_REGISTER_RIP; +} + static ZydisBool ZydisIsStackReg(ZydisRegister reg) { return ZydisIsSPReg(reg) || ZydisIsBPReg(reg); @@ -572,9 +579,7 @@ static ZydisStatus ZydisPrepareMemoryOperand(ZydisEncoderContext* ctx, ZYDIS_ASSERT(operand); ZYDIS_ASSERT(tableEntry); - // TODO: RIP relative addressing - - // Absolute memory access? + // Absolute memory access? Special case. if (operand->mem.base == ZYDIS_REGISTER_NONE) { ctx->disp = operand->mem.disp.value.sdword; @@ -600,6 +605,34 @@ static ZydisStatus ZydisPrepareMemoryOperand(ZydisEncoderContext* ctx, return ZYDIS_STATUS_SUCCESS; } + // rIP relative addressing? Special case. + if (ZydisIsIPReg(operand->mem.base)) + { + // rIP addressing is only available since AMD64. + if (ctx->info->mode != ZYDIS_DISASSEMBLER_MODE_64BIT) + { + return ZYDIS_STATUS_IMPOSSIBLE_INSTRUCTION; // TODO + } + + // Only available with either EIP or RIP, not with IP. + if (operand->mem.base == ZYDIS_REGISTER_IP) + { + return ZYDIS_STATUS_IMPOSSIBLE_INSTRUCTION; // TODO + } + + ctx->disp = operand->mem.disp.value.sdword; + ctx->dispBitSize = 32; + ctx->info->details.modrm.mod = 0x00; + ctx->info->details.modrm.rm = 0x05 /* RIP relative mem */; + + if (operand->mem.base == ZYDIS_REGISTER_EIP) + { + ctx->info->attributes |= ZYDIS_ATTRIB_HAS_ADDRESSSIZE; + } + + return ZYDIS_STATUS_SUCCESS; + } + // Process base register. ZYDIS_CHECK(ZydisPrepareRegOperand(ctx, operand->mem.base, 'B')); From fda4f15c6d3c1603cea8c5aeb72c867aae8899df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20H=C3=B6ner?= Date: Mon, 23 Jan 2017 21:52:26 +0100 Subject: [PATCH 4/7] Many encoder bug-fixes, movabs support --- src/Encoder.c | 91 ++++++++++++++++++++++++++------------------------- 1 file changed, 47 insertions(+), 44 deletions(-) diff --git a/src/Encoder.c b/src/Encoder.c index 48e58f1..782bcc5 100644 --- a/src/Encoder.c +++ b/src/Encoder.c @@ -82,6 +82,7 @@ typedef struct ZydisEncoderTableEntry_ ZydisPrefixBit prefixBits; uint8_t mandatoryPrefix; // 0x00 = None uint8_t modrmReg; // 0xFF = None + const char* cmt; } ZydisEncoderTableEntry; struct ZydisPrefixAcceptMapping @@ -553,20 +554,38 @@ static ZydisBool ZydisIsStackReg(ZydisRegister reg) return ZydisIsSPReg(reg) || ZydisIsBPReg(reg); } -static ZydisStatus ZydisSetREXWIfRequired(ZydisEncoderContext* ctx, ZydisRegister reg) +static ZydisStatus ZydisPrepareSegmentPrefix(ZydisEncoderContext* ctx, + ZydisRegister segment, ZydisRegister base) { - ZydisRegisterClass regClass = ZydisRegisterGetClass(reg); - if (regClass == ZYDIS_REGCLASS_GPR64) + // Segment prefix required? + switch (segment) { - if (ctx->info->mode == ZYDIS_DISASSEMBLER_MODE_64BIT) + case ZYDIS_REGISTER_ES: + ctx->info->attributes |= ZYDIS_ATTRIB_HAS_SEGMENT_ES; + break; + case ZYDIS_REGISTER_SS: + if (!ZydisIsStackReg(base)) { - ctx->info->details.rex.W = 0x01; - ctx->info->attributes |= ZYDIS_ATTRIB_HAS_REX; + ctx->info->attributes |= ZYDIS_ATTRIB_HAS_SEGMENT_SS; } - else + break; + case ZYDIS_REGISTER_CS: + ctx->info->attributes |= ZYDIS_ATTRIB_HAS_SEGMENT_CS; + break; + case ZYDIS_REGISTER_DS: + if (ZydisIsStackReg(base)) { - return ZYDIS_STATUS_IMPOSSIBLE_INSTRUCTION; // TODO + ctx->info->attributes |= ZYDIS_ATTRIB_HAS_SEGMENT_DS; } + break; + case ZYDIS_REGISTER_FS: + ctx->info->attributes |= ZYDIS_ATTRIB_HAS_SEGMENT_FS; + break; + case ZYDIS_REGISTER_GS: + ctx->info->attributes |= ZYDIS_ATTRIB_HAS_SEGMENT_GS; + break; + default: + return ZYDIS_STATUS_IMPOSSIBLE_INSTRUCTION; // TODO: Better status. } return ZYDIS_STATUS_SUCCESS; @@ -579,6 +598,8 @@ static ZydisStatus ZydisPrepareMemoryOperand(ZydisEncoderContext* ctx, ZYDIS_ASSERT(operand); ZYDIS_ASSERT(tableEntry); + ZYDIS_CHECK(ZydisPrepareSegmentPrefix(ctx, operand->mem.segment, operand->mem.base)); + // Absolute memory access? Special case. if (operand->mem.base == ZYDIS_REGISTER_NONE) { @@ -678,37 +699,6 @@ static ZydisStatus ZydisPrepareMemoryOperand(ZydisEncoderContext* ctx, return ZYDIS_STATUS_INVALID_PARAMETER; // TODO } - // Segment prefix required? - switch (operand->mem.segment) - { - case ZYDIS_REGISTER_ES: - ctx->info->attributes |= ZYDIS_ATTRIB_HAS_SEGMENT_ES; - break; - case ZYDIS_REGISTER_SS: - if (!ZydisIsStackReg(operand->mem.base)) - { - ctx->info->attributes |= ZYDIS_ATTRIB_HAS_SEGMENT_SS; - } - break; - case ZYDIS_REGISTER_CS: - ctx->info->attributes |= ZYDIS_ATTRIB_HAS_SEGMENT_CS; - break; - case ZYDIS_REGISTER_DS: - if (ZydisIsStackReg(operand->mem.base)) - { - ctx->info->attributes |= ZYDIS_ATTRIB_HAS_SEGMENT_DS; - } - break; - case ZYDIS_REGISTER_FS: - ctx->info->attributes |= ZYDIS_ATTRIB_HAS_SEGMENT_FS; - break; - case ZYDIS_REGISTER_GS: - ctx->info->attributes |= ZYDIS_ATTRIB_HAS_SEGMENT_GS; - break; - default: - return ZYDIS_STATUS_IMPOSSIBLE_INSTRUCTION; // TODO: Better status. - } - // SIB byte required? rSP can only be encoded with SIB. if (operand->mem.index || operand->mem.scale || ZydisIsSPReg(operand->mem.base)) { @@ -809,12 +799,27 @@ static ZydisStatus ZydisPrepareOperand(ZydisEncoderContext* ctx, switch (tableEntry->encoding) { case ZYDIS_OPERAND_ENCODING_NONE: - break; // Nothing to do. + // For some encodings, we have to switch on the sem op type. + switch (tableEntry->type) + { + case ZYDIS_SEM_OPERAND_TYPE_MOFFS16: + case ZYDIS_SEM_OPERAND_TYPE_MOFFS32: + case ZYDIS_SEM_OPERAND_TYPE_MOFFS64: + ZYDIS_CHECK(ZydisPrepareSegmentPrefix( + ctx, operand->mem.segment, ZYDIS_REGISTER_NONE + )); + ctx->imms[0] = operand->mem.disp.value.sqword; + ctx->immBitSizes[0] = operand->mem.disp.dataSize; + break; + default: + // Hidden operand, nothing to encode. + break; + } + break; case ZYDIS_OPERAND_ENCODING_REG: { ZYDIS_ASSERT(!ctx->info->details.modrm.reg); ZYDIS_CHECK(ZydisPrepareRegOperand(ctx, operand->reg, 'R')); - ZYDIS_CHECK(ZydisSetREXWIfRequired(ctx, operand->reg)); } break; case ZYDIS_OPERAND_ENCODING_RM: case ZYDIS_OPERAND_ENCODING_RM_CD2: @@ -839,7 +844,6 @@ static ZydisStatus ZydisPrepareOperand(ZydisEncoderContext* ctx, else if (operand->type == ZYDIS_OPERAND_TYPE_REGISTER) { ZYDIS_CHECK(ZydisPrepareRegOperand(ctx, operand->reg, 'B')); - ZYDIS_CHECK(ZydisSetREXWIfRequired(ctx, operand->reg)); ctx->info->details.modrm.mod = 0x03 /* reg */; } @@ -853,7 +857,6 @@ static ZydisStatus ZydisPrepareOperand(ZydisEncoderContext* ctx, ctx->info->opcode += reg & 0x07; ctx->info->details.rex.B = (reg & 0x08) >> 3; if (ctx->info->details.rex.B) ctx->info->attributes |= ZYDIS_ATTRIB_HAS_REX; - //ZYDIS_CHECK(ZydisSetREXWIfRequired(ctx, operand->reg)); break; } case ZYDIS_OPERAND_ENCODING_VVVV: @@ -1057,7 +1060,7 @@ ZydisStatus ZydisEncoderEncodeInstruction(void* buffer, size_t* bufferLen, info->details.evex.B = (pb & ZYDIS_PREFBIT_EVEX_B ) ? 1 : 0; info->details.evex.L2 = (pb & ZYDIS_PREFBIT_EVEX_L2) ? 1 : 0; info->details.vex.L = (pb & ZYDIS_PREFBIT_VEX_L ) ? 1 : 0; - if (info->details.rex.W) + if (pb & ZYDIS_PREFBIT_REX_W) { info->details.rex.W = 1; info->attributes |= ZYDIS_ATTRIB_HAS_REX; From 0376376b838ad7f39956146e42eed45197cdb1c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20H=C3=B6ner?= Date: Sat, 8 Apr 2017 19:36:16 +0200 Subject: [PATCH 5/7] Temp. disabled encoder, updated CMake defaults --- CMakeLists.txt | 20 ++++++++++---------- include/Zydis/Zydis.h | 1 + tools/ZydisDisasm.c | 2 ++ 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4dbe067..72de30b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,21 +6,21 @@ set_property(GLOBAL PROPERTY USE_FOLDERS ON) option(ZYDIS_BUILD_SHARED_LIBS "Build shared libraries rather than static ones" - FALSE) + OFF) option(ZYDIS_FORCE_SHARED_CRT - "Forces shared linkage against the CRT even when building a static library" - FALSE) + "Forces shared linkage against the CRT even when building a static library. MSVC only." + OFF) option(ZYDIS_FEATURE_IMPLICITLY_USED_REGISTERS "Include information about implicitly used registers" - TRUE) + OFF) option(ZYDIS_FEATURE_AFFECTED_FLAGS "Include information about affected flags" - TRUE) + OFF) option(ZYDIS_FEATURE_CPUID "Include information about CPUID feature-flags" - FALSE) -option(ZYDIS_BUILD_EXAMPLES "Build examples" TRUE) -option(ZYDIS_BUILD_TOOLS "Build tools" TRUE) + OFF) +option(ZYDIS_BUILD_EXAMPLES "Build examples" ON) +option(ZYDIS_BUILD_TOOLS "Build tools" ON) if (NOT CONFIGURED_ONCE) if ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR @@ -49,7 +49,7 @@ endif () # Library set(headers "include/Zydis/Decoder.h" - "include/Zydis/Encoder.h" + #"include/Zydis/Encoder.h" "include/Zydis/Defines.h" "include/Zydis/Formatter.h" "include/Zydis/InstructionInfo.h" @@ -62,7 +62,7 @@ set(headers "include/Zydis/Internal/InstructionTable.h") set(sources "src/Decoder.c" - "src/Encoder.c" + #"src/Encoder.c" "src/Formatter.c" "src/InstructionTable.c" "src/Mnemonic.c" diff --git a/include/Zydis/Zydis.h b/include/Zydis/Zydis.h index a434f40..5afc7a4 100644 --- a/include/Zydis/Zydis.h +++ b/include/Zydis/Zydis.h @@ -36,6 +36,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { diff --git a/tools/ZydisDisasm.c b/tools/ZydisDisasm.c index 8cca3bf..fc583b1 100644 --- a/tools/ZydisDisasm.c +++ b/tools/ZydisDisasm.c @@ -95,6 +95,7 @@ int main(int argc, char** argv) // TODO: Remove // DEBUG CODE START +#if 0 for (size_t i = 0; i < info.length; ++i) { printf("%02X ", *(readBuf + readOffs + i)); @@ -115,6 +116,7 @@ int main(int argc, char** argv) putchar('\n'); ZYDIS_ASSERT(encBufferSize == info.length); ZYDIS_ASSERT(!memcmp(encBuffer, readBuf + readOffs, encBufferSize)); +#endif // DEBUG CODE END readOffs += info.length; From ae5a9005918ea4e275e87576f154e498bf22286f Mon Sep 17 00:00:00 2001 From: Duncan Ogilvie Date: Sat, 8 Apr 2017 20:33:58 +0200 Subject: [PATCH 6/7] changes AccessMode to Action in frmMain This fixes a compile error because TOperandAccessMode was refactored to TOperandAction. --- assets/InstructionEditor/Forms/formMain.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/InstructionEditor/Forms/formMain.pas b/assets/InstructionEditor/Forms/formMain.pas index afbd937..7b729f1 100644 --- a/assets/InstructionEditor/Forms/formMain.pas +++ b/assets/InstructionEditor/Forms/formMain.pas @@ -931,7 +931,7 @@ begin begin O := NodeData^.Definition.Operands.Operands[I]; S := S + IntToStr(Integer(O.OperandType)) + ',' + IntToStr(Integer(O.Encoding)) + ',' + - IntToStr(Integer(O.AccessMode)) + ','; + IntToStr(Integer(O.Action)) + ','; end; Clipboard.AsText := S; end; @@ -959,7 +959,7 @@ begin O := NodeData^.Definition.Operands.Operands[J]; O.OperandType := TOperandType(StrToInt(A[I])); O.Encoding := TOperandEncoding(StrToInt(A[I + 1])); - O.AccessMode := TOperandAccessMode(StrToInt(A[I + 2])); + O.Action := TOperandAction(StrToInt(A[I + 2])); Inc(I, 3); Inc(J); end; From 3b47ed4a9a3dc78943704f7de63ea57565f3eafb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20H=C3=B6ner?= Date: Sun, 9 Apr 2017 20:55:49 +0200 Subject: [PATCH 7/7] Fixed inaccurate relative operands on decoding Resolves #13 --- src/Decoder.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/Decoder.c b/src/Decoder.c index 40fecf7..726085f 100644 --- a/src/Decoder.c +++ b/src/Decoder.c @@ -524,7 +524,7 @@ static ZydisStatus ZydisDecodeOperandImmediate(ZydisInstructionDecoder* decoder, case 32: { uint32_t data[4] = { 0, 0, 0, 0 }; - for (int i = sizeof(data) / sizeof(data[0]); i > 0; --i) + for (int i = ZYDIS_ARRAY_SIZE(data); i > 0; --i) { ZYDIS_CHECK(ZydisInputNext(decoder, info, (uint8_t*)&data[i - 1])); } @@ -1255,6 +1255,7 @@ static ZydisStatus ZydisDecodeOperand(ZydisInstructionDecoder* decoder, ZydisIns case ZYDIS_SEM_OPERAND_TYPE_REL8: info->attributes |= ZYDIS_ATTRIB_IS_RELATIVE; operand->imm.isRelative = ZYDIS_TRUE; + // Intentional fallthrough. case ZYDIS_SEM_OPERAND_TYPE_IMM8: operand->size = 8; operand->imm.isSigned = ZYDIS_TRUE; @@ -1266,6 +1267,7 @@ static ZydisStatus ZydisDecodeOperand(ZydisInstructionDecoder* decoder, ZydisIns case ZYDIS_SEM_OPERAND_TYPE_REL16: info->attributes |= ZYDIS_ATTRIB_IS_RELATIVE; operand->imm.isRelative = ZYDIS_TRUE; + // Intentional fallthrough. case ZYDIS_SEM_OPERAND_TYPE_IMM16: operand->size = 16; operand->imm.isSigned = ZYDIS_TRUE; @@ -1280,6 +1282,7 @@ static ZydisStatus ZydisDecodeOperand(ZydisInstructionDecoder* decoder, ZydisIns case ZYDIS_SEM_OPERAND_TYPE_REL64: info->attributes |= ZYDIS_ATTRIB_IS_RELATIVE; operand->imm.isRelative = ZYDIS_TRUE; + // Intentional fallthrough. case ZYDIS_SEM_OPERAND_TYPE_IMM64: operand->size = 64; operand->imm.isSigned = ZYDIS_TRUE; @@ -2383,6 +2386,16 @@ ZydisStatus ZydisDecoderDecodeInstructionEx(ZydisInstructionDecoder* decoder, } } + // For relative operands, apply instruction length offset. + for (size_t i = 0; i < info->operandCount; ++i) + { + if (info->operands[i].type == ZYDIS_OPERAND_TYPE_IMMEDIATE && + info->operands[i].imm.isRelative) + { + info->operands[i].imm.value.sqword += info->length; + } + } + // Replace XCHG rAX, rAX with NOP alias if (info->mnemonic == ZYDIS_MNEMONIC_XCHG) {