/*************************************************************************************************** Zyan Disassembler Engine Version 1.0 Remarks : Freeware, Copyright must be included Original Author : Florian Bernd Modifications : Joel Höner * 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 "ZydisAPI.h" #include "ZydisInstructionDecoder.hpp" #include "ZydisInstructionFormatter.hpp" /* Static Checks ================================================================================ */ static_assert( sizeof(ZydisOperandInfo) == sizeof(Zydis::OperandInfo), "struct size mismatch"); static_assert( sizeof(ZydisInstructionInfo) == sizeof(Zydis::InstructionInfo), "struct size mismatch"); /* Error Handling =============================================================================== */ static uint32_t g_zydisLastError = ZYDIS_ERROR_SUCCESS; uint32_t ZydisGetLastError() { return g_zydisLastError; } void ZydisSetLastError(uint32_t errorCode) { g_zydisLastError = errorCode; } /* Conversion Helper ============================================================================ */ typedef enum _ZydisClassType { ZYDIS_CONTEXT_INPUT = 0x00000080, ZYDIS_CONTEXT_INPUT_CUSTOM = ZYDIS_CONTEXT_INPUT | 0x00000001, ZYDIS_CONTEXT_INPUT_MEMORY = ZYDIS_CONTEXT_INPUT | 0x00000002, ZYDIS_CONTEXT_INSTRUCTIONDECODER = 0x00000040, ZYDIS_CONTEXT_INSTRUCTIONFORMATTER = 0x00000020, ZYDIS_CONTEXT_INSTRUCTIONFORMATTER_CUSTOM = ZYDIS_CONTEXT_INSTRUCTIONFORMATTER | 0x00000001, ZYDIS_CONTEXT_INSTRUCTIONFORMATTER_INTEL = ZYDIS_CONTEXT_INSTRUCTIONFORMATTER | 0x00000002, ZYDIS_CONTEXT_SYMBOLRESOLVER = 0x00000010, ZYDIS_CONTEXT_SYMBOLRESOLVER_CUSTOM = ZYDIS_CONTEXT_SYMBOLRESOLVER | 0x00000001, ZYDIS_CONTEXT_SYMBOLRESOLVER_EXACT = ZYDIS_CONTEXT_SYMBOLRESOLVER | 0x00000002 } ZydisClassType; /** * @brief This helper class extends a zydis class with a type field. It is used by the C-bindings * to check type correctness for input parameters. * @param ZydisClassT The zydis class type. */ #pragma pack(push, 1) template class ZydisClassEx final { private: using FullClassT = ZydisClassEx; public: uint32_t type; uint32_t align; std::conditional_t::value, char, ZydisClassT> instance; public: /** * @brief Constructor * @param InstanceCtorArgsT The argument types for the constructor of the zydis class. * @param classType The type of the zydis class. * @param args... The arguments for the constructor of the zydis class. */ template< typename ZydisClassTT=ZydisClassT, std::enable_if_t::value, int> = 0, typename... InstanceCtorArgsT> ZydisClassEx(uint32_t classType, InstanceCtorArgsT... args) : type(classType) , align(0) , instance(args...) { }; public: /** * @brief Returns the class type. * @return The assigned class type. */ uint32_t getClassType() const { return type; } /** * @brief Returns the zydis class instance. * @return Pointer to the zydis class instance. */ ZydisClassT* getInstance() { return reinterpret_cast(&instance); } public: /** * @brief Casts the given instance to @c ZydisClassEx. * @param instance The zydis class instance. * @return Pointer to the @c ZydisClassEx instance. */ static FullClassT* fromInstance(ZydisClassT* instance) { return reinterpret_cast( reinterpret_cast(instance) - sizeof(std::declval().type) - sizeof(std::declval().align)); } }; #pragma pack(pop) /** * @brief Creates a context by constructing a new wrapped zydis class instance. * @param ContextClassT The context class. * @param ZydisClassT The zydis class type. * @param ZydisClassCtorArgsT The argument types for the constructor of the zydis class. * @param classType The type of the zydis class. * @param args... The arguments for the constructor of the zydis class. */ template ContextClassT* ZydisCreateContext(uint32_t classType, ZydisClassCtorArgsT... args) { auto instanceEx = new (std::nothrow) ZydisClassEx(classType, args...); if (!instanceEx) { ZydisSetLastError(ZYDIS_ERROR_NOT_ENOUGH_MEMORY); return nullptr; } // Return the original instance as context. return reinterpret_cast(instanceEx->getInstance()); } /** * @brief Retrieves the zydis class instance of the given context. * @param ContextClassT The context class. * @param ZydisClassT The zydis class type. * @param expectedType The expected type of the zydis class. */ template ZydisClassT* ZydisRetrieveInstance(uint32_t expectedType, const ContextClassT* context) { auto instanceEx = ZydisClassEx::fromInstance( reinterpret_cast(const_cast(context))); if ((instanceEx->getClassType() & expectedType) != expectedType) { ZydisSetLastError(ZYDIS_ERROR_INVALID_PARAMETER); return nullptr; } // The context points to the same address as the instance. We just need to cast it. return reinterpret_cast(const_cast(context)); } /** * @brief Creates a context by constructing a new wrapped zydis instance. * @param ContextClassT The context class. * @param ZydisClassT The zydis class type. * @param expectedType The expected type of the zydis class. */ template bool ZydisFreeContext(uint32_t expectedType, const ContextClassT* context) { auto instanceEx = ZydisClassEx::fromInstance( reinterpret_cast(const_cast(context))); if ((instanceEx->getClassType() & expectedType) != expectedType) { ZydisSetLastError(ZYDIS_ERROR_INVALID_PARAMETER); return false; } delete instanceEx; return true; } /* Input ======================================================================================== */ /** * @brief Helper class for custom input implementations. */ class ZydisCustomInput : public Zydis::BaseInput { private: void* m_userData; ZydisCustomDestructorT m_cbDestructor; ZydisCustomInputPeekT m_cbPeek; ZydisCustomInputNextT m_cbNext; ZydisCustomInputIsEndOfInputT m_cbIsEndOfInput; ZydisCustomInputGetPositionT m_cbGetPosition; ZydisCustomInputSetPositionT m_cbSetPosition; protected: uint8_t internalInputPeek() override { return m_cbPeek(m_userData); } uint8_t internalInputNext() override { return m_cbNext(m_userData); } public: ZydisCustomInput(void* userData, ZydisCustomInputPeekT cbPeek, ZydisCustomInputNextT cbNext, ZydisCustomInputIsEndOfInputT cbIsEndOfInput, ZydisCustomInputGetPositionT cbGetPosition, ZydisCustomInputSetPositionT cbSetPosition, ZydisCustomDestructorT cbDestructor) : m_userData(userData) , m_cbDestructor(cbDestructor) , m_cbPeek(cbPeek) , m_cbNext(cbNext) , m_cbIsEndOfInput(cbIsEndOfInput) , m_cbGetPosition(cbGetPosition) , m_cbSetPosition(cbSetPosition) { } ~ZydisCustomInput() override { if (m_cbDestructor) { m_cbDestructor(m_userData); } } public: bool isEndOfInput() const override { return m_cbIsEndOfInput(m_userData); } uint64_t getPosition() const override { return m_cbGetPosition(m_userData); } bool setPosition(uint64_t position) override { return m_cbSetPosition(m_userData, position); } }; ZydisInputContext* ZydisCreateCustomInput(void* userData, ZydisCustomInputPeekT cbPeek, ZydisCustomInputNextT cbNext, ZydisCustomInputIsEndOfInputT cbIsEndOfInput, ZydisCustomInputGetPositionT cbGetPosition, ZydisCustomInputSetPositionT cbSetPosition, ZydisCustomDestructorT cbDestructor) { if (!cbPeek || !cbNext || !cbIsEndOfInput || !cbGetPosition || !cbSetPosition) { ZydisSetLastError(ZYDIS_ERROR_INVALID_PARAMETER); return nullptr; } return ZydisCreateContext(ZYDIS_CONTEXT_INPUT_CUSTOM, userData, cbPeek, cbNext, cbIsEndOfInput, cbGetPosition, cbSetPosition, cbDestructor); } ZydisInputContext* ZydisCreateMemoryInput(const void* buffer, size_t bufferLen) { return ZydisCreateContext( ZYDIS_CONTEXT_INPUT_MEMORY, buffer, bufferLen); } bool ZydisIsEndOfInput(const ZydisInputContext* input, bool* isEndOfInput) { Zydis::BaseInput* instance = ZydisRetrieveInstance(ZYDIS_CONTEXT_INPUT, input); if (!instance) { return false; } *isEndOfInput = instance->isEndOfInput(); return true; } bool ZydisGetInputPosition(const ZydisInputContext* input, uint64_t* position) { Zydis::BaseInput* instance = ZydisRetrieveInstance(ZYDIS_CONTEXT_INPUT, input); if (!instance) { return false; } *position = instance->getPosition(); return true; } bool ZydisSetInputPosition(const ZydisInputContext* input, uint64_t position) { Zydis::BaseInput* instance = ZydisRetrieveInstance(ZYDIS_CONTEXT_INPUT, input); if (!instance) { return false; } ZydisSetLastError(ZYDIS_ERROR_SUCCESS); return instance->setPosition(position); } bool ZydisFreeInput(const ZydisInputContext* input) { return ZydisFreeContext(ZYDIS_CONTEXT_INPUT, input); } /* InstructionDecoder =========================================================================== */ ZydisInstructionDecoderContext* ZydisCreateInstructionDecoder() { return ZydisCreateContext( ZYDIS_CONTEXT_INSTRUCTIONDECODER); } ZydisInstructionDecoderContext* ZydisCreateInstructionDecoderEx( const ZydisInputContext* input, ZydisDisassemblerMode disassemblerMode, ZydisInstructionSetVendor preferredVendor, uint64_t instructionPointer) { Zydis::BaseInput* object = ZydisRetrieveInstance(ZYDIS_CONTEXT_INPUT, input); if (!object) { return nullptr; } return ZydisCreateContext( ZYDIS_CONTEXT_INSTRUCTIONDECODER, object, static_cast(disassemblerMode), static_cast(preferredVendor), instructionPointer); } bool ZydisDecodeInstruction(const ZydisInstructionDecoderContext* decoder, ZydisInstructionInfo* info) { Zydis::InstructionDecoder* instance = ZydisRetrieveInstance(ZYDIS_CONTEXT_INSTRUCTIONDECODER, decoder); if (!instance) { return false; } ZydisSetLastError(ZYDIS_ERROR_SUCCESS); return instance->decodeInstruction(*reinterpret_cast(info)); } bool ZydisGetDataSource(const ZydisInstructionDecoderContext* decoder, ZydisInputContext** input) { Zydis::InstructionDecoder* instance = ZydisRetrieveInstance(ZYDIS_CONTEXT_INSTRUCTIONDECODER, decoder); if (!instance) { return false; } *input = reinterpret_cast(instance->getDataSource()); if (!input) { return false; } return true; } bool ZydisSetDataSource(const ZydisInstructionDecoderContext* decoder, ZydisInputContext* input) { Zydis::InstructionDecoder* instance = ZydisRetrieveInstance(ZYDIS_CONTEXT_INSTRUCTIONDECODER, decoder); if (!instance) { return false; } Zydis::BaseInput* object = ZydisRetrieveInstance(ZYDIS_CONTEXT_INPUT, input); if (!object) { return false; } instance->setDataSource(object); return true; } bool ZydisGetDisassemblerMode(const ZydisInstructionDecoderContext* decoder, ZydisDisassemblerMode* disassemblerMode) { Zydis::InstructionDecoder* instance = ZydisRetrieveInstance(ZYDIS_CONTEXT_INSTRUCTIONDECODER, decoder); if (!instance) { return false; } *disassemblerMode = static_cast(instance->getDisassemblerMode()); return true; } bool ZydisSetDisassemblerMode(const ZydisInstructionDecoderContext* decoder, ZydisDisassemblerMode disassemblerMode) { Zydis::InstructionDecoder* instance = ZydisRetrieveInstance(ZYDIS_CONTEXT_INSTRUCTIONDECODER, decoder); if (!instance) { return false; } instance->setDisassemblerMode(static_cast(disassemblerMode)); return true; } bool ZydisGetPreferredVendor(const ZydisInstructionDecoderContext* decoder, ZydisInstructionSetVendor* preferredVendor) { Zydis::InstructionDecoder* instance = ZydisRetrieveInstance(ZYDIS_CONTEXT_INSTRUCTIONDECODER, decoder); if (!instance) { return false; } *preferredVendor = static_cast(instance->getPreferredVendor()); return true; } bool ZydisSetPreferredVendor(const ZydisInstructionDecoderContext* decoder, ZydisInstructionSetVendor preferredVendor) { Zydis::InstructionDecoder* instance = ZydisRetrieveInstance(ZYDIS_CONTEXT_INSTRUCTIONDECODER, decoder); if (!instance) { return false; } instance->setPreferredVendor(static_cast(preferredVendor)); return true; } bool ZydisGetInstructionPointer(const ZydisInstructionDecoderContext* decoder, uint64_t* instructionPointer) { Zydis::InstructionDecoder* instance = ZydisRetrieveInstance(ZYDIS_CONTEXT_INSTRUCTIONDECODER, decoder); if (!instance) { return false; } *instructionPointer = instance->getInstructionPointer(); return true; } bool ZydisSetInstructionPointer(const ZydisInstructionDecoderContext* decoder, uint64_t instructionPointer) { Zydis::InstructionDecoder* instance = ZydisRetrieveInstance(ZYDIS_CONTEXT_INSTRUCTIONDECODER, decoder); if (!instance) { return false; } instance->setInstructionPointer(instructionPointer); return true; } bool ZydisFreeInstructionDecoder(const ZydisInstructionDecoderContext* decoder) { return ZydisFreeContext( ZYDIS_CONTEXT_INSTRUCTIONDECODER, decoder); } /* InstructionFormatter ========================================================================= */ ZydisInstructionFormatterContext* ZydisCreateCustomInstructionFormatter(/* TODO */) { return nullptr; } ZydisInstructionFormatterContext* ZydisCreateIntelInstructionFormatter() { return ZydisCreateContext(ZYDIS_CONTEXT_INSTRUCTIONFORMATTER_INTEL); } bool ZydisFormatInstruction(const ZydisInstructionFormatterContext* formatter, const ZydisInstructionInfo* info, const char** instructionText) { Zydis::BaseInstructionFormatter* instance = ZydisRetrieveInstance(ZYDIS_CONTEXT_INSTRUCTIONFORMATTER, formatter); if (!instance) { return false; } *instructionText = instance->formatInstruction(*reinterpret_cast(info)); return true; } bool ZydisGetSymbolResolver(const ZydisInstructionFormatterContext* formatter, ZydisSymbolResolverContext** resolver) { Zydis::BaseInstructionFormatter* instance = ZydisRetrieveInstance(ZYDIS_CONTEXT_INSTRUCTIONFORMATTER, formatter); if (!instance) { return false; } *resolver = reinterpret_cast(instance->getSymbolResolver()); if (!resolver) { return false; } return true; } bool ZydisSetSymbolResolver(const ZydisInstructionFormatterContext* formatter, ZydisSymbolResolverContext* resolver) { Zydis::BaseInstructionFormatter* instance = ZydisRetrieveInstance(ZYDIS_CONTEXT_INSTRUCTIONFORMATTER, formatter); if (!instance) { return false; } Zydis::BaseSymbolResolver* object = ZydisRetrieveInstance(ZYDIS_CONTEXT_SYMBOLRESOLVER, resolver); if (!object) { return false; } instance->setSymbolResolver(object); return true; } bool ZydisFreeInstructionFormatter(const ZydisInstructionFormatterContext* formatter) { return ZydisFreeContext( ZYDIS_CONTEXT_INSTRUCTIONFORMATTER, formatter); } /* SymbolResolver =============================================================================== */ ZydisSymbolResolverContext* ZydisCreateCustomSymbolResolver(/*TODO*/) { return nullptr; } ZydisSymbolResolverContext* ZydisCreateExactSymbolResolver() { return ZydisCreateContext( ZYDIS_CONTEXT_SYMBOLRESOLVER_EXACT); } bool ZydisResolveSymbol(const ZydisSymbolResolverContext* resolver, const ZydisInstructionInfo* info, uint64_t address, const char** symbol, uint64_t* offset) { Zydis::BaseSymbolResolver* instance = ZydisRetrieveInstance(ZYDIS_CONTEXT_SYMBOLRESOLVER, resolver); if (!instance) { return false; } *symbol = instance->resolveSymbol(*reinterpret_cast(info), address, *offset); return true; } bool ZydisExactSymbolResolverContainsSymbol( const ZydisSymbolResolverContext* resolver, uint64_t address, bool* containsSymbol) { Zydis::ExactSymbolResolver* instance = ZydisRetrieveInstance(ZYDIS_CONTEXT_SYMBOLRESOLVER_EXACT, resolver); if (!instance) { return false; } *containsSymbol = instance->containsSymbol(address); return true; } bool ZydisExactSymbolResolverSetSymbol(const ZydisSymbolResolverContext* resolver, uint64_t address, const char* name) { Zydis::ExactSymbolResolver* instance = ZydisRetrieveInstance(ZYDIS_CONTEXT_SYMBOLRESOLVER_EXACT, resolver); if (!instance) { return false; } instance->setSymbol(address, name); return true; } bool ZydisExactSymbolResolverRemoveSymbol(const ZydisSymbolResolverContext* resolver, uint64_t address) { Zydis::ExactSymbolResolver* instance = ZydisRetrieveInstance(ZYDIS_CONTEXT_SYMBOLRESOLVER_EXACT, resolver); if (!instance) { return false; } instance->removeSymbol(address); return true; } bool ZydisExactSymbolResolverClear(const ZydisSymbolResolverContext* resolver) { Zydis::ExactSymbolResolver* instance = ZydisRetrieveInstance(ZYDIS_CONTEXT_SYMBOLRESOLVER_EXACT, resolver); if (!instance) { return false; } instance->clear(); return true; } bool ZydisFreeSymbolResolver(const ZydisSymbolResolverContext* resolver) { return ZydisFreeContext( ZYDIS_CONTEXT_SYMBOLRESOLVER, resolver); } /* ============================================================================================== */