2016-05-26 03:25:48 +08:00
|
|
|
/***************************************************************************************************
|
|
|
|
|
2016-12-05 09:24:01 +08:00
|
|
|
Zyan Disassembler Library (Zydis)
|
2016-05-26 03:25:48 +08:00
|
|
|
|
|
|
|
Original Author : Florian Bernd
|
|
|
|
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
|
|
* in the Software without restriction, including without limitation the rights
|
|
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
|
|
* furnished to do so, subject to the following conditions:
|
|
|
|
*
|
|
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
|
|
* copies or substantial portions of the Software.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
|
|
* SOFTWARE.
|
|
|
|
|
|
|
|
***************************************************************************************************/
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
#include <Zydis/Status.h>
|
|
|
|
#include <Zydis/Decoder.h>
|
|
|
|
#include <Zydis/Internal/InstructionTable.h>
|
|
|
|
|
|
|
|
/* ============================================================================================== */
|
2017-04-11 08:19:53 +08:00
|
|
|
/* Internal functions and types */
|
2016-05-26 03:25:48 +08:00
|
|
|
/* ============================================================================================== */
|
|
|
|
|
2017-04-11 08:19:53 +08:00
|
|
|
/* ---------------------------------------------------------------------------------------------- */
|
|
|
|
/* Internals structs */
|
|
|
|
/* ---------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
/**
|
2017-04-11 09:18:08 +08:00
|
|
|
* @brief Defines the @c ZydisDecoderContext struct.
|
2017-04-11 08:19:53 +08:00
|
|
|
*/
|
|
|
|
typedef struct ZydisDecoderContext_
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* @brief The current disassembler-mode.
|
|
|
|
*/
|
|
|
|
ZydisOperatingMode operatingMode;
|
|
|
|
// TODO: Remove from this struct and pass as argument
|
|
|
|
/**
|
|
|
|
* @brief The current input buffer.
|
|
|
|
*/
|
|
|
|
struct
|
|
|
|
{
|
|
|
|
const uint8_t* buffer;
|
|
|
|
size_t bufferLen;
|
|
|
|
} input;
|
|
|
|
/**
|
|
|
|
* @brief Internal field. @c TRUE, if the @c imm8 value is already initialized.
|
|
|
|
*/
|
|
|
|
ZydisBool imm8initialized;
|
|
|
|
/**
|
|
|
|
* @brief Internal field. We have to store a copy of the imm8 value for instructions that
|
|
|
|
* encode different operands in the lo and hi part of the immediate.
|
|
|
|
*/
|
|
|
|
uint8_t imm8;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Internal field. The 0x66 prefix can be consumed, if it is used as mandatory-prefix.
|
|
|
|
* This field contains the prefix-byte, if the prefix is present and not already
|
|
|
|
* consumed.
|
|
|
|
*/
|
|
|
|
uint8_t hasUnusedPrefix66;
|
|
|
|
/**
|
|
|
|
* @brief Internal field. The mutally exclusive 0xF2 and 0xF3 prefixs can be consumed, if
|
|
|
|
* they are used as mandatory-prefix. This field contains the prefix-byte of the
|
|
|
|
* latest 0xF2 or 0xF3 prefix, if one of the prefixes is present and not already
|
|
|
|
* consumed.
|
|
|
|
*/
|
|
|
|
uint8_t hasUnusedPrefixF2F3;
|
|
|
|
/**
|
|
|
|
* @brief Internal field. Contains the latest (significant) segment prefix.
|
|
|
|
*/
|
|
|
|
uint8_t lastSegmentPrefix;
|
|
|
|
/**
|
|
|
|
* @brief How granular the instructions should be decoded.
|
|
|
|
*/
|
|
|
|
ZydisDecodeGranularity granularity;
|
2017-04-11 09:18:08 +08:00
|
|
|
const void* definition;
|
|
|
|
/**
|
|
|
|
* @brief Internal data.
|
|
|
|
*/
|
|
|
|
// TODO: Find a better name for this.
|
|
|
|
struct
|
|
|
|
{
|
|
|
|
uint8_t W;
|
|
|
|
uint8_t R;
|
|
|
|
uint8_t X;
|
|
|
|
uint8_t B;
|
|
|
|
uint8_t L;
|
|
|
|
uint8_t L2;
|
|
|
|
uint8_t R2;
|
|
|
|
uint8_t V2;
|
|
|
|
} internal;
|
2017-04-11 08:19:53 +08:00
|
|
|
} ZydisDecoderContext;
|
|
|
|
|
2016-05-26 03:25:48 +08:00
|
|
|
/* ---------------------------------------------------------------------------------------------- */
|
|
|
|
/* Input helper functions */
|
|
|
|
/* ---------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Reads one byte from the current read-position of the input data-source.
|
|
|
|
*
|
2017-04-11 09:18:08 +08:00
|
|
|
* @param ctx A pointer to the @c ZydisDecoderContext instance.
|
2016-05-26 03:25:48 +08:00
|
|
|
* @param info A pointer to the @c ZydisInstructionInfo struct.
|
|
|
|
* @param value A pointer to the memory that receives the byte from the input data-source.
|
|
|
|
*
|
2016-12-05 09:24:01 +08:00
|
|
|
* @return A zydis status code.
|
2016-05-26 03:25:48 +08:00
|
|
|
*
|
2017-04-11 09:18:08 +08:00
|
|
|
* If not empty, the internal buffer of the @c ZydisDecoderContext instance is used as temporary
|
2016-05-26 03:25:48 +08:00
|
|
|
* data-source, instead of reading the byte from the actual input data-source.
|
|
|
|
*
|
|
|
|
* This function may fail, if the @c ZYDIS_MAX_INSTRUCTION_LENGTH limit got exceeded, or no more
|
|
|
|
* data is available.
|
|
|
|
*/
|
2017-04-11 09:18:08 +08:00
|
|
|
static ZydisStatus ZydisInputPeek(ZydisDecoderContext* ctx, ZydisInstructionInfo* info,
|
2016-12-05 09:24:01 +08:00
|
|
|
uint8_t* value)
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_ASSERT(ctx);
|
2016-05-26 03:25:48 +08:00
|
|
|
ZYDIS_ASSERT(info);
|
|
|
|
ZYDIS_ASSERT(value);
|
|
|
|
|
|
|
|
if (info->length >= ZYDIS_MAX_INSTRUCTION_LENGTH)
|
|
|
|
{
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_INSTRUCTION_TOO_LONG;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
|
2017-04-11 09:18:08 +08:00
|
|
|
if (ctx->input.bufferLen > 0)
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
2017-04-11 09:18:08 +08:00
|
|
|
*value = ctx->input.buffer[0];
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
|
2017-01-11 18:20:24 +08:00
|
|
|
return ZYDIS_STATUS_NO_MORE_DATA;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Increases the read-position of the input data-source by one byte.
|
|
|
|
*
|
2017-04-11 09:18:08 +08:00
|
|
|
* @param ctx A pointer to the @c ZydisDecoderContext instance
|
2016-05-26 03:25:48 +08:00
|
|
|
* @param info A pointer to the @c ZydisInstructionInfo struct.
|
|
|
|
*
|
|
|
|
* This function is supposed to get called ONLY after a successfull call of @c ZydisInputPeek.
|
|
|
|
*
|
2017-04-11 09:18:08 +08:00
|
|
|
* If not empty, the read-position of the @c ZydisDecoderContext instances internal buffer is
|
2016-05-26 03:25:48 +08:00
|
|
|
* increased, instead of the actual input data-sources read-position.
|
|
|
|
*
|
|
|
|
* This function increases the @c length field of the @c ZydisInstructionInfo struct by one and
|
|
|
|
* adds the current byte to the @c data array.
|
|
|
|
*/
|
2017-04-11 09:18:08 +08:00
|
|
|
static void ZydisInputSkip(ZydisDecoderContext* ctx, ZydisInstructionInfo* info)
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_ASSERT(ctx);
|
2016-05-26 03:25:48 +08:00
|
|
|
ZYDIS_ASSERT(info);
|
|
|
|
ZYDIS_ASSERT(info->length < ZYDIS_MAX_INSTRUCTION_LENGTH);
|
|
|
|
|
2017-04-11 09:18:08 +08:00
|
|
|
info->data[info->length++] = ctx->input.buffer++[0];
|
|
|
|
--ctx->input.bufferLen;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Reads one byte from the current read-position of the input data-source and increases the
|
|
|
|
* read-position by one byte afterwards.
|
|
|
|
*
|
2017-04-11 09:18:08 +08:00
|
|
|
* @param ctx A pointer to the @c ZydisDecoderContext instance.
|
2016-05-26 03:25:48 +08:00
|
|
|
* @param info A pointer to the @c ZydisInstructionInfo struct.
|
|
|
|
* @param value A pointer to the memory that receives the byte from the input data-source.
|
|
|
|
*
|
2016-12-05 09:24:01 +08:00
|
|
|
* @return A zydis status code.
|
2016-05-26 03:25:48 +08:00
|
|
|
*
|
|
|
|
* This function acts like a subsequent call of @c ZydisInputPeek and @c ZydisInputSkip.
|
|
|
|
*/
|
2017-04-11 09:18:08 +08:00
|
|
|
static ZydisStatus ZydisInputNext(ZydisDecoderContext* ctx, ZydisInstructionInfo* info,
|
2016-12-05 09:24:01 +08:00
|
|
|
uint8_t* value)
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_ASSERT(ctx);
|
2017-01-11 18:20:24 +08:00
|
|
|
ZYDIS_ASSERT(info);
|
|
|
|
ZYDIS_ASSERT(value);
|
|
|
|
|
|
|
|
if (info->length >= ZYDIS_MAX_INSTRUCTION_LENGTH)
|
|
|
|
{
|
|
|
|
return ZYDIS_STATUS_INSTRUCTION_TOO_LONG;
|
|
|
|
}
|
|
|
|
|
2017-04-11 09:18:08 +08:00
|
|
|
if (ctx->input.bufferLen > 0)
|
2017-01-11 18:20:24 +08:00
|
|
|
{
|
2017-04-11 09:18:08 +08:00
|
|
|
*value = ctx->input.buffer++[0];
|
2017-01-11 18:20:24 +08:00
|
|
|
info->data[info->length++] = *value;
|
2017-04-11 09:18:08 +08:00
|
|
|
--ctx->input.bufferLen;
|
2017-01-11 18:20:24 +08:00
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ZYDIS_STATUS_NO_MORE_DATA;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------------------------------- */
|
|
|
|
/* Decoder functions */
|
|
|
|
/* ---------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
/**
|
2017-01-13 02:37:57 +08:00
|
|
|
* @brief Decodes the REX-prefix.
|
2016-05-26 03:25:48 +08:00
|
|
|
*
|
2017-04-11 09:18:08 +08:00
|
|
|
* @param ctx A pointer to the @c ZydisDecoderContext struct.
|
2016-05-26 03:25:48 +08:00
|
|
|
* @param info A pointer to the @c ZydisInstructionInfo struct.
|
2017-04-11 09:18:08 +08:00
|
|
|
* @param rexByte The REX byte.
|
2016-05-26 03:25:48 +08:00
|
|
|
*/
|
2017-04-11 09:18:08 +08:00
|
|
|
static void ZydisDecodeREX(ZydisDecoderContext* ctx, ZydisInstructionInfo* info, uint8_t rexByte)
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
|
|
|
ZYDIS_ASSERT(info);
|
|
|
|
ZYDIS_ASSERT((rexByte & 0xF0) == 0x40);
|
|
|
|
|
2016-12-05 09:24:01 +08:00
|
|
|
info->attributes |= ZYDIS_ATTRIB_HAS_REX;
|
|
|
|
info->details.rex.isDecoded = ZYDIS_TRUE;
|
2016-05-26 03:25:48 +08:00
|
|
|
info->details.rex.data[0] = rexByte;
|
2016-12-05 09:24:01 +08:00
|
|
|
info->details.rex.W = (rexByte >> 3) & 0x01;
|
|
|
|
info->details.rex.R = (rexByte >> 2) & 0x01;
|
|
|
|
info->details.rex.X = (rexByte >> 1) & 0x01;
|
|
|
|
info->details.rex.B = (rexByte >> 0) & 0x01;
|
2017-04-11 09:18:08 +08:00
|
|
|
|
2016-12-05 09:24:01 +08:00
|
|
|
// Update internal fields
|
2017-04-11 09:18:08 +08:00
|
|
|
ctx->internal.W = info->details.rex.W;
|
|
|
|
ctx->internal.R = info->details.rex.R;
|
|
|
|
ctx->internal.X = info->details.rex.X;
|
|
|
|
ctx->internal.B = info->details.rex.B;
|
2016-12-05 09:24:01 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2017-01-13 02:37:57 +08:00
|
|
|
* @brief Decodes the XOP-prefix.
|
2016-12-05 09:24:01 +08:00
|
|
|
*
|
2017-04-11 09:18:08 +08:00
|
|
|
* @param ctx A pointer to the @c ZydisDecoderContext struct.
|
|
|
|
* @param info A pointer to the @c ZydisInstructionInfo struct.
|
2017-01-13 02:37:57 +08:00
|
|
|
* @param xopByte1 The first XOP byte.
|
|
|
|
* @param xopByte2 The second XOP byte.
|
2016-12-05 09:24:01 +08:00
|
|
|
*
|
|
|
|
* @return A zydis status code.
|
|
|
|
*/
|
2017-04-11 09:18:08 +08:00
|
|
|
static ZydisStatus ZydisDecodeXOP(ZydisDecoderContext* ctx, ZydisInstructionInfo* info,
|
|
|
|
uint8_t xopByte1, uint8_t xopByte2)
|
2016-12-05 09:24:01 +08:00
|
|
|
{
|
|
|
|
ZYDIS_ASSERT(info);
|
|
|
|
ZYDIS_ASSERT(((xopByte1 >> 0) & 0x1F) >= 8);
|
|
|
|
|
|
|
|
info->attributes |= ZYDIS_ATTRIB_HAS_XOP;
|
|
|
|
info->details.xop.isDecoded = ZYDIS_TRUE;
|
|
|
|
info->details.xop.data[0] = 0x8F;
|
|
|
|
info->details.xop.data[1] = xopByte1;
|
|
|
|
info->details.xop.data[2] = xopByte2;
|
|
|
|
info->details.xop.R = (xopByte1 >> 7) & 0x01;
|
|
|
|
info->details.xop.X = (xopByte1 >> 6) & 0x01;
|
|
|
|
info->details.xop.B = (xopByte1 >> 5) & 0x01;
|
|
|
|
info->details.xop.m_mmmm = (xopByte1 >> 0) & 0x1F;
|
2017-04-11 09:18:08 +08:00
|
|
|
|
2016-12-05 09:24:01 +08:00
|
|
|
if ((info->details.xop.m_mmmm < 0x08) || (info->details.xop.m_mmmm > 0x0A))
|
|
|
|
{
|
|
|
|
// Invalid according to the AMD documentation
|
|
|
|
return ZYDIS_STATUS_INVALID_MAP;
|
|
|
|
}
|
2017-04-11 09:18:08 +08:00
|
|
|
|
2016-12-05 09:24:01 +08:00
|
|
|
info->details.xop.W = (xopByte2 >> 7) & 0x01;
|
|
|
|
info->details.xop.vvvv = (xopByte2 >> 3) & 0x0F;
|
|
|
|
info->details.xop.L = (xopByte2 >> 2) & 0x01;
|
|
|
|
info->details.xop.pp = (xopByte2 >> 0) & 0x03;
|
2017-04-11 09:18:08 +08:00
|
|
|
|
2016-05-26 03:25:48 +08:00
|
|
|
// Update internal fields
|
2017-04-11 09:18:08 +08:00
|
|
|
ctx->internal.W = info->details.xop.W;
|
|
|
|
ctx->internal.R = 0x01 & ~info->details.xop.R;
|
|
|
|
ctx->internal.X = 0x01 & ~info->details.xop.X;
|
|
|
|
ctx->internal.B = 0x01 & ~info->details.xop.B;
|
|
|
|
ctx->internal.L = info->details.xop.L;
|
|
|
|
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2017-01-13 02:37:57 +08:00
|
|
|
* @brief Decodes the VEX-prefix.
|
2016-05-26 03:25:48 +08:00
|
|
|
*
|
2017-04-11 09:18:08 +08:00
|
|
|
* @param ctx A pointer to the @c ZydisDecoderContext struct.
|
|
|
|
* @param info A pointer to the @c ZydisInstructionInfo struct.
|
2017-01-13 02:37:57 +08:00
|
|
|
* @param vexOpcode The VEX opcode.
|
|
|
|
* @param vexByte1 The first VEX byte.
|
|
|
|
* @param vexByte2 The second VEX byte.
|
2016-05-26 03:25:48 +08:00
|
|
|
*
|
2016-12-05 09:24:01 +08:00
|
|
|
* @return A zydis status code.
|
2016-05-26 03:25:48 +08:00
|
|
|
*/
|
2017-04-11 09:18:08 +08:00
|
|
|
static ZydisStatus ZydisDecodeVEX(ZydisDecoderContext* ctx, ZydisInstructionInfo* info,
|
|
|
|
uint8_t vexOpcode, uint8_t vexByte1, uint8_t vexByte2)
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
|
|
|
ZYDIS_ASSERT(info);
|
|
|
|
|
2016-12-05 09:24:01 +08:00
|
|
|
info->attributes |= ZYDIS_ATTRIB_HAS_VEX;
|
|
|
|
info->details.vex.isDecoded = ZYDIS_TRUE;
|
2016-05-26 03:25:48 +08:00
|
|
|
info->details.vex.data[0] = vexOpcode;
|
|
|
|
switch (vexOpcode)
|
|
|
|
{
|
|
|
|
case 0xC4:
|
|
|
|
info->details.vex.data[1] = vexByte1;
|
|
|
|
info->details.vex.data[2] = vexByte2;
|
2016-12-05 09:24:01 +08:00
|
|
|
info->details.vex.R = (vexByte1 >> 7) & 0x01;
|
|
|
|
info->details.vex.X = (vexByte1 >> 6) & 0x01;
|
|
|
|
info->details.vex.B = (vexByte1 >> 5) & 0x01;
|
2016-05-26 03:25:48 +08:00
|
|
|
info->details.vex.m_mmmm = (vexByte1 >> 0) & 0x1F;
|
2016-12-05 09:24:01 +08:00
|
|
|
info->details.vex.W = (vexByte2 >> 7) & 0x01;
|
2016-05-26 03:25:48 +08:00
|
|
|
info->details.vex.vvvv = (vexByte2 >> 3) & 0x0F;
|
2016-12-05 09:24:01 +08:00
|
|
|
info->details.vex.L = (vexByte2 >> 2) & 0x01;
|
2016-05-26 03:25:48 +08:00
|
|
|
info->details.vex.pp = (vexByte2 >> 0) & 0x03;
|
|
|
|
break;
|
|
|
|
case 0xC5:
|
|
|
|
info->details.vex.data[1] = vexByte1;
|
|
|
|
info->details.vex.data[2] = 0;
|
2016-12-05 09:24:01 +08:00
|
|
|
info->details.vex.R = (vexByte1 >> 7) & 0x01;
|
|
|
|
info->details.vex.X = 1;
|
|
|
|
info->details.vex.B = 1;
|
2016-05-26 03:25:48 +08:00
|
|
|
info->details.vex.m_mmmm = 1;
|
2016-12-05 09:24:01 +08:00
|
|
|
info->details.vex.W = 0;
|
2016-05-26 03:25:48 +08:00
|
|
|
info->details.vex.vvvv = (vexByte1 >> 3) & 0x0F;
|
2016-12-05 09:24:01 +08:00
|
|
|
info->details.vex.L = (vexByte1 >> 2) & 0x01;
|
2016-05-26 03:25:48 +08:00
|
|
|
info->details.vex.pp = (vexByte1 >> 0) & 0x03;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ZYDIS_UNREACHABLE;
|
|
|
|
}
|
|
|
|
if ((info->details.vex.m_mmmm == 0x00) || (info->details.vex.m_mmmm > 0x03))
|
|
|
|
{
|
|
|
|
// Invalid according to the intel documentation
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_INVALID_MAP;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
// Update internal fields
|
2017-04-11 09:18:08 +08:00
|
|
|
ctx->internal.W = info->details.vex.W;
|
|
|
|
ctx->internal.R = 0x01 & ~info->details.vex.R;
|
|
|
|
ctx->internal.X = 0x01 & ~info->details.vex.X;
|
|
|
|
ctx->internal.B = 0x01 & ~info->details.vex.B;
|
|
|
|
ctx->internal.L = info->details.vex.L;
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2017-01-13 02:37:57 +08:00
|
|
|
* @brief Decodes the EVEX-prefix.
|
2016-05-26 03:25:48 +08:00
|
|
|
*
|
2017-04-11 09:18:08 +08:00
|
|
|
* @param ctx A pointer to the @c ZydisDecoderContext struct.
|
|
|
|
* @param info A pointer to the @c ZydisInstructionInfo struct.
|
2017-01-13 02:37:57 +08:00
|
|
|
* @param evexByte1 The first EVEX byte.
|
|
|
|
* @param evexByte2 The second EVEX byte.
|
|
|
|
* @param evexByte3 The third EVEX byte.
|
2016-05-26 03:25:48 +08:00
|
|
|
*
|
2016-12-05 09:24:01 +08:00
|
|
|
* @return A zydis status code.
|
2016-05-26 03:25:48 +08:00
|
|
|
*/
|
2017-04-11 09:18:08 +08:00
|
|
|
static ZydisStatus ZydisDecodeEVEX(ZydisDecoderContext* ctx, ZydisInstructionInfo* info,
|
|
|
|
uint8_t evexByte1, uint8_t evexByte2, uint8_t evexByte3)
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
|
|
|
ZYDIS_ASSERT(info);
|
|
|
|
|
2016-12-05 09:24:01 +08:00
|
|
|
info->attributes |= ZYDIS_ATTRIB_HAS_EVEX;
|
|
|
|
info->details.evex.isDecoded = ZYDIS_TRUE;
|
2016-05-26 03:25:48 +08:00
|
|
|
info->details.evex.data[0] = 0x62;
|
|
|
|
info->details.evex.data[1] = evexByte1;
|
|
|
|
info->details.evex.data[2] = evexByte2;
|
|
|
|
info->details.evex.data[3] = evexByte3;
|
2016-12-05 09:24:01 +08:00
|
|
|
info->details.evex.R = (evexByte1 >> 7) & 0x01;
|
|
|
|
info->details.evex.X = (evexByte1 >> 6) & 0x01;
|
|
|
|
info->details.evex.B = (evexByte1 >> 5) & 0x01;
|
|
|
|
info->details.evex.R2 = (evexByte1 >> 4) & 0x01;
|
2016-05-26 03:25:48 +08:00
|
|
|
if (((evexByte1 >> 2) & 0x03) != 0x00)
|
|
|
|
{
|
|
|
|
// Invalid according to the intel documentation
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_MALFORMED_EVEX;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
info->details.evex.mm = (evexByte1 >> 0) & 0x03;
|
|
|
|
if (info->details.evex.mm == 0x00)
|
|
|
|
{
|
|
|
|
// Invalid according to the intel documentation
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_INVALID_MAP;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
2016-12-05 09:24:01 +08:00
|
|
|
info->details.evex.W = (evexByte2 >> 7) & 0x01;
|
2016-05-26 03:25:48 +08:00
|
|
|
info->details.evex.vvvv = (evexByte2 >> 3) & 0x0F;
|
|
|
|
if (((evexByte2 >> 2) & 0x01) != 0x01)
|
|
|
|
{
|
|
|
|
// Invalid according to the intel documentation
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_MALFORMED_EVEX;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
info->details.evex.pp = (evexByte2 >> 0) & 0x03;
|
|
|
|
info->details.evex.z = (evexByte3 >> 7) & 0x01;
|
2016-12-05 09:24:01 +08:00
|
|
|
info->details.evex.L2 = (evexByte3 >> 6) & 0x01;
|
|
|
|
info->details.evex.L = (evexByte3 >> 5) & 0x01;
|
|
|
|
info->details.evex.b = (evexByte3 >> 4) & 0x01;
|
|
|
|
info->details.evex.V2 = (evexByte3 >> 3) & 0x01;
|
2016-05-26 03:25:48 +08:00
|
|
|
info->details.evex.aaa = (evexByte3 >> 0) & 0x07;
|
|
|
|
// Update internal fields
|
2017-04-11 09:18:08 +08:00
|
|
|
ctx->internal.W = info->details.evex.W;
|
|
|
|
ctx->internal.R = 0x01 & ~info->details.evex.R;
|
|
|
|
ctx->internal.X = 0x01 & ~info->details.evex.X;
|
|
|
|
ctx->internal.B = 0x01 & ~info->details.evex.B;
|
|
|
|
ctx->internal.L = info->details.evex.L;
|
|
|
|
ctx->internal.R2 = 0x01 & ~info->details.evex.R2;
|
|
|
|
ctx->internal.V2 = 0x01 & ~info->details.evex.V2;
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2017-01-13 02:37:57 +08:00
|
|
|
* @brief Decodes the ModRM-byte.
|
2016-05-26 03:25:48 +08:00
|
|
|
*
|
2017-01-13 02:37:57 +08:00
|
|
|
* @param modrmByte The ModRM byte.
|
2016-05-26 03:25:48 +08:00
|
|
|
* @param info A pointer to the @c ZydisInstructionInfo struct.
|
|
|
|
*/
|
2016-12-05 09:24:01 +08:00
|
|
|
static void ZydisDecodeModRM(uint8_t modrmByte, ZydisInstructionInfo* info)
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
|
|
|
ZYDIS_ASSERT(info);
|
|
|
|
|
2016-12-05 09:24:01 +08:00
|
|
|
info->attributes |= ZYDIS_ATTRIB_HAS_MODRM;
|
|
|
|
info->details.modrm.isDecoded = ZYDIS_TRUE;
|
2016-05-26 03:25:48 +08:00
|
|
|
info->details.modrm.data[0] = modrmByte;
|
|
|
|
info->details.modrm.mod = (modrmByte >> 6) & 0x03;
|
|
|
|
info->details.modrm.reg = (modrmByte >> 3) & 0x07;
|
|
|
|
info->details.modrm.rm = (modrmByte >> 0) & 0x07;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2017-01-13 02:37:57 +08:00
|
|
|
* @brief Decodes the SIB-byte.
|
2016-05-26 03:25:48 +08:00
|
|
|
*
|
2017-01-13 02:37:57 +08:00
|
|
|
* @param sibByte The SIB byte.
|
2016-05-26 03:25:48 +08:00
|
|
|
* @param info A pointer to the @c ZydisInstructionInfo struct
|
|
|
|
*/
|
2016-12-05 09:24:01 +08:00
|
|
|
static void ZydisDecodeSIB(uint8_t sibByte, ZydisInstructionInfo* info)
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
|
|
|
ZYDIS_ASSERT(info);
|
|
|
|
ZYDIS_ASSERT(info->details.modrm.isDecoded);
|
|
|
|
ZYDIS_ASSERT((info->details.modrm.rm & 0x7) == 4);
|
|
|
|
|
2016-12-05 09:24:01 +08:00
|
|
|
info->attributes |= ZYDIS_ATTRIB_HAS_SIB;
|
|
|
|
info->details.sib.isDecoded = ZYDIS_TRUE;
|
2016-05-26 03:25:48 +08:00
|
|
|
info->details.sib.data[0] = sibByte;
|
|
|
|
info->details.sib.scale = (sibByte >> 6) & 0x03;
|
|
|
|
info->details.sib.index = (sibByte >> 3) & 0x07;
|
|
|
|
info->details.sib.base = (sibByte >> 0) & 0x07;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Collects optional instruction prefixes.
|
|
|
|
*
|
2017-04-11 09:18:08 +08:00
|
|
|
* @param ctx A pointer to the @c ZydisDecoderContext struct.
|
|
|
|
* @param info A pointer to the @c ZydisInstructionInfo struct.
|
2016-05-26 03:25:48 +08:00
|
|
|
*
|
2016-12-05 09:24:01 +08:00
|
|
|
* @return A zydis status code.
|
2016-05-26 03:25:48 +08:00
|
|
|
*
|
|
|
|
* This function sets the corresponding flag for each prefix and automatically decodes the last
|
2017-01-13 02:37:57 +08:00
|
|
|
* REX-prefix (if exists).
|
2016-05-26 03:25:48 +08:00
|
|
|
*/
|
2017-04-11 09:18:08 +08:00
|
|
|
static ZydisStatus ZydisCollectOptionalPrefixes(ZydisDecoderContext* ctx,
|
2016-05-26 03:25:48 +08:00
|
|
|
ZydisInstructionInfo* info)
|
|
|
|
{
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_ASSERT(ctx);
|
2016-05-26 03:25:48 +08:00
|
|
|
ZYDIS_ASSERT(info);
|
|
|
|
|
2016-12-05 09:24:01 +08:00
|
|
|
ZydisBool done = ZYDIS_FALSE;
|
2016-05-26 03:25:48 +08:00
|
|
|
do
|
|
|
|
{
|
|
|
|
uint8_t prefixByte;
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_CHECK(ZydisInputPeek(ctx, info, &prefixByte));
|
2016-05-26 03:25:48 +08:00
|
|
|
switch (prefixByte)
|
|
|
|
{
|
|
|
|
case 0xF0:
|
2016-12-05 09:24:01 +08:00
|
|
|
++info->details.prefixes.hasF0;
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case 0xF2:
|
2017-04-11 09:18:08 +08:00
|
|
|
ctx->hasUnusedPrefixF2F3 = 0xF2;
|
2016-12-05 09:24:01 +08:00
|
|
|
++info->details.prefixes.hasF2;
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case 0xF3:
|
2017-04-11 09:18:08 +08:00
|
|
|
ctx->hasUnusedPrefixF2F3 = 0xF3;
|
2016-12-05 09:24:01 +08:00
|
|
|
++info->details.prefixes.hasF3;
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case 0x2E:
|
2016-12-05 09:24:01 +08:00
|
|
|
++info->details.prefixes.has2E;
|
2017-04-11 09:18:08 +08:00
|
|
|
ctx->lastSegmentPrefix = 0x2E;
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case 0x36:
|
2016-12-05 09:24:01 +08:00
|
|
|
++info->details.prefixes.has36;
|
2017-04-11 09:18:08 +08:00
|
|
|
ctx->lastSegmentPrefix = 0x36;
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case 0x3E:
|
2016-12-05 09:24:01 +08:00
|
|
|
++info->details.prefixes.has3E;
|
2017-04-11 09:18:08 +08:00
|
|
|
ctx->lastSegmentPrefix = 0x3E;
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case 0x26:
|
2016-12-05 09:24:01 +08:00
|
|
|
++info->details.prefixes.has26;
|
2017-04-11 09:18:08 +08:00
|
|
|
ctx->lastSegmentPrefix = 0x26;
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case 0x64:
|
2016-12-05 09:24:01 +08:00
|
|
|
++info->details.prefixes.has64;
|
2017-04-11 09:18:08 +08:00
|
|
|
ctx->lastSegmentPrefix = 0x64;
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case 0x65:
|
2016-12-05 09:24:01 +08:00
|
|
|
++info->details.prefixes.has65;
|
2017-04-11 09:18:08 +08:00
|
|
|
ctx->lastSegmentPrefix = 0x65;
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case 0x66:
|
2017-04-11 09:18:08 +08:00
|
|
|
ctx->hasUnusedPrefix66 = 0x66;
|
2016-12-05 09:24:01 +08:00
|
|
|
++info->details.prefixes.has66;
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case 0x67:
|
2016-12-05 09:24:01 +08:00
|
|
|
++info->details.prefixes.has67;
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
default:
|
2017-04-13 03:12:18 +08:00
|
|
|
if ((ctx->operatingMode == ZYDIS_OPERATING_MODE_64BIT) &&
|
2016-05-26 03:25:48 +08:00
|
|
|
(prefixByte & 0xF0) == 0x40)
|
|
|
|
{
|
|
|
|
info->details.rex.data[0] = prefixByte;
|
|
|
|
} else
|
|
|
|
{
|
2016-12-05 09:24:01 +08:00
|
|
|
done = ZYDIS_TRUE;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!done)
|
|
|
|
{
|
2017-04-11 09:18:08 +08:00
|
|
|
ZydisInputSkip(ctx, info);
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
} while (!done);
|
|
|
|
|
2016-12-05 09:24:01 +08:00
|
|
|
if (info->details.rex.data[0])
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
2017-04-11 09:18:08 +08:00
|
|
|
ZydisDecodeREX(ctx, info, info->details.rex.data[0]);
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Decodes an immediate operand.
|
|
|
|
*
|
2017-04-11 09:18:08 +08:00
|
|
|
* @param ctx A pointer to the @c ZydisDecoderContext instance.
|
2016-05-26 03:25:48 +08:00
|
|
|
* @param info A pointer to the @c ZydisInstructionInfo struct.
|
|
|
|
* @param operand A pointer to the @c ZydisOperandInfo struct.
|
|
|
|
* @param physicalSize The physical size of the immediate operand.
|
|
|
|
* @param isSigned Set @c true, if the immediate value is signed or @c false, if not.
|
|
|
|
*
|
2016-12-05 09:24:01 +08:00
|
|
|
* @return A zydis status code.
|
2016-05-26 03:25:48 +08:00
|
|
|
*/
|
2017-04-11 09:18:08 +08:00
|
|
|
static ZydisStatus ZydisDecodeOperandImmediate(ZydisDecoderContext* ctx,
|
2016-12-05 09:24:01 +08:00
|
|
|
ZydisInstructionInfo* info, ZydisOperandInfo* operand, uint8_t physicalSize,
|
|
|
|
ZydisBool isSigned)
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_ASSERT(ctx);
|
2016-05-26 03:25:48 +08:00
|
|
|
ZYDIS_ASSERT(info);
|
|
|
|
ZYDIS_ASSERT(operand);
|
|
|
|
|
|
|
|
operand->type = ZYDIS_OPERAND_TYPE_IMMEDIATE;
|
|
|
|
operand->imm.isSigned = isSigned;
|
2016-11-12 05:03:26 +08:00
|
|
|
operand->imm.dataSize = physicalSize;
|
2016-05-26 03:25:48 +08:00
|
|
|
operand->imm.dataOffset = info->length;
|
|
|
|
switch (physicalSize)
|
|
|
|
{
|
|
|
|
case 8:
|
|
|
|
{
|
2016-09-13 11:26:55 +08:00
|
|
|
// We have to store a copy of the imm8 value for instructions that encode different operands
|
|
|
|
// in the lo and hi part of the immediate.
|
2017-04-11 09:18:08 +08:00
|
|
|
if (ctx->imm8initialized)
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
2017-04-11 09:18:08 +08:00
|
|
|
operand->imm.value.ubyte = ctx->imm8;
|
2016-05-26 03:25:48 +08:00
|
|
|
} else
|
|
|
|
{
|
2016-09-13 11:26:55 +08:00
|
|
|
uint8_t immediate;
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_CHECK(ZydisInputNext(ctx, info, &immediate));
|
2016-09-13 11:26:55 +08:00
|
|
|
if (isSigned)
|
|
|
|
{
|
|
|
|
operand->imm.value.sqword = (int8_t)immediate;
|
|
|
|
} else
|
|
|
|
{
|
|
|
|
operand->imm.value.uqword = immediate;
|
|
|
|
}
|
2017-04-11 09:18:08 +08:00
|
|
|
ctx->imm8initialized = ZYDIS_TRUE;
|
|
|
|
ctx->imm8 = operand->imm.value.ubyte;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 16:
|
|
|
|
{
|
|
|
|
uint16_t data[2] = { 0, 0 };
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_CHECK(ZydisInputNext(ctx, info, (uint8_t*)&data[1]));
|
|
|
|
ZYDIS_CHECK(ZydisInputNext(ctx, info, (uint8_t*)&data[0]));
|
2016-05-26 03:25:48 +08:00
|
|
|
uint16_t immediate;
|
|
|
|
immediate = (data[0] << 8) | data[1];
|
|
|
|
if (isSigned)
|
|
|
|
{
|
|
|
|
operand->imm.value.sqword = (int16_t)immediate;
|
|
|
|
} else
|
|
|
|
{
|
|
|
|
operand->imm.value.uqword = immediate;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 32:
|
|
|
|
{
|
|
|
|
uint32_t data[4] = { 0, 0, 0, 0 };
|
2017-04-10 02:55:49 +08:00
|
|
|
for (int i = ZYDIS_ARRAY_SIZE(data); i > 0; --i)
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_CHECK(ZydisInputNext(ctx, info, (uint8_t*)&data[i - 1]));
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
uint32_t immediate;
|
|
|
|
immediate = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
|
|
|
|
if (isSigned)
|
|
|
|
{
|
|
|
|
operand->imm.value.sqword = (int32_t)immediate;
|
|
|
|
} else
|
|
|
|
{
|
|
|
|
operand->imm.value.uqword = immediate;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 64:
|
|
|
|
{
|
|
|
|
uint64_t data[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
|
|
for (int i = sizeof(data) / sizeof(data[0]); i > 0; --i)
|
|
|
|
{
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_CHECK(ZydisInputNext(ctx, info, (uint8_t*)&data[i - 1]));
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
uint64_t immediate;
|
|
|
|
immediate = (data[0] << 56) | (data[1] << 48) | (data[2] << 40) | (data[3] << 32) |
|
|
|
|
(data[4] << 24) | (data[5] << 16) | (data[6] << 8) | data[7];
|
|
|
|
if (isSigned)
|
|
|
|
{
|
|
|
|
operand->imm.value.sqword = (int64_t)immediate;
|
|
|
|
} else
|
|
|
|
{
|
|
|
|
operand->imm.value.uqword = immediate;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
ZYDIS_UNREACHABLE;
|
|
|
|
}
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Decodes an register-operand.
|
|
|
|
*
|
|
|
|
* @param info A pointer to the @c ZydisInstructionInfo struct.
|
|
|
|
* @param operand A pointer to the @c ZydisOperandInfo struct.
|
|
|
|
* @param registerClass The register class.
|
|
|
|
* @param registerId The register id.
|
|
|
|
*
|
2016-12-05 09:24:01 +08:00
|
|
|
* @return A zydis status code.
|
2016-05-26 03:25:48 +08:00
|
|
|
*/
|
2016-12-05 09:24:01 +08:00
|
|
|
static ZydisStatus ZydisDecodeOperandRegister(ZydisInstructionInfo* info,
|
2016-05-26 03:25:48 +08:00
|
|
|
ZydisOperandInfo* operand, ZydisRegisterClass registerClass, uint8_t registerId)
|
|
|
|
{
|
|
|
|
ZYDIS_ASSERT(info);
|
|
|
|
ZYDIS_ASSERT(operand);
|
|
|
|
|
|
|
|
operand->type = ZYDIS_OPERAND_TYPE_REGISTER;
|
2016-12-05 09:24:01 +08:00
|
|
|
if (registerClass == ZYDIS_REGCLASS_GPR8)
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
2016-12-05 09:24:01 +08:00
|
|
|
if ((info->attributes & ZYDIS_ATTRIB_HAS_REX) && (registerId >= 4))
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
|
|
|
operand->reg = ZYDIS_REGISTER_SPL + (registerId - 4);
|
|
|
|
} else
|
|
|
|
{
|
|
|
|
operand->reg = ZYDIS_REGISTER_AL + registerId;
|
|
|
|
}
|
|
|
|
if (operand->reg > ZYDIS_REGISTER_R15B)
|
|
|
|
{
|
|
|
|
operand->reg = ZYDIS_REGISTER_NONE;
|
|
|
|
}
|
2016-12-05 09:24:01 +08:00
|
|
|
// TODO: Return critical error, if an invalid register was found
|
2016-05-26 03:25:48 +08:00
|
|
|
} else
|
|
|
|
{
|
2016-12-05 09:24:01 +08:00
|
|
|
operand->reg = ZydisRegisterEncode(registerClass, registerId);
|
|
|
|
if (!operand->reg)
|
|
|
|
{
|
2017-01-20 07:01:56 +08:00
|
|
|
return ZYDIS_STATUS_BAD_REGISTER;
|
2016-12-05 09:24:01 +08:00
|
|
|
}
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2017-01-13 02:37:57 +08:00
|
|
|
* @brief Decodes a memory or register operand encoded in the ModRM.rm field.
|
2016-05-26 03:25:48 +08:00
|
|
|
*
|
2017-04-11 09:18:08 +08:00
|
|
|
* @param ctx A pointer to the @c ZydisDecoderContext instance.
|
2016-05-26 03:25:48 +08:00
|
|
|
* @param info A pointer to the @c ZydisInstructionInfo struct.
|
|
|
|
* @param operand A pointer to the @c ZydisOperandInfo struct.
|
|
|
|
* @param registerClass The register class.
|
|
|
|
*
|
2016-12-05 09:24:01 +08:00
|
|
|
* @return A zydis status code.
|
2016-05-26 03:25:48 +08:00
|
|
|
*/
|
2017-04-11 09:18:08 +08:00
|
|
|
static ZydisStatus ZydisDecodeOperandModrmRm(ZydisDecoderContext* ctx,
|
2016-05-26 03:25:48 +08:00
|
|
|
ZydisInstructionInfo* info, ZydisOperandInfo* operand, ZydisRegisterClass registerClass)
|
|
|
|
{
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_ASSERT(ctx);
|
2016-05-26 03:25:48 +08:00
|
|
|
ZYDIS_ASSERT(info);
|
|
|
|
ZYDIS_ASSERT(operand);
|
|
|
|
ZYDIS_ASSERT(info->details.modrm.isDecoded);
|
|
|
|
|
2017-04-11 09:18:08 +08:00
|
|
|
uint8_t modrm_rm = (ctx->internal.B << 3) | info->details.modrm.rm;
|
2016-05-26 03:25:48 +08:00
|
|
|
if (info->details.modrm.mod == 3)
|
|
|
|
{
|
2016-12-06 04:06:29 +08:00
|
|
|
return ZydisDecodeOperandRegister(info, operand, registerClass,
|
2017-04-11 09:18:08 +08:00
|
|
|
(ctx->internal.X << 4) | modrm_rm);
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
operand->type = ZYDIS_OPERAND_TYPE_MEMORY;
|
|
|
|
uint8_t displacementSize = 0;
|
2016-12-05 09:24:01 +08:00
|
|
|
// TODO: Some instructions (like the MPX ones) do not accept the address-size prefix
|
|
|
|
info->attributes |= ZYDIS_ATTRIB_ACCEPTS_ADDRESSSIZE;
|
|
|
|
if (info->details.prefixes.has67)
|
|
|
|
{
|
|
|
|
info->attributes |= ZYDIS_ATTRIB_HAS_ADDRESSSIZE;
|
|
|
|
}
|
2017-04-11 09:18:08 +08:00
|
|
|
switch (ctx->operatingMode)
|
2016-11-14 09:10:59 +08:00
|
|
|
{
|
2017-04-13 03:12:18 +08:00
|
|
|
case ZYDIS_OPERATING_MODE_16BIT: // TODO: Set ZYDIS_ATTRIB_ACCEPTS_ADDRESSSIZE and ZYDIS_ATTRIB_HAS_ADDRESSSIZE after getting the instruction definition
|
2016-12-05 09:24:01 +08:00
|
|
|
operand->mem.addressSize = (info->attributes & ZYDIS_ATTRIB_HAS_ADDRESSSIZE) ? 32 : 16;
|
2016-11-14 09:10:59 +08:00
|
|
|
break;
|
2017-04-13 03:12:18 +08:00
|
|
|
case ZYDIS_OPERATING_MODE_32BIT:
|
2016-12-05 09:24:01 +08:00
|
|
|
operand->mem.addressSize = (info->attributes & ZYDIS_ATTRIB_HAS_ADDRESSSIZE) ? 16 : 32;
|
2016-11-14 09:10:59 +08:00
|
|
|
break;
|
2017-04-13 03:12:18 +08:00
|
|
|
case ZYDIS_OPERATING_MODE_64BIT:
|
2016-12-05 09:24:01 +08:00
|
|
|
operand->mem.addressSize = (info->attributes & ZYDIS_ATTRIB_HAS_ADDRESSSIZE) ? 32 : 64;
|
2016-11-14 09:10:59 +08:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ZYDIS_UNREACHABLE;
|
|
|
|
}
|
|
|
|
switch (operand->mem.addressSize)
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
|
|
|
case 16:
|
|
|
|
{
|
|
|
|
static const ZydisRegister bases[] =
|
|
|
|
{
|
|
|
|
ZYDIS_REGISTER_BX, ZYDIS_REGISTER_BX, ZYDIS_REGISTER_BP, ZYDIS_REGISTER_BP,
|
|
|
|
ZYDIS_REGISTER_SI, ZYDIS_REGISTER_DI, ZYDIS_REGISTER_BP, ZYDIS_REGISTER_BX
|
|
|
|
};
|
|
|
|
static const ZydisRegister indices[] =
|
|
|
|
{
|
|
|
|
ZYDIS_REGISTER_SI, ZYDIS_REGISTER_DI, ZYDIS_REGISTER_SI, ZYDIS_REGISTER_DI,
|
|
|
|
ZYDIS_REGISTER_NONE, ZYDIS_REGISTER_NONE, ZYDIS_REGISTER_NONE, ZYDIS_REGISTER_NONE
|
|
|
|
};
|
|
|
|
operand->mem.base = bases[modrm_rm & 0x07];
|
|
|
|
operand->mem.index = indices[modrm_rm & 0x07];
|
|
|
|
operand->mem.scale = 0;
|
|
|
|
if ((info->details.modrm.mod == 0) && (modrm_rm == 6))
|
|
|
|
{
|
|
|
|
displacementSize = 16;
|
|
|
|
operand->mem.base = ZYDIS_REGISTER_NONE;
|
|
|
|
} else if (info->details.modrm.mod == 1)
|
|
|
|
{
|
|
|
|
displacementSize = 8;
|
|
|
|
} else if (info->details.modrm.mod == 2)
|
|
|
|
{
|
|
|
|
displacementSize = 16;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 32:
|
|
|
|
{
|
|
|
|
operand->mem.base = ZYDIS_REGISTER_EAX + modrm_rm;
|
|
|
|
switch (info->details.modrm.mod)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
if (modrm_rm == 5)
|
|
|
|
{
|
2017-04-13 03:12:18 +08:00
|
|
|
if (ctx->operatingMode == ZYDIS_OPERATING_MODE_64BIT)
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
2016-12-05 09:24:01 +08:00
|
|
|
info->attributes |= ZYDIS_ATTRIB_IS_RELATIVE;
|
2016-05-26 03:25:48 +08:00
|
|
|
operand->mem.base = ZYDIS_REGISTER_EIP;
|
|
|
|
} else
|
|
|
|
{
|
|
|
|
operand->mem.base = ZYDIS_REGISTER_NONE;
|
|
|
|
}
|
|
|
|
displacementSize = 32;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
displacementSize = 8;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
displacementSize = 32;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ZYDIS_UNREACHABLE;
|
|
|
|
}
|
|
|
|
if ((modrm_rm & 0x07) == 4)
|
|
|
|
{
|
|
|
|
if (!info->details.sib.isDecoded)
|
|
|
|
{
|
|
|
|
uint8_t sibByte;
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_CHECK(ZydisInputNext(ctx, info, &sibByte));
|
2016-12-05 09:24:01 +08:00
|
|
|
ZydisDecodeSIB(sibByte, info);
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
2017-04-11 09:18:08 +08:00
|
|
|
uint8_t sib_index = (ctx->internal.X << 3) | info->details.sib.index;
|
|
|
|
uint8_t sib_base = (ctx->internal.B << 3) | info->details.sib.base;
|
2016-05-26 03:25:48 +08:00
|
|
|
operand->mem.base = ZYDIS_REGISTER_EAX + sib_base;
|
|
|
|
operand->mem.index = ZYDIS_REGISTER_EAX + sib_index;
|
|
|
|
operand->mem.scale = (1 << info->details.sib.scale) & ~1;
|
|
|
|
if (operand->mem.index == ZYDIS_REGISTER_ESP)
|
|
|
|
{
|
|
|
|
operand->mem.index = ZYDIS_REGISTER_NONE;
|
|
|
|
operand->mem.scale = 0;
|
|
|
|
}
|
|
|
|
if (operand->mem.base == ZYDIS_REGISTER_EBP)
|
|
|
|
{
|
|
|
|
if (info->details.modrm.mod == 0)
|
|
|
|
{
|
|
|
|
operand->mem.base = ZYDIS_REGISTER_NONE;
|
|
|
|
}
|
|
|
|
displacementSize = (info->details.modrm.mod == 1) ? 8 : 32;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
{
|
|
|
|
operand->mem.index = ZYDIS_REGISTER_NONE;
|
|
|
|
operand->mem.scale = 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 64:
|
|
|
|
{
|
|
|
|
operand->mem.base = ZYDIS_REGISTER_RAX + modrm_rm;
|
|
|
|
switch (info->details.modrm.mod)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
if (modrm_rm == 5)
|
|
|
|
{
|
2016-12-05 09:24:01 +08:00
|
|
|
info->attributes |= ZYDIS_ATTRIB_IS_RELATIVE;
|
2016-05-26 03:25:48 +08:00
|
|
|
operand->mem.base = ZYDIS_REGISTER_RIP;
|
|
|
|
displacementSize = 32;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
displacementSize = 8;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
displacementSize = 32;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ZYDIS_UNREACHABLE;
|
|
|
|
}
|
|
|
|
if ((modrm_rm & 0x07) == 4)
|
|
|
|
{
|
|
|
|
if (!info->details.sib.isDecoded)
|
|
|
|
{
|
|
|
|
uint8_t sibByte;
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_CHECK(ZydisInputNext(ctx, info, &sibByte));
|
2016-12-05 09:24:01 +08:00
|
|
|
ZydisDecodeSIB(sibByte, info);
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
2017-04-11 09:18:08 +08:00
|
|
|
uint8_t sib_index = (ctx->internal.X << 3) | info->details.sib.index;
|
|
|
|
uint8_t sib_base = (ctx->internal.B << 3) | info->details.sib.base;
|
2016-05-26 03:25:48 +08:00
|
|
|
operand->mem.base = ZYDIS_REGISTER_RAX + sib_base;
|
|
|
|
operand->mem.index = ZYDIS_REGISTER_RAX + sib_index;
|
|
|
|
operand->mem.scale = (1 << info->details.sib.scale) & ~1;
|
|
|
|
if (operand->mem.index == ZYDIS_REGISTER_RSP)
|
|
|
|
{
|
|
|
|
operand->mem.index = ZYDIS_REGISTER_NONE;
|
|
|
|
operand->mem.scale = 0;
|
|
|
|
}
|
|
|
|
if ((operand->mem.base == ZYDIS_REGISTER_RBP) ||
|
|
|
|
(operand->mem.base == ZYDIS_REGISTER_R13))
|
|
|
|
{
|
|
|
|
if (info->details.modrm.mod == 0)
|
|
|
|
{
|
|
|
|
operand->mem.base = ZYDIS_REGISTER_NONE;
|
|
|
|
}
|
|
|
|
displacementSize = (info->details.modrm.mod == 1) ? 8 : 32;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
{
|
|
|
|
operand->mem.index = ZYDIS_REGISTER_NONE;
|
|
|
|
operand->mem.scale = 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
ZYDIS_UNREACHABLE;
|
|
|
|
}
|
|
|
|
if (displacementSize)
|
|
|
|
{
|
2016-12-05 09:24:01 +08:00
|
|
|
ZYDIS_CHECK(
|
2017-04-11 09:18:08 +08:00
|
|
|
ZydisDecodeOperandImmediate(ctx, info, operand, displacementSize, ZYDIS_TRUE));
|
|
|
|
ctx->imm8initialized = ZYDIS_FALSE;
|
2016-05-26 03:25:48 +08:00
|
|
|
operand->type = ZYDIS_OPERAND_TYPE_MEMORY;
|
2016-11-12 05:03:26 +08:00
|
|
|
operand->mem.disp.dataSize = displacementSize;
|
2016-05-26 03:25:48 +08:00
|
|
|
operand->mem.disp.value.sqword = operand->imm.value.sqword;
|
|
|
|
operand->mem.disp.dataOffset = operand->imm.dataOffset;
|
2016-12-05 09:24:01 +08:00
|
|
|
operand->imm.isSigned = ZYDIS_FALSE;
|
2016-11-12 05:03:26 +08:00
|
|
|
operand->imm.dataSize = 0;
|
2016-05-26 03:25:48 +08:00
|
|
|
operand->imm.value.sqword = 0;
|
|
|
|
operand->imm.dataOffset = 0;
|
|
|
|
}
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Decodes an instruction-operand.
|
|
|
|
*
|
2017-04-11 09:18:08 +08:00
|
|
|
* @param ctx A pointer to the @c ZydisDecoderContext instance.
|
2016-05-26 03:25:48 +08:00
|
|
|
* @param info A pointer to the @c ZydisInstructionInfo struct.
|
|
|
|
* @param operand A pointer to the @c ZydisOperandInfo struct.
|
|
|
|
* @param type The sementic operand-type.
|
|
|
|
* @param encoding The operand encoding.
|
|
|
|
*
|
2016-12-05 09:24:01 +08:00
|
|
|
* @return A zydis status code.
|
2016-05-26 03:25:48 +08:00
|
|
|
*/
|
2017-04-11 09:18:08 +08:00
|
|
|
static ZydisStatus ZydisDecodeOperand(ZydisDecoderContext* ctx, ZydisInstructionInfo* info,
|
2016-12-05 09:24:01 +08:00
|
|
|
ZydisOperandInfo* operand, ZydisSemanticOperandType type, ZydisOperandEncoding encoding)
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_ASSERT(ctx);
|
2016-05-26 03:25:48 +08:00
|
|
|
ZYDIS_ASSERT(info);
|
|
|
|
ZYDIS_ASSERT(operand);
|
|
|
|
|
|
|
|
// Fixed registers
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_AL:
|
2016-12-05 09:24:01 +08:00
|
|
|
operand->visibility = ZYDIS_OPERAND_VISIBILITY_IMPLICIT;
|
2016-05-26 03:25:48 +08:00
|
|
|
operand->size = 8;
|
|
|
|
operand->type = ZYDIS_OPERAND_TYPE_REGISTER;
|
|
|
|
operand->reg = ZYDIS_REGISTER_AL;
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
2016-05-26 03:25:48 +08:00
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_CL:
|
2016-12-05 09:24:01 +08:00
|
|
|
operand->visibility = ZYDIS_OPERAND_VISIBILITY_IMPLICIT;
|
2016-05-26 03:25:48 +08:00
|
|
|
operand->size = 8;
|
|
|
|
operand->type = ZYDIS_OPERAND_TYPE_REGISTER;
|
|
|
|
operand->reg = ZYDIS_REGISTER_CL;
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
2016-05-26 03:25:48 +08:00
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_AX:
|
2016-12-05 09:24:01 +08:00
|
|
|
operand->visibility = ZYDIS_OPERAND_VISIBILITY_IMPLICIT;
|
2016-05-26 03:25:48 +08:00
|
|
|
operand->size = 16;
|
|
|
|
operand->type = ZYDIS_OPERAND_TYPE_REGISTER;
|
|
|
|
operand->reg = ZYDIS_REGISTER_AX;
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
2016-05-26 03:25:48 +08:00
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_DX:
|
2016-12-05 09:24:01 +08:00
|
|
|
operand->visibility = ZYDIS_OPERAND_VISIBILITY_IMPLICIT;
|
2016-05-26 03:25:48 +08:00
|
|
|
operand->size = 16;
|
|
|
|
operand->type = ZYDIS_OPERAND_TYPE_REGISTER;
|
|
|
|
operand->reg = ZYDIS_REGISTER_DX;
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
2016-11-24 17:57:23 +08:00
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_ECX:
|
2016-12-05 09:24:01 +08:00
|
|
|
operand->visibility = ZYDIS_OPERAND_VISIBILITY_IMPLICIT;
|
2016-11-24 17:57:23 +08:00
|
|
|
operand->size = 32;
|
|
|
|
operand->type = ZYDIS_OPERAND_TYPE_REGISTER;
|
|
|
|
operand->reg = ZYDIS_REGISTER_ECX;
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
2016-05-26 03:25:48 +08:00
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_EAX:
|
2016-12-05 09:24:01 +08:00
|
|
|
operand->visibility = ZYDIS_OPERAND_VISIBILITY_IMPLICIT;
|
2016-05-26 03:25:48 +08:00
|
|
|
operand->size = 32;
|
|
|
|
operand->type = ZYDIS_OPERAND_TYPE_REGISTER;
|
|
|
|
operand->reg = ZYDIS_REGISTER_EAX;
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
2016-05-26 03:25:48 +08:00
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_RAX:
|
2016-12-05 09:24:01 +08:00
|
|
|
operand->visibility = ZYDIS_OPERAND_VISIBILITY_IMPLICIT;
|
2016-05-26 03:25:48 +08:00
|
|
|
operand->size = 64;
|
|
|
|
operand->type = ZYDIS_OPERAND_TYPE_REGISTER;
|
|
|
|
operand->reg = ZYDIS_REGISTER_RAX;
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
2016-05-26 03:25:48 +08:00
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_ES:
|
2016-12-05 09:24:01 +08:00
|
|
|
operand->visibility = ZYDIS_OPERAND_VISIBILITY_IMPLICIT;
|
2016-05-26 03:25:48 +08:00
|
|
|
operand->size = 16;
|
|
|
|
operand->type = ZYDIS_OPERAND_TYPE_REGISTER;
|
|
|
|
operand->reg = ZYDIS_REGISTER_ES;
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
2016-05-26 03:25:48 +08:00
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_CS:
|
2016-12-05 09:24:01 +08:00
|
|
|
operand->visibility = ZYDIS_OPERAND_VISIBILITY_IMPLICIT;
|
2016-05-26 03:25:48 +08:00
|
|
|
operand->size = 16;
|
|
|
|
operand->type = ZYDIS_OPERAND_TYPE_REGISTER;
|
|
|
|
operand->reg = ZYDIS_REGISTER_CS;
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
2016-05-26 03:25:48 +08:00
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_SS:
|
2016-12-05 09:24:01 +08:00
|
|
|
operand->visibility = ZYDIS_OPERAND_VISIBILITY_IMPLICIT;
|
2016-05-26 03:25:48 +08:00
|
|
|
operand->size = 16;
|
|
|
|
operand->type = ZYDIS_OPERAND_TYPE_REGISTER;
|
|
|
|
operand->reg = ZYDIS_REGISTER_SS;
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
2016-05-26 03:25:48 +08:00
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_DS:
|
2016-12-05 09:24:01 +08:00
|
|
|
operand->visibility = ZYDIS_OPERAND_VISIBILITY_IMPLICIT;
|
2016-05-26 03:25:48 +08:00
|
|
|
operand->size = 16;
|
|
|
|
operand->type = ZYDIS_OPERAND_TYPE_REGISTER;
|
|
|
|
operand->reg = ZYDIS_REGISTER_DS;
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
2016-05-26 03:25:48 +08:00
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_GS:
|
2016-12-05 09:24:01 +08:00
|
|
|
operand->visibility = ZYDIS_OPERAND_VISIBILITY_IMPLICIT;
|
2016-05-26 03:25:48 +08:00
|
|
|
operand->size = 16;
|
|
|
|
operand->type = ZYDIS_OPERAND_TYPE_REGISTER;
|
|
|
|
operand->reg = ZYDIS_REGISTER_GS;
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
2016-05-26 03:25:48 +08:00
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_FS:
|
2016-12-05 09:24:01 +08:00
|
|
|
operand->visibility = ZYDIS_OPERAND_VISIBILITY_IMPLICIT;
|
2016-05-26 03:25:48 +08:00
|
|
|
operand->size = 16;
|
|
|
|
operand->type = ZYDIS_OPERAND_TYPE_REGISTER;
|
|
|
|
operand->reg = ZYDIS_REGISTER_FS;
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
2016-05-26 03:25:48 +08:00
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_ST0:
|
2016-12-05 09:24:01 +08:00
|
|
|
operand->visibility = ZYDIS_OPERAND_VISIBILITY_IMPLICIT;
|
2016-05-26 03:25:48 +08:00
|
|
|
operand->size = 80;
|
|
|
|
operand->type = ZYDIS_OPERAND_TYPE_REGISTER;
|
|
|
|
operand->reg = ZYDIS_REGISTER_ST0;
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
2016-11-12 05:03:26 +08:00
|
|
|
default:
|
|
|
|
break;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Register operands
|
2016-12-05 09:24:01 +08:00
|
|
|
ZydisRegisterClass registerClass = ZYDIS_REGCLASS_INVALID;
|
2016-05-26 03:25:48 +08:00
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_GPR8:
|
|
|
|
operand->size = 8;
|
2016-12-05 09:24:01 +08:00
|
|
|
registerClass = ZYDIS_REGCLASS_GPR8;
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_GPR16:
|
|
|
|
operand->size = 16;
|
2016-12-05 09:24:01 +08:00
|
|
|
registerClass = ZYDIS_REGCLASS_GPR16;
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_GPR32:
|
|
|
|
operand->size = 32;
|
2016-12-05 09:24:01 +08:00
|
|
|
registerClass = ZYDIS_REGCLASS_GPR32;
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_GPR64:
|
|
|
|
operand->size = 64;
|
2016-12-05 09:24:01 +08:00
|
|
|
registerClass = ZYDIS_REGCLASS_GPR64;
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
2016-11-14 10:39:17 +08:00
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_TR:
|
2016-11-21 21:55:17 +08:00
|
|
|
operand->size = 32;
|
2016-12-05 09:24:01 +08:00
|
|
|
registerClass = ZYDIS_REGCLASS_TEST;
|
2016-11-14 10:39:17 +08:00
|
|
|
break;
|
2016-05-26 03:25:48 +08:00
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_CR:
|
2017-04-13 03:12:18 +08:00
|
|
|
operand->size = (ctx->operatingMode == ZYDIS_OPERATING_MODE_64BIT) ? 64 : 32;
|
2016-12-05 09:24:01 +08:00
|
|
|
registerClass = ZYDIS_REGCLASS_CONTROL;
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_DR:
|
2017-04-13 03:12:18 +08:00
|
|
|
operand->size = (ctx->operatingMode == ZYDIS_OPERATING_MODE_64BIT) ? 64 : 32;
|
2016-12-05 09:24:01 +08:00
|
|
|
registerClass = ZYDIS_REGCLASS_DEBUG;
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_FPR:
|
|
|
|
operand->size = 80;
|
2016-12-05 09:24:01 +08:00
|
|
|
registerClass = ZYDIS_REGCLASS_X87;
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_SREG:
|
|
|
|
operand->size = 16;
|
2016-12-05 09:24:01 +08:00
|
|
|
registerClass = ZYDIS_REGCLASS_SEGMENT;
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_VR64:
|
|
|
|
operand->size = 64;
|
2016-12-05 09:24:01 +08:00
|
|
|
registerClass = ZYDIS_REGCLASS_MMX;
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_VR128:
|
|
|
|
operand->size = 128;
|
2016-12-05 09:24:01 +08:00
|
|
|
registerClass = ZYDIS_REGCLASS_XMM;
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_VR256:
|
|
|
|
operand->size = 256;
|
2016-12-05 09:24:01 +08:00
|
|
|
registerClass = ZYDIS_REGCLASS_YMM;
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_VR512:
|
|
|
|
operand->size = 512;
|
2016-12-05 09:24:01 +08:00
|
|
|
registerClass = ZYDIS_REGCLASS_ZMM;
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_MSKR:
|
|
|
|
operand->size = 64;
|
2016-12-05 09:24:01 +08:00
|
|
|
registerClass = ZYDIS_REGCLASS_MASK;
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_BNDR:
|
|
|
|
operand->size = 128;
|
2016-12-05 09:24:01 +08:00
|
|
|
registerClass = ZYDIS_REGCLASS_BOUND;
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
2016-11-12 05:03:26 +08:00
|
|
|
default:
|
|
|
|
break;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
2016-12-05 09:24:01 +08:00
|
|
|
if (registerClass != ZYDIS_REGCLASS_INVALID)
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
|
|
|
switch (encoding)
|
|
|
|
{
|
|
|
|
case ZYDIS_OPERAND_ENCODING_REG:
|
|
|
|
ZYDIS_ASSERT(info->details.modrm.isDecoded);
|
|
|
|
return ZydisDecodeOperandRegister(info, operand, registerClass,
|
2017-04-11 09:18:08 +08:00
|
|
|
(ctx->internal.R2 << 4) |
|
|
|
|
(ctx->internal.R << 3) | info->details.modrm.reg);
|
2016-05-26 03:25:48 +08:00
|
|
|
case ZYDIS_OPERAND_ENCODING_RM:
|
|
|
|
case ZYDIS_OPERAND_ENCODING_RM_CD2:
|
|
|
|
case ZYDIS_OPERAND_ENCODING_RM_CD4:
|
|
|
|
case ZYDIS_OPERAND_ENCODING_RM_CD8:
|
|
|
|
case ZYDIS_OPERAND_ENCODING_RM_CD16:
|
|
|
|
case ZYDIS_OPERAND_ENCODING_RM_CD32:
|
|
|
|
case ZYDIS_OPERAND_ENCODING_RM_CD64:
|
|
|
|
ZYDIS_ASSERT(info->details.modrm.isDecoded);
|
2017-04-11 09:18:08 +08:00
|
|
|
return ZydisDecodeOperandModrmRm(ctx, info, operand, registerClass);
|
2016-05-26 03:25:48 +08:00
|
|
|
case ZYDIS_OPERAND_ENCODING_OPCODE:
|
|
|
|
{
|
|
|
|
uint8_t registerId = (info->opcode & 0x0F);
|
|
|
|
if (registerId > 7)
|
|
|
|
{
|
|
|
|
registerId = registerId - 8;
|
|
|
|
}
|
|
|
|
return ZydisDecodeOperandRegister(info, operand, registerClass,
|
2017-04-11 09:18:08 +08:00
|
|
|
(ctx->internal.B << 3) | registerId);
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
case ZYDIS_OPERAND_ENCODING_VVVV:
|
|
|
|
switch (info->encoding)
|
|
|
|
{
|
|
|
|
case ZYDIS_INSTRUCTION_ENCODING_VEX:
|
|
|
|
ZYDIS_ASSERT(info->details.vex.isDecoded);
|
|
|
|
return ZydisDecodeOperandRegister(info, operand, registerClass,
|
|
|
|
(0x0F & ~info->details.vex.vvvv));
|
|
|
|
case ZYDIS_INSTRUCTION_ENCODING_EVEX:
|
|
|
|
ZYDIS_ASSERT(info->details.evex.isDecoded);
|
|
|
|
return ZydisDecodeOperandRegister(info, operand, registerClass,
|
2017-04-11 09:18:08 +08:00
|
|
|
(ctx->internal.V2 << 4) | (0x0F & ~info->details.evex.vvvv));
|
2016-05-26 03:25:48 +08:00
|
|
|
case ZYDIS_INSTRUCTION_ENCODING_XOP:
|
|
|
|
ZYDIS_ASSERT(info->details.xop.isDecoded);
|
|
|
|
return ZydisDecodeOperandRegister(info, operand, registerClass,
|
|
|
|
(0x0F & ~info->details.xop.vvvv));
|
|
|
|
default:
|
|
|
|
ZYDIS_UNREACHABLE;
|
|
|
|
}
|
|
|
|
break;
|
2016-09-13 11:26:55 +08:00
|
|
|
case ZYDIS_OPERAND_ENCODING_IMM8_HI:
|
2016-05-26 03:25:48 +08:00
|
|
|
ZYDIS_ASSERT((info->encoding == ZYDIS_INSTRUCTION_ENCODING_VEX) ||
|
|
|
|
(info->encoding == ZYDIS_INSTRUCTION_ENCODING_EVEX) ||
|
|
|
|
(info->encoding == ZYDIS_INSTRUCTION_ENCODING_XOP));
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_CHECK(ZydisDecodeOperandImmediate(ctx, info, operand, 8, ZYDIS_FALSE));
|
2016-05-26 03:25:48 +08:00
|
|
|
ZYDIS_CHECK(ZydisDecodeOperandRegister(info, operand, registerClass,
|
|
|
|
(operand->imm.value.ubyte & 0xF0) >> 4));
|
2016-11-12 05:03:26 +08:00
|
|
|
operand->imm.dataSize = 0;
|
2016-05-26 03:25:48 +08:00
|
|
|
operand->imm.dataOffset = 0;
|
|
|
|
operand->imm.value.uqword = 0;
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
2016-05-26 03:25:48 +08:00
|
|
|
default:
|
|
|
|
ZYDIS_UNREACHABLE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Memory operands
|
|
|
|
uint8_t evexCD8Scale = 0;
|
|
|
|
switch (encoding)
|
|
|
|
{
|
|
|
|
case ZYDIS_OPERAND_ENCODING_RM_CD2:
|
|
|
|
evexCD8Scale = 2;
|
|
|
|
break;
|
|
|
|
case ZYDIS_OPERAND_ENCODING_RM_CD4:
|
|
|
|
evexCD8Scale = 4;
|
|
|
|
break;
|
|
|
|
case ZYDIS_OPERAND_ENCODING_RM_CD8:
|
|
|
|
evexCD8Scale = 8;
|
|
|
|
break;
|
|
|
|
case ZYDIS_OPERAND_ENCODING_RM_CD16:
|
|
|
|
evexCD8Scale = 16;
|
|
|
|
break;
|
|
|
|
case ZYDIS_OPERAND_ENCODING_RM_CD32:
|
|
|
|
evexCD8Scale = 32;
|
|
|
|
break;
|
|
|
|
case ZYDIS_OPERAND_ENCODING_RM_CD64:
|
|
|
|
evexCD8Scale = 64;
|
|
|
|
break;
|
2016-11-12 05:03:26 +08:00
|
|
|
default:
|
|
|
|
break;
|
2016-05-26 03:25:48 +08:00
|
|
|
};
|
|
|
|
ZydisRegister vsibBaseRegister = ZYDIS_REGISTER_NONE;
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_MEM:
|
|
|
|
operand->size = 0;
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_CHECK(ZydisDecodeOperandModrmRm(ctx, info, operand, ZYDIS_REGCLASS_INVALID));
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_MEM8:
|
|
|
|
operand->size = 8;
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_CHECK(ZydisDecodeOperandModrmRm(ctx, info, operand, ZYDIS_REGCLASS_INVALID));
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_MEM16:
|
|
|
|
operand->size = 16;
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_CHECK(ZydisDecodeOperandModrmRm(ctx, info, operand, ZYDIS_REGCLASS_INVALID));
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_MEM32_BCST2:
|
2016-12-05 09:24:01 +08:00
|
|
|
info->avx.broadcast = ZYDIS_AVX512_BCSTMODE_2;
|
2016-05-26 03:25:48 +08:00
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_MEM32_BCST4:
|
2016-12-05 09:24:01 +08:00
|
|
|
if (info->avx.broadcast == ZYDIS_AVX512_BCSTMODE_INVALID)
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
2016-12-05 09:24:01 +08:00
|
|
|
info->avx.broadcast = ZYDIS_AVX512_BCSTMODE_4;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_MEM32_BCST8:
|
2016-12-05 09:24:01 +08:00
|
|
|
if (info->avx.broadcast == ZYDIS_AVX512_BCSTMODE_INVALID)
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
2016-12-05 09:24:01 +08:00
|
|
|
info->avx.broadcast = ZYDIS_AVX512_BCSTMODE_8;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_MEM32_BCST16:
|
2016-12-05 09:24:01 +08:00
|
|
|
if (info->avx.broadcast == ZYDIS_AVX512_BCSTMODE_INVALID)
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
2016-12-05 09:24:01 +08:00
|
|
|
info->avx.broadcast = ZYDIS_AVX512_BCSTMODE_16;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_MEM32:
|
|
|
|
operand->size = 32;
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_CHECK(ZydisDecodeOperandModrmRm(ctx, info, operand, ZYDIS_REGCLASS_INVALID));
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_MEM64_BCST2:
|
2016-12-05 09:24:01 +08:00
|
|
|
info->avx.broadcast = ZYDIS_AVX512_BCSTMODE_2;
|
2016-05-26 03:25:48 +08:00
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_MEM64_BCST4:
|
2016-12-05 09:24:01 +08:00
|
|
|
if (info->avx.broadcast == ZYDIS_AVX512_BCSTMODE_INVALID)
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
2016-12-05 09:24:01 +08:00
|
|
|
info->avx.broadcast = ZYDIS_AVX512_BCSTMODE_4;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_MEM64_BCST8:
|
2016-12-05 09:24:01 +08:00
|
|
|
if (info->avx.broadcast == ZYDIS_AVX512_BCSTMODE_INVALID)
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
2016-12-05 09:24:01 +08:00
|
|
|
info->avx.broadcast = ZYDIS_AVX512_BCSTMODE_8;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_MEM64_BCST16:
|
2016-12-05 09:24:01 +08:00
|
|
|
if (info->avx.broadcast == ZYDIS_AVX512_BCSTMODE_INVALID)
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
2016-12-05 09:24:01 +08:00
|
|
|
info->avx.broadcast = ZYDIS_AVX512_BCSTMODE_16;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_MEM64:
|
|
|
|
operand->size = 64;
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_CHECK(ZydisDecodeOperandModrmRm(ctx, info, operand, ZYDIS_REGCLASS_INVALID));
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_MEM80:
|
|
|
|
ZYDIS_ASSERT(evexCD8Scale == 0);
|
|
|
|
operand->size = 80;
|
2017-04-11 09:18:08 +08:00
|
|
|
return ZydisDecodeOperandModrmRm(ctx, info, operand, ZYDIS_REGCLASS_INVALID);
|
2016-05-26 03:25:48 +08:00
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_MEM112:
|
|
|
|
ZYDIS_ASSERT(evexCD8Scale == 0);
|
|
|
|
operand->size = 112;
|
2017-04-11 09:18:08 +08:00
|
|
|
return ZydisDecodeOperandModrmRm(ctx, info, operand, ZYDIS_REGCLASS_INVALID);
|
2016-05-26 03:25:48 +08:00
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_MEM128:
|
|
|
|
operand->size = 128;
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_CHECK(ZydisDecodeOperandModrmRm(ctx, info, operand, ZYDIS_REGCLASS_INVALID));
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_MEM224:
|
|
|
|
ZYDIS_ASSERT(evexCD8Scale == 0);
|
|
|
|
operand->size = 224;
|
2017-04-11 09:18:08 +08:00
|
|
|
return ZydisDecodeOperandModrmRm(ctx, info, operand, ZYDIS_REGCLASS_INVALID);
|
2016-05-26 03:25:48 +08:00
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_MEM256:
|
|
|
|
operand->size = 256;
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_CHECK(ZydisDecodeOperandModrmRm(ctx, info, operand, ZYDIS_REGCLASS_INVALID));
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_MEM512:
|
|
|
|
operand->size = 512;
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_CHECK(ZydisDecodeOperandModrmRm(ctx, info, operand, ZYDIS_REGCLASS_INVALID));
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_M1616:
|
|
|
|
ZYDIS_ASSERT(evexCD8Scale == 0);
|
|
|
|
operand->size = 32;
|
2017-04-11 09:18:08 +08:00
|
|
|
return ZydisDecodeOperandModrmRm(ctx, info, operand, ZYDIS_REGCLASS_INVALID);
|
2016-05-26 03:25:48 +08:00
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_M1632:
|
|
|
|
ZYDIS_ASSERT(evexCD8Scale == 0);
|
|
|
|
operand->size = 48;
|
2017-04-11 09:18:08 +08:00
|
|
|
return ZydisDecodeOperandModrmRm(ctx, info, operand, ZYDIS_REGCLASS_INVALID);
|
2016-05-26 03:25:48 +08:00
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_M1664:
|
|
|
|
ZYDIS_ASSERT(evexCD8Scale == 0);
|
|
|
|
operand->size = 80;
|
2017-04-11 09:18:08 +08:00
|
|
|
return ZydisDecodeOperandModrmRm(ctx, info, operand, ZYDIS_REGCLASS_INVALID);
|
2016-05-26 03:25:48 +08:00
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_MEM32_VSIBX:
|
|
|
|
vsibBaseRegister = ZYDIS_REGISTER_XMM0;
|
|
|
|
operand->size = 32;
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_CHECK(ZydisDecodeOperandModrmRm(ctx, info, operand, ZYDIS_REGCLASS_INVALID));
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_MEM32_VSIBY:
|
|
|
|
vsibBaseRegister = ZYDIS_REGISTER_YMM0;
|
|
|
|
operand->size = 32;
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_CHECK(ZydisDecodeOperandModrmRm(ctx, info, operand, ZYDIS_REGCLASS_INVALID));
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_MEM32_VSIBZ:
|
|
|
|
vsibBaseRegister = ZYDIS_REGISTER_ZMM0;
|
|
|
|
operand->size = 32;
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_CHECK(ZydisDecodeOperandModrmRm(ctx, info, operand, ZYDIS_REGCLASS_INVALID));
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_MEM64_VSIBX:
|
|
|
|
vsibBaseRegister = ZYDIS_REGISTER_XMM0;
|
|
|
|
operand->size = 64;
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_CHECK(ZydisDecodeOperandModrmRm(ctx, info, operand, ZYDIS_REGCLASS_INVALID));
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_MEM64_VSIBY:
|
|
|
|
vsibBaseRegister = ZYDIS_REGISTER_YMM0;
|
|
|
|
operand->size = 64;
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_CHECK(ZydisDecodeOperandModrmRm(ctx, info, operand, ZYDIS_REGCLASS_INVALID));
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_MEM64_VSIBZ:
|
|
|
|
vsibBaseRegister = ZYDIS_REGISTER_ZMM0;
|
|
|
|
operand->size = 64;
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_CHECK(ZydisDecodeOperandModrmRm(ctx, info, operand, ZYDIS_REGCLASS_INVALID));
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
2016-11-12 05:03:26 +08:00
|
|
|
default:
|
|
|
|
break;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
if (evexCD8Scale)
|
|
|
|
{
|
|
|
|
ZYDIS_ASSERT(info->encoding == ZYDIS_INSTRUCTION_ENCODING_EVEX);
|
2016-11-12 05:03:26 +08:00
|
|
|
if (operand->mem.disp.dataSize == 8)
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
|
|
|
operand->mem.disp.value.sdword *= evexCD8Scale;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (vsibBaseRegister)
|
|
|
|
{
|
|
|
|
if (info->details.modrm.rm != 0x04)
|
|
|
|
{
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_INVALID_VSIB;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
2016-11-14 09:10:59 +08:00
|
|
|
switch (operand->mem.addressSize)
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
|
|
|
case 16:
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_INVALID_VSIB;
|
2016-05-26 03:25:48 +08:00
|
|
|
case 32:
|
2016-12-06 04:06:29 +08:00
|
|
|
operand->mem.index = operand->mem.index - ZYDIS_REGISTER_EAX + vsibBaseRegister +
|
|
|
|
((info->details.evex.V2 == 1) ? 0 : 16);
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case 64:
|
2016-12-06 04:06:29 +08:00
|
|
|
operand->mem.index = operand->mem.index - ZYDIS_REGISTER_RAX + vsibBaseRegister +
|
|
|
|
((info->details.evex.V2 == 1) ? 0 : 16);
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ZYDIS_UNREACHABLE;
|
|
|
|
}
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Immediate operands
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_FIXED1:
|
2016-12-06 04:06:29 +08:00
|
|
|
operand->visibility = ZYDIS_OPERAND_VISIBILITY_IMPLICIT;
|
2016-05-26 03:25:48 +08:00
|
|
|
operand->type = ZYDIS_OPERAND_TYPE_IMMEDIATE;
|
|
|
|
operand->size = 8;
|
2016-12-05 09:24:01 +08:00
|
|
|
operand->imm.isSigned = ZYDIS_TRUE;
|
2016-05-26 03:25:48 +08:00
|
|
|
operand->imm.value.ubyte = 1;
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
2016-05-26 03:25:48 +08:00
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_REL8:
|
2016-12-05 09:24:01 +08:00
|
|
|
info->attributes |= ZYDIS_ATTRIB_IS_RELATIVE;
|
|
|
|
operand->imm.isRelative = ZYDIS_TRUE;
|
2017-04-10 02:55:49 +08:00
|
|
|
// Intentional fallthrough.
|
2016-05-26 03:25:48 +08:00
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_IMM8:
|
|
|
|
operand->size = 8;
|
2016-12-05 09:24:01 +08:00
|
|
|
operand->imm.isSigned = ZYDIS_TRUE;
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_IMM8U:
|
|
|
|
operand->size = 8;
|
2016-12-05 09:24:01 +08:00
|
|
|
operand->imm.isSigned = ZYDIS_FALSE;
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_REL16:
|
2016-12-05 09:24:01 +08:00
|
|
|
info->attributes |= ZYDIS_ATTRIB_IS_RELATIVE;
|
|
|
|
operand->imm.isRelative = ZYDIS_TRUE;
|
2017-04-10 02:55:49 +08:00
|
|
|
// Intentional fallthrough.
|
2016-05-26 03:25:48 +08:00
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_IMM16:
|
|
|
|
operand->size = 16;
|
2016-12-05 09:24:01 +08:00
|
|
|
operand->imm.isSigned = ZYDIS_TRUE;
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_REL32:
|
2016-12-05 09:24:01 +08:00
|
|
|
info->attributes |= ZYDIS_ATTRIB_IS_RELATIVE;
|
|
|
|
operand->imm.isRelative = ZYDIS_TRUE;
|
2016-05-26 03:25:48 +08:00
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_IMM32:
|
|
|
|
operand->size = 32;
|
2016-12-05 09:24:01 +08:00
|
|
|
operand->imm.isSigned = ZYDIS_TRUE;
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_REL64:
|
2016-12-05 09:24:01 +08:00
|
|
|
info->attributes |= ZYDIS_ATTRIB_IS_RELATIVE;
|
|
|
|
operand->imm.isRelative = ZYDIS_TRUE;
|
2017-04-10 02:55:49 +08:00
|
|
|
// Intentional fallthrough.
|
2016-05-26 03:25:48 +08:00
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_IMM64:
|
|
|
|
operand->size = 64;
|
2016-12-05 09:24:01 +08:00
|
|
|
operand->imm.isSigned = ZYDIS_TRUE;
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
2016-11-12 05:03:26 +08:00
|
|
|
default:
|
|
|
|
break;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_REL8:
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_IMM8:
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_IMM8U:
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_REL16:
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_IMM16:
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_REL32:
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_IMM32:
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_REL64:
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_IMM64:
|
|
|
|
switch (encoding)
|
|
|
|
{
|
2016-09-13 11:26:55 +08:00
|
|
|
case ZYDIS_OPERAND_ENCODING_IMM8_LO:
|
|
|
|
ZYDIS_CHECK(
|
2017-04-11 09:18:08 +08:00
|
|
|
ZydisDecodeOperandImmediate(ctx, info, operand, 8, operand->imm.isSigned));
|
2016-09-13 11:26:55 +08:00
|
|
|
operand->imm.value.ubyte &= 0x0F;
|
|
|
|
break;
|
2016-05-26 03:25:48 +08:00
|
|
|
case ZYDIS_OPERAND_ENCODING_IMM8:
|
2017-04-11 09:18:08 +08:00
|
|
|
return ZydisDecodeOperandImmediate(ctx, info, operand, 8, operand->imm.isSigned);
|
2016-05-26 03:25:48 +08:00
|
|
|
case ZYDIS_OPERAND_ENCODING_IMM16:
|
2017-04-11 09:18:08 +08:00
|
|
|
return ZydisDecodeOperandImmediate(ctx, info, operand, 16, operand->imm.isSigned);
|
2016-05-26 03:25:48 +08:00
|
|
|
case ZYDIS_OPERAND_ENCODING_IMM32:
|
2017-04-11 09:18:08 +08:00
|
|
|
return ZydisDecodeOperandImmediate(ctx, info, operand, 32, operand->imm.isSigned);
|
2016-05-26 03:25:48 +08:00
|
|
|
case ZYDIS_OPERAND_ENCODING_IMM64:
|
2017-04-11 09:18:08 +08:00
|
|
|
return ZydisDecodeOperandImmediate(ctx, info, operand, 64, operand->imm.isSigned);
|
2016-05-26 03:25:48 +08:00
|
|
|
default:
|
|
|
|
ZYDIS_UNREACHABLE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_PTR1616:
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_CHECK(ZydisDecodeOperandImmediate(ctx, info, operand, 16, ZYDIS_FALSE));
|
2016-05-26 03:25:48 +08:00
|
|
|
operand->ptr.offset = operand->imm.value.uword;
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_CHECK(ZydisDecodeOperandImmediate(ctx, info, operand, 16, ZYDIS_FALSE));
|
2016-05-26 03:25:48 +08:00
|
|
|
operand->ptr.segment = operand->imm.value.uword;
|
2016-11-12 05:03:26 +08:00
|
|
|
operand->imm.dataSize = 0;
|
2016-05-26 03:25:48 +08:00
|
|
|
operand->imm.dataOffset = 0;
|
|
|
|
operand->imm.value.uqword = 0;
|
|
|
|
operand->type = ZYDIS_OPERAND_TYPE_POINTER;
|
|
|
|
operand->size = 32;
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
2016-05-26 03:25:48 +08:00
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_PTR1632:
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_CHECK(ZydisDecodeOperandImmediate(ctx, info, operand, 32, ZYDIS_FALSE));
|
2016-05-26 03:25:48 +08:00
|
|
|
operand->ptr.offset = operand->imm.value.udword;
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_CHECK(ZydisDecodeOperandImmediate(ctx, info, operand, 16, ZYDIS_FALSE));
|
2016-05-26 03:25:48 +08:00
|
|
|
operand->ptr.segment = operand->imm.value.uword;
|
2016-11-12 05:03:26 +08:00
|
|
|
operand->imm.dataSize = 0;
|
2016-05-26 03:25:48 +08:00
|
|
|
operand->imm.dataOffset = 0;
|
|
|
|
operand->imm.value.uqword = 0;
|
|
|
|
operand->type = ZYDIS_OPERAND_TYPE_POINTER;
|
|
|
|
operand->size = 48;
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
2016-05-26 03:25:48 +08:00
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_PTR1664:
|
|
|
|
// TODO: ?
|
|
|
|
assert(0);
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
2016-11-12 05:03:26 +08:00
|
|
|
default:
|
|
|
|
break;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Moffs
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_MOFFS16:
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_CHECK(ZydisDecodeOperandImmediate(ctx, info, operand, 16, ZYDIS_FALSE));
|
2016-05-26 03:25:48 +08:00
|
|
|
operand->type = ZYDIS_OPERAND_TYPE_MEMORY;
|
|
|
|
operand->size = 16;
|
2016-11-12 05:03:26 +08:00
|
|
|
operand->mem.disp.dataSize = 16;
|
2016-05-26 03:25:48 +08:00
|
|
|
operand->mem.disp.dataOffset = operand->imm.dataOffset;
|
|
|
|
operand->mem.disp.value.sword = operand->imm.value.sword;
|
2016-11-12 05:03:26 +08:00
|
|
|
operand->imm.dataSize = 0;
|
2016-05-26 03:25:48 +08:00
|
|
|
operand->imm.dataOffset = 0;
|
|
|
|
operand->imm.value.uqword = 0;
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
2016-05-26 03:25:48 +08:00
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_MOFFS32:
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_CHECK(ZydisDecodeOperandImmediate(ctx, info, operand, 32, ZYDIS_FALSE));
|
2016-05-26 03:25:48 +08:00
|
|
|
operand->type = ZYDIS_OPERAND_TYPE_MEMORY;
|
|
|
|
operand->size = 32;
|
2016-11-12 05:03:26 +08:00
|
|
|
operand->mem.disp.dataSize = 32;
|
2016-05-26 03:25:48 +08:00
|
|
|
operand->mem.disp.dataOffset = operand->imm.dataOffset;
|
|
|
|
operand->mem.disp.value.sdword = operand->imm.value.sdword;
|
2016-11-12 05:03:26 +08:00
|
|
|
operand->imm.dataSize = 0;
|
2016-05-26 03:25:48 +08:00
|
|
|
operand->imm.dataOffset = 0;
|
|
|
|
operand->imm.value.uqword = 0;
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
2016-05-26 03:25:48 +08:00
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_MOFFS64:
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_CHECK(ZydisDecodeOperandImmediate(ctx, info, operand, 64, ZYDIS_FALSE));
|
2016-05-26 03:25:48 +08:00
|
|
|
operand->type = ZYDIS_OPERAND_TYPE_MEMORY;
|
|
|
|
operand->size = 64;
|
2016-11-12 05:03:26 +08:00
|
|
|
operand->mem.disp.dataSize = 64;
|
2016-05-26 03:25:48 +08:00
|
|
|
operand->mem.disp.dataOffset = operand->imm.dataOffset;
|
|
|
|
operand->mem.disp.value.sqword = operand->imm.value.sqword;
|
2016-11-12 05:03:26 +08:00
|
|
|
operand->imm.dataSize = 0;
|
2016-05-26 03:25:48 +08:00
|
|
|
operand->imm.dataOffset = 0;
|
|
|
|
operand->imm.value.uqword = 0;
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
2016-11-12 05:03:26 +08:00
|
|
|
default:
|
|
|
|
break;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// SrcIdx and DstIdx operands
|
|
|
|
uint8_t srcidx = 0;
|
|
|
|
uint8_t dstidx = 0;
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_SRCIDX8:
|
|
|
|
srcidx = 8;
|
|
|
|
break;
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_SRCIDX16:
|
|
|
|
srcidx = 16;
|
|
|
|
break;
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_SRCIDX32:
|
|
|
|
srcidx = 32;
|
|
|
|
break;
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_SRCIDX64:
|
|
|
|
srcidx = 64;
|
|
|
|
break;
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_DSTIDX8:
|
|
|
|
dstidx = 8;
|
|
|
|
break;
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_DSTIDX16:
|
|
|
|
dstidx = 16;
|
|
|
|
break;
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_DSTIDX32:
|
|
|
|
dstidx = 32;
|
|
|
|
break;
|
|
|
|
case ZYDIS_SEM_OPERAND_TYPE_DSTIDX64:
|
|
|
|
dstidx = 64;
|
|
|
|
break;
|
2016-11-12 05:03:26 +08:00
|
|
|
default:
|
|
|
|
break;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
if (srcidx || dstidx)
|
|
|
|
{
|
2016-12-05 09:24:01 +08:00
|
|
|
info->attributes |= ZYDIS_ATTRIB_ACCEPTS_ADDRESSSIZE;
|
|
|
|
if (info->details.prefixes.has67)
|
|
|
|
{
|
|
|
|
info->attributes |= ZYDIS_ATTRIB_HAS_ADDRESSSIZE;
|
|
|
|
}
|
2017-04-11 09:18:08 +08:00
|
|
|
switch (ctx->operatingMode)
|
2016-11-14 09:10:59 +08:00
|
|
|
{
|
2017-04-13 03:12:18 +08:00
|
|
|
case ZYDIS_OPERATING_MODE_16BIT:
|
2016-12-05 09:24:01 +08:00
|
|
|
operand->mem.addressSize = (info->attributes & ZYDIS_ATTRIB_HAS_ADDRESSSIZE) ? 32 : 16;
|
2016-11-14 09:10:59 +08:00
|
|
|
break;
|
2017-04-13 03:12:18 +08:00
|
|
|
case ZYDIS_OPERATING_MODE_32BIT:
|
2016-12-05 09:24:01 +08:00
|
|
|
operand->mem.addressSize = (info->attributes & ZYDIS_ATTRIB_HAS_ADDRESSSIZE) ? 16 : 32;
|
2016-11-14 09:10:59 +08:00
|
|
|
break;
|
2017-04-13 03:12:18 +08:00
|
|
|
case ZYDIS_OPERATING_MODE_64BIT:
|
2016-12-05 09:24:01 +08:00
|
|
|
operand->mem.addressSize = (info->attributes & ZYDIS_ATTRIB_HAS_ADDRESSSIZE) ? 32 : 64;
|
2016-11-14 09:10:59 +08:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ZYDIS_UNREACHABLE;
|
|
|
|
}
|
2016-12-05 09:24:01 +08:00
|
|
|
registerClass = ZYDIS_REGCLASS_INVALID;
|
2016-11-14 09:10:59 +08:00
|
|
|
switch (operand->mem.addressSize)
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
|
|
|
case 16:
|
2016-12-05 09:24:01 +08:00
|
|
|
registerClass = ZYDIS_REGCLASS_GPR16;
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case 32:
|
2016-12-05 09:24:01 +08:00
|
|
|
registerClass = ZYDIS_REGCLASS_GPR32;
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case 64:
|
2016-12-05 09:24:01 +08:00
|
|
|
registerClass = ZYDIS_REGCLASS_GPR64;
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ZYDIS_UNREACHABLE;
|
|
|
|
}
|
2016-12-05 09:24:01 +08:00
|
|
|
operand->visibility = ZYDIS_OPERAND_VISIBILITY_IMPLICIT;
|
2016-05-26 03:25:48 +08:00
|
|
|
if (srcidx)
|
|
|
|
{
|
|
|
|
ZYDIS_CHECK(ZydisDecodeOperandRegister(info, operand, registerClass, 6));
|
|
|
|
operand->type = ZYDIS_OPERAND_TYPE_MEMORY;
|
|
|
|
operand->size = srcidx;
|
|
|
|
operand->mem.segment = ZYDIS_REGISTER_DS;
|
|
|
|
operand->mem.base = operand->reg;
|
|
|
|
operand->reg = ZYDIS_REGISTER_NONE;
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
if (dstidx)
|
|
|
|
{
|
|
|
|
ZYDIS_CHECK(ZydisDecodeOperandRegister(info, operand, registerClass, 7));
|
|
|
|
operand->type = ZYDIS_OPERAND_TYPE_MEMORY;
|
|
|
|
operand->size = dstidx;
|
|
|
|
operand->mem.base = operand->reg;
|
|
|
|
operand->mem.segment = ZYDIS_REGISTER_ES;
|
|
|
|
operand->reg = ZYDIS_REGISTER_NONE;
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Decodes all instruction-operands.
|
|
|
|
*
|
2017-04-11 09:18:08 +08:00
|
|
|
* @param ctx A pointer to the @c ZydisDecoderContext instance.
|
2016-11-23 01:12:05 +08:00
|
|
|
* @param info A pointer to the @c ZydisInstructionInfo struct.
|
|
|
|
* @param operands A pointer to the first operand-definition of the instruction.
|
|
|
|
* @param operandCount The number of operands.
|
2016-05-26 03:25:48 +08:00
|
|
|
*
|
2016-12-05 09:24:01 +08:00
|
|
|
* @return A zydis status code.
|
2016-05-26 03:25:48 +08:00
|
|
|
*/
|
2017-04-13 03:00:46 +08:00
|
|
|
static ZydisStatus ZydisDecodeOperands(ZydisDecoderContext* ctx, ZydisInstructionInfo* info,
|
|
|
|
const ZydisOperandDefinition* operands, uint8_t operandCount)
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_ASSERT(ctx);
|
2016-05-26 03:25:48 +08:00
|
|
|
ZYDIS_ASSERT(info);
|
2016-11-23 01:12:05 +08:00
|
|
|
ZYDIS_ASSERT(operands);
|
2016-11-24 17:57:23 +08:00
|
|
|
ZYDIS_ASSERT((operandCount > 0) && (operandCount < 6));
|
2016-05-26 03:25:48 +08:00
|
|
|
|
2016-11-23 01:12:05 +08:00
|
|
|
info->operandCount = operandCount;
|
2016-11-26 20:08:37 +08:00
|
|
|
for (uint8_t i = 0; i < operandCount; ++i)
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
2016-12-05 09:24:01 +08:00
|
|
|
if (operands[i].type == ZYDIS_SEM_OPERAND_TYPE_UNUSED)
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
2016-12-05 09:24:01 +08:00
|
|
|
info->operands[i].id = i;
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_CHECK(ZydisDecodeOperand(ctx, info, &info->operands[i], operands[i].type,
|
2016-12-05 09:24:01 +08:00
|
|
|
operands[i].encoding));
|
2017-01-23 08:17:15 +08:00
|
|
|
|
|
|
|
// temp
|
|
|
|
info->operands[i].temp = operands[i].type;
|
|
|
|
|
2016-12-05 09:24:01 +08:00
|
|
|
info->operands[i].encoding = operands[i].encoding;
|
|
|
|
info->operands[i].action = operands[i].action;
|
2016-05-26 03:25:48 +08:00
|
|
|
// Adjust segment register for memory operands
|
2016-12-05 09:24:01 +08:00
|
|
|
if (info->operands[i].type == ZYDIS_OPERAND_TYPE_MEMORY)
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
2016-12-05 09:24:01 +08:00
|
|
|
info->attributes |= ZYDIS_ATTRIB_ACCEPTS_SEGMENT;
|
2017-04-11 09:18:08 +08:00
|
|
|
switch (ctx->lastSegmentPrefix)
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
2016-12-05 09:24:01 +08:00
|
|
|
case 0x2E:
|
|
|
|
info->attributes |= ZYDIS_ATTRIB_HAS_SEGMENT_CS;
|
|
|
|
info->operands[i].mem.segment = ZYDIS_REGISTER_CS;
|
2017-04-11 09:18:08 +08:00
|
|
|
ctx->lastSegmentPrefix = 0;
|
2016-12-05 09:24:01 +08:00
|
|
|
break;
|
|
|
|
case 0x36:
|
|
|
|
info->attributes |= ZYDIS_ATTRIB_HAS_SEGMENT_SS;
|
|
|
|
info->operands[i].mem.segment = ZYDIS_REGISTER_SS;
|
2017-04-11 09:18:08 +08:00
|
|
|
ctx->lastSegmentPrefix = 0;
|
2016-12-05 09:24:01 +08:00
|
|
|
break;
|
|
|
|
case 0x3E:
|
|
|
|
info->attributes |= ZYDIS_ATTRIB_HAS_SEGMENT_DS;
|
|
|
|
info->operands[i].mem.segment = ZYDIS_REGISTER_DS;
|
2017-04-11 09:18:08 +08:00
|
|
|
ctx->lastSegmentPrefix = 0;
|
2016-12-05 09:24:01 +08:00
|
|
|
break;
|
|
|
|
case 0x26:
|
|
|
|
info->attributes |= ZYDIS_ATTRIB_HAS_SEGMENT_ES;
|
|
|
|
info->operands[i].mem.segment = ZYDIS_REGISTER_ES;
|
2017-04-11 09:18:08 +08:00
|
|
|
ctx->lastSegmentPrefix = 0;
|
2016-12-05 09:24:01 +08:00
|
|
|
break;
|
|
|
|
case 0x64:
|
|
|
|
info->attributes |= ZYDIS_ATTRIB_HAS_SEGMENT_FS;
|
|
|
|
info->operands[i].mem.segment = ZYDIS_REGISTER_FS;
|
2017-04-11 09:18:08 +08:00
|
|
|
ctx->lastSegmentPrefix = 0;
|
2016-12-05 09:24:01 +08:00
|
|
|
break;
|
|
|
|
case 0x65:
|
|
|
|
info->attributes |= ZYDIS_ATTRIB_HAS_SEGMENT_GS;
|
|
|
|
info->operands[i].mem.segment = ZYDIS_REGISTER_GS;
|
2017-04-11 09:18:08 +08:00
|
|
|
ctx->lastSegmentPrefix = 0;
|
2016-12-05 09:24:01 +08:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if ((info->operands[i].mem.base == ZYDIS_REGISTER_RSP) ||
|
|
|
|
(info->operands[i].mem.base == ZYDIS_REGISTER_RBP) ||
|
|
|
|
(info->operands[i].mem.base == ZYDIS_REGISTER_ESP) ||
|
|
|
|
(info->operands[i].mem.base == ZYDIS_REGISTER_EBP) ||
|
|
|
|
(info->operands[i].mem.base == ZYDIS_REGISTER_SP) ||
|
|
|
|
(info->operands[i].mem.base == ZYDIS_REGISTER_BP))
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
2016-12-05 09:24:01 +08:00
|
|
|
info->operands[i].mem.segment = ZYDIS_REGISTER_SS;
|
2016-05-26 03:25:48 +08:00
|
|
|
} else
|
|
|
|
{
|
2016-12-05 09:24:01 +08:00
|
|
|
info->operands[i].mem.segment = ZYDIS_REGISTER_DS;
|
|
|
|
};
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------------------------------- */
|
|
|
|
|
2016-11-23 01:12:05 +08:00
|
|
|
/**
|
2016-12-05 09:24:01 +08:00
|
|
|
* @brief Applies additional information from the instruction-definition to the
|
|
|
|
* @c ZydisInstructionInfo struct.
|
2016-11-23 01:12:05 +08:00
|
|
|
*
|
2017-04-11 09:18:08 +08:00
|
|
|
* @param ctx A pointer to the @c ZydisDecoderContext instance.
|
2016-12-05 09:24:01 +08:00
|
|
|
* @param info A pointer to the @c ZydisInstructionInfo struct.
|
2016-11-23 01:12:05 +08:00
|
|
|
*/
|
2017-04-13 03:00:46 +08:00
|
|
|
static void ZydisApplyInstructionDefinition(ZydisDecoderContext* ctx, ZydisInstructionInfo* info)
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
|
|
|
ZYDIS_ASSERT(info);
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_ASSERT(ctx->definition);
|
2016-11-24 17:57:23 +08:00
|
|
|
|
|
|
|
const ZydisInstructionDefinition* definition =
|
2017-04-11 09:18:08 +08:00
|
|
|
(ZydisInstructionDefinition*)ctx->definition;
|
2016-05-26 03:25:48 +08:00
|
|
|
|
2016-11-23 01:12:05 +08:00
|
|
|
// Set prefix-flags
|
|
|
|
if (definition->acceptsLock)
|
|
|
|
{
|
2016-12-05 09:24:01 +08:00
|
|
|
info->attributes |= ZYDIS_ATTRIB_ACCEPTS_LOCK;
|
|
|
|
if (info->details.prefixes.hasF0)
|
|
|
|
{
|
|
|
|
info->attributes |= ZYDIS_ATTRIB_HAS_LOCK;
|
|
|
|
}
|
2016-11-23 01:12:05 +08:00
|
|
|
}
|
|
|
|
if (definition->acceptsREP)
|
|
|
|
{
|
2016-12-05 09:24:01 +08:00
|
|
|
info->attributes |= ZYDIS_ATTRIB_ACCEPTS_REP;
|
|
|
|
}
|
|
|
|
if (definition->acceptsREPEREPNE)
|
|
|
|
{
|
|
|
|
info->attributes |= ZYDIS_ATTRIB_ACCEPTS_REPE | ZYDIS_ATTRIB_ACCEPTS_REPNE;
|
|
|
|
}
|
|
|
|
if (definition->acceptsBOUND)
|
2016-11-23 01:12:05 +08:00
|
|
|
{
|
2016-12-05 09:24:01 +08:00
|
|
|
info->attributes |= ZYDIS_ATTRIB_ACCEPTS_BOUND;
|
2016-11-23 01:12:05 +08:00
|
|
|
}
|
2016-11-24 17:57:23 +08:00
|
|
|
if (definition->acceptsXACQUIRE)
|
|
|
|
{
|
2016-12-05 09:24:01 +08:00
|
|
|
info->attributes |= ZYDIS_ATTRIB_ACCEPTS_XACQUIRE;
|
2016-11-24 17:57:23 +08:00
|
|
|
}
|
|
|
|
if (definition->acceptsXRELEASE)
|
|
|
|
{
|
2016-12-05 09:24:01 +08:00
|
|
|
info->attributes |= ZYDIS_ATTRIB_ACCEPTS_XRELEASE;
|
2016-11-24 17:57:23 +08:00
|
|
|
}
|
|
|
|
if (definition->acceptsHLEWithoutLock)
|
|
|
|
{
|
2016-12-05 09:24:01 +08:00
|
|
|
info->attributes |= ZYDIS_ATTRIB_ACCEPTS_HLE_WITHOUT_LOCK;
|
|
|
|
}
|
2017-04-11 09:18:08 +08:00
|
|
|
switch (ctx->hasUnusedPrefixF2F3)
|
2016-11-23 01:12:05 +08:00
|
|
|
{
|
2016-12-05 09:24:01 +08:00
|
|
|
case 0xF2:
|
|
|
|
if (info->attributes & ZYDIS_ATTRIB_ACCEPTS_REPNE)
|
2016-11-23 01:12:05 +08:00
|
|
|
{
|
2016-12-05 09:24:01 +08:00
|
|
|
info->attributes |= ZYDIS_ATTRIB_HAS_REPNE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (info->attributes & ZYDIS_ATTRIB_ACCEPTS_XACQUIRE)
|
|
|
|
{
|
|
|
|
if ((info->attributes & ZYDIS_ATTRIB_HAS_LOCK) || (definition->acceptsHLEWithoutLock))
|
|
|
|
{
|
|
|
|
info->attributes |= ZYDIS_ATTRIB_HAS_XACQUIRE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (info->attributes & ZYDIS_ATTRIB_ACCEPTS_BOUND)
|
|
|
|
{
|
|
|
|
info->attributes |= ZYDIS_ATTRIB_HAS_BOUND;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 0xF3:
|
|
|
|
if (info->attributes & ZYDIS_ATTRIB_ACCEPTS_REP)
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
2016-12-05 09:24:01 +08:00
|
|
|
info->attributes |= ZYDIS_ATTRIB_HAS_REP;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (info->attributes & ZYDIS_ATTRIB_ACCEPTS_REPE)
|
|
|
|
{
|
|
|
|
info->attributes |= ZYDIS_ATTRIB_HAS_REPE;
|
|
|
|
break;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
2016-12-05 09:24:01 +08:00
|
|
|
if (info->attributes & ZYDIS_ATTRIB_ACCEPTS_XRELEASE)
|
|
|
|
{
|
|
|
|
if ((info->attributes & ZYDIS_ATTRIB_HAS_LOCK) || (definition->acceptsHLEWithoutLock))
|
|
|
|
{
|
|
|
|
info->attributes |= ZYDIS_ATTRIB_HAS_XRELEASE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
2016-11-23 01:12:05 +08:00
|
|
|
}
|
2016-12-05 09:24:01 +08:00
|
|
|
|
2016-11-23 01:12:05 +08:00
|
|
|
if (definition->acceptsBranchHints)
|
|
|
|
{
|
2016-12-05 09:24:01 +08:00
|
|
|
info->attributes |= ZYDIS_ATTRIB_ACCEPTS_BRANCH_HINTS;
|
2017-04-11 09:18:08 +08:00
|
|
|
switch (ctx->lastSegmentPrefix)
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
2016-12-05 09:24:01 +08:00
|
|
|
case 0x2E:
|
|
|
|
info->attributes |= ZYDIS_ATTRIB_HAS_BRANCH_NOT_TAKEN;
|
|
|
|
break;
|
|
|
|
case 0x3E:
|
|
|
|
info->attributes |= ZYDIS_ATTRIB_HAS_BRANCH_TAKEN;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------------------------------- */
|
|
|
|
|
2017-04-11 09:18:08 +08:00
|
|
|
static ZydisStatus ZydisNodeHandlerOpcode(ZydisDecoderContext* ctx,
|
2016-05-26 03:25:48 +08:00
|
|
|
ZydisInstructionInfo* info, uint16_t* index)
|
|
|
|
{
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_ASSERT(ctx);
|
2016-05-26 03:25:48 +08:00
|
|
|
ZYDIS_ASSERT(info);
|
|
|
|
ZYDIS_ASSERT(index);
|
|
|
|
|
|
|
|
// Handle possible encoding-prefix and opcode-map changes
|
|
|
|
switch (info->encoding)
|
|
|
|
{
|
|
|
|
case ZYDIS_INSTRUCTION_ENCODING_DEFAULT:
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_CHECK(ZydisInputNext(ctx, info, &info->opcode));
|
2016-05-26 03:25:48 +08:00
|
|
|
switch (info->opcodeMap)
|
|
|
|
{
|
|
|
|
case ZYDIS_OPCODE_MAP_DEFAULT:
|
|
|
|
switch (info->opcode)
|
|
|
|
{
|
|
|
|
case 0x0F:
|
|
|
|
info->opcodeMap = ZYDIS_OPCODE_MAP_0F;
|
|
|
|
break;
|
|
|
|
case 0xC4:
|
|
|
|
case 0xC5:
|
|
|
|
case 0x62:
|
|
|
|
{
|
|
|
|
uint8_t nextInput;
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_CHECK(ZydisInputPeek(ctx, info, &nextInput));
|
2017-01-11 18:20:24 +08:00
|
|
|
if ((nextInput & 0xF0) >= 0xC0)
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
2016-12-05 09:24:01 +08:00
|
|
|
if (info->attributes & ZYDIS_ATTRIB_HAS_REX)
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_ILLEGAL_REX;
|
|
|
|
}
|
2017-04-11 09:18:08 +08:00
|
|
|
if ((ctx->hasUnusedPrefixF2F3) || (ctx->hasUnusedPrefix66))
|
2016-12-05 09:24:01 +08:00
|
|
|
{
|
|
|
|
return ZYDIS_STATUS_ILLEGAL_LEGACY_PFX;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
uint8_t prefixBytes[3];
|
|
|
|
switch (info->opcode)
|
|
|
|
{
|
|
|
|
case 0xC4:
|
|
|
|
// Read additional 3-byte vex-prefix data
|
|
|
|
ZYDIS_ASSERT(!info->details.vex.isDecoded);
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_CHECK(ZydisInputNext(ctx, info, &prefixBytes[0]));
|
|
|
|
ZYDIS_CHECK(ZydisInputNext(ctx, info, &prefixBytes[1]));
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case 0xC5:
|
|
|
|
// Read additional 2-byte vex-prefix data
|
|
|
|
ZYDIS_ASSERT(!info->details.vex.isDecoded);
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_CHECK(ZydisInputNext(ctx, info, &prefixBytes[0]));
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case 0x62:
|
|
|
|
// Read additional evex-prefix data
|
|
|
|
ZYDIS_ASSERT(!info->details.evex.isDecoded);
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_CHECK(ZydisInputNext(ctx, info, &prefixBytes[0]));
|
|
|
|
ZYDIS_CHECK(ZydisInputNext(ctx, info, &prefixBytes[1]));
|
|
|
|
ZYDIS_CHECK(ZydisInputNext(ctx, info, &prefixBytes[2]));
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ZYDIS_UNREACHABLE;
|
|
|
|
}
|
|
|
|
switch (info->opcode)
|
|
|
|
{
|
|
|
|
case 0xC4:
|
|
|
|
case 0xC5:
|
|
|
|
// Decode vex-prefix
|
|
|
|
info->encoding = ZYDIS_INSTRUCTION_ENCODING_VEX;
|
2017-04-13 03:00:46 +08:00
|
|
|
ZYDIS_CHECK(ZydisDecodeVEX(
|
|
|
|
ctx, info, info->opcode, prefixBytes[0], prefixBytes[1]));
|
2016-05-26 03:25:48 +08:00
|
|
|
info->opcodeMap = info->details.vex.m_mmmm;
|
|
|
|
break;
|
|
|
|
case 0x62:
|
|
|
|
// Decode evex-prefix
|
|
|
|
info->encoding = ZYDIS_INSTRUCTION_ENCODING_EVEX;
|
2017-04-13 03:00:46 +08:00
|
|
|
ZYDIS_CHECK(ZydisDecodeEVEX(
|
|
|
|
ctx, info, prefixBytes[0], prefixBytes[1], prefixBytes[2]));
|
2016-05-26 03:25:48 +08:00
|
|
|
info->opcodeMap = info->details.evex.mm;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ZYDIS_UNREACHABLE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 0x8F:
|
|
|
|
{
|
|
|
|
uint8_t nextInput;
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_CHECK(ZydisInputPeek(ctx, info, &nextInput));
|
2016-05-26 03:25:48 +08:00
|
|
|
if (((nextInput >> 0) & 0x1F) >= 8)
|
|
|
|
{
|
2016-12-05 09:24:01 +08:00
|
|
|
if (info->attributes & ZYDIS_ATTRIB_HAS_REX)
|
|
|
|
{
|
|
|
|
return ZYDIS_STATUS_ILLEGAL_REX;
|
|
|
|
}
|
2017-04-11 09:18:08 +08:00
|
|
|
if ((ctx->hasUnusedPrefixF2F3) || (ctx->hasUnusedPrefix66))
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_ILLEGAL_LEGACY_PFX;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
uint8_t prefixBytes[2];
|
|
|
|
// Read additional xop-prefix data
|
|
|
|
ZYDIS_ASSERT(!info->details.xop.isDecoded);
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_CHECK(ZydisInputNext(ctx, info, &prefixBytes[0]));
|
|
|
|
ZYDIS_CHECK(ZydisInputNext(ctx, info, &prefixBytes[1]));
|
2016-05-26 03:25:48 +08:00
|
|
|
// Decode xop-prefix
|
|
|
|
info->encoding = ZYDIS_INSTRUCTION_ENCODING_XOP;
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_CHECK(ZydisDecodeXOP(ctx, info, prefixBytes[0], prefixBytes[1]));
|
2016-05-26 03:25:48 +08:00
|
|
|
info->opcodeMap = ZYDIS_OPCODE_MAP_XOP8 + info->details.xop.m_mmmm - 0x08;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2016-11-12 05:03:26 +08:00
|
|
|
default:
|
|
|
|
break;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ZYDIS_OPCODE_MAP_0F:
|
|
|
|
switch (info->opcode)
|
|
|
|
{
|
|
|
|
case 0x0F:
|
|
|
|
info->encoding = ZYDIS_INSTRUCTION_ENCODING_3DNOW;
|
|
|
|
info->opcodeMap = ZYDIS_OPCODE_MAP_DEFAULT;
|
|
|
|
break;
|
|
|
|
case 0x38:
|
|
|
|
info->opcodeMap = ZYDIS_OPCODE_MAP_0F38;
|
|
|
|
break;
|
|
|
|
case 0x3A:
|
|
|
|
info->opcodeMap = ZYDIS_OPCODE_MAP_0F3A;
|
|
|
|
break;
|
2016-11-12 05:03:26 +08:00
|
|
|
default:
|
|
|
|
break;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ZYDIS_OPCODE_MAP_0F38:
|
|
|
|
case ZYDIS_OPCODE_MAP_0F3A:
|
|
|
|
case ZYDIS_OPCODE_MAP_XOP8:
|
|
|
|
case ZYDIS_OPCODE_MAP_XOP9:
|
|
|
|
case ZYDIS_OPCODE_MAP_XOPA:
|
|
|
|
// Nothing to do here
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ZYDIS_UNREACHABLE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ZYDIS_INSTRUCTION_ENCODING_3DNOW:
|
|
|
|
// All 3dnow (0x0F 0x0F) instructions are using the same operand encoding. We just
|
|
|
|
// decode a random (pi2fw) instruction and extract the actual opcode later.
|
|
|
|
*index = 0x0C;
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
2016-05-26 03:25:48 +08:00
|
|
|
default:
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_CHECK(ZydisInputNext(ctx, info, &info->opcode));
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
*index = info->opcode;
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
|
2016-12-05 09:24:01 +08:00
|
|
|
static ZydisStatus ZydisNodeHandlerXop(ZydisInstructionInfo* info, uint16_t* index)
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
|
|
|
ZYDIS_ASSERT(info);
|
|
|
|
ZYDIS_ASSERT(index);
|
|
|
|
|
|
|
|
switch (info->encoding)
|
|
|
|
{
|
|
|
|
case ZYDIS_INSTRUCTION_ENCODING_DEFAULT:
|
|
|
|
*index = 0;
|
|
|
|
break;
|
|
|
|
case ZYDIS_INSTRUCTION_ENCODING_XOP:
|
|
|
|
ZYDIS_ASSERT(info->details.xop.isDecoded);
|
|
|
|
*index = (info->details.xop.m_mmmm - 0x08) + 1;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ZYDIS_UNREACHABLE;
|
|
|
|
}
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
|
2017-04-13 03:00:46 +08:00
|
|
|
static ZydisStatus ZydisNodeHandlerMode(ZydisDecoderContext* ctx, uint16_t* index)
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_ASSERT(ctx);
|
2016-05-26 03:25:48 +08:00
|
|
|
ZYDIS_ASSERT(index);
|
|
|
|
|
2017-04-13 03:12:18 +08:00
|
|
|
*index = (ctx->operatingMode == ZYDIS_OPERATING_MODE_64BIT) ? 0 : 1;
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
|
2016-12-05 09:24:01 +08:00
|
|
|
static ZydisStatus ZydisNodeHandlerVex(ZydisInstructionInfo* info, uint16_t* index)
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
|
|
|
ZYDIS_ASSERT(info);
|
|
|
|
ZYDIS_ASSERT(index);
|
|
|
|
|
|
|
|
switch (info->encoding)
|
|
|
|
{
|
|
|
|
case ZYDIS_INSTRUCTION_ENCODING_DEFAULT:
|
|
|
|
*index = 0;
|
|
|
|
break;
|
|
|
|
case ZYDIS_INSTRUCTION_ENCODING_VEX:
|
|
|
|
ZYDIS_ASSERT(info->details.vex.isDecoded);
|
|
|
|
*index = info->details.vex.m_mmmm + (info->details.vex.pp << 2);
|
|
|
|
break;
|
|
|
|
case ZYDIS_INSTRUCTION_ENCODING_EVEX:
|
|
|
|
ZYDIS_ASSERT(info->details.evex.isDecoded);
|
|
|
|
*index = info->details.evex.mm + (info->details.evex.pp << 2);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ZYDIS_UNREACHABLE;
|
|
|
|
}
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
|
2017-04-13 03:00:46 +08:00
|
|
|
static ZydisStatus ZydisNodeHandlerMandatoryPrefix(ZydisDecoderContext* ctx, uint16_t* index)
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
|
|
|
ZYDIS_ASSERT(index);
|
|
|
|
|
2016-12-05 09:24:01 +08:00
|
|
|
// 0x66 has precedence over 0xF2 and 0xF3
|
2017-04-11 09:18:08 +08:00
|
|
|
if (ctx->hasUnusedPrefix66)
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
2017-04-11 09:18:08 +08:00
|
|
|
ctx->hasUnusedPrefix66 = 0;
|
2016-12-05 09:24:01 +08:00
|
|
|
*index = 1;
|
|
|
|
} else
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
2017-04-11 09:18:08 +08:00
|
|
|
switch (ctx->hasUnusedPrefixF2F3)
|
2016-12-05 09:24:01 +08:00
|
|
|
{
|
|
|
|
case 0xF3:
|
2017-04-11 09:18:08 +08:00
|
|
|
ctx->hasUnusedPrefixF2F3 = 0;
|
2016-12-05 09:24:01 +08:00
|
|
|
*index = 2;
|
|
|
|
|
|
|
|
break;
|
|
|
|
case 0xF2:
|
2017-04-11 09:18:08 +08:00
|
|
|
ctx->hasUnusedPrefixF2F3 = 0;
|
2016-12-05 09:24:01 +08:00
|
|
|
*index = 3;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
2016-12-05 09:24:01 +08:00
|
|
|
|
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
|
2017-04-11 08:19:53 +08:00
|
|
|
static ZydisStatus ZydisNodeHandlerModrmMod(ZydisDecoderContext* decoder,
|
2016-05-26 03:25:48 +08:00
|
|
|
ZydisInstructionInfo* info, uint16_t* index)
|
|
|
|
{
|
|
|
|
ZYDIS_ASSERT(decoder);
|
|
|
|
ZYDIS_ASSERT(info);
|
|
|
|
ZYDIS_ASSERT(index);
|
|
|
|
|
|
|
|
if (!info->details.modrm.isDecoded)
|
|
|
|
{
|
|
|
|
uint8_t modrmByte;
|
|
|
|
ZYDIS_CHECK(ZydisInputNext(decoder, info, &modrmByte));
|
2016-12-05 09:24:01 +08:00
|
|
|
ZydisDecodeModRM(modrmByte, info);
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
*index = (info->details.modrm.mod == 0x3) ? 1 : 0;
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
|
2017-04-11 08:19:53 +08:00
|
|
|
static ZydisStatus ZydisNodeHandlerModrmReg(ZydisDecoderContext* decoder,
|
2016-05-26 03:25:48 +08:00
|
|
|
ZydisInstructionInfo* info, uint16_t* index)
|
|
|
|
{
|
|
|
|
ZYDIS_ASSERT(decoder);
|
|
|
|
ZYDIS_ASSERT(info);
|
|
|
|
ZYDIS_ASSERT(index);
|
|
|
|
|
|
|
|
if (!info->details.modrm.isDecoded)
|
|
|
|
{
|
|
|
|
uint8_t modrmByte;
|
|
|
|
ZYDIS_CHECK(ZydisInputNext(decoder, info, &modrmByte));
|
2016-12-05 09:24:01 +08:00
|
|
|
ZydisDecodeModRM(modrmByte, info);
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
*index = info->details.modrm.reg;
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
|
2017-04-11 08:19:53 +08:00
|
|
|
static ZydisStatus ZydisNodeHandlerModrmRm(ZydisDecoderContext* decoder,
|
2016-05-26 03:25:48 +08:00
|
|
|
ZydisInstructionInfo* info, uint16_t* index)
|
|
|
|
{
|
|
|
|
ZYDIS_ASSERT(decoder);
|
|
|
|
ZYDIS_ASSERT(info);
|
|
|
|
ZYDIS_ASSERT(index);
|
|
|
|
|
|
|
|
if (!info->details.modrm.isDecoded)
|
|
|
|
{
|
|
|
|
uint8_t modrmByte;
|
|
|
|
ZYDIS_CHECK(ZydisInputNext(decoder, info, &modrmByte));
|
2016-12-05 09:24:01 +08:00
|
|
|
ZydisDecodeModRM(modrmByte, info);
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
*index = info->details.modrm.rm;
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
|
2017-04-13 03:00:46 +08:00
|
|
|
static ZydisStatus ZydisNodeHandlerOperandSize(ZydisDecoderContext* ctx,
|
2016-05-26 03:25:48 +08:00
|
|
|
ZydisInstructionInfo* info, uint16_t* index)
|
|
|
|
{
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_ASSERT(ctx);
|
2016-05-26 03:25:48 +08:00
|
|
|
ZYDIS_ASSERT(info);
|
|
|
|
ZYDIS_ASSERT(index);
|
|
|
|
|
2016-12-05 09:24:01 +08:00
|
|
|
info->attributes |= ZYDIS_ATTRIB_ACCEPTS_OPERANDSIZE;
|
2017-04-11 09:18:08 +08:00
|
|
|
if (ctx->hasUnusedPrefix66)
|
2016-12-05 09:24:01 +08:00
|
|
|
{
|
|
|
|
info->attributes |= ZYDIS_ATTRIB_HAS_OPERANDSIZE;
|
2017-04-11 09:18:08 +08:00
|
|
|
ctx->hasUnusedPrefix66 = 0;
|
2016-12-05 09:24:01 +08:00
|
|
|
}
|
2016-11-14 09:10:59 +08:00
|
|
|
|
2017-04-11 09:18:08 +08:00
|
|
|
switch (ctx->operatingMode)
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
2017-04-13 03:12:18 +08:00
|
|
|
case ZYDIS_OPERATING_MODE_16BIT:
|
2016-12-05 09:24:01 +08:00
|
|
|
*index = (info->attributes & ZYDIS_ATTRIB_HAS_OPERANDSIZE) ? 1 : 0;
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
2017-04-13 03:12:18 +08:00
|
|
|
case ZYDIS_OPERATING_MODE_32BIT:
|
|
|
|
case ZYDIS_OPERATING_MODE_64BIT:
|
2016-12-05 09:24:01 +08:00
|
|
|
*index = (info->attributes & ZYDIS_ATTRIB_HAS_OPERANDSIZE) ? 0 : 1;
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ZYDIS_UNREACHABLE;
|
|
|
|
}
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
|
2017-04-13 03:00:46 +08:00
|
|
|
static ZydisStatus ZydisNodeHandlerAddressSize(ZydisDecoderContext* ctx,
|
2016-05-26 03:25:48 +08:00
|
|
|
ZydisInstructionInfo* info, uint16_t* index)
|
|
|
|
{
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_ASSERT(ctx);
|
2016-05-26 03:25:48 +08:00
|
|
|
ZYDIS_ASSERT(info);
|
|
|
|
ZYDIS_ASSERT(index);
|
|
|
|
|
2016-12-05 09:24:01 +08:00
|
|
|
info->attributes |= ZYDIS_ATTRIB_ACCEPTS_ADDRESSSIZE;
|
|
|
|
if (info->details.prefixes.has67)
|
|
|
|
{
|
|
|
|
info->attributes |= ZYDIS_ATTRIB_HAS_ADDRESSSIZE;
|
|
|
|
}
|
2016-11-14 09:10:59 +08:00
|
|
|
|
2017-04-11 09:18:08 +08:00
|
|
|
switch (ctx->operatingMode)
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
2017-04-13 03:12:18 +08:00
|
|
|
case ZYDIS_OPERATING_MODE_16BIT:
|
2016-12-05 09:24:01 +08:00
|
|
|
*index = (info->attributes & ZYDIS_ATTRIB_HAS_ADDRESSSIZE) ? 1 : 0;
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
2017-04-13 03:12:18 +08:00
|
|
|
case ZYDIS_OPERATING_MODE_32BIT:
|
2016-12-05 09:24:01 +08:00
|
|
|
*index = (info->attributes & ZYDIS_ATTRIB_HAS_ADDRESSSIZE) ? 0 : 1;
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
2017-04-13 03:12:18 +08:00
|
|
|
case ZYDIS_OPERATING_MODE_64BIT:
|
2016-12-05 09:24:01 +08:00
|
|
|
*index = (info->attributes & ZYDIS_ATTRIB_HAS_ADDRESSSIZE) ? 1 : 2;
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ZYDIS_UNREACHABLE;
|
|
|
|
}
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
|
2017-04-13 03:00:46 +08:00
|
|
|
static ZydisStatus ZydisNodeHandlerRexW(ZydisDecoderContext* ctx, ZydisInstructionInfo* info,
|
|
|
|
uint16_t* index)
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
|
|
|
ZYDIS_ASSERT(info);
|
|
|
|
ZYDIS_ASSERT(index);
|
|
|
|
|
|
|
|
switch (info->encoding)
|
|
|
|
{
|
|
|
|
case ZYDIS_INSTRUCTION_ENCODING_DEFAULT:
|
|
|
|
// nothing to do here
|
|
|
|
break;
|
|
|
|
case ZYDIS_INSTRUCTION_ENCODING_VEX:
|
|
|
|
ZYDIS_ASSERT(info->details.vex.isDecoded);
|
|
|
|
break;
|
|
|
|
case ZYDIS_INSTRUCTION_ENCODING_EVEX:
|
|
|
|
ZYDIS_ASSERT(info->details.evex.isDecoded);
|
|
|
|
break;
|
|
|
|
case ZYDIS_INSTRUCTION_ENCODING_XOP:
|
|
|
|
ZYDIS_ASSERT(info->details.xop.isDecoded);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ZYDIS_UNREACHABLE;
|
|
|
|
}
|
2017-04-11 09:18:08 +08:00
|
|
|
*index = ctx->internal.W;
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
|
2017-04-13 03:00:46 +08:00
|
|
|
static ZydisStatus ZydisNodeHandlerVexL(ZydisDecoderContext* ctx, ZydisInstructionInfo* info,
|
|
|
|
uint16_t* index)
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
|
|
|
ZYDIS_ASSERT(info);
|
|
|
|
ZYDIS_ASSERT(index);
|
|
|
|
|
|
|
|
switch (info->encoding)
|
|
|
|
{
|
|
|
|
case ZYDIS_INSTRUCTION_ENCODING_VEX:
|
|
|
|
ZYDIS_ASSERT(info->details.vex.isDecoded);
|
|
|
|
break;
|
|
|
|
case ZYDIS_INSTRUCTION_ENCODING_EVEX:
|
|
|
|
ZYDIS_ASSERT(info->details.evex.isDecoded);
|
|
|
|
break;
|
|
|
|
case ZYDIS_INSTRUCTION_ENCODING_XOP:
|
|
|
|
ZYDIS_ASSERT(info->details.xop.isDecoded);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ZYDIS_UNREACHABLE;
|
|
|
|
}
|
2017-04-11 09:18:08 +08:00
|
|
|
*index = ctx->internal.L;
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
|
2016-12-05 09:24:01 +08:00
|
|
|
static ZydisStatus ZydisNodeHandlerEvexL2(ZydisInstructionInfo* info, uint16_t* index)
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
|
|
|
ZYDIS_ASSERT(info);
|
|
|
|
ZYDIS_ASSERT(index);
|
|
|
|
|
|
|
|
ZYDIS_ASSERT(info->encoding == ZYDIS_INSTRUCTION_ENCODING_EVEX);
|
|
|
|
ZYDIS_ASSERT(info->details.evex.isDecoded);
|
2016-12-05 09:24:01 +08:00
|
|
|
*index = info->details.evex.L2;
|
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
|
2016-12-05 09:24:01 +08:00
|
|
|
static ZydisStatus ZydisNodeHandlerEvexB(ZydisInstructionInfo* info, uint16_t* index)
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
|
|
|
ZYDIS_ASSERT(info);
|
|
|
|
ZYDIS_ASSERT(index);
|
|
|
|
|
|
|
|
ZYDIS_ASSERT(info->encoding == ZYDIS_INSTRUCTION_ENCODING_EVEX);
|
|
|
|
ZYDIS_ASSERT(info->details.evex.isDecoded);
|
2016-12-05 09:24:01 +08:00
|
|
|
*index = info->details.evex.b;
|
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Uses the instruction-table to decode the bytestream until an instruction-definition
|
|
|
|
* is found.
|
|
|
|
*
|
2017-04-11 09:18:08 +08:00
|
|
|
* @param ctx A pointer to the @c ZydisDecoderContext instance.
|
|
|
|
* @param info A pointer to the @c ZydisInstructionInfo struct.
|
2016-05-26 03:25:48 +08:00
|
|
|
*
|
|
|
|
* @return A zydis decoder status code.
|
|
|
|
*/
|
2017-04-13 03:00:46 +08:00
|
|
|
static ZydisStatus ZydisDecodeOpcode(ZydisDecoderContext* ctx, ZydisInstructionInfo* info)
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_ASSERT(ctx);
|
2016-05-26 03:25:48 +08:00
|
|
|
ZYDIS_ASSERT(info);
|
|
|
|
|
|
|
|
// Iterate through the instruction table
|
2016-11-23 01:12:05 +08:00
|
|
|
const ZydisInstructionTableNode* node = ZydisInstructionTableGetRootNode();
|
2016-05-26 03:25:48 +08:00
|
|
|
ZydisInstructionTableNodeType nodeType;
|
|
|
|
do
|
|
|
|
{
|
2016-11-23 01:12:05 +08:00
|
|
|
nodeType = node->type;
|
2016-05-26 03:25:48 +08:00
|
|
|
uint16_t index = 0;
|
2016-12-05 09:24:01 +08:00
|
|
|
ZydisStatus status = 0;
|
2016-05-26 03:25:48 +08:00
|
|
|
switch (nodeType)
|
|
|
|
{
|
|
|
|
case ZYDIS_NODETYPE_INVALID:
|
|
|
|
{
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_DECODING_ERROR;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
2016-09-13 11:26:55 +08:00
|
|
|
case ZYDIS_NODETYPE_DEFINITION_0OP:
|
|
|
|
case ZYDIS_NODETYPE_DEFINITION_1OP:
|
|
|
|
case ZYDIS_NODETYPE_DEFINITION_2OP:
|
|
|
|
case ZYDIS_NODETYPE_DEFINITION_3OP:
|
|
|
|
case ZYDIS_NODETYPE_DEFINITION_4OP:
|
|
|
|
case ZYDIS_NODETYPE_DEFINITION_5OP:
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
2016-11-23 01:12:05 +08:00
|
|
|
const ZydisInstructionDefinition* definition = NULL;
|
|
|
|
const ZydisOperandDefinition* operands = NULL;
|
|
|
|
uint8_t operandCount;
|
|
|
|
ZydisInstructionTableGetDefinition(node, &definition, &operands, &operandCount);
|
|
|
|
|
|
|
|
ZYDIS_ASSERT(definition);
|
2016-11-24 17:57:23 +08:00
|
|
|
ZYDIS_ASSERT(operands || (operandCount == 0));
|
2016-11-23 01:12:05 +08:00
|
|
|
|
|
|
|
info->mnemonic = (ZydisInstructionMnemonic)definition->mnemonic;
|
2017-04-11 09:18:08 +08:00
|
|
|
ctx->definition = (void*)definition;
|
|
|
|
ZydisApplyInstructionDefinition(ctx, info);
|
2016-05-26 03:25:48 +08:00
|
|
|
|
|
|
|
if (info->encoding == ZYDIS_INSTRUCTION_ENCODING_3DNOW)
|
|
|
|
{
|
|
|
|
// Save input-buffer state and decode dummy operands
|
2017-04-11 09:18:08 +08:00
|
|
|
const uint8_t* buffer = ctx->input.buffer;
|
|
|
|
size_t bufferLen = ctx->input.bufferLen;
|
2016-05-26 03:25:48 +08:00
|
|
|
uint8_t length = info->length;
|
2016-11-24 17:57:23 +08:00
|
|
|
ZYDIS_ASSERT(operandCount == 2);
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_CHECK(ZydisDecodeOperands(ctx, info, operands, operandCount));
|
2016-05-26 03:25:48 +08:00
|
|
|
// Read actual 3dnow opcode
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_CHECK(ZydisInputNext(ctx, info, &info->opcode));
|
2016-05-26 03:25:48 +08:00
|
|
|
// Restore input-buffer state
|
2017-04-11 09:18:08 +08:00
|
|
|
ctx->input.buffer = buffer;
|
|
|
|
ctx->input.bufferLen = bufferLen;
|
2016-05-26 03:25:48 +08:00
|
|
|
info->length = length;
|
|
|
|
node = ZydisInstructionTableGetRootNode();
|
|
|
|
node = ZydisInstructionTableGetChildNode(node, 0x0F);
|
|
|
|
node = ZydisInstructionTableGetChildNode(node, 0x0F);
|
|
|
|
node = ZydisInstructionTableGetChildNode(node, info->opcode);
|
2016-11-23 01:12:05 +08:00
|
|
|
if (node->type == ZYDIS_NODETYPE_INVALID)
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_DECODING_ERROR;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
node = ZydisInstructionTableGetChildNode(node,
|
|
|
|
(info->details.modrm.mod == 0x3) ? 1 : 0);
|
2016-12-05 09:24:01 +08:00
|
|
|
|
|
|
|
// Decode actual operands and fix the instruction-info
|
2016-11-23 01:12:05 +08:00
|
|
|
ZydisInstructionTableGetDefinition(node, &definition, &operands, &operandCount);
|
|
|
|
ZYDIS_ASSERT(definition);
|
2016-11-24 17:57:23 +08:00
|
|
|
ZYDIS_ASSERT(operands && (operandCount == 2));
|
2016-12-05 09:24:01 +08:00
|
|
|
|
2016-11-23 01:12:05 +08:00
|
|
|
info->mnemonic = (ZydisInstructionMnemonic)definition->mnemonic;
|
2017-04-11 09:18:08 +08:00
|
|
|
ctx->definition = (void*)definition;
|
|
|
|
ZydisApplyInstructionDefinition(ctx, info);
|
2016-12-05 09:24:01 +08:00
|
|
|
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_CHECK(ZydisDecodeOperands(ctx, info, operands, operandCount));
|
2016-12-05 09:24:01 +08:00
|
|
|
|
2017-04-11 09:18:08 +08:00
|
|
|
return ZydisInputNext(ctx, info, &info->opcode);
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
|
2016-11-24 17:57:23 +08:00
|
|
|
if (operandCount != 0)
|
|
|
|
{
|
2017-04-11 09:18:08 +08:00
|
|
|
ZYDIS_CHECK(ZydisDecodeOperands(ctx, info, operands, operandCount));
|
2016-11-24 17:57:23 +08:00
|
|
|
}
|
2016-05-26 03:25:48 +08:00
|
|
|
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
case ZYDIS_NODETYPE_FILTER_OPCODE:
|
2017-04-11 09:18:08 +08:00
|
|
|
status = ZydisNodeHandlerOpcode(ctx, info, &index);
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case ZYDIS_NODETYPE_FILTER_VEX:
|
|
|
|
status = ZydisNodeHandlerVex(info, &index);
|
|
|
|
break;
|
|
|
|
case ZYDIS_NODETYPE_FILTER_XOP:
|
|
|
|
status = ZydisNodeHandlerXop(info, &index);
|
|
|
|
break;
|
|
|
|
case ZYDIS_NODETYPE_FILTER_MODE:
|
2017-04-11 09:18:08 +08:00
|
|
|
status = ZydisNodeHandlerMode(ctx, &index);
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case ZYDIS_NODETYPE_FILTER_MANDATORYPREFIX:
|
2017-04-11 09:18:08 +08:00
|
|
|
status = ZydisNodeHandlerMandatoryPrefix(ctx, &index);
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case ZYDIS_NODETYPE_FILTER_MODRMMOD:
|
2017-04-11 09:18:08 +08:00
|
|
|
status = ZydisNodeHandlerModrmMod(ctx, info, &index);
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case ZYDIS_NODETYPE_FILTER_MODRMREG:
|
2017-04-11 09:18:08 +08:00
|
|
|
status = ZydisNodeHandlerModrmReg(ctx, info, &index);
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case ZYDIS_NODETYPE_FILTER_MODRMRM:
|
2017-04-11 09:18:08 +08:00
|
|
|
status = ZydisNodeHandlerModrmRm(ctx, info, &index);
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case ZYDIS_NODETYPE_FILTER_OPERANDSIZE:
|
2017-04-11 09:18:08 +08:00
|
|
|
status = ZydisNodeHandlerOperandSize(ctx, info, &index);
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case ZYDIS_NODETYPE_FILTER_ADDRESSSIZE:
|
2017-04-11 09:18:08 +08:00
|
|
|
status = ZydisNodeHandlerAddressSize(ctx, info, &index);
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case ZYDIS_NODETYPE_FILTER_REXW:
|
2017-04-11 09:18:08 +08:00
|
|
|
status = ZydisNodeHandlerRexW(ctx, info, &index);
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case ZYDIS_NODETYPE_FILTER_VEXL:
|
2017-04-11 09:18:08 +08:00
|
|
|
status = ZydisNodeHandlerVexL(ctx, info, &index);
|
2016-05-26 03:25:48 +08:00
|
|
|
break;
|
|
|
|
case ZYDIS_NODETYPE_FILTER_EVEXL2:
|
|
|
|
status = ZydisNodeHandlerEvexL2(info, &index);
|
|
|
|
break;
|
|
|
|
case ZYDIS_NODETYPE_FILTER_EVEXB:
|
|
|
|
status = ZydisNodeHandlerEvexB(info, &index);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ZYDIS_UNREACHABLE;
|
|
|
|
}
|
|
|
|
ZYDIS_CHECK(status);
|
|
|
|
node = ZydisInstructionTableGetChildNode(node, index);
|
2016-09-13 11:26:55 +08:00
|
|
|
} while((nodeType != ZYDIS_NODETYPE_INVALID) &&
|
|
|
|
(nodeType != ZYDIS_NODETYPE_DEFINITION_0OP) &&
|
|
|
|
(nodeType != ZYDIS_NODETYPE_DEFINITION_1OP) &&
|
|
|
|
(nodeType != ZYDIS_NODETYPE_DEFINITION_2OP) &&
|
|
|
|
(nodeType != ZYDIS_NODETYPE_DEFINITION_3OP) &&
|
|
|
|
(nodeType != ZYDIS_NODETYPE_DEFINITION_4OP) &&
|
|
|
|
(nodeType != ZYDIS_NODETYPE_DEFINITION_5OP));
|
2016-12-05 09:24:01 +08:00
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
2016-05-26 03:25:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
/* ============================================================================================== */
|
|
|
|
/* Exported functions */
|
|
|
|
/* ============================================================================================== */
|
|
|
|
|
2017-04-13 03:00:46 +08:00
|
|
|
ZydisStatus ZydisDecode(ZydisOperatingMode operatingMode, const void* buffer, size_t bufferLen,
|
|
|
|
uint64_t instructionPointer, ZydisInstructionInfo* info)
|
2017-01-11 18:20:24 +08:00
|
|
|
{
|
2017-04-11 08:19:53 +08:00
|
|
|
return ZydisDecodeEx(
|
|
|
|
operatingMode, buffer, bufferLen, instructionPointer,
|
|
|
|
ZYDIS_DECODE_GRANULARITY_DEFAULT, info);
|
2017-01-11 18:20:24 +08:00
|
|
|
}
|
|
|
|
|
2017-04-13 03:00:46 +08:00
|
|
|
ZydisStatus ZydisDecodeEx(ZydisOperatingMode operatingMode, const void* buffer, size_t bufferLen,
|
|
|
|
uint64_t instructionPointer, ZydisDecodeGranularity granularity, ZydisInstructionInfo* info)
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
2017-04-13 03:12:18 +08:00
|
|
|
if ((operatingMode != ZYDIS_OPERATING_MODE_16BIT) &&
|
|
|
|
(operatingMode != ZYDIS_OPERATING_MODE_32BIT) &&
|
|
|
|
(operatingMode != ZYDIS_OPERATING_MODE_64BIT))
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
|
|
|
return ZYDIS_STATUS_INVALID_PARAMETER;
|
|
|
|
}
|
2017-04-11 08:19:53 +08:00
|
|
|
|
|
|
|
if (!buffer || !bufferLen)
|
2016-05-26 03:25:48 +08:00
|
|
|
{
|
|
|
|
return ZYDIS_STATUS_NO_MORE_DATA;
|
|
|
|
}
|
2017-04-11 08:19:53 +08:00
|
|
|
|
|
|
|
ZydisDecoderContext ctx;
|
2017-04-13 03:00:46 +08:00
|
|
|
memset(&ctx.internal, 0, sizeof(ctx.internal));
|
2017-04-11 08:19:53 +08:00
|
|
|
ctx.operatingMode = operatingMode;
|
|
|
|
ctx.granularity = granularity;
|
2017-04-13 03:00:46 +08:00
|
|
|
if (granularity == ZYDIS_DECODE_GRANULARITY_DEFAULT)
|
|
|
|
{
|
|
|
|
ctx.granularity = ZYDIS_DECODE_GRANULARITY_FULL;
|
|
|
|
}
|
2017-04-11 08:19:53 +08:00
|
|
|
ctx.input.buffer = (uint8_t*)buffer;
|
|
|
|
ctx.input.bufferLen = bufferLen;
|
|
|
|
ctx.hasUnusedPrefix66 = 0;
|
|
|
|
ctx.hasUnusedPrefixF2F3 = 0;
|
|
|
|
ctx.lastSegmentPrefix = 0;
|
|
|
|
ctx.imm8initialized = ZYDIS_FALSE;
|
2016-11-12 05:03:26 +08:00
|
|
|
|
2017-01-13 03:14:12 +08:00
|
|
|
void* userData = info->userData;
|
2016-05-26 03:25:48 +08:00
|
|
|
memset(info, 0, sizeof(*info));
|
2017-04-11 08:19:53 +08:00
|
|
|
info->mode = ctx.operatingMode;
|
2017-01-13 03:14:12 +08:00
|
|
|
info->instrAddress = instructionPointer;
|
|
|
|
info->userData = userData;
|
2016-05-26 03:25:48 +08:00
|
|
|
|
2017-04-11 08:19:53 +08:00
|
|
|
ZYDIS_CHECK(ZydisCollectOptionalPrefixes(&ctx, info));
|
|
|
|
ZYDIS_CHECK(ZydisDecodeOpcode(&ctx, info));
|
2016-05-26 03:25:48 +08:00
|
|
|
|
2017-01-11 18:20:24 +08:00
|
|
|
// TODO: The index, dest and mask regs for AVX2 gathers must be different.
|
|
|
|
// TODO: More EVEX UD conditions (page 81)
|
2016-12-06 04:06:29 +08:00
|
|
|
// Set AVX-512 info
|
2017-04-11 08:19:53 +08:00
|
|
|
if (info->encoding == ZYDIS_INSTRUCTION_ENCODING_EVEX)
|
2016-12-06 04:06:29 +08:00
|
|
|
{
|
2017-04-13 03:00:46 +08:00
|
|
|
const ZydisInstructionDefinition* definition = (ZydisInstructionDefinition*)ctx.definition;
|
2016-12-06 04:06:29 +08:00
|
|
|
|
|
|
|
switch (definition->evexContext)
|
|
|
|
{
|
|
|
|
case ZYDIS_EVEX_CONTEXT_INVALID:
|
|
|
|
if (info->details.evex.b)
|
|
|
|
{
|
|
|
|
return ZYDIS_STATUS_DECODING_ERROR; // TODO:
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ZYDIS_EVEX_CONTEXT_BC:
|
|
|
|
break;
|
|
|
|
case ZYDIS_EVEX_CONTEXT_RC:
|
|
|
|
info->avx.roundingMode =
|
|
|
|
(((info->details.evex.L2 & 0x01) << 1) | info->details.evex.L) + 1;
|
|
|
|
break;
|
|
|
|
case ZYDIS_EVEX_CONTEXT_SAE:
|
|
|
|
info->avx.hasSAE = ZYDIS_TRUE;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
info->avx.broadcast = ZYDIS_AVX512_BCSTMODE_INVALID;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (definition->evexMaskPolicy)
|
|
|
|
{
|
|
|
|
case ZYDIS_AVX512_MASKPOLICY_MASK_ACCEPTED:
|
|
|
|
info->avx.maskRegister = ZYDIS_REGISTER_K0 + info->details.evex.aaa;
|
|
|
|
break;
|
|
|
|
case ZYDIS_AVX512_MASKPOLICY_MASK_REQUIRED:
|
|
|
|
if (info->details.evex.aaa == 0)
|
|
|
|
{
|
2017-01-11 18:20:24 +08:00
|
|
|
return ZYDIS_STATUS_INVALID_MASK;
|
2016-12-06 04:06:29 +08:00
|
|
|
}
|
|
|
|
info->avx.maskRegister = ZYDIS_REGISTER_K0 + info->details.evex.aaa;
|
|
|
|
break;
|
|
|
|
case ZYDIS_AVX512_MASKPOLICY_MASK_FORBIDDEN:
|
|
|
|
if (info->details.evex.aaa != 0)
|
|
|
|
{
|
2017-01-11 18:20:24 +08:00
|
|
|
return ZYDIS_STATUS_INVALID_MASK;
|
2016-12-06 04:06:29 +08:00
|
|
|
}
|
|
|
|
info->avx.maskRegister = ZYDIS_REGISTER_K0;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ZYDIS_UNREACHABLE;
|
|
|
|
}
|
2017-04-11 08:19:53 +08:00
|
|
|
|
2017-01-11 18:20:24 +08:00
|
|
|
if (info->details.evex.z)
|
2016-12-06 04:06:29 +08:00
|
|
|
{
|
2017-01-11 18:20:24 +08:00
|
|
|
if (!definition->evexZeroMaskAccepted)
|
|
|
|
{
|
|
|
|
return ZYDIS_STATUS_INVALID_MASK;
|
|
|
|
}
|
|
|
|
info->avx.maskMode = ZYDIS_AVX512_MASKMODE_MERGE;
|
2016-12-06 04:06:29 +08:00
|
|
|
} else
|
|
|
|
{
|
|
|
|
info->avx.maskMode = ZYDIS_AVX512_MASKMODE_MERGE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-05 09:24:01 +08:00
|
|
|
// Replace XCHG rAX, rAX with NOP alias
|
|
|
|
if (info->mnemonic == ZYDIS_MNEMONIC_XCHG)
|
|
|
|
{
|
|
|
|
if (((info->operands[0].reg == ZYDIS_REGISTER_RAX) &&
|
|
|
|
(info->operands[1].reg == ZYDIS_REGISTER_RAX)) ||
|
|
|
|
((info->operands[0].reg == ZYDIS_REGISTER_EAX) &&
|
|
|
|
(info->operands[1].reg == ZYDIS_REGISTER_EAX)) ||
|
|
|
|
((info->operands[0].reg == ZYDIS_REGISTER_AX) &&
|
|
|
|
(info->operands[1].reg == ZYDIS_REGISTER_AX)))
|
|
|
|
{
|
|
|
|
info->mnemonic = ZYDIS_MNEMONIC_NOP;
|
|
|
|
info->operandCount = 0;
|
|
|
|
memset(&info->operands[0], 0, sizeof(ZydisOperandInfo) * 2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-26 03:25:48 +08:00
|
|
|
return ZYDIS_STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ============================================================================================== */
|