cbeed6396f
Merge commit '6fa8d51479e9a5542c67bec715a1f68e7ed057ba'
1402 lines
48 KiB
C
1402 lines
48 KiB
C
/***************************************************************************************************
|
|
|
|
Zyan Disassembler Library (Zydis)
|
|
|
|
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.
|
|
|
|
***************************************************************************************************/
|
|
|
|
/**
|
|
* @file
|
|
* Disassembles a given hex-buffer and prints detailed information about the decoded
|
|
* instruction, the operands and additional attributes.
|
|
*/
|
|
|
|
#include <inttypes.h>
|
|
#include <Zycore/API/Terminal.h>
|
|
#include <Zycore/LibC.h>
|
|
#include <Zydis/Zydis.h>
|
|
|
|
/* ============================================================================================== */
|
|
/* Colors */
|
|
/* ============================================================================================== */
|
|
|
|
/* ---------------------------------------------------------------------------------------------- */
|
|
/* Configuration */
|
|
/* ---------------------------------------------------------------------------------------------- */
|
|
|
|
#define COLOR_DEFAULT ZYAN_VT100SGR_FG_DEFAULT
|
|
#define COLOR_ERROR ZYAN_VT100SGR_FG_BRIGHT_RED
|
|
#define COLOR_HEADER ZYAN_VT100SGR_FG_DEFAULT
|
|
#define COLOR_HEADER_TITLE ZYAN_VT100SGR_FG_CYAN
|
|
#define COLOR_VALUE_LABEL ZYAN_VT100SGR_FG_DEFAULT
|
|
#define COLOR_VALUE_R ZYAN_VT100SGR_FG_BRIGHT_RED
|
|
#define COLOR_VALUE_G ZYAN_VT100SGR_FG_BRIGHT_GREEN
|
|
#define COLOR_VALUE_B ZYAN_VT100SGR_FG_CYAN
|
|
|
|
/* ---------------------------------------------------------------------------------------------- */
|
|
/* Global variables */
|
|
/* ---------------------------------------------------------------------------------------------- */
|
|
|
|
static ZyanBool g_vt100_stdout;
|
|
static ZyanBool g_vt100_stderr;
|
|
|
|
/* ---------------------------------------------------------------------------------------------- */
|
|
/* Helper macros */
|
|
/* ---------------------------------------------------------------------------------------------- */
|
|
|
|
/**
|
|
* Conditionally expands to the passed VT100 sequence, if `g_colors_stdout` is
|
|
* `ZYAN_TRUE`, or an empty string, if not.
|
|
*
|
|
* @param The VT100 SGT sequence.
|
|
*/
|
|
#define CVT100_OUT(sequence) (g_vt100_stdout ? (sequence) : "")
|
|
|
|
/**
|
|
* Conditionally expands to the passed VT100 sequence, if `g_colors_stderr` is
|
|
* `ZYAN_TRUE`, or an empty string, if not.
|
|
*
|
|
* @param The VT100 SGT sequence.
|
|
*/
|
|
#define CVT100_ERR(sequence) (g_vt100_stderr ? (sequence) : "")
|
|
|
|
/* ---------------------------------------------------------------------------------------------- */
|
|
|
|
/* ============================================================================================== */
|
|
/* Helper functions */
|
|
/* ============================================================================================== */
|
|
|
|
/* ---------------------------------------------------------------------------------------------- */
|
|
/* General */
|
|
/* ---------------------------------------------------------------------------------------------- */
|
|
|
|
/**
|
|
* Formats the given zyan status code to a human readable string.
|
|
*
|
|
* @param status The zyan status code.
|
|
*
|
|
* @return The status code string.
|
|
*/
|
|
static const char* FormatZyanStatus(ZyanStatus status)
|
|
{
|
|
static const char* strings_zycore[] =
|
|
{
|
|
/* 00 */ "SUCCESS",
|
|
/* 01 */ "FAILED",
|
|
/* 02 */ "TRUE",
|
|
/* 03 */ "FALSE",
|
|
/* 04 */ "INVALID_ARGUMENT",
|
|
/* 05 */ "INVALID_OPERATION",
|
|
/* 06 */ "NOT_FOUND",
|
|
/* 07 */ "OUT_OF_RANGE",
|
|
/* 08 */ "INSUFFICIENT_BUFFER_SIZE",
|
|
/* 09 */ "NOT_ENOUGH_MEMORY",
|
|
/* 0A */ "NOT_ENOUGH_MEMORY",
|
|
/* 0B */ "BAD_SYSTEMCALL"
|
|
};
|
|
static const char* strings_zydis[] =
|
|
{
|
|
/* 00 */ "NO_MORE_DATA",
|
|
/* 01 */ "DECODING_ERROR",
|
|
/* 02 */ "INSTRUCTION_TOO_LONG",
|
|
/* 03 */ "BAD_REGISTER",
|
|
/* 04 */ "ILLEGAL_LOCK",
|
|
/* 05 */ "ILLEGAL_LEGACY_PFX",
|
|
/* 06 */ "ILLEGAL_REX",
|
|
/* 07 */ "INVALID_MAP",
|
|
/* 08 */ "MALFORMED_EVEX",
|
|
/* 09 */ "MALFORMED_MVEX",
|
|
/* 0A */ "INVALID_MASK",
|
|
/* 0B */ "SKIP_TOKEN",
|
|
/* 0C */ "IMPOSSIBLE_INSTRUCTION"
|
|
};
|
|
|
|
if (ZYAN_STATUS_MODULE(status) == ZYAN_MODULE_ZYCORE)
|
|
{
|
|
status = ZYAN_STATUS_CODE(status);
|
|
ZYAN_ASSERT(status < ZYAN_ARRAY_LENGTH(strings_zycore));
|
|
return strings_zycore[status];
|
|
}
|
|
|
|
if (ZYAN_STATUS_MODULE(status) == ZYAN_MODULE_ZYDIS)
|
|
{
|
|
status = ZYAN_STATUS_CODE(status);
|
|
ZYAN_ASSERT(status < ZYAN_ARRAY_LENGTH(strings_zydis));
|
|
return strings_zydis[status];
|
|
}
|
|
|
|
ZYAN_UNREACHABLE;
|
|
}
|
|
|
|
/**
|
|
* Returns the action string for a specific CPU/FPU flag.
|
|
*
|
|
* @param accessed_flags A pointer to the `ZydisAccessedFlags` struct.
|
|
* @param flag The number of the flag.
|
|
*
|
|
* @return The action string for the requested flag, or `ZYAN_NULL`.
|
|
*/
|
|
static const char* GetAccessedFlagActionString(const ZydisAccessedFlags* accessed_flags,
|
|
ZyanU8 flag)
|
|
{
|
|
ZYAN_ASSERT(flag < 32);
|
|
|
|
const char* result = ZYAN_NULL;
|
|
|
|
if (accessed_flags->tested & (1 << flag))
|
|
{
|
|
result = "T";
|
|
}
|
|
if (accessed_flags->modified & (1 << flag))
|
|
{
|
|
result = (result == ZYAN_NULL) ? "M" : "T_M";
|
|
return result;
|
|
}
|
|
|
|
if (accessed_flags->set_0 & (1 << flag))
|
|
{
|
|
return "0";
|
|
}
|
|
if (accessed_flags->set_1 & (1 << flag))
|
|
{
|
|
return "1";
|
|
}
|
|
if (accessed_flags->undefined & (1 << flag))
|
|
{
|
|
return "U";
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------------------------------- */
|
|
/* Text output */
|
|
/* ---------------------------------------------------------------------------------------------- */
|
|
|
|
/**
|
|
* Prints the given error message and status code.
|
|
* @param status The status code.
|
|
* @param message The error message.
|
|
*/
|
|
static void PrintStatusError(ZyanStatus status, const char* message)
|
|
{
|
|
ZYAN_ASSERT(ZYAN_FAILED(status));
|
|
|
|
if (ZYAN_STATUS_MODULE(status) >= ZYAN_MODULE_USER)
|
|
{
|
|
ZYAN_FPRINTF(ZYAN_STDERR,
|
|
"%s%s: User defined status code [0x%" PRIx32 "]%s\n",
|
|
CVT100_ERR(COLOR_ERROR), message, status,
|
|
CVT100_ERR(ZYAN_VT100SGR_RESET));
|
|
}
|
|
else
|
|
{
|
|
ZYAN_FPRINTF(ZYAN_STDERR, "%s%s: %s [0x%" PRIx32 "]%s\n",
|
|
CVT100_ERR(COLOR_ERROR), message, FormatZyanStatus(status), status,
|
|
CVT100_ERR(ZYAN_VT100SGR_RESET));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Prints a section header.
|
|
*
|
|
* @param name The section name.
|
|
*/
|
|
static void PrintSectionHeader(const char* name)
|
|
{
|
|
ZYAN_ASSERT(ZYAN_STRLEN(name) <= 8);
|
|
ZYAN_PRINTF("%s== [ %s%8s%s ] ==============================================================" \
|
|
"==============================%s\n",
|
|
CVT100_OUT(COLOR_HEADER), CVT100_OUT(COLOR_HEADER_TITLE), name, CVT100_OUT(COLOR_HEADER),
|
|
CVT100_OUT(COLOR_DEFAULT));
|
|
}
|
|
|
|
/**
|
|
* Prints a value label.
|
|
*
|
|
* @param name The value name.
|
|
*/
|
|
static void PrintValueLabel(const char* name)
|
|
{
|
|
ZYAN_ASSERT(ZYAN_STRLEN(name) <= 11);
|
|
ZYAN_PRINTF("%s%11s:%s ", CVT100_OUT(COLOR_VALUE_LABEL), name, CVT100_OUT(COLOR_DEFAULT));
|
|
}
|
|
|
|
/**
|
|
* Prints a formatted value using red color.
|
|
*
|
|
* @param name The value name.
|
|
* @param format The format string.
|
|
* @param ... The format arguments.
|
|
*/
|
|
#define PRINT_VALUE_R(name, format, ...) \
|
|
PrintValueLabel(name); \
|
|
ZYAN_PRINTF("%s" format "%s\n", CVT100_OUT(COLOR_VALUE_R), __VA_ARGS__, \
|
|
CVT100_OUT(COLOR_DEFAULT));
|
|
|
|
/**
|
|
* Prints a formatted value using green color.
|
|
*
|
|
* @param name The value name.
|
|
* @param format The format string.
|
|
* @param ... The format arguments.
|
|
*/
|
|
#define PRINT_VALUE_G(name, format, ...) \
|
|
PrintValueLabel(name); \
|
|
ZYAN_PRINTF("%s" format "%s\n", CVT100_OUT(COLOR_VALUE_G), __VA_ARGS__, \
|
|
CVT100_OUT(COLOR_DEFAULT));
|
|
|
|
/**
|
|
* Prints a formatted value using blue color.
|
|
*
|
|
* @param name The value name.
|
|
* @param format The format string.
|
|
* @param ... The format arguments.
|
|
*/
|
|
#define PRINT_VALUE_B(name, format, ...) \
|
|
PrintValueLabel(name); \
|
|
ZYAN_PRINTF("%s" format "%s\n", CVT100_OUT(COLOR_VALUE_B), __VA_ARGS__, \
|
|
CVT100_OUT(COLOR_DEFAULT));
|
|
|
|
/* ---------------------------------------------------------------------------------------------- */
|
|
|
|
/* ============================================================================================== */
|
|
/* Print functions */
|
|
/* ============================================================================================== */
|
|
|
|
#if !defined(ZYDIS_DISABLE_SEGMENT)
|
|
|
|
/**
|
|
* Prints instruction segments (parts).
|
|
*
|
|
* @param instruction A pointer to the `ZydisDecodedInstruction` struct.
|
|
* @param buffer The buffer that contains the instruction bytes.
|
|
* @param print_hints Controls the printing of descriptive hints.
|
|
*/
|
|
static void PrintSegments(const ZydisDecodedInstruction* instruction, const ZyanU8* buffer,
|
|
ZyanBool print_hints)
|
|
{
|
|
ZydisInstructionSegments segments;
|
|
ZydisGetInstructionSegments(instruction, &segments);
|
|
|
|
struct
|
|
{
|
|
ZyanU8 pos;
|
|
const char* color;
|
|
const char* name;
|
|
} print_info[ZYAN_ARRAY_LENGTH(segments.segments)];
|
|
|
|
ZyanU8 pos = 0;
|
|
ZyanU8 imm = 0;
|
|
for (ZyanU8 i = 0; i < segments.count; ++i)
|
|
{
|
|
print_info[i].pos = pos;
|
|
|
|
switch (segments.segments[i].type)
|
|
{
|
|
case ZYDIS_INSTR_SEGMENT_PREFIXES:
|
|
print_info[i].color = CVT100_OUT(ZYAN_VT100SGR_FG_BRIGHT_MAGENTA);
|
|
print_info[i].name = "PREFIXES";
|
|
break;
|
|
case ZYDIS_INSTR_SEGMENT_REX:
|
|
print_info[i].color = CVT100_OUT(ZYAN_VT100SGR_FG_MAGENTA);
|
|
print_info[i].name = "REX";
|
|
break;
|
|
case ZYDIS_INSTR_SEGMENT_XOP:
|
|
print_info[i].color = CVT100_OUT(ZYAN_VT100SGR_FG_MAGENTA);
|
|
print_info[i].name = "XOP";
|
|
break;
|
|
case ZYDIS_INSTR_SEGMENT_VEX:
|
|
print_info[i].color = CVT100_OUT(ZYAN_VT100SGR_FG_MAGENTA);
|
|
print_info[i].name = "VEX";
|
|
break;
|
|
case ZYDIS_INSTR_SEGMENT_EVEX:
|
|
print_info[i].color = CVT100_OUT(ZYAN_VT100SGR_FG_MAGENTA);
|
|
print_info[i].name = "EVEX";
|
|
break;
|
|
case ZYDIS_INSTR_SEGMENT_MVEX:
|
|
print_info[i].color = CVT100_OUT(ZYAN_VT100SGR_FG_MAGENTA);
|
|
print_info[i].name = "MVEX";
|
|
break;
|
|
case ZYDIS_INSTR_SEGMENT_OPCODE:
|
|
print_info[i].color = CVT100_OUT(ZYAN_VT100SGR_FG_CYAN);
|
|
print_info[i].name = "OPCODE";
|
|
break;
|
|
case ZYDIS_INSTR_SEGMENT_MODRM:
|
|
print_info[i].color = CVT100_OUT(ZYAN_VT100SGR_FG_GREEN);
|
|
print_info[i].name = "MODRM";
|
|
break;
|
|
case ZYDIS_INSTR_SEGMENT_SIB:
|
|
print_info[i].color = CVT100_OUT(ZYAN_VT100SGR_FG_BRIGHT_GREEN);
|
|
print_info[i].name = "SIB";
|
|
break;
|
|
case ZYDIS_INSTR_SEGMENT_DISPLACEMENT:
|
|
print_info[i].color = CVT100_OUT(ZYAN_VT100SGR_FG_BRIGHT_YELLOW);
|
|
print_info[i].name = "DISP";
|
|
break;
|
|
case ZYDIS_INSTR_SEGMENT_IMMEDIATE:
|
|
if (imm == 0)
|
|
{
|
|
print_info[i].color = CVT100_OUT(ZYAN_VT100SGR_FG_YELLOW);
|
|
imm = 1;
|
|
} else
|
|
{
|
|
print_info[i].color = CVT100_OUT(ZYAN_VT100SGR_FG_BRIGHT_YELLOW);
|
|
}
|
|
print_info[i].name = "IMM";
|
|
break;
|
|
default:
|
|
ZYAN_UNREACHABLE;
|
|
}
|
|
|
|
ZYAN_PRINTF("%s", print_info[i].color);
|
|
for (int j = 0; j < segments.segments[i].size; ++j)
|
|
{
|
|
if (segments.segments[i].type == ZYDIS_INSTR_SEGMENT_PREFIXES)
|
|
{
|
|
ZYAN_ASSERT(segments.segments[i].size <= instruction->raw.prefix_count);
|
|
switch (instruction->raw.prefixes[j].type)
|
|
{
|
|
case ZYDIS_PREFIX_TYPE_IGNORED:
|
|
ZYAN_PRINTF("%s%02X%s ", CVT100_OUT(ZYAN_VT100SGR_FG_BRIGHT_BLACK),
|
|
buffer[segments.segments[i].offset + j], print_info[i].color);
|
|
pos += 3;
|
|
break;
|
|
case ZYDIS_PREFIX_TYPE_EFFECTIVE:
|
|
pos += (ZyanU8)ZYAN_PRINTF("%02X ", buffer[segments.segments[i].offset + j]);
|
|
break;
|
|
case ZYDIS_PREFIX_TYPE_MANDATORY:
|
|
ZYAN_PRINTF("%s%02X%s ",
|
|
CVT100_OUT(ZYAN_VT100SGR_FG_CYAN),
|
|
buffer[segments.segments[i].offset + j], print_info[i].color);
|
|
pos += 3;
|
|
break;
|
|
default:
|
|
ZYAN_UNREACHABLE;
|
|
}
|
|
} else
|
|
{
|
|
pos += (ZyanU8)ZYAN_PRINTF("%02X ", buffer[segments.segments[i].offset + j]);
|
|
}
|
|
}
|
|
}
|
|
ZYAN_PRINTF("%s\n", CVT100_OUT(COLOR_DEFAULT));
|
|
|
|
if (!print_hints)
|
|
{
|
|
return;
|
|
}
|
|
|
|
for (ZyanU8 i = 0; i < segments.count; ++i)
|
|
{
|
|
ZyanU8 j = 0;
|
|
ZyanU8 k = 0;
|
|
while (j <= print_info[segments.count - i - 1].pos)
|
|
{
|
|
if (j == print_info[k].pos)
|
|
{
|
|
ZYAN_PRINTF("%s:", print_info[k].color);
|
|
++k;
|
|
} else
|
|
{
|
|
ZYAN_PRINTF(" ");
|
|
}
|
|
++j;
|
|
}
|
|
ZYAN_PRINTF("..%s%s\n", print_info[segments.count - i - 1].color,
|
|
print_info[segments.count - i - 1].name);
|
|
}
|
|
|
|
ZYAN_PRINTF(CVT100_OUT(COLOR_DEFAULT));
|
|
}
|
|
|
|
#endif
|
|
|
|
#if !defined(ZYDIS_DISABLE_ENCODER)
|
|
|
|
/**
|
|
* Prints a size optimized form of the input instruction.
|
|
*
|
|
* @param decoder A pointer to the `ZydisDecoder` instance.
|
|
* @param instruction A pointer to the `ZydisDecodedInstruction` struct.
|
|
* @param operands A pointer to the `operands` array.
|
|
* @param operand_count The length of the `operands` array.
|
|
*/
|
|
static void PrintSizeOptimizedForm(const ZydisDecoder* decoder,
|
|
const ZydisDecodedInstruction* instruction, const ZydisDecodedOperand* operands,
|
|
ZyanU8 operand_count)
|
|
{
|
|
ZydisEncoderRequest request;
|
|
ZyanStatus status = ZydisEncoderDecodedInstructionToEncoderRequest(instruction, operands,
|
|
operand_count, &request);
|
|
if (!ZYAN_SUCCESS(status))
|
|
{
|
|
PrintStatusError(status, "Failed to craft encoder request");
|
|
exit(status);
|
|
}
|
|
|
|
ZyanU8 data[ZYDIS_MAX_INSTRUCTION_LENGTH];
|
|
ZyanUSize len = sizeof(data);
|
|
status = ZydisEncoderEncodeInstruction(&request, data, &len);
|
|
if (!ZYAN_SUCCESS(status))
|
|
{
|
|
PrintStatusError(status, "Could not encode instruction");
|
|
exit(status);
|
|
}
|
|
|
|
ZydisDecodedInstruction new_instruction;
|
|
status = ZydisDecoderDecodeInstruction(decoder, ZYAN_NULL, &data, len, &new_instruction);
|
|
if (!ZYAN_SUCCESS(status))
|
|
{
|
|
PrintStatusError(status, "Could not decode instruction");
|
|
exit(status);
|
|
}
|
|
|
|
#if !defined(ZYDIS_DISABLE_SEGMENT)
|
|
PrintSegments(&new_instruction, &data[0], ZYAN_FALSE);
|
|
#endif
|
|
}
|
|
|
|
#endif
|
|
|
|
/**
|
|
* Prints instruction operands info.
|
|
*
|
|
* @param instruction A pointer to the `ZydisDecodedInstruction` struct.
|
|
* @param operands A pointer to the first `ZydisDecodedOperand` struct of the instruction.
|
|
*/
|
|
static void PrintOperands(const ZydisDecodedInstruction* instruction,
|
|
const ZydisDecodedOperand* operands)
|
|
{
|
|
PrintSectionHeader("OPERANDS");
|
|
ZYAN_PRINTF("%s## TYPE VISIBILITY ACTION ENCODING SIZE NELEM ELEMSZ ELEMTY" \
|
|
"PE VALUE%s\n", CVT100_OUT(COLOR_HEADER), CVT100_OUT(COLOR_DEFAULT));
|
|
ZYAN_PRINTF("%s-- --------- ---------- ------ ------------ ---- ----- ------ ------" \
|
|
"-- ---------------------------%s\n", CVT100_OUT(COLOR_HEADER), CVT100_OUT(COLOR_DEFAULT));
|
|
|
|
ZyanU8 imm_id = 0;
|
|
for (ZyanU8 i = 0; i < instruction->operand_count; ++i)
|
|
{
|
|
static const char* strings_operand_type[] =
|
|
{
|
|
"UNUSED",
|
|
"REGISTER",
|
|
"MEMORY",
|
|
"POINTER",
|
|
"IMMEDIATE"
|
|
};
|
|
ZYAN_ASSERT(ZYAN_ARRAY_LENGTH(strings_operand_type) == ZYDIS_OPERAND_TYPE_MAX_VALUE + 1);
|
|
|
|
static const char* strings_operand_visibility[] =
|
|
{
|
|
"INVALID",
|
|
"EXPLICIT",
|
|
"IMPLICIT",
|
|
"HIDDEN"
|
|
};
|
|
ZYAN_ASSERT(ZYAN_ARRAY_LENGTH(strings_operand_visibility) == ZYDIS_OPERAND_VISIBILITY_MAX_VALUE + 1);
|
|
|
|
static const char* strings_operand_actions[] =
|
|
{
|
|
"NONE", // 0 0 0 0
|
|
"R", // 0 0 0 1
|
|
"W", // 0 0 1 0
|
|
"RW", // 0 0 1 1
|
|
"CR", // 0 1 0 0
|
|
"-", // 0 1 0 1
|
|
"CRW", // 0 1 1 0
|
|
"-", // 0 1 1 1
|
|
"CW", // 1 0 0 0
|
|
"RCW", // 1 0 0 1
|
|
"-", // 1 0 1 0
|
|
"-", // 1 0 1 1
|
|
"CRCW", // 1 1 0 0
|
|
"-", // 1 1 0 1
|
|
"-" // 1 1 1 1
|
|
};
|
|
|
|
static const char* strings_element_type[] =
|
|
{
|
|
"INVALID",
|
|
"STRUCT",
|
|
"UINT",
|
|
"INT",
|
|
"FLOAT16",
|
|
"FLOAT32",
|
|
"FLOAT64",
|
|
"FLOAT80",
|
|
"LONGBCD",
|
|
"CC"
|
|
};
|
|
ZYAN_ASSERT(ZYAN_ARRAY_LENGTH(strings_element_type) == ZYDIS_ELEMENT_TYPE_MAX_VALUE + 1);
|
|
|
|
static const char* strings_operand_encoding[] =
|
|
{
|
|
"NONE",
|
|
"MODRM_REG",
|
|
"MODRM_RM",
|
|
"OPCODE",
|
|
"NDSNDD",
|
|
"IS4",
|
|
"MASK",
|
|
"DISP8",
|
|
"DISP16",
|
|
"DISP32",
|
|
"DISP64",
|
|
"DISP16_32_64",
|
|
"DISP32_32_64",
|
|
"DISP16_32_32",
|
|
"UIMM8",
|
|
"UIMM16",
|
|
"UIMM32",
|
|
"UIMM64",
|
|
"UIMM16_32_64",
|
|
"UIMM32_32_64",
|
|
"UIMM16_32_32",
|
|
"SIMM8",
|
|
"SIMM16",
|
|
"SIMM32",
|
|
"SIMM64",
|
|
"SIMM16_32_64",
|
|
"SIMM32_32_64",
|
|
"SIMM16_32_32",
|
|
"JIMM8",
|
|
"JIMM16",
|
|
"JIMM32",
|
|
"JIMM64",
|
|
"JIMM16_32_64",
|
|
"JIMM32_32_64",
|
|
"JIMM16_32_32"
|
|
};
|
|
ZYAN_ASSERT(ZYAN_ARRAY_LENGTH(strings_operand_encoding) == ZYDIS_OPERAND_ENCODING_MAX_VALUE + 1);
|
|
|
|
static const char* strings_memop_type[] =
|
|
{
|
|
"INVALID",
|
|
"MEM",
|
|
"AGEN",
|
|
"MIB",
|
|
"VSIB"
|
|
};
|
|
ZYAN_ASSERT(ZYAN_ARRAY_LENGTH(strings_memop_type) == ZYDIS_MEMOP_TYPE_MAX_VALUE + 1);
|
|
|
|
ZYAN_PRINTF("%s%2d %s%9s %10s %6s %12s %s%5d %4d %6d %s%8s%s",
|
|
CVT100_OUT(COLOR_VALUE_G),
|
|
i,
|
|
CVT100_OUT(COLOR_VALUE_B),
|
|
strings_operand_type[operands[i].type],
|
|
strings_operand_visibility[operands[i].visibility],
|
|
strings_operand_actions[operands[i].actions],
|
|
strings_operand_encoding[operands[i].encoding],
|
|
CVT100_OUT(COLOR_VALUE_G),
|
|
operands[i].size,
|
|
operands[i].element_count,
|
|
operands[i].element_size,
|
|
CVT100_OUT(COLOR_VALUE_B),
|
|
strings_element_type[operands[i].element_type],
|
|
CVT100_OUT(COLOR_DEFAULT));
|
|
switch (operands[i].type)
|
|
{
|
|
case ZYDIS_OPERAND_TYPE_REGISTER:
|
|
ZYAN_PRINTF(" %s%27s%s", CVT100_OUT(COLOR_VALUE_R),
|
|
ZydisRegisterGetString(operands[i].reg.value),
|
|
CVT100_OUT(COLOR_DEFAULT));
|
|
break;
|
|
case ZYDIS_OPERAND_TYPE_MEMORY:
|
|
ZYAN_PRINTF(" %sTYPE =%s%20s%s\n", CVT100_OUT(COLOR_VALUE_LABEL),
|
|
CVT100_OUT(COLOR_VALUE_B), strings_memop_type[operands[i].mem.type],
|
|
CVT100_OUT(COLOR_DEFAULT));
|
|
ZYAN_PRINTF(" %s%84s =%s%20s%s\n",
|
|
CVT100_OUT(COLOR_VALUE_LABEL), "SEG ", CVT100_OUT(COLOR_VALUE_R),
|
|
ZydisRegisterGetString(operands[i].mem.segment),
|
|
CVT100_OUT(COLOR_DEFAULT));
|
|
ZYAN_PRINTF(" %s%84s =%s%20s%s\n",
|
|
CVT100_OUT(COLOR_VALUE_LABEL), "BASE ", CVT100_OUT(COLOR_VALUE_R),
|
|
ZydisRegisterGetString(operands[i].mem.base),
|
|
CVT100_OUT(COLOR_DEFAULT));
|
|
ZYAN_PRINTF(" %s%84s =%s%20s%s\n",
|
|
CVT100_OUT(COLOR_VALUE_LABEL), "INDEX", CVT100_OUT(COLOR_VALUE_R),
|
|
ZydisRegisterGetString(operands[i].mem.index),
|
|
CVT100_OUT(COLOR_DEFAULT));
|
|
ZYAN_PRINTF(" %s%84s =%s%20d%s\n",
|
|
CVT100_OUT(COLOR_VALUE_LABEL), "SCALE", CVT100_OUT(COLOR_VALUE_G),
|
|
operands[i].mem.scale,
|
|
CVT100_OUT(COLOR_DEFAULT));
|
|
ZYAN_PRINTF(" %s%84s = %s0x%016" PRIX64 "%s",
|
|
CVT100_OUT(COLOR_VALUE_LABEL), "DISP ", CVT100_OUT(COLOR_VALUE_G),
|
|
operands[i].mem.disp.value,
|
|
CVT100_OUT(COLOR_DEFAULT));
|
|
break;
|
|
case ZYDIS_OPERAND_TYPE_POINTER:
|
|
ZYAN_PRINTF(" %sSEG = %s0x%04" PRIX16 "%s\n",
|
|
CVT100_OUT(COLOR_VALUE_LABEL), CVT100_OUT(COLOR_VALUE_G),
|
|
operands[i].ptr.segment,
|
|
CVT100_OUT(COLOR_DEFAULT));
|
|
ZYAN_PRINTF(" %s%84s = %s0x%08" PRIX32 "%s",
|
|
CVT100_OUT(COLOR_VALUE_LABEL), "OFF ", CVT100_OUT(COLOR_VALUE_G),
|
|
operands[i].ptr.offset,
|
|
CVT100_OUT(COLOR_DEFAULT));
|
|
break;
|
|
case ZYDIS_OPERAND_TYPE_IMMEDIATE:
|
|
if (operands[i].imm.is_signed)
|
|
{
|
|
ZYAN_PRINTF(" %s[%s%s %s %s%2d%s] %s0x%016" PRIX64 "%s",
|
|
CVT100_OUT(COLOR_VALUE_LABEL),
|
|
CVT100_OUT(COLOR_VALUE_B),
|
|
operands[i].imm.is_signed ? "S" : "U",
|
|
operands[i].imm.is_relative ? "R" : "A",
|
|
CVT100_OUT(COLOR_VALUE_G),
|
|
instruction->raw.imm[imm_id].size,
|
|
CVT100_OUT(COLOR_VALUE_LABEL),
|
|
CVT100_OUT(COLOR_VALUE_G),
|
|
operands[i].imm.value.s,
|
|
CVT100_OUT(COLOR_DEFAULT));
|
|
} else
|
|
{
|
|
ZYAN_PRINTF(" %s[%s%s %s %s%2d%s] %s0x%016" PRIX64 "%s",
|
|
CVT100_OUT(COLOR_VALUE_LABEL),
|
|
CVT100_OUT(COLOR_VALUE_B),
|
|
operands[i].imm.is_signed ? "S" : "U",
|
|
operands[i].imm.is_relative ? "R" : "A",
|
|
CVT100_OUT(COLOR_VALUE_G),
|
|
instruction->raw.imm[imm_id].size,
|
|
CVT100_OUT(COLOR_VALUE_LABEL),
|
|
CVT100_OUT(COLOR_VALUE_G),
|
|
operands[i].imm.value.u,
|
|
CVT100_OUT(COLOR_DEFAULT));
|
|
}
|
|
++imm_id;
|
|
break;
|
|
default:
|
|
ZYAN_UNREACHABLE;
|
|
}
|
|
ZYAN_PUTS("");
|
|
}
|
|
|
|
ZYAN_PRINTF("%s-- --------- ---------- ------ ------------ ---- ----- ------ ------" \
|
|
"-- ---------------------------%s\n", CVT100_OUT(COLOR_HEADER), CVT100_OUT(COLOR_DEFAULT));
|
|
}
|
|
|
|
/**
|
|
* Prints instruction flags info.
|
|
*
|
|
* @param instruction A pointer to the `ZydisDecodedInstruction` struct.
|
|
*/
|
|
static void PrintFlags(const ZydisDecodedInstruction* instruction)
|
|
{
|
|
static const char* strings_cpu_flags[] =
|
|
{
|
|
"CF",
|
|
ZYAN_NULL,
|
|
"PF",
|
|
ZYAN_NULL,
|
|
"AF",
|
|
ZYAN_NULL,
|
|
"ZF",
|
|
"SF",
|
|
"TF",
|
|
"IF",
|
|
"DF",
|
|
"OF",
|
|
"IOPL",
|
|
ZYAN_NULL,
|
|
"NT",
|
|
ZYAN_NULL,
|
|
"RF",
|
|
"VM",
|
|
"AC",
|
|
"VIF",
|
|
"VIP",
|
|
"ID",
|
|
};
|
|
|
|
static const char* strings_fpu_flags[] =
|
|
{
|
|
"C0",
|
|
"C1",
|
|
"C2",
|
|
"C3",
|
|
};
|
|
|
|
typedef struct FlagInfo_
|
|
{
|
|
const char* name;
|
|
const char* action;
|
|
} FlagInfo;
|
|
|
|
FlagInfo flags[ZYAN_ARRAY_LENGTH(strings_cpu_flags) + ZYAN_ARRAY_LENGTH(strings_fpu_flags)];
|
|
ZYAN_MEMSET(flags, 0, sizeof(flags));
|
|
|
|
// CPU
|
|
for (ZyanUSize i = 0; i < ZYAN_ARRAY_LENGTH(strings_cpu_flags); ++i)
|
|
{
|
|
flags[i].name = strings_cpu_flags[i];
|
|
flags[i].action = GetAccessedFlagActionString(instruction->cpu_flags, (ZyanU8)i);
|
|
}
|
|
|
|
// FPU
|
|
const ZyanUSize offset = ZYAN_ARRAY_LENGTH(strings_cpu_flags);
|
|
for (ZyanUSize i = 0; i < ZYAN_ARRAY_LENGTH(strings_fpu_flags); ++i)
|
|
{
|
|
flags[offset + i].name = strings_fpu_flags[i];
|
|
flags[offset + i].action = GetAccessedFlagActionString(instruction->fpu_flags, (ZyanU8)i);
|
|
}
|
|
|
|
PrintSectionHeader("FLAGS");
|
|
|
|
PrintValueLabel("ACTIONS");
|
|
|
|
ZyanU8 c = 0;
|
|
for (ZyanUSize i = 0; i < ZYAN_ARRAY_LENGTH(flags); ++i)
|
|
{
|
|
if (flags[i].action == ZYAN_NULL)
|
|
{
|
|
continue;
|
|
}
|
|
if (c && (c % 8 == 0))
|
|
{
|
|
ZYAN_PRINTF("\n ");
|
|
}
|
|
++c;
|
|
ZYAN_PRINTF("%s[%s%-4s%s: %s%-3s%s]%s ",
|
|
CVT100_OUT(COLOR_VALUE_LABEL), CVT100_OUT(COLOR_VALUE_B),
|
|
flags[i].name,
|
|
CVT100_OUT(COLOR_VALUE_LABEL), CVT100_OUT(COLOR_VALUE_B),
|
|
flags[i].action,
|
|
CVT100_OUT(COLOR_VALUE_LABEL), CVT100_OUT(COLOR_DEFAULT));
|
|
}
|
|
ZYAN_PUTS("");
|
|
|
|
PRINT_VALUE_G("READ", "0x%08" PRIX32, instruction->cpu_flags->tested);
|
|
PRINT_VALUE_G("WRITTEN", "0x%08" PRIX32,
|
|
instruction->cpu_flags->modified |
|
|
instruction->cpu_flags->set_0 |
|
|
instruction->cpu_flags->set_1 |
|
|
instruction->cpu_flags->undefined);
|
|
}
|
|
|
|
/**
|
|
* Prints instruction AVX info.
|
|
*
|
|
* @param instruction A pointer to the `ZydisDecodedInstruction` struct.
|
|
*/
|
|
static void PrintAVXInfo(const ZydisDecodedInstruction* instruction)
|
|
{
|
|
static const char* strings_broadcast_mode[] =
|
|
{
|
|
"NONE",
|
|
"1_TO_2",
|
|
"1_TO_4",
|
|
"1_TO_8",
|
|
"1_TO_16",
|
|
"1_TO_32",
|
|
"1_TO_64",
|
|
"2_TO_4",
|
|
"2_TO_8",
|
|
"2_TO_16",
|
|
"4_TO_8",
|
|
"4_TO_16",
|
|
"8_TO_16"
|
|
};
|
|
ZYAN_ASSERT(ZYAN_ARRAY_LENGTH(strings_broadcast_mode) == ZYDIS_BROADCAST_MODE_MAX_VALUE + 1);
|
|
|
|
static const char* strings_mask_mode[] =
|
|
{
|
|
"INVALID",
|
|
"DISABLED",
|
|
"MERGING",
|
|
"ZEROING",
|
|
"CONTROL",
|
|
"CONTROL_ZEROING"
|
|
};
|
|
ZYAN_ASSERT(ZYAN_ARRAY_LENGTH(strings_mask_mode) == ZYDIS_MASK_MODE_MAX_VALUE + 1);
|
|
|
|
static const char* strings_rounding_mode[] =
|
|
{
|
|
"DEFAULT",
|
|
"RN",
|
|
"RD",
|
|
"RU",
|
|
"RZ"
|
|
};
|
|
ZYAN_ASSERT(ZYAN_ARRAY_LENGTH(strings_rounding_mode) == ZYDIS_ROUNDING_MODE_MAX_VALUE + 1);
|
|
|
|
static const char* strings_swizzle_mode[] =
|
|
{
|
|
"NONE",
|
|
"DCBA",
|
|
"CDAB",
|
|
"BADC",
|
|
"DACB",
|
|
"AAAA",
|
|
"BBBB",
|
|
"CCCC",
|
|
"DDDD"
|
|
};
|
|
ZYAN_ASSERT(ZYAN_ARRAY_LENGTH(strings_swizzle_mode) == ZYDIS_SWIZZLE_MODE_MAX_VALUE + 1);
|
|
|
|
static const char* strings_conversion_mode[] =
|
|
{
|
|
"NONE",
|
|
"FLOAT16",
|
|
"SINT8",
|
|
"UINT8",
|
|
"SINT16",
|
|
"UINT16"
|
|
};
|
|
ZYAN_ASSERT(ZYAN_ARRAY_LENGTH(strings_conversion_mode) == ZYDIS_CONVERSION_MODE_MAX_VALUE + 1);
|
|
|
|
PrintSectionHeader("AVX");
|
|
|
|
PRINT_VALUE_B("VECTORLEN", "%03d", instruction->avx.vector_length);
|
|
PRINT_VALUE_B("BROADCAST", "%s%s%s", strings_broadcast_mode[instruction->avx.broadcast.mode],
|
|
CVT100_OUT(COLOR_VALUE_LABEL), instruction->avx.broadcast.is_static ? " (static)" : "");
|
|
|
|
switch (instruction->encoding)
|
|
{
|
|
case ZYDIS_INSTRUCTION_ENCODING_EVEX:
|
|
PRINT_VALUE_B("ROUNDING", "%s", strings_rounding_mode[instruction->avx.rounding.mode]);
|
|
PRINT_VALUE_B("SAE", "%s", instruction->avx.has_sae ? "Y" : "N");
|
|
PRINT_VALUE_R("MASK", "%s %s[%s%s%s]",
|
|
ZydisRegisterGetString(instruction->avx.mask.reg),
|
|
CVT100_OUT(COLOR_VALUE_LABEL), CVT100_OUT(COLOR_VALUE_B),
|
|
strings_mask_mode[instruction->avx.mask.mode], CVT100_OUT(COLOR_VALUE_LABEL));
|
|
break;
|
|
case ZYDIS_INSTRUCTION_ENCODING_MVEX:
|
|
PRINT_VALUE_B("ROUNDING", "%s", strings_rounding_mode[instruction->avx.rounding.mode]);
|
|
PRINT_VALUE_B("SAE", "%s", instruction->avx.has_sae ? "Y" : "N");
|
|
PRINT_VALUE_R("MASK", "%s %s[%sMERGING%s]",
|
|
ZydisRegisterGetString(instruction->avx.mask.reg),
|
|
CVT100_OUT(COLOR_VALUE_LABEL), CVT100_OUT(COLOR_VALUE_B),
|
|
CVT100_OUT(COLOR_VALUE_LABEL));
|
|
PRINT_VALUE_B("EH", "%s", instruction->avx.has_eviction_hint ? "Y" : "N");
|
|
PRINT_VALUE_B("SWIZZLE", "%s", strings_swizzle_mode[instruction->avx.swizzle.mode]);
|
|
PRINT_VALUE_B("CONVERT", "%s", strings_conversion_mode[instruction->avx.conversion.mode]);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Prints the tokenized instruction.
|
|
*
|
|
* @param token A pointer to the first token.
|
|
*/
|
|
static void PrintTokenizedInstruction(const ZydisFormatterToken* token)
|
|
{
|
|
ZyanStatus status = ZYAN_STATUS_SUCCESS;
|
|
while (ZYAN_SUCCESS(status))
|
|
{
|
|
ZydisTokenType type;
|
|
ZyanConstCharPointer value;
|
|
if (!ZYAN_SUCCESS(status = ZydisFormatterTokenGetValue(token, &type, &value)))
|
|
{
|
|
PrintStatusError(status, "Failed to get token value");
|
|
exit(status);
|
|
}
|
|
|
|
const char* color;
|
|
switch (token->type)
|
|
{
|
|
case ZYDIS_TOKEN_DELIMITER:
|
|
ZYAN_FALLTHROUGH;
|
|
case ZYDIS_TOKEN_PARENTHESIS_OPEN:
|
|
ZYAN_FALLTHROUGH;
|
|
case ZYDIS_TOKEN_PARENTHESIS_CLOSE:
|
|
color = CVT100_OUT(ZYAN_VT100SGR_FG_WHITE);
|
|
break;
|
|
case ZYDIS_TOKEN_PREFIX:
|
|
case ZYDIS_TOKEN_MNEMONIC:
|
|
color = CVT100_OUT(ZYAN_VT100SGR_FG_BRIGHT_RED);
|
|
break;
|
|
case ZYDIS_TOKEN_REGISTER:
|
|
color = CVT100_OUT(ZYAN_VT100SGR_FG_CYAN);
|
|
break;
|
|
case ZYDIS_TOKEN_ADDRESS_ABS:
|
|
case ZYDIS_TOKEN_ADDRESS_REL:
|
|
case ZYDIS_TOKEN_DISPLACEMENT:
|
|
color = CVT100_OUT(ZYAN_VT100SGR_FG_BRIGHT_GREEN);
|
|
break;
|
|
case ZYDIS_TOKEN_IMMEDIATE:
|
|
color = CVT100_OUT(ZYAN_VT100SGR_FG_GREEN);
|
|
break;
|
|
case ZYDIS_TOKEN_TYPECAST:
|
|
case ZYDIS_TOKEN_DECORATOR:
|
|
color = CVT100_OUT(ZYAN_VT100SGR_FG_WHITE);
|
|
break;
|
|
default:
|
|
color = CVT100_OUT(COLOR_DEFAULT);
|
|
break;
|
|
}
|
|
ZYAN_PRINTF("%s%s", color, value);
|
|
|
|
status = ZydisFormatterTokenNext(&token);
|
|
}
|
|
ZYAN_ASSERT(status == ZYAN_STATUS_OUT_OF_RANGE);
|
|
|
|
ZYAN_PRINTF("%s\n", CVT100_OUT(COLOR_DEFAULT));
|
|
}
|
|
|
|
/**
|
|
* Prints the formatted instruction disassembly.
|
|
*
|
|
* @param instruction A pointer to the `ZydisDecodedInstruction` struct.
|
|
* @param operands A pointer to the first `ZydisDecodedOperand` struct of the instruction.
|
|
* @param style The formatter style.
|
|
*/
|
|
static void PrintDisassembly(const ZydisDecodedInstruction* instruction,
|
|
const ZydisDecodedOperand* operands, ZydisFormatterStyle style)
|
|
{
|
|
ZyanStatus status;
|
|
ZydisFormatter formatter;
|
|
|
|
switch (style)
|
|
{
|
|
case ZYDIS_FORMATTER_STYLE_ATT:
|
|
if (!ZYAN_SUCCESS(status = ZydisFormatterInit(&formatter, ZYDIS_FORMATTER_STYLE_ATT)))
|
|
{
|
|
PrintStatusError(status, "Failed to initialize instruction-formatter");
|
|
exit(status);
|
|
}
|
|
PrintSectionHeader("ATT");
|
|
break;
|
|
case ZYDIS_FORMATTER_STYLE_INTEL:
|
|
if (!ZYAN_SUCCESS(status = ZydisFormatterInit(&formatter, ZYDIS_FORMATTER_STYLE_INTEL)) ||
|
|
!ZYAN_SUCCESS(status = ZydisFormatterSetProperty(&formatter,
|
|
ZYDIS_FORMATTER_PROP_FORCE_SEGMENT, ZYAN_TRUE)) ||
|
|
!ZYAN_SUCCESS(status = ZydisFormatterSetProperty(&formatter,
|
|
ZYDIS_FORMATTER_PROP_FORCE_SIZE, ZYAN_TRUE)))
|
|
{
|
|
PrintStatusError(status, "Failed to initialize instruction-formatter");
|
|
exit(status);
|
|
}
|
|
PrintSectionHeader("INTEL");
|
|
break;
|
|
default:
|
|
ZYAN_UNREACHABLE;
|
|
}
|
|
|
|
ZyanU8 buffer[256];
|
|
const ZydisFormatterToken* token;
|
|
|
|
PrintValueLabel("ABSOLUTE");
|
|
if (!ZYAN_SUCCESS(status = ZydisFormatterTokenizeInstruction(&formatter, instruction, operands,
|
|
instruction->operand_count_visible, buffer, sizeof(buffer), 0, &token, NULL)))
|
|
{
|
|
PrintStatusError(status, "Failed to tokenize instruction");
|
|
exit(status);
|
|
}
|
|
PrintTokenizedInstruction(token);
|
|
PrintValueLabel("RELATIVE");
|
|
if (!ZYAN_SUCCESS(status = ZydisFormatterTokenizeInstruction(&formatter, instruction, operands,
|
|
instruction->operand_count_visible, buffer, sizeof(buffer), ZYDIS_RUNTIME_ADDRESS_NONE,
|
|
&token, NULL)))
|
|
{
|
|
PrintStatusError(status, "Failed to tokenize instruction");
|
|
exit(status);
|
|
}
|
|
PrintTokenizedInstruction(token);
|
|
}
|
|
|
|
/**
|
|
* Dumps basic instruction info.
|
|
*
|
|
* @param decoder A pointer to the `ZydisDecoder` instance.
|
|
* @param instruction A pointer to the `ZydisDecodedInstruction` struct.
|
|
* @param operands A pointer to the first `ZydisDecodedOperand` struct of the instruction.
|
|
*/
|
|
static void PrintInstruction(const ZydisDecoder* decoder,
|
|
const ZydisDecodedInstruction* instruction, const ZydisDecodedOperand* operands)
|
|
{
|
|
static const char* opcode_maps[] =
|
|
{
|
|
"DEFAULT",
|
|
"0F",
|
|
"0F38",
|
|
"0F3A",
|
|
"MAP4",
|
|
"MAP5",
|
|
"MAP6",
|
|
"MAP7",
|
|
"0F0F",
|
|
"XOP8",
|
|
"XOP9",
|
|
"XOPA"
|
|
};
|
|
ZYAN_ASSERT(ZYAN_ARRAY_LENGTH(opcode_maps) == ZYDIS_OPCODE_MAP_MAX_VALUE + 1);
|
|
|
|
static const char* instr_encodings[] =
|
|
{
|
|
"DEFAULT",
|
|
"3DNOW",
|
|
"XOP",
|
|
"VEX",
|
|
"EVEX",
|
|
"MVEX"
|
|
};
|
|
ZYAN_ASSERT(ZYAN_ARRAY_LENGTH(instr_encodings) == ZYDIS_INSTRUCTION_ENCODING_MAX_VALUE + 1);
|
|
|
|
static const char* exception_classes[] =
|
|
{
|
|
"NONE",
|
|
"SSE1",
|
|
"SSE2",
|
|
"SSE3",
|
|
"SSE4",
|
|
"SSE5",
|
|
"SSE7",
|
|
"AVX1",
|
|
"AVX2",
|
|
"AVX3",
|
|
"AVX4",
|
|
"AVX5",
|
|
"AVX6",
|
|
"AVX7",
|
|
"AVX8",
|
|
"AVX11",
|
|
"AVX12",
|
|
"E1",
|
|
"E1NF",
|
|
"E2",
|
|
"E2NF",
|
|
"E3",
|
|
"E3NF",
|
|
"E4",
|
|
"E4NF",
|
|
"E5",
|
|
"E5NF",
|
|
"E6",
|
|
"E6NF",
|
|
"E7NM",
|
|
"E7NM128",
|
|
"E9NF",
|
|
"E10",
|
|
"E10NF",
|
|
"E11",
|
|
"E11NF",
|
|
"E12",
|
|
"E12NP",
|
|
"K20",
|
|
"K21",
|
|
"AMXE1",
|
|
"AMXE2",
|
|
"AMXE3",
|
|
"AMXE4",
|
|
"AMXE5",
|
|
"AMXE6"
|
|
};
|
|
ZYAN_ASSERT(ZYAN_ARRAY_LENGTH(exception_classes) == ZYDIS_EXCEPTION_CLASS_MAX_VALUE + 1);
|
|
|
|
static const struct
|
|
{
|
|
ZydisInstructionAttributes attribute_mask;
|
|
const char* str;
|
|
} attribute_map[] =
|
|
{
|
|
{ ZYDIS_ATTRIB_HAS_MODRM, "HAS_MODRM" },
|
|
{ ZYDIS_ATTRIB_HAS_SIB, "HAS_SIB" },
|
|
{ ZYDIS_ATTRIB_HAS_REX, "HAS_REX" },
|
|
{ ZYDIS_ATTRIB_HAS_XOP, "HAS_XOP" },
|
|
{ ZYDIS_ATTRIB_HAS_VEX, "HAS_VEX" },
|
|
{ ZYDIS_ATTRIB_HAS_EVEX, "HAS_EVEX" },
|
|
{ ZYDIS_ATTRIB_HAS_MVEX, "HAS_MVEX" },
|
|
{ ZYDIS_ATTRIB_IS_RELATIVE, "IS_RELATIVE" },
|
|
{ ZYDIS_ATTRIB_IS_PRIVILEGED, "IS_PRIVILEGED" },
|
|
{ ZYDIS_ATTRIB_CPUFLAG_ACCESS, "CPUFLAG_ACCESS" },
|
|
{ ZYDIS_ATTRIB_CPU_STATE_CR, "CPU_STATE_CR" },
|
|
{ ZYDIS_ATTRIB_CPU_STATE_CW, "CPU_STATE_CW" },
|
|
{ ZYDIS_ATTRIB_FPU_STATE_CR, "FPU_STATE_CR" },
|
|
{ ZYDIS_ATTRIB_FPU_STATE_CW, "FPU_STATE_CW" },
|
|
{ ZYDIS_ATTRIB_XMM_STATE_CR, "XMM_STATE_CR" },
|
|
{ ZYDIS_ATTRIB_XMM_STATE_CW, "XMM_STATE_CW" },
|
|
{ ZYDIS_ATTRIB_ACCEPTS_LOCK, "ACCEPTS_LOCK" },
|
|
{ ZYDIS_ATTRIB_ACCEPTS_REP, "ACCEPTS_REP" },
|
|
{ ZYDIS_ATTRIB_ACCEPTS_REPE, "ACCEPTS_REPE" },
|
|
{ ZYDIS_ATTRIB_ACCEPTS_REPZ, "ACCEPTS_REPZ" },
|
|
{ ZYDIS_ATTRIB_ACCEPTS_REPNE, "ACCEPTS_REPNE" },
|
|
{ ZYDIS_ATTRIB_ACCEPTS_REPNZ, "ACCEPTS_REPNZ" },
|
|
{ ZYDIS_ATTRIB_ACCEPTS_BND, "ACCEPTS_BND" },
|
|
{ ZYDIS_ATTRIB_ACCEPTS_XACQUIRE, "ACCEPTS_XACQUIRE" },
|
|
{ ZYDIS_ATTRIB_ACCEPTS_XRELEASE, "ACCEPTS_XRELEASE" },
|
|
{ ZYDIS_ATTRIB_ACCEPTS_HLE_WITHOUT_LOCK, "ACCEPTS_HLE_WITHOUT_LOCK" },
|
|
{ ZYDIS_ATTRIB_ACCEPTS_BRANCH_HINTS, "ACCEPTS_BRANCH_HINTS" },
|
|
{ ZYDIS_ATTRIB_ACCEPTS_SEGMENT, "ACCEPTS_SEGMENT" },
|
|
{ ZYDIS_ATTRIB_HAS_LOCK, "HAS_LOCK" },
|
|
{ ZYDIS_ATTRIB_HAS_REP, "HAS_REP" },
|
|
{ ZYDIS_ATTRIB_HAS_REPE, "HAS_REPE" },
|
|
{ ZYDIS_ATTRIB_HAS_REPZ, "HAS_REPZ" },
|
|
{ ZYDIS_ATTRIB_HAS_REPNE, "HAS_REPNE" },
|
|
{ ZYDIS_ATTRIB_HAS_REPNZ, "HAS_REPNZ" },
|
|
{ ZYDIS_ATTRIB_HAS_BND, "HAS_BND" },
|
|
{ ZYDIS_ATTRIB_HAS_XACQUIRE, "HAS_XACQUIRE" },
|
|
{ ZYDIS_ATTRIB_HAS_XRELEASE, "HAS_XRELEASE" },
|
|
{ ZYDIS_ATTRIB_HAS_BRANCH_NOT_TAKEN, "HAS_BRANCH_NOT_TAKEN" },
|
|
{ ZYDIS_ATTRIB_HAS_BRANCH_TAKEN, "HAS_BRANCH_TAKEN" },
|
|
{ ZYDIS_ATTRIB_HAS_SEGMENT, "HAS_SEGMENT" },
|
|
{ ZYDIS_ATTRIB_HAS_SEGMENT_CS, "HAS_SEGMENT_CS" },
|
|
{ ZYDIS_ATTRIB_HAS_SEGMENT_SS, "HAS_SEGMENT_SS" },
|
|
{ ZYDIS_ATTRIB_HAS_SEGMENT_DS, "HAS_SEGMENT_DS" },
|
|
{ ZYDIS_ATTRIB_HAS_SEGMENT_ES, "HAS_SEGMENT_ES" },
|
|
{ ZYDIS_ATTRIB_HAS_SEGMENT_FS, "HAS_SEGMENT_FS" },
|
|
{ ZYDIS_ATTRIB_HAS_SEGMENT_GS, "HAS_SEGMENT_GS" },
|
|
{ ZYDIS_ATTRIB_HAS_OPERANDSIZE, "HAS_OPERANDSIZE" },
|
|
{ ZYDIS_ATTRIB_HAS_ADDRESSSIZE, "HAS_ADDRESSSIZE" },
|
|
{ ZYDIS_ATTRIB_ACCEPTS_NOTRACK, "ACCEPTS_NOTRACK" },
|
|
{ ZYDIS_ATTRIB_HAS_NOTRACK, "HAS_NOTRACK" }
|
|
};
|
|
|
|
PrintSectionHeader("BASIC");
|
|
PrintValueLabel("MNEMONIC");
|
|
ZYAN_PRINTF("%s%s%s [ENC: %s%s%s, MAP: %s%s%s, OPC: %s0x%02X%s]%s\n",
|
|
CVT100_OUT(COLOR_VALUE_R), ZydisMnemonicGetString(instruction->mnemonic),
|
|
CVT100_OUT(COLOR_VALUE_LABEL),
|
|
CVT100_OUT(COLOR_VALUE_B), instr_encodings[instruction->encoding],
|
|
CVT100_OUT(COLOR_VALUE_LABEL),
|
|
CVT100_OUT(COLOR_VALUE_B), opcode_maps[instruction->opcode_map],
|
|
CVT100_OUT(COLOR_VALUE_LABEL),
|
|
CVT100_OUT(COLOR_VALUE_G), instruction->opcode,
|
|
CVT100_OUT(COLOR_VALUE_LABEL), CVT100_OUT(COLOR_DEFAULT));
|
|
PRINT_VALUE_G("LENGTH" , "%2d", instruction->length);
|
|
PRINT_VALUE_G("SSZ" , "%2d", instruction->stack_width);
|
|
PRINT_VALUE_G("EOSZ" , "%2d", instruction->operand_width);
|
|
PRINT_VALUE_G("EASZ" , "%2d", instruction->address_width);
|
|
PRINT_VALUE_B("CATEGORY" , "%s" , ZydisCategoryGetString(instruction->meta.category));
|
|
PRINT_VALUE_B("ISA-SET" , "%s" , ZydisISASetGetString(instruction->meta.isa_set));
|
|
PRINT_VALUE_B("ISA-EXT" , "%s" , ZydisISAExtGetString(instruction->meta.isa_ext));
|
|
PRINT_VALUE_B("EXCEPTIONS", "%s" , exception_classes[instruction->meta.exception_class]);
|
|
|
|
if (instruction->attributes)
|
|
{
|
|
PrintValueLabel("ATTRIBUTES");
|
|
ZYAN_FPUTS(CVT100_OUT(COLOR_VALUE_B), ZYAN_STDOUT);
|
|
ZyanUSize len_total = 13;
|
|
for (ZyanUSize i = 0; i < ZYAN_ARRAY_LENGTH(attribute_map); ++i)
|
|
{
|
|
if (instruction->attributes & attribute_map[i].attribute_mask)
|
|
{
|
|
const ZyanUSize len = ZYAN_STRLEN(attribute_map[i].str);
|
|
if (len_total + len > 109)
|
|
{
|
|
len_total = 13;
|
|
ZYAN_PRINTF("\n ");
|
|
}
|
|
len_total += ZYAN_PRINTF("%s ", attribute_map[i].str);
|
|
}
|
|
}
|
|
ZYAN_PUTS(CVT100_OUT(COLOR_DEFAULT));
|
|
}
|
|
|
|
#if !defined(ZYDIS_DISABLE_ENCODER)
|
|
|
|
PrintValueLabel("OPTIMIZED");
|
|
PrintSizeOptimizedForm(decoder, instruction, operands, instruction->operand_count_visible);
|
|
|
|
#else
|
|
ZYAN_UNUSED(decoder);
|
|
#endif
|
|
|
|
if (instruction->operand_count > 0)
|
|
{
|
|
ZYAN_PUTS("");
|
|
PrintOperands(instruction, operands);
|
|
}
|
|
|
|
if (instruction->attributes & ZYDIS_ATTRIB_CPUFLAG_ACCESS)
|
|
{
|
|
ZYAN_PUTS("");
|
|
PrintFlags(instruction);
|
|
}
|
|
|
|
if ((instruction->encoding == ZYDIS_INSTRUCTION_ENCODING_XOP) ||
|
|
(instruction->encoding == ZYDIS_INSTRUCTION_ENCODING_VEX) ||
|
|
(instruction->encoding == ZYDIS_INSTRUCTION_ENCODING_EVEX) ||
|
|
(instruction->encoding == ZYDIS_INSTRUCTION_ENCODING_MVEX))
|
|
{
|
|
ZYAN_PUTS("");
|
|
PrintAVXInfo(instruction);
|
|
}
|
|
|
|
ZYAN_PUTS("");
|
|
PrintDisassembly(instruction, operands, ZYDIS_FORMATTER_STYLE_ATT);
|
|
ZYAN_PUTS("");
|
|
PrintDisassembly(instruction, operands, ZYDIS_FORMATTER_STYLE_INTEL);
|
|
}
|
|
|
|
/* ============================================================================================== */
|
|
/* Entry point */
|
|
/* ============================================================================================== */
|
|
|
|
void PrintUsage(int argc, char *argv[])
|
|
{
|
|
ZYAN_FPRINTF(ZYAN_STDERR, "%sUsage: %s <machine_mode> [stack_width] <hexbytes>\n\n"
|
|
"Machine mode: -real|-16|-32|-64\n"
|
|
"Stack width: -16|-32|-64%s\n",
|
|
CVT100_ERR(COLOR_ERROR), (argc > 0 ? argv[0] : "ZydisInfo"),
|
|
CVT100_ERR(ZYAN_VT100SGR_RESET));
|
|
}
|
|
|
|
int main(int argc, char** argv)
|
|
{
|
|
// Enable VT100 escape sequences on Windows, if the output is not redirected
|
|
g_vt100_stdout = (ZyanTerminalIsTTY(ZYAN_STDSTREAM_OUT) == ZYAN_STATUS_TRUE) &&
|
|
ZYAN_SUCCESS(ZyanTerminalEnableVT100(ZYAN_STDSTREAM_OUT));
|
|
g_vt100_stderr = (ZyanTerminalIsTTY(ZYAN_STDSTREAM_ERR) == ZYAN_STATUS_TRUE) &&
|
|
ZYAN_SUCCESS(ZyanTerminalEnableVT100(ZYAN_STDSTREAM_ERR));
|
|
|
|
// ZYAN_PRINTF("%zu\n", sizeof(ZydisDecodedInstruction));
|
|
// ZYAN_PRINTF("%zu\n", sizeof(ZydisDecodedOperand));
|
|
|
|
if (ZydisGetVersion() != ZYDIS_VERSION)
|
|
{
|
|
ZYAN_FPRINTF(ZYAN_STDERR, "%sInvalid zydis version%s\n",
|
|
CVT100_ERR(COLOR_ERROR), CVT100_ERR(ZYAN_VT100SGR_RESET));
|
|
return ZYAN_STATUS_INVALID_OPERATION;
|
|
}
|
|
|
|
if (argc < 3)
|
|
{
|
|
PrintUsage(argc, argv);
|
|
return ZYAN_STATUS_INVALID_ARGUMENT;
|
|
}
|
|
|
|
ZydisDecoder decoder;
|
|
ZydisMachineMode machine_mode;
|
|
ZydisStackWidth stack_width;
|
|
ZyanU8 hexbytes_index = 2;
|
|
if (!ZYAN_STRCMP(argv[1], "-real"))
|
|
{
|
|
machine_mode = ZYDIS_MACHINE_MODE_REAL_16;
|
|
stack_width = ZYDIS_STACK_WIDTH_16;
|
|
} else
|
|
if (!ZYAN_STRCMP(argv[1], "-16"))
|
|
{
|
|
machine_mode = ZYDIS_MACHINE_MODE_LONG_COMPAT_16;
|
|
stack_width = ZYDIS_STACK_WIDTH_16;
|
|
} else
|
|
if (!ZYAN_STRCMP(argv[1], "-32"))
|
|
{
|
|
machine_mode = ZYDIS_MACHINE_MODE_LONG_COMPAT_32;
|
|
stack_width = ZYDIS_STACK_WIDTH_32;
|
|
} else
|
|
if (!ZYAN_STRCMP(argv[1], "-64"))
|
|
{
|
|
machine_mode = ZYDIS_MACHINE_MODE_LONG_64;
|
|
stack_width = ZYDIS_STACK_WIDTH_64;
|
|
} else
|
|
{
|
|
PrintUsage(argc, argv);
|
|
return ZYAN_STATUS_INVALID_ARGUMENT;
|
|
}
|
|
if ((argc > 3) && (argv[2][0] == '-'))
|
|
{
|
|
++hexbytes_index;
|
|
if (!ZYAN_STRCMP(argv[2], "-16"))
|
|
{
|
|
stack_width = ZYDIS_STACK_WIDTH_16;
|
|
} else
|
|
if (!ZYAN_STRCMP(argv[2], "-32"))
|
|
{
|
|
stack_width = ZYDIS_STACK_WIDTH_32;
|
|
} else
|
|
if (!ZYAN_STRCMP(argv[2], "-64"))
|
|
{
|
|
stack_width = ZYDIS_STACK_WIDTH_64;
|
|
} else
|
|
{
|
|
PrintUsage(argc, argv);
|
|
return ZYAN_STATUS_INVALID_ARGUMENT;
|
|
}
|
|
}
|
|
ZyanStatus status = ZydisDecoderInit(&decoder, machine_mode, stack_width);
|
|
if (!ZYAN_SUCCESS(status))
|
|
{
|
|
PrintStatusError(status, "Failed to initialize decoder");
|
|
return status;
|
|
}
|
|
|
|
ZyanU8 data[ZYDIS_MAX_INSTRUCTION_LENGTH];
|
|
ZyanU8 byte_length = 0;
|
|
for (ZyanU8 i = hexbytes_index; i < argc; ++i)
|
|
{
|
|
char* cur_arg = argv[i];
|
|
|
|
// Strip whitespace in-place.
|
|
const ZyanUSize arg_len = ZYAN_STRLEN(cur_arg);
|
|
ZyanUSize write = 0;
|
|
for (ZyanUSize read = 0; read < arg_len; ++read)
|
|
{
|
|
char ch = cur_arg[read];
|
|
if (ch == ' ' || ch == '\t') continue;
|
|
cur_arg[write++] = ch;
|
|
}
|
|
cur_arg[write] = '\0';
|
|
|
|
if (write % 2)
|
|
{
|
|
ZYAN_FPRINTF(ZYAN_STDERR, "%sEven number of hex nibbles expected%s\n",
|
|
CVT100_ERR(COLOR_ERROR), CVT100_ERR(ZYAN_VT100SGR_RESET));
|
|
return ZYAN_STATUS_INVALID_ARGUMENT;
|
|
}
|
|
if ((write / 2) + byte_length > ZYDIS_MAX_INSTRUCTION_LENGTH)
|
|
{
|
|
ZYAN_FPRINTF(ZYAN_STDERR, "%sMaximum number of %d bytes exceeded%s\n",
|
|
CVT100_ERR(COLOR_ERROR), ZYDIS_MAX_INSTRUCTION_LENGTH,
|
|
CVT100_ERR(ZYAN_VT100SGR_RESET));
|
|
return ZYAN_STATUS_INVALID_ARGUMENT;
|
|
}
|
|
for (ZyanU8 j = 0; j < write / 2; ++j)
|
|
{
|
|
unsigned value;
|
|
if (!ZYAN_SSCANF(&cur_arg[j * 2], "%02x", &value))
|
|
{
|
|
ZYAN_FPRINTF(ZYAN_STDERR, "%sInvalid hex value%s\n",
|
|
CVT100_ERR(COLOR_ERROR), CVT100_ERR(ZYAN_VT100SGR_RESET));
|
|
return ZYAN_STATUS_INVALID_ARGUMENT;
|
|
}
|
|
data[byte_length] = (ZyanU8)value;
|
|
++byte_length;
|
|
}
|
|
}
|
|
|
|
ZydisDecodedInstruction instruction;
|
|
ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT];
|
|
|
|
status = ZydisDecoderDecodeFull(&decoder, &data, byte_length, &instruction, operands);
|
|
if (!ZYAN_SUCCESS(status))
|
|
{
|
|
PrintStatusError(status, "Could not decode instruction");
|
|
return status;
|
|
}
|
|
|
|
PrintInstruction(&decoder, &instruction, operands);
|
|
|
|
#if !defined(ZYDIS_DISABLE_SEGMENT)
|
|
ZYAN_PUTS("");
|
|
PrintSectionHeader("SEGMENTS");
|
|
PrintSegments(&instruction, &data[0], ZYAN_TRUE);
|
|
#endif
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
/* ============================================================================================== */
|