#include <Zydis/Zydis.h>
#include <asmjit/x86.h>

#include <cstdint>
#include <vector>
#include <stack>
#include <time.h>
#include <random>
#include <map>
#include "../utils.hpp"

#define JMP_RIP_SIZE 14
#define JMP_RIP_ADDR_IDX 6

namespace obfuscation
{
	inline const std::vector<std::uint8_t> jmp_rip =
	{
		0xFF, 0x25, 0x00, 0x00, 0x00, 0x00,			// jmp [rip+0x0]
		0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0		// address...
	};

	enum class reloc_type
	{
		none = -1,
		jcc = 1,
		next_instruction_addr = 2
	};

	struct reloc_t
	{
		reloc_type type;
		std::uint32_t offset;
		std::int32_t rva;
	};

	using instruction_info_t = std::pair<ZydisDecodedInstruction, std::vector<std::uint8_t>>;
	using gadget_stack_t = std::vector<std::pair<std::vector<std::uint8_t>, reloc_t>>;

	class obfuscate
	{
	public:
		explicit obfuscate(instruction_info_t info);
		auto get_size() const -> std::uint32_t;
		auto get_gadget() const -> gadget_stack_t;
		auto get_instruc() const -> ZydisDecodedInstruction;
		instruction_info_t instruction;
		gadget_stack_t gadget_stack;
	};

	// you can inherit "obfuscate" and add 
	// whatever code you want to each gadget...
	//
	// this is just an example of dynamic push/pop palandromes...
	class mutation : public obfuscate
	{
	public:
		explicit mutation(instruction_info_t info);
	};
}