2015-05-16 11:05:17 +08:00
|
|
|
|
/***************************************************************************************************
|
2015-03-16 23:37:15 +08:00
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
Zyan Disassembler Engine
|
2015-03-16 23:37:15 +08:00
|
|
|
|
Version 1.0
|
|
|
|
|
|
|
|
|
|
Remarks : Freeware, Copyright must be included
|
|
|
|
|
|
|
|
|
|
Original Author : Florian Bernd
|
2015-05-16 11:05:17 +08:00
|
|
|
|
Modifications : Joel H<EFBFBD>ner
|
2015-03-16 23:37:15 +08:00
|
|
|
|
|
|
|
|
|
* 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:
|
2015-05-16 11:05:17 +08:00
|
|
|
|
*
|
2015-03-16 23:37:15 +08:00
|
|
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
|
|
|
* copies or substantial portions of the Software.
|
2015-05-16 11:05:17 +08:00
|
|
|
|
*
|
2015-03-16 23:37:15 +08:00
|
|
|
|
* 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.
|
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
***************************************************************************************************/
|
|
|
|
|
|
|
|
|
|
#ifndef _ZYDIS_INSTRUCTIONDECODER_HPP_
|
|
|
|
|
#define _ZYDIS_INSTRUCTIONDECODER_HPP_
|
2015-03-16 23:37:15 +08:00
|
|
|
|
|
|
|
|
|
#include <type_traits>
|
|
|
|
|
#include <istream>
|
2015-05-16 11:05:17 +08:00
|
|
|
|
#include "ZydisTypes.hpp"
|
2015-03-16 23:37:15 +08:00
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
namespace Zydis
|
2015-03-16 23:37:15 +08:00
|
|
|
|
{
|
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
/* BaseInput ==================================================================================== */
|
2015-03-16 23:37:15 +08:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief The base class for all data-source implementations.
|
|
|
|
|
*/
|
2015-05-16 11:05:17 +08:00
|
|
|
|
class BaseInput
|
2015-03-16 23:37:15 +08:00
|
|
|
|
{
|
|
|
|
|
private:
|
|
|
|
|
uint8_t m_currentInput;
|
|
|
|
|
protected:
|
|
|
|
|
/**
|
|
|
|
|
* @brief Override this method in your custom data source implementations.
|
|
|
|
|
* Reads the next byte from the data source. This method increases the current
|
|
|
|
|
* input position by one.
|
|
|
|
|
* @return The current input byte.
|
|
|
|
|
*/
|
|
|
|
|
virtual uint8_t internalInputPeek() = 0;
|
|
|
|
|
/**
|
|
|
|
|
* @brief Override this method in your custom data source implementations.
|
|
|
|
|
* Reads the next byte from the data source. This method does NOT increase the
|
|
|
|
|
* current input position.
|
|
|
|
|
* @return The current input byte.
|
|
|
|
|
*/
|
|
|
|
|
virtual uint8_t internalInputNext() = 0;
|
|
|
|
|
protected:
|
|
|
|
|
/**
|
|
|
|
|
* @brief Default constructor.
|
|
|
|
|
*/
|
2015-05-16 11:05:17 +08:00
|
|
|
|
BaseInput() { };
|
2015-03-16 23:37:15 +08:00
|
|
|
|
public:
|
|
|
|
|
/**
|
|
|
|
|
* @brief Destructor.
|
|
|
|
|
*/
|
2015-05-16 11:05:17 +08:00
|
|
|
|
virtual ~BaseInput() { };
|
2015-03-16 23:37:15 +08:00
|
|
|
|
public:
|
|
|
|
|
/**
|
|
|
|
|
* @brief Reads the next byte from the data source. This method does NOT increase the
|
|
|
|
|
* current input position or the @c length field of the @c info parameter.
|
|
|
|
|
* @param info The instruction info.
|
|
|
|
|
* @return The current input byte. If the result is zero, you should always check the
|
|
|
|
|
* @c flags field of the @c info parameter for error flags.
|
|
|
|
|
* Possible error values are @c IF_ERROR_END_OF_INPUT or @c IF_ERROR_LENGTH.
|
|
|
|
|
*/
|
2015-05-16 11:05:17 +08:00
|
|
|
|
uint8_t inputPeek(InstructionInfo& info);
|
2015-03-16 23:37:15 +08:00
|
|
|
|
/**
|
|
|
|
|
* @brief Reads the next byte from the data source. This method increases the current
|
|
|
|
|
* input position and the @c length field of the @c info parameter.
|
|
|
|
|
* This method also appends the new byte to to @c data field of the @c info
|
|
|
|
|
* parameter.
|
|
|
|
|
* @param info The instruction info.
|
|
|
|
|
* @return The current input byte. If the result is zero, you should always check the
|
|
|
|
|
* @c flags field of the @c info parameter for error flags.
|
|
|
|
|
* Possible error values are @c IF_ERROR_END_OF_INPUT or @c IF_ERROR_LENGTH.
|
|
|
|
|
*/
|
2015-05-16 11:05:17 +08:00
|
|
|
|
uint8_t inputNext(InstructionInfo& info);
|
2015-03-16 23:37:15 +08:00
|
|
|
|
/**
|
|
|
|
|
* @brief Reads the next byte(s) from the data source. This method increases the current
|
|
|
|
|
* input position and the @c length field of the @c info parameter.
|
|
|
|
|
* This method also appends the new byte(s) to to @c data field of the @c info
|
|
|
|
|
* parameter.
|
|
|
|
|
* @param info The instruction info.
|
|
|
|
|
* @return The current input data. If the result is zero, you should always check the
|
|
|
|
|
* @c flags field of the @c info parameter for error flags.
|
|
|
|
|
* Possible error values are @c IF_ERROR_END_OF_INPUT or @c IF_ERROR_LENGTH.
|
|
|
|
|
*/
|
|
|
|
|
template <typename T>
|
2015-05-16 11:05:17 +08:00
|
|
|
|
T inputNext(InstructionInfo& info);
|
2015-03-16 23:37:15 +08:00
|
|
|
|
/**
|
|
|
|
|
* @brief Returns the current input byte. The current input byte is set everytime the
|
|
|
|
|
* @c inputPeek or @c inputNext method is called.
|
|
|
|
|
* @return The current input byte.
|
|
|
|
|
*/
|
|
|
|
|
uint8_t inputCurrent() const;
|
|
|
|
|
public:
|
|
|
|
|
/**
|
|
|
|
|
* @brief Override this method in your custom data source implementations.
|
|
|
|
|
* Signals, if the end of the data source is reached.
|
|
|
|
|
* @return True if end of input, false if not.
|
|
|
|
|
*/
|
|
|
|
|
virtual bool isEndOfInput() const = 0;
|
|
|
|
|
/**
|
|
|
|
|
* @brief Override this method in your custom data source implementations.
|
|
|
|
|
* Returns the current input position.
|
|
|
|
|
* @return The current input position.
|
|
|
|
|
*/
|
|
|
|
|
virtual uint64_t getPosition() const = 0;
|
|
|
|
|
/**
|
|
|
|
|
* @brief Override this method in your custom data source implementations.
|
|
|
|
|
* Sets a new input position.
|
|
|
|
|
* @param position The new input position.
|
|
|
|
|
* @return Returns false, if the new position exceeds the maximum input length.
|
|
|
|
|
*/
|
|
|
|
|
virtual bool setPosition(uint64_t position) = 0;
|
|
|
|
|
};
|
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
inline uint8_t BaseInput::inputPeek(InstructionInfo& info)
|
2015-03-16 23:37:15 +08:00
|
|
|
|
{
|
|
|
|
|
if (info.length == 15)
|
|
|
|
|
{
|
|
|
|
|
info.flags |= IF_ERROR_LENGTH;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (isEndOfInput())
|
|
|
|
|
{
|
|
|
|
|
info.flags |= IF_ERROR_END_OF_INPUT;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
m_currentInput = internalInputPeek();
|
|
|
|
|
return m_currentInput;
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
inline uint8_t BaseInput::inputNext(InstructionInfo& info)
|
2015-03-16 23:37:15 +08:00
|
|
|
|
{
|
|
|
|
|
if (info.length == 15)
|
|
|
|
|
{
|
|
|
|
|
info.flags |= IF_ERROR_LENGTH;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (isEndOfInput())
|
|
|
|
|
{
|
|
|
|
|
info.flags |= IF_ERROR_END_OF_INPUT;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
m_currentInput = internalInputNext();
|
|
|
|
|
info.data[info.length] = m_currentInput;
|
|
|
|
|
info.length++;
|
|
|
|
|
return m_currentInput;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
2015-05-16 11:05:17 +08:00
|
|
|
|
inline T BaseInput::inputNext(InstructionInfo& info)
|
2015-03-16 23:37:15 +08:00
|
|
|
|
{
|
|
|
|
|
static_assert(std::is_integral<T>::value, "integral type required");
|
|
|
|
|
T result = 0;
|
|
|
|
|
for (unsigned i = 0; i < (sizeof(T) / sizeof(uint8_t)); ++i)
|
|
|
|
|
{
|
|
|
|
|
T b = inputNext(info);
|
2015-05-16 11:05:17 +08:00
|
|
|
|
if (!b&& (info.flags& IF_ERROR_MASK))
|
2015-03-16 23:37:15 +08:00
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
result |= (b << (i * 8));
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
inline uint8_t BaseInput::inputCurrent() const
|
2015-03-16 23:37:15 +08:00
|
|
|
|
{
|
|
|
|
|
return m_currentInput;
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
/* MemoryInput ================================================================================== */
|
2015-03-16 23:37:15 +08:00
|
|
|
|
|
|
|
|
|
/**
|
2015-05-16 11:05:17 +08:00
|
|
|
|
* @brief A memory-buffer based data source for the @c InstructionDecoder class.
|
2015-03-16 23:37:15 +08:00
|
|
|
|
*/
|
2015-05-16 11:05:17 +08:00
|
|
|
|
class MemoryInput : public BaseInput
|
2015-03-16 23:37:15 +08:00
|
|
|
|
{
|
|
|
|
|
private:
|
2015-05-16 11:05:17 +08:00
|
|
|
|
const void* m_inputBuffer;
|
2015-03-16 23:37:15 +08:00
|
|
|
|
uint64_t m_inputBufferLen;
|
|
|
|
|
uint64_t m_inputBufferPos;
|
|
|
|
|
protected:
|
|
|
|
|
/**
|
|
|
|
|
* @brief Reads the next byte from the data source. This method increases the current
|
|
|
|
|
* input position by one.
|
|
|
|
|
* @return The current input byte.
|
|
|
|
|
*/
|
|
|
|
|
uint8_t internalInputPeek() override;
|
|
|
|
|
/**
|
|
|
|
|
* @brief Reads the next byte from the data source. This method does NOT increase the
|
|
|
|
|
* current input position.
|
|
|
|
|
* @return The current input byte.
|
|
|
|
|
*/
|
|
|
|
|
uint8_t internalInputNext() override;
|
|
|
|
|
public:
|
|
|
|
|
/**
|
|
|
|
|
* @brief Constructor.
|
|
|
|
|
* @param buffer The input buffer.
|
|
|
|
|
* @param bufferLen The length of the input buffer.
|
|
|
|
|
*/
|
2015-05-16 11:05:17 +08:00
|
|
|
|
MemoryInput(const void* buffer, size_t bufferLen)
|
2015-03-16 23:37:15 +08:00
|
|
|
|
: m_inputBuffer(buffer)
|
|
|
|
|
, m_inputBufferLen(bufferLen)
|
|
|
|
|
, m_inputBufferPos(0) { };
|
|
|
|
|
public:
|
|
|
|
|
/**
|
|
|
|
|
* @brief Signals, if the end of the data source is reached.
|
|
|
|
|
* @return True if end of input, false if not.
|
|
|
|
|
*/
|
|
|
|
|
bool isEndOfInput() const override;
|
|
|
|
|
/**
|
|
|
|
|
* @brief Returns the current input position.
|
|
|
|
|
* @return The current input position.
|
|
|
|
|
*/
|
|
|
|
|
uint64_t getPosition() const override;
|
|
|
|
|
/**
|
|
|
|
|
* @brief Sets a new input position.
|
|
|
|
|
* @param position The new input position.
|
|
|
|
|
* @return Returns false, if the new position exceeds the maximum input length.
|
|
|
|
|
*/
|
|
|
|
|
bool setPosition(uint64_t position) override;
|
|
|
|
|
};
|
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
inline uint8_t MemoryInput::internalInputPeek()
|
2015-03-16 23:37:15 +08:00
|
|
|
|
{
|
|
|
|
|
return *(static_cast<const uint8_t*>(m_inputBuffer) + m_inputBufferPos);
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
inline uint8_t MemoryInput::internalInputNext()
|
2015-03-16 23:37:15 +08:00
|
|
|
|
{
|
|
|
|
|
++m_inputBufferPos;
|
|
|
|
|
return *(static_cast<const uint8_t*>(m_inputBuffer) + m_inputBufferPos - 1);
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
inline bool MemoryInput::isEndOfInput() const
|
2015-03-16 23:37:15 +08:00
|
|
|
|
{
|
|
|
|
|
return (m_inputBufferPos >= m_inputBufferLen);
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
inline uint64_t MemoryInput::getPosition() const
|
2015-03-16 23:37:15 +08:00
|
|
|
|
{
|
|
|
|
|
return m_inputBufferPos;
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
inline bool MemoryInput::setPosition(uint64_t position)
|
2015-03-16 23:37:15 +08:00
|
|
|
|
{
|
|
|
|
|
m_inputBufferPos = position;
|
|
|
|
|
return isEndOfInput();
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
/* StreamInput ================================================================================== */
|
2015-03-16 23:37:15 +08:00
|
|
|
|
|
|
|
|
|
/**
|
2015-05-16 11:05:17 +08:00
|
|
|
|
* @brief A stream based data source for the @c InstructionDecoder class.
|
2015-03-16 23:37:15 +08:00
|
|
|
|
*/
|
2015-05-16 11:05:17 +08:00
|
|
|
|
class StreamInput : public BaseInput
|
2015-03-16 23:37:15 +08:00
|
|
|
|
{
|
|
|
|
|
private:
|
2015-05-16 11:05:17 +08:00
|
|
|
|
std::istream* m_inputStream;
|
2015-03-16 23:37:15 +08:00
|
|
|
|
protected:
|
|
|
|
|
/**
|
|
|
|
|
* @brief Reads the next byte from the data source. This method increases the current
|
|
|
|
|
* input position by one.
|
|
|
|
|
* @return The current input byte.
|
|
|
|
|
*/
|
|
|
|
|
uint8_t internalInputPeek() override;
|
|
|
|
|
/**
|
|
|
|
|
* @brief Reads the next byte from the data source. This method does NOT increase the
|
|
|
|
|
* current input position.
|
|
|
|
|
* @return The current input byte.
|
|
|
|
|
*/
|
|
|
|
|
uint8_t internalInputNext() override;
|
|
|
|
|
public:
|
|
|
|
|
/**
|
|
|
|
|
* @brief Constructor.
|
|
|
|
|
* @param stream The input stream.
|
|
|
|
|
*/
|
2015-05-16 11:05:17 +08:00
|
|
|
|
explicit StreamInput(std::istream* stream)
|
2015-03-16 23:37:15 +08:00
|
|
|
|
: m_inputStream(stream) { };
|
|
|
|
|
public:
|
|
|
|
|
/**
|
|
|
|
|
* @brief Signals, if the end of the data source is reached.
|
|
|
|
|
* @return True if end of input, false if not.
|
|
|
|
|
*/
|
|
|
|
|
bool isEndOfInput() const override;
|
|
|
|
|
/**
|
|
|
|
|
* @brief Returns the current input position.
|
|
|
|
|
* @return The current input position.
|
|
|
|
|
*/
|
|
|
|
|
uint64_t getPosition() const override;
|
|
|
|
|
/**
|
|
|
|
|
* @brief Sets a new input position.
|
|
|
|
|
* @param position The new input position.
|
|
|
|
|
* @return Returns false, if the new position exceeds the maximum input length.
|
|
|
|
|
*/
|
|
|
|
|
bool setPosition(uint64_t position) override;
|
|
|
|
|
};
|
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
inline uint8_t StreamInput::internalInputPeek()
|
2015-03-16 23:37:15 +08:00
|
|
|
|
{
|
|
|
|
|
if (!m_inputStream)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2015-03-20 00:13:37 +08:00
|
|
|
|
return static_cast<uint8_t>(m_inputStream->peek());
|
2015-03-16 23:37:15 +08:00
|
|
|
|
}
|
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
inline uint8_t StreamInput::internalInputNext()
|
2015-03-16 23:37:15 +08:00
|
|
|
|
{
|
|
|
|
|
if (!m_inputStream)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2015-03-20 00:13:37 +08:00
|
|
|
|
return static_cast<uint8_t>(m_inputStream->get());
|
2015-03-16 23:37:15 +08:00
|
|
|
|
}
|
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
inline bool StreamInput::isEndOfInput() const
|
2015-03-16 23:37:15 +08:00
|
|
|
|
{
|
|
|
|
|
if (!m_inputStream)
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
// We use good() instead of eof() to make sure the decoding will fail, if an stream internal
|
|
|
|
|
// error occured.
|
|
|
|
|
return !m_inputStream->good();
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
inline uint64_t StreamInput::getPosition() const
|
2015-03-16 23:37:15 +08:00
|
|
|
|
{
|
|
|
|
|
if (!m_inputStream)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
return m_inputStream->tellg();
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
inline bool StreamInput::setPosition(uint64_t position)
|
2015-03-16 23:37:15 +08:00
|
|
|
|
{
|
|
|
|
|
if (!m_inputStream)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
m_inputStream->seekg(position);
|
|
|
|
|
return isEndOfInput();
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
/* Enums ======================================================================================== */
|
2015-03-16 23:37:15 +08:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Values that represent a disassembler mode.
|
|
|
|
|
*/
|
2015-05-16 11:05:17 +08:00
|
|
|
|
enum class DisassemblerMode : uint8_t
|
2015-03-16 23:37:15 +08:00
|
|
|
|
{
|
|
|
|
|
M16BIT,
|
|
|
|
|
M32BIT,
|
|
|
|
|
M64BIT
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Values that represent an instruction-set vendor.
|
|
|
|
|
*/
|
2015-05-16 11:05:17 +08:00
|
|
|
|
enum class InstructionSetVendor : uint8_t
|
2015-03-16 23:37:15 +08:00
|
|
|
|
{
|
|
|
|
|
ANY,
|
|
|
|
|
INTEL,
|
|
|
|
|
AMD
|
|
|
|
|
};
|
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
/* InstructionDecoder =========================================================================== */
|
|
|
|
|
|
2015-03-16 23:37:15 +08:00
|
|
|
|
/**
|
2015-05-16 11:05:17 +08:00
|
|
|
|
* @brief The @c InstructionDecoder class decodes x86/x86-64 assembly instructions from a
|
2015-03-16 23:37:15 +08:00
|
|
|
|
* given data source.
|
|
|
|
|
*/
|
2015-05-16 11:05:17 +08:00
|
|
|
|
class InstructionDecoder
|
2015-03-16 23:37:15 +08:00
|
|
|
|
{
|
|
|
|
|
private:
|
|
|
|
|
enum class RegisterClass : uint8_t
|
|
|
|
|
{
|
|
|
|
|
GENERAL_PURPOSE,
|
|
|
|
|
MMX,
|
|
|
|
|
CONTROL,
|
|
|
|
|
DEBUG,
|
|
|
|
|
SEGMENT,
|
|
|
|
|
XMM
|
|
|
|
|
};
|
|
|
|
|
private:
|
2015-05-16 11:05:17 +08:00
|
|
|
|
BaseInput* m_input;
|
|
|
|
|
DisassemblerMode m_disassemblerMode;
|
|
|
|
|
InstructionSetVendor m_preferredVendor;
|
|
|
|
|
uint64_t m_instructionPointer;
|
2015-03-16 23:37:15 +08:00
|
|
|
|
private:
|
|
|
|
|
/**
|
|
|
|
|
* @brief Reads the next byte from the data source. This method does NOT increase the
|
|
|
|
|
* current input position or the @c length field of the @c info parameter.
|
|
|
|
|
* @param info The instruction info.
|
|
|
|
|
* @return The current input byte. If the result is zero, you should always check the
|
|
|
|
|
* @c flags field of the @c info parameter for error flags.
|
|
|
|
|
* Possible error values are @c IF_ERROR_END_OF_INPUT or @c IF_ERROR_LENGTH.
|
|
|
|
|
*/
|
2015-05-16 11:05:17 +08:00
|
|
|
|
uint8_t inputPeek(InstructionInfo& info);
|
2015-03-16 23:37:15 +08:00
|
|
|
|
/**
|
|
|
|
|
* @brief Reads the next byte from the data source. This method increases the current
|
|
|
|
|
* input position and the @c length field of the @info parameter.
|
|
|
|
|
* This method also appends the new byte to to @c data field of the @c info
|
|
|
|
|
* parameter.
|
|
|
|
|
* @param info The instruction info.
|
|
|
|
|
* @return The current input byte. If the result is zero, you should always check the
|
|
|
|
|
* @c flags field of the @c info parameter for error flags.
|
|
|
|
|
* Possible error values are @c IF_ERROR_END_OF_INPUT or @c IF_ERROR_LENGTH.
|
|
|
|
|
*/
|
2015-05-16 11:05:17 +08:00
|
|
|
|
uint8_t inputNext(InstructionInfo& info);
|
2015-03-16 23:37:15 +08:00
|
|
|
|
/**
|
|
|
|
|
* @brief Reads the next byte(s) from the data source. This method increases the current
|
|
|
|
|
* input position and the @c length field of the @info parameter.
|
|
|
|
|
* This method also appends the new byte(s) to to @c data field of the @c info
|
|
|
|
|
* parameter.
|
|
|
|
|
* @param info The instruction info.
|
|
|
|
|
* @return The current input data. If the result is zero, you should always check the
|
|
|
|
|
* @c flags field of the @c info parameter for error flags.
|
|
|
|
|
* Possible error values are @c IF_ERROR_END_OF_INPUT or @c IF_ERROR_LENGTH.
|
|
|
|
|
*/
|
|
|
|
|
template <typename T>
|
2015-05-16 11:05:17 +08:00
|
|
|
|
T inputNext(InstructionInfo& info);
|
2015-03-16 23:37:15 +08:00
|
|
|
|
/**
|
|
|
|
|
* @brief Returns the current input byte. The current input byte is set everytime the
|
|
|
|
|
* @c inputPeek or @c inputNext method is called.
|
|
|
|
|
* @return The current input byte.
|
|
|
|
|
*/
|
|
|
|
|
uint8_t inputCurrent() const;
|
|
|
|
|
private:
|
|
|
|
|
/**
|
|
|
|
|
* @brief Decodes a register operand.
|
|
|
|
|
* @param info The instruction info.
|
2015-05-16 11:05:17 +08:00
|
|
|
|
* @param operand The @c OperandInfo struct that receives the decoded data.
|
2015-03-16 23:37:15 +08:00
|
|
|
|
* @param registerClass The register class to use.
|
|
|
|
|
* @param registerId The register id.
|
|
|
|
|
* @param operandSize The defined size of the operand.
|
|
|
|
|
* @return True if it succeeds, false if it fails.
|
|
|
|
|
*/
|
2015-05-16 11:05:17 +08:00
|
|
|
|
bool decodeRegisterOperand(InstructionInfo& info, OperandInfo& operand,
|
|
|
|
|
RegisterClass registerClass, uint8_t registerId, DefinedOperandSize operandSize) const;
|
2015-03-16 23:37:15 +08:00
|
|
|
|
/**
|
|
|
|
|
* @brief Decodes a register/memory operand.
|
|
|
|
|
* @param info The instruction info.
|
2015-05-16 11:05:17 +08:00
|
|
|
|
* @param operand The @c OperandInfo struct that receives the decoded data.
|
2015-03-16 23:37:15 +08:00
|
|
|
|
* @param registerClass The register class to use.
|
|
|
|
|
* @param operandSize The defined size of the operand.
|
|
|
|
|
* @return True if it succeeds, false if it fails.
|
|
|
|
|
*/
|
2015-05-16 11:05:17 +08:00
|
|
|
|
bool decodeRegisterMemoryOperand(InstructionInfo& info, OperandInfo& operand,
|
|
|
|
|
RegisterClass registerClass, DefinedOperandSize operandSize);
|
2015-03-16 23:37:15 +08:00
|
|
|
|
/**
|
|
|
|
|
* @brief Decodes an immediate operand.
|
|
|
|
|
* @param info The instruction info.
|
2015-05-16 11:05:17 +08:00
|
|
|
|
* @param operand The @c OperandInfo struct that receives the decoded data.
|
2015-03-16 23:37:15 +08:00
|
|
|
|
* @param operandSize The defined size of the operand.
|
|
|
|
|
* @return True if it succeeds, false if it fails.
|
|
|
|
|
*/
|
2015-05-16 11:05:17 +08:00
|
|
|
|
bool decodeImmediate(InstructionInfo& info, OperandInfo& operand,
|
|
|
|
|
DefinedOperandSize operandSize);
|
2015-03-16 23:37:15 +08:00
|
|
|
|
/**
|
|
|
|
|
* @brief Decodes a displacement operand.
|
|
|
|
|
* @param info The instruction info.
|
2015-05-16 11:05:17 +08:00
|
|
|
|
* @param operand The @c OperandInfo struct that receives the decoded data.
|
2015-03-16 23:37:15 +08:00
|
|
|
|
* @param size The size of the displacement data.
|
|
|
|
|
* @return True if it succeeds, false if it fails.
|
|
|
|
|
*/
|
2015-05-16 11:05:17 +08:00
|
|
|
|
bool decodeDisplacement(InstructionInfo& info, OperandInfo& operand, uint8_t size);
|
2015-03-16 23:37:15 +08:00
|
|
|
|
private:
|
|
|
|
|
/**
|
|
|
|
|
* @brief Decodes the modrm field of the instruction. This method reads an additional
|
|
|
|
|
* input byte.
|
2015-05-16 11:05:17 +08:00
|
|
|
|
* @param The @c InstructionInfo struct that receives the decoded data.
|
2015-03-16 23:37:15 +08:00
|
|
|
|
* @return True if it succeeds, false if it fails.
|
|
|
|
|
*/
|
2015-05-16 11:05:17 +08:00
|
|
|
|
bool decodeModrm(InstructionInfo& info);
|
2015-03-16 23:37:15 +08:00
|
|
|
|
/**
|
|
|
|
|
* @brief Decodes the sib field of the instruction. This method reads an additional
|
|
|
|
|
* input byte.
|
2015-05-16 11:05:17 +08:00
|
|
|
|
* @param info The @c InstructionInfo struct that receives the decoded data.
|
2015-03-16 23:37:15 +08:00
|
|
|
|
* @return True if it succeeds, false if it fails.
|
|
|
|
|
*/
|
2015-05-16 11:05:17 +08:00
|
|
|
|
bool decodeSIB(InstructionInfo& info);
|
2015-03-16 23:37:15 +08:00
|
|
|
|
/**
|
|
|
|
|
* @brief Decodes vex prefix of the instruction. This method takes the current input byte
|
|
|
|
|
* to determine the vex prefix type and reads one or two additional input bytes
|
|
|
|
|
* on demand.
|
2015-05-16 11:05:17 +08:00
|
|
|
|
* @param info The @c InstructionInfo struct that receives the decoded data.
|
2015-03-16 23:37:15 +08:00
|
|
|
|
* @return True if it succeeds, false if it fails.
|
|
|
|
|
*/
|
2015-05-16 11:05:17 +08:00
|
|
|
|
bool decodeVex(InstructionInfo& info);
|
2015-03-16 23:37:15 +08:00
|
|
|
|
private:
|
|
|
|
|
/**
|
|
|
|
|
* @brief Returns the effective operand size.
|
|
|
|
|
* @param info The instruction info.
|
|
|
|
|
* @param operandSize The defined operand size.
|
|
|
|
|
* @return The effective operand size.
|
|
|
|
|
*/
|
2015-05-16 11:05:17 +08:00
|
|
|
|
uint16_t getEffectiveOperandSize(const InstructionInfo& info,
|
|
|
|
|
DefinedOperandSize operandSize) const;
|
2015-03-16 23:37:15 +08:00
|
|
|
|
/**
|
|
|
|
|
* @brief Decodes all instruction operands.
|
2015-05-16 11:05:17 +08:00
|
|
|
|
* @param info The @c InstructionInfo struct that receives the decoded data.
|
2015-03-16 23:37:15 +08:00
|
|
|
|
* @return True if it succeeds, false if it fails.
|
|
|
|
|
*/
|
2015-05-16 11:05:17 +08:00
|
|
|
|
bool decodeOperands(InstructionInfo& info);
|
2015-03-16 23:37:15 +08:00
|
|
|
|
/**
|
|
|
|
|
* @brief Decodes the specified instruction operand.
|
|
|
|
|
* @param info The instruction info.
|
2015-05-16 11:05:17 +08:00
|
|
|
|
* @param operand The @c OperandInfo struct that receives the decoded data.
|
2015-03-16 23:37:15 +08:00
|
|
|
|
* @param operandType The defined type of the operand.
|
|
|
|
|
* @param operandSize The defined size of the operand.
|
|
|
|
|
* @return True if it succeeds, false if it fails.
|
|
|
|
|
*/
|
2015-05-16 11:05:17 +08:00
|
|
|
|
bool decodeOperand(InstructionInfo& info, OperandInfo& operand,
|
|
|
|
|
DefinedOperandType operandType, DefinedOperandSize operandSize);
|
2015-03-16 23:37:15 +08:00
|
|
|
|
private:
|
|
|
|
|
/**
|
|
|
|
|
* @brief Resolves the effective operand and address mode of the instruction.
|
|
|
|
|
* This method requires a non-null value in the @c instrDefinition field of the
|
|
|
|
|
* @c info struct.
|
2015-05-16 11:05:17 +08:00
|
|
|
|
* @param info The @c InstructionInfo struct that receives the effective operand and
|
2015-03-16 23:37:15 +08:00
|
|
|
|
* address mode.
|
|
|
|
|
*/
|
2015-05-16 11:05:17 +08:00
|
|
|
|
void resolveOperandAndAddressMode(InstructionInfo& info) const;
|
2015-03-16 23:37:15 +08:00
|
|
|
|
/**
|
|
|
|
|
* @brief Calculates the effective REX/VEX.w, r, x, b, l values.
|
|
|
|
|
* This method requires a non-null value in the @c instrDefinition field of the
|
|
|
|
|
* @c info struct.
|
2015-05-16 11:05:17 +08:00
|
|
|
|
* @param info The @c InstructionInfo struct that receives the effective operand and
|
2015-03-16 23:37:15 +08:00
|
|
|
|
* address mode.
|
|
|
|
|
*/
|
2015-05-16 11:05:17 +08:00
|
|
|
|
void calculateEffectiveRexVexValues(InstructionInfo& info) const;
|
2015-03-16 23:37:15 +08:00
|
|
|
|
private:
|
|
|
|
|
/**
|
|
|
|
|
* @brief Collects and decodes optional instruction prefixes.
|
2015-05-16 11:05:17 +08:00
|
|
|
|
* @param info The @c InstructionInfo struct that receives the decoded data.
|
2015-03-16 23:37:15 +08:00
|
|
|
|
* @return True if it succeeds, false if it fails.
|
|
|
|
|
*/
|
2015-05-16 11:05:17 +08:00
|
|
|
|
bool decodePrefixes(InstructionInfo& info);
|
2015-03-16 23:37:15 +08:00
|
|
|
|
/**
|
|
|
|
|
* @brief Collects and decodes the instruction opcodes using the opcode tree.
|
2015-05-16 11:05:17 +08:00
|
|
|
|
* @param info The @c InstructionInfo struct that receives the decoded data.
|
2015-03-16 23:37:15 +08:00
|
|
|
|
* @return True if it succeeds, false if it fails.
|
|
|
|
|
*/
|
2015-05-16 11:05:17 +08:00
|
|
|
|
bool decodeOpcode(InstructionInfo& info);
|
2015-03-16 23:37:15 +08:00
|
|
|
|
public:
|
|
|
|
|
/**
|
|
|
|
|
* @brief Default constructor.
|
|
|
|
|
*/
|
2015-05-16 11:05:17 +08:00
|
|
|
|
InstructionDecoder();
|
2015-03-16 23:37:15 +08:00
|
|
|
|
/**
|
|
|
|
|
* @brief Constructor.
|
|
|
|
|
* @param input A reference to the input data source.
|
|
|
|
|
* @param disassemblerMode The disasasembler mode.
|
|
|
|
|
* @param preferredVendor The preferred instruction-set vendor.
|
|
|
|
|
* @param instructionPointer The initial instruction pointer.
|
|
|
|
|
*/
|
2015-05-16 11:05:17 +08:00
|
|
|
|
explicit InstructionDecoder(BaseInput* input,
|
|
|
|
|
DisassemblerMode disassemblerMode = DisassemblerMode::M32BIT,
|
|
|
|
|
InstructionSetVendor preferredVendor = InstructionSetVendor::ANY,
|
2015-03-16 23:37:15 +08:00
|
|
|
|
uint64_t instructionPointer = 0);
|
|
|
|
|
public:
|
|
|
|
|
/**
|
|
|
|
|
* @brief Decodes the next instruction from the input data source.
|
2015-05-16 11:05:17 +08:00
|
|
|
|
* @param info The @c InstructionInfo struct that receives the information about the
|
2015-03-16 23:37:15 +08:00
|
|
|
|
* decoded instruction.
|
|
|
|
|
* @return This method returns false, if the current position has exceeded the maximum input
|
|
|
|
|
* length.
|
|
|
|
|
* In all other cases (valid and invalid instructions) the return value is true.
|
|
|
|
|
*/
|
2015-05-16 11:05:17 +08:00
|
|
|
|
bool decodeInstruction(InstructionInfo& info);
|
2015-03-16 23:37:15 +08:00
|
|
|
|
public:
|
|
|
|
|
/**
|
|
|
|
|
* @brief Returns a pointer to the current data source.
|
|
|
|
|
* @return A pointer to the current data source.
|
|
|
|
|
*/
|
2015-05-16 11:05:17 +08:00
|
|
|
|
BaseInput* getDataSource() const;
|
2015-03-16 23:37:15 +08:00
|
|
|
|
/**
|
|
|
|
|
* @brief Sets a new data source.
|
|
|
|
|
* @param input A reference to the new input data source.
|
|
|
|
|
*/
|
2015-05-16 11:05:17 +08:00
|
|
|
|
void setDataSource(BaseInput* input);
|
2015-03-16 23:37:15 +08:00
|
|
|
|
/**
|
|
|
|
|
* @brief Returns the current disassembler mode.
|
|
|
|
|
* @return The current disassembler mode.
|
|
|
|
|
*/
|
2015-05-16 11:05:17 +08:00
|
|
|
|
DisassemblerMode getDisassemblerMode() const;
|
2015-03-16 23:37:15 +08:00
|
|
|
|
/**
|
|
|
|
|
* @brief Sets the current disassembler mode.
|
|
|
|
|
* @param disassemblerMode The new disassembler mode.
|
|
|
|
|
*/
|
2015-05-16 11:05:17 +08:00
|
|
|
|
void setDisassemblerMode(DisassemblerMode disassemblerMode);
|
2015-03-16 23:37:15 +08:00
|
|
|
|
/**
|
|
|
|
|
* @brief Returns the preferred instruction-set vendor.
|
|
|
|
|
* @return The preferred instruction-set vendor.
|
|
|
|
|
*/
|
2015-05-16 11:05:17 +08:00
|
|
|
|
InstructionSetVendor getPreferredVendor() const;
|
2015-03-16 23:37:15 +08:00
|
|
|
|
/**
|
|
|
|
|
* @brief Sets the preferred instruction-set vendor.
|
|
|
|
|
* @param preferredVendor The new preferred instruction-set vendor.
|
|
|
|
|
*/
|
2015-05-16 11:05:17 +08:00
|
|
|
|
void setPreferredVendor(InstructionSetVendor preferredVendor);
|
2015-03-16 23:37:15 +08:00
|
|
|
|
/**
|
|
|
|
|
* @brief Returns the current instruction pointer.
|
|
|
|
|
* @return The current instruction pointer.
|
|
|
|
|
*/
|
|
|
|
|
uint64_t getInstructionPointer() const;
|
|
|
|
|
/**
|
|
|
|
|
* @brief Sets a new instruction pointer.
|
|
|
|
|
* @param instructionPointer The new instruction pointer.
|
|
|
|
|
*/
|
|
|
|
|
void setInstructionPointer(uint64_t instructionPointer);
|
|
|
|
|
};
|
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
inline uint8_t InstructionDecoder::inputPeek(InstructionInfo& info)
|
2015-03-16 23:37:15 +08:00
|
|
|
|
{
|
2015-05-16 11:05:17 +08:00
|
|
|
|
if (!m_input)
|
2015-03-16 23:37:15 +08:00
|
|
|
|
{
|
|
|
|
|
info.flags |= IF_ERROR_END_OF_INPUT;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2015-05-16 11:05:17 +08:00
|
|
|
|
return m_input->inputPeek(info);
|
2015-03-16 23:37:15 +08:00
|
|
|
|
}
|
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
inline uint8_t InstructionDecoder::inputNext(InstructionInfo& info)
|
2015-03-16 23:37:15 +08:00
|
|
|
|
{
|
2015-05-16 11:05:17 +08:00
|
|
|
|
if (!m_input)
|
2015-03-16 23:37:15 +08:00
|
|
|
|
{
|
|
|
|
|
info.flags |= IF_ERROR_END_OF_INPUT;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2015-05-16 11:05:17 +08:00
|
|
|
|
return m_input->inputNext(info);
|
2015-03-16 23:37:15 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
2015-05-16 11:05:17 +08:00
|
|
|
|
inline T InstructionDecoder::inputNext(InstructionInfo& info)
|
2015-03-16 23:37:15 +08:00
|
|
|
|
{
|
2015-05-16 11:05:17 +08:00
|
|
|
|
if (!m_input)
|
2015-03-16 23:37:15 +08:00
|
|
|
|
{
|
|
|
|
|
info.flags |= IF_ERROR_END_OF_INPUT;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2015-05-16 11:05:17 +08:00
|
|
|
|
return m_input->inputNext<T>(info);
|
2015-03-16 23:37:15 +08:00
|
|
|
|
}
|
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
inline uint8_t InstructionDecoder::inputCurrent() const
|
2015-03-16 23:37:15 +08:00
|
|
|
|
{
|
2015-05-16 11:05:17 +08:00
|
|
|
|
if (!m_input)
|
2015-03-16 23:37:15 +08:00
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2015-05-16 11:05:17 +08:00
|
|
|
|
return m_input->inputCurrent();
|
2015-03-16 23:37:15 +08:00
|
|
|
|
}
|
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
inline BaseInput *InstructionDecoder::getDataSource() const
|
2015-03-16 23:37:15 +08:00
|
|
|
|
{
|
2015-05-16 11:05:17 +08:00
|
|
|
|
return m_input;
|
2015-03-16 23:37:15 +08:00
|
|
|
|
}
|
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
inline void InstructionDecoder::setDataSource(BaseInput* input)
|
2015-03-16 23:37:15 +08:00
|
|
|
|
{
|
2015-05-16 11:05:17 +08:00
|
|
|
|
m_input = input;
|
2015-03-16 23:37:15 +08:00
|
|
|
|
}
|
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
inline DisassemblerMode InstructionDecoder::getDisassemblerMode() const
|
2015-03-16 23:37:15 +08:00
|
|
|
|
{
|
|
|
|
|
return m_disassemblerMode;
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
inline void InstructionDecoder::setDisassemblerMode(DisassemblerMode disassemblerMode)
|
2015-03-16 23:37:15 +08:00
|
|
|
|
{
|
|
|
|
|
m_disassemblerMode = disassemblerMode;
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
inline InstructionSetVendor InstructionDecoder::getPreferredVendor() const
|
2015-03-16 23:37:15 +08:00
|
|
|
|
{
|
|
|
|
|
return m_preferredVendor;
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
inline void InstructionDecoder::setPreferredVendor(InstructionSetVendor preferredVendor)
|
2015-03-16 23:37:15 +08:00
|
|
|
|
{
|
|
|
|
|
m_preferredVendor = preferredVendor;
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
inline uint64_t InstructionDecoder::getInstructionPointer() const
|
2015-03-16 23:37:15 +08:00
|
|
|
|
{
|
|
|
|
|
return m_instructionPointer;
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
inline void InstructionDecoder::setInstructionPointer(uint64_t instructionPointer)
|
2015-03-16 23:37:15 +08:00
|
|
|
|
{
|
|
|
|
|
m_instructionPointer = instructionPointer;
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
/* ============================================================================================== */
|
2015-03-16 23:37:15 +08:00
|
|
|
|
|
|
|
|
|
}
|
2015-05-16 11:05:17 +08:00
|
|
|
|
|
|
|
|
|
#endif /* _ZYDIS_INSTRUCTIONDECODER_HPP_ */
|