diff --git a/include/Zydis/Formatter.h b/include/Zydis/Formatter.h index fba3813..9cee3f1 100644 --- a/include/Zydis/Formatter.h +++ b/include/Zydis/Formatter.h @@ -129,28 +129,40 @@ enum ZydisFormatterProperties ZYDIS_FORMATTER_PROP_IMM_FORMAT, /** - * @brief Controls the padding (minimum number of chars) of address values. + * @brief Sets the prefix for hexadecimal values. * - * The default value is `2`. + * The default value is `0x`. */ - ZYDIS_FORMATTER_PROP_ADDR_PADDING, + ZYDIS_FORMATTER_PROP_HEX_PREFIX, /** - * @brief Controls the padding (minimum number of chars) of displacement values. + * @brief Sets the suffix for hexadecimal values. * - * The default value is `2`. + * The default value is `NULL`. */ - ZYDIS_FORMATTER_PROP_DISP_PADDING, + ZYDIS_FORMATTER_PROP_HEX_SUFFIX, /** - * @brief Controls the padding (minimum number of chars) of immediate values. + * @brief Controls the padding (minimum number of chars) of hexadecimal address values. * * The default value is `2`. */ - ZYDIS_FORMATTER_PROP_IMM_PADDING, + ZYDIS_FORMATTER_PROP_HEX_PADDING_ADDR, + /** + * @brief Controls the padding (minimum number of chars) of hexadecimal displacement values. + * + * The default value is `2`. + */ + ZYDIS_FORMATTER_PROP_HEX_PADDING_DISP, + /** + * @brief Controls the padding (minimum number of chars) of hexadecimal immediate values. + * + * The default value is `2`. + */ + ZYDIS_FORMATTER_PROP_HEX_PADDING_IMM, /** * @brief Maximum value of this enum. */ - ZYDIS_FORMATTER_PROP_MAX_VALUE = ZYDIS_FORMATTER_PROP_IMM_PADDING + ZYDIS_FORMATTER_PROP_MAX_VALUE = ZYDIS_FORMATTER_PROP_HEX_PADDING_IMM }; /* ---------------------------------------------------------------------------------------------- */ @@ -518,9 +530,11 @@ struct ZydisFormatter_ uint8_t addressFormat; uint8_t displacementFormat; uint8_t immediateFormat; - uint8_t addressPadding; - uint8_t displacementPadding; - uint8_t immediatePadding; + char* hexPrefix; + char* hexSuffix; + uint8_t hexPaddingAddress; + uint8_t hexPaddingDisplacement; + uint8_t hexPaddingImmediate; ZydisFormatterNotifyFunc funcPre; ZydisFormatterNotifyFunc funcPost; ZydisFormatterFormatFunc funcFormatInstruction; diff --git a/src/FormatHelper.c b/src/FormatHelper.c index bf1a958..685e3d2 100644 --- a/src/FormatHelper.c +++ b/src/FormatHelper.c @@ -138,15 +138,16 @@ ZydisStatus ZydisPrintDecU32(char** buffer, size_t bufferLen, uint32_t value, ui } ZydisStatus ZydisPrintHexU32(char** buffer, size_t bufferLen, uint32_t value, uint8_t paddingLength, - ZydisBool uppercase, ZydisBool prefix) + ZydisBool uppercase, const char* prefix, const char* suffix) { ZYDIS_ASSERT(buffer); ZYDIS_ASSERT(bufferLen); if (prefix) { - ZYDIS_CHECK(ZydisPrintStr(buffer, bufferLen, "0x", ZYDIS_LETTER_CASE_DEFAULT)); - bufferLen -= 2; + const char* bufEnd = *buffer + bufferLen; + ZYDIS_CHECK(ZydisPrintStr(buffer, bufferLen, prefix, ZYDIS_LETTER_CASE_DEFAULT)); + bufferLen = bufEnd - *buffer; } if (bufferLen < (size_t)(paddingLength + 1)) { @@ -197,9 +198,13 @@ ZydisStatus ZydisPrintHexU32(char** buffer, size_t bufferLen, uint32_t value, ui } } (*buffer)[n] = '\0'; - *buffer += n; + if (suffix) + { + ZYDIS_CHECK(ZydisPrintStr(buffer, bufferLen - n, suffix, ZYDIS_LETTER_CASE_DEFAULT)); + } + return ZYDIS_STATUS_SUCCESS; } #endif @@ -242,15 +247,16 @@ ZydisStatus ZydisPrintDecU64(char** buffer, size_t bufferLen, uint64_t value, ui } ZydisStatus ZydisPrintHexU64(char** buffer, size_t bufferLen, uint64_t value, uint8_t paddingLength, - ZydisBool uppercase, ZydisBool prefix) + ZydisBool uppercase, const char* prefix, const char* suffix) { ZYDIS_ASSERT(buffer); ZYDIS_ASSERT(bufferLen); if (prefix) { - ZYDIS_CHECK(ZydisPrintStr(buffer, bufferLen, "0x", ZYDIS_LETTER_CASE_DEFAULT)); - bufferLen -= 2; + const char* bufEnd = *buffer + bufferLen; + ZYDIS_CHECK(ZydisPrintStr(buffer, bufferLen, prefix, ZYDIS_LETTER_CASE_DEFAULT)); + bufferLen = bufEnd - *buffer; } if (bufferLen < (size_t)(paddingLength + 1)) { @@ -302,9 +308,13 @@ ZydisStatus ZydisPrintHexU64(char** buffer, size_t bufferLen, uint64_t value, ui } } (*buffer)[n] = '\0'; - *buffer += n; + if (suffix) + { + ZYDIS_CHECK(ZydisPrintStr(buffer, bufferLen - n, suffix, ZYDIS_LETTER_CASE_DEFAULT)); + } + return ZYDIS_STATUS_SUCCESS; } @@ -369,39 +379,37 @@ ZydisStatus ZydisPrintDecS(char** buffer, size_t bufferLen, int64_t value, uint8 } ZydisStatus ZydisPrintHexU(char** buffer, size_t bufferLen, uint64_t value, uint8_t paddingLength, - ZydisBool uppercase, ZydisBool prefix) + ZydisBool uppercase, const char* prefix, const char* suffix) { #ifdef ZYDIS_X64 - return ZydisPrintHexU64(buffer, bufferLen, value, paddingLength, uppercase, prefix); + return ZydisPrintHexU64(buffer, bufferLen, value, paddingLength, uppercase, prefix, suffix); #else if (value & 0xFFFFFFFF00000000) { - return ZydisPrintHexU64(buffer, bufferLen, value, paddingLength, uppercase, prefix); + return ZydisPrintHexU64(buffer, bufferLen, value, paddingLength, uppercase, prefix, suffix); } else { - return ZydisPrintHexU32( - buffer, bufferLen, (uint32_t)value, paddingLength, uppercase, prefix); + return ZydisPrintHexU32(buffer, bufferLen, (uint32_t)value, paddingLength, uppercase, + prefix, suffix); } #endif } ZydisStatus ZydisPrintHexS(char** buffer, size_t bufferLen, int64_t value, uint8_t paddingLength, - ZydisBool uppercase, ZydisBool prefix) + ZydisBool uppercase, const char* prefix, const char* suffix) { if (value < 0) { + const char* bufEnd = *buffer + bufferLen; + ZYDIS_CHECK(ZydisPrintStr(buffer, bufferLen, "-", ZYDIS_LETTER_CASE_DEFAULT)); if (prefix) { - ZYDIS_CHECK(ZydisPrintStr(buffer, bufferLen, "-0x", ZYDIS_LETTER_CASE_DEFAULT)); - bufferLen -= 3; - } else - { - ZYDIS_CHECK(ZydisPrintStr(buffer, bufferLen, "-", ZYDIS_LETTER_CASE_DEFAULT)); - --bufferLen; + ZYDIS_CHECK(ZydisPrintStr(buffer, bufEnd - *buffer, prefix, ZYDIS_LETTER_CASE_DEFAULT)); } - return ZydisPrintHexU(buffer, bufferLen, -value, paddingLength, uppercase, ZYDIS_FALSE); + return ZydisPrintHexU(buffer, bufEnd - *buffer, -value, paddingLength, uppercase, + NULL, suffix); } - return ZydisPrintHexU(buffer, bufferLen, value, paddingLength, uppercase, prefix); + return ZydisPrintHexU(buffer, bufferLen, value, paddingLength, uppercase, prefix, suffix); } /* ---------------------------------------------------------------------------------------------- */ diff --git a/src/FormatHelper.h b/src/FormatHelper.h index f8d72ac..1e401e2 100644 --- a/src/FormatHelper.h +++ b/src/FormatHelper.h @@ -153,7 +153,8 @@ ZYDIS_NO_EXPORT ZydisStatus ZydisPrintDecS(char** buffer, size_t bufferLen, int6 * less than the @c paddingLength. * @param uppercase Set @c TRUE to print the hexadecimal value in uppercase letters instead * of lowercase ones. - * @param prefix Set @c TRUE to add the "0x" prefix to the hexadecimal value. + * @param prefix The string to use as prefix or `NULL`, if not needed. + * @param suffix The string to use as suffix or `NULL`, if not needed. * * @return @c ZYDIS_STATUS_SUCCESS, if the function succeeded, or * @c ZYDIS_STATUS_INSUFFICIENT_BUFFER_SIZE, if the size of the buffer was not @@ -163,7 +164,7 @@ ZYDIS_NO_EXPORT ZydisStatus ZydisPrintDecS(char** buffer, size_t bufferLen, int6 * successfull. */ ZYDIS_NO_EXPORT ZydisStatus ZydisPrintHexU(char** buffer, size_t bufferLen, uint64_t value, - uint8_t paddingLength, ZydisBool uppercase, ZydisBool prefix); + uint8_t paddingLength, ZydisBool uppercase, const char* prefix, const char* suffix); /** * @brief Formats the given signed ordinal @c value to its hexadecimal text-representation and @@ -176,7 +177,8 @@ ZYDIS_NO_EXPORT ZydisStatus ZydisPrintHexU(char** buffer, size_t bufferLen, uint * less than the @c paddingLength (the sign char is ignored). * @param uppercase Set @c TRUE to print the hexadecimal value in uppercase letters instead * of lowercase ones. - * @param prefix Set @c TRUE to add the "0x" prefix to the hexadecimal value. + * @param prefix The string to use as prefix or `NULL`, if not needed. + * @param suffix The string to use as suffix or `NULL`, if not needed. * * @return @c ZYDIS_STATUS_SUCCESS, if the function succeeded, or * @c ZYDIS_STATUS_INSUFFICIENT_BUFFER_SIZE, if the size of the buffer was not @@ -186,7 +188,7 @@ ZYDIS_NO_EXPORT ZydisStatus ZydisPrintHexU(char** buffer, size_t bufferLen, uint * successfull. */ ZYDIS_NO_EXPORT ZydisStatus ZydisPrintHexS(char** buffer, size_t bufferLen, int64_t value, - uint8_t paddingLength, ZydisBool uppercase, ZydisBool prefix); + uint8_t paddingLength, ZydisBool uppercase, const char* prefix, const char* suffix); /* ---------------------------------------------------------------------------------------------- */ diff --git a/src/Formatter.c b/src/Formatter.c index 9b49eca..9131621 100644 --- a/src/Formatter.c +++ b/src/Formatter.c @@ -222,11 +222,11 @@ static ZydisStatus ZydisFormatterFormatOperandPtrIntel(const ZydisFormatter* for } char* bufEnd = *buffer + bufferLen; - ZYDIS_CHECK(ZydisPrintHexU( - buffer, bufEnd - *buffer, operand->ptr.segment, 4, ZYDIS_TRUE, ZYDIS_TRUE)); + ZYDIS_CHECK(ZydisPrintHexU(buffer, bufEnd - *buffer, operand->ptr.segment, 4, ZYDIS_TRUE, + formatter->hexPrefix, formatter->hexSuffix)); ZYDIS_CHECK(ZydisPrintStr(buffer, bufEnd - *buffer, ":", ZYDIS_LETTER_CASE_DEFAULT)); - return ZydisPrintHexU( - buffer, bufEnd - *buffer, operand->ptr.offset, 8, ZYDIS_TRUE, ZYDIS_TRUE); + return ZydisPrintHexU(buffer, bufEnd - *buffer, operand->ptr.offset, 8, ZYDIS_TRUE, + formatter->hexPrefix, formatter->hexSuffix); } static ZydisStatus ZydisFormatterFormatOperandImmIntel(const ZydisFormatter* formatter, @@ -263,10 +263,12 @@ static ZydisStatus ZydisFormatterFormatOperandImmIntel(const ZydisFormatter* for if (printSignedHEX) { return ZydisPrintHexS(buffer, bufferLen, (int32_t)operand->imm.value.s, - formatter->addressPadding, ZYDIS_TRUE, ZYDIS_TRUE); + formatter->hexPaddingAddress, ZYDIS_TRUE, formatter->hexPrefix, + formatter->hexSuffix); } - return ZydisPrintHexU(buffer, bufferLen, operand->imm.value.u, formatter->addressPadding, - ZYDIS_TRUE, ZYDIS_TRUE); + return ZydisPrintHexU(buffer, bufferLen, operand->imm.value.u, + formatter->hexPaddingAddress, ZYDIS_TRUE, formatter->hexPrefix, + formatter->hexSuffix); } // The immediate operand contains an actual ordinal value @@ -290,11 +292,14 @@ static ZydisStatus ZydisFormatterPrintAddressIntel(const ZydisFormatter* formatt switch (instruction->stackWidth) { case 16: - return ZydisPrintHexU(buffer, bufferLen, (uint16_t)address, 4, ZYDIS_TRUE, ZYDIS_TRUE); + return ZydisPrintHexU(buffer, bufferLen, (uint16_t)address, 4, ZYDIS_TRUE, + formatter->hexPrefix, formatter->hexSuffix); case 32: - return ZydisPrintHexU(buffer, bufferLen, (uint32_t)address, 8, ZYDIS_TRUE, ZYDIS_TRUE); + return ZydisPrintHexU(buffer, bufferLen, (uint32_t)address, 8, ZYDIS_TRUE, + formatter->hexPrefix, formatter->hexSuffix); case 64: - return ZydisPrintHexU(buffer, bufferLen, address, 16, ZYDIS_TRUE, ZYDIS_TRUE); + return ZydisPrintHexU(buffer, bufferLen, address, 16, ZYDIS_TRUE, + formatter->hexPrefix, formatter->hexSuffix); default: return ZYDIS_STATUS_INVALID_PARAMETER; } @@ -322,7 +327,8 @@ static ZydisStatus ZydisFormatterPrintDisplacementIntel(const ZydisFormatter* fo (operand->mem.index != ZYDIS_REGISTER_NONE))) { return ZydisPrintHexS(buffer, bufferLen, operand->mem.disp.value, - formatter->displacementPadding, ZYDIS_TRUE, ZYDIS_TRUE); + formatter->hexPaddingDisplacement, ZYDIS_TRUE, formatter->hexPrefix, + formatter->hexSuffix); } char* bufEnd = *buffer + bufferLen; if ((operand->mem.base != ZYDIS_REGISTER_NONE) || @@ -331,7 +337,8 @@ static ZydisStatus ZydisFormatterPrintDisplacementIntel(const ZydisFormatter* fo ZYDIS_CHECK(ZydisPrintStr(buffer, bufferLen, "+", ZYDIS_LETTER_CASE_DEFAULT)); } return ZydisPrintHexU(buffer, bufEnd - *buffer, (uint64_t)operand->mem.disp.value, - formatter->displacementPadding, ZYDIS_TRUE, ZYDIS_TRUE); + formatter->hexPaddingDisplacement, ZYDIS_TRUE, formatter->hexPrefix, + formatter->hexSuffix); } return ZYDIS_STATUS_SUCCESS; } @@ -359,16 +366,20 @@ static ZydisStatus ZydisFormatterPrintImmediateIntel(const ZydisFormatter* forma { case 8: return ZydisPrintHexS(buffer, bufferLen, (int8_t)operand->imm.value.s, - formatter->immediatePadding, ZYDIS_TRUE, ZYDIS_TRUE); + formatter->hexPaddingImmediate, ZYDIS_TRUE, formatter->hexPrefix, + formatter->hexSuffix); case 16: return ZydisPrintHexS(buffer, bufferLen, (int16_t)operand->imm.value.s, - formatter->immediatePadding, ZYDIS_TRUE, ZYDIS_TRUE); + formatter->hexPaddingImmediate, ZYDIS_TRUE, formatter->hexPrefix, + formatter->hexSuffix); case 32: return ZydisPrintHexS(buffer, bufferLen, (int32_t)operand->imm.value.s, - formatter->immediatePadding, ZYDIS_TRUE, ZYDIS_TRUE); + formatter->hexPaddingImmediate, ZYDIS_TRUE, formatter->hexPrefix, + formatter->hexSuffix); case 64: return ZydisPrintHexS(buffer, bufferLen, operand->imm.value.s, - formatter->immediatePadding, ZYDIS_TRUE, ZYDIS_TRUE); + formatter->hexPaddingImmediate, ZYDIS_TRUE, formatter->hexPrefix, + formatter->hexSuffix); default: return ZYDIS_STATUS_INVALID_PARAMETER; } @@ -377,16 +388,20 @@ static ZydisStatus ZydisFormatterPrintImmediateIntel(const ZydisFormatter* forma { case 8: return ZydisPrintHexU(buffer, bufferLen, (uint8_t)operand->imm.value.u, - formatter->immediatePadding, ZYDIS_TRUE, ZYDIS_TRUE); + formatter->hexPaddingImmediate, ZYDIS_TRUE, formatter->hexPrefix, + formatter->hexSuffix); case 16: return ZydisPrintHexU(buffer, bufferLen, (uint16_t)operand->imm.value.u, - formatter->immediatePadding, ZYDIS_TRUE, ZYDIS_TRUE); + formatter->hexPaddingImmediate, ZYDIS_TRUE, formatter->hexPrefix, + formatter->hexSuffix); case 32: return ZydisPrintHexU(buffer, bufferLen, (uint32_t)operand->imm.value.u, - formatter->immediatePadding, ZYDIS_TRUE, ZYDIS_TRUE); + formatter->hexPaddingImmediate, ZYDIS_TRUE, formatter->hexPrefix, + formatter->hexSuffix); case 64: return ZydisPrintHexU(buffer, bufferLen, operand->imm.value.u, - formatter->immediatePadding, ZYDIS_TRUE, ZYDIS_TRUE); + formatter->hexPaddingImmediate, ZYDIS_TRUE, formatter->hexPrefix, + formatter->hexSuffix); default: return ZYDIS_STATUS_INVALID_PARAMETER; } @@ -895,15 +910,17 @@ ZydisStatus ZydisFormatterInit(ZydisFormatter* formatter, ZydisFormatterStyle st } memset(formatter, 0, sizeof(ZydisFormatter)); - formatter->letterCase = ZYDIS_LETTER_CASE_DEFAULT; - formatter->forceSegments = ZYDIS_FALSE; - formatter->forceOperandSize = ZYDIS_FALSE; - formatter->addressFormat = ZYDIS_ADDR_FORMAT_ABSOLUTE; - formatter->displacementFormat = ZYDIS_DISP_FORMAT_HEX_SIGNED; - formatter->immediateFormat = ZYDIS_IMM_FORMAT_HEX_UNSIGNED; - formatter->addressPadding = 2; - formatter->displacementPadding = 2; - formatter->immediatePadding = 2; + formatter->letterCase = ZYDIS_LETTER_CASE_DEFAULT; + formatter->forceSegments = ZYDIS_FALSE; + formatter->forceOperandSize = ZYDIS_FALSE; + formatter->addressFormat = ZYDIS_ADDR_FORMAT_ABSOLUTE; + formatter->displacementFormat = ZYDIS_DISP_FORMAT_HEX_SIGNED; + formatter->immediateFormat = ZYDIS_IMM_FORMAT_HEX_UNSIGNED; + formatter->hexPrefix = "0x"; + formatter->hexSuffix = NULL; + formatter->hexPaddingAddress = 2; + formatter->hexPaddingDisplacement = 2; + formatter->hexPaddingImmediate = 2; switch (style) { @@ -999,26 +1016,32 @@ ZydisStatus ZydisFormatterSetProperty(ZydisFormatter* formatter, } formatter->immediateFormat = (uint8_t)value; break; - case ZYDIS_FORMATTER_PROP_ADDR_PADDING: - if (value > 20) - { - return ZYDIS_STATUS_INVALID_PARAMETER; - } - formatter->addressPadding = (uint8_t)value; + case ZYDIS_FORMATTER_PROP_HEX_PREFIX: + formatter->hexPrefix = (char*)value; break; - case ZYDIS_FORMATTER_PROP_DISP_PADDING: - if (value > 20) - { - return ZYDIS_STATUS_INVALID_PARAMETER; - } - formatter->displacementPadding = (uint8_t)value; + case ZYDIS_FORMATTER_PROP_HEX_SUFFIX: + formatter->hexSuffix = (char*)value; break; - case ZYDIS_FORMATTER_PROP_IMM_PADDING: + case ZYDIS_FORMATTER_PROP_HEX_PADDING_ADDR: if (value > 20) { return ZYDIS_STATUS_INVALID_PARAMETER; } - formatter->immediatePadding = (uint8_t)value; + formatter->hexPaddingAddress = (uint8_t)value; + break; + case ZYDIS_FORMATTER_PROP_HEX_PADDING_DISP: + if (value > 20) + { + return ZYDIS_STATUS_INVALID_PARAMETER; + } + formatter->hexPaddingDisplacement = (uint8_t)value; + break; + case ZYDIS_FORMATTER_PROP_HEX_PADDING_IMM: + if (value > 20) + { + return ZYDIS_STATUS_INVALID_PARAMETER; + } + formatter->hexPaddingImmediate = (uint8_t)value; break; default: return ZYDIS_STATUS_INVALID_PARAMETER;