#include "RyujinObfuscationCore.hh"

RyujinObfuscationCore::RyujinObfuscationCore(const RyujinObfuscatorConfig& config, const RyujinProcedure& proc, uintptr_t ProcImageBase) {

	m_proc = proc;
	m_config = config;
	m_ProcImageBase = ProcImageBase;

	if (!extractUnusedRegisters())
		throw std::exception("No registers avaliable for obfuscation...");

}

RyujinProcedure RyujinObfuscationCore::getProcessedProc() {

	return this->m_proc;
}

BOOL RyujinObfuscationCore::extractUnusedRegisters() {

	// List of all general-purpose registers considered as candidates for junk/mutation during comparison.
	const std::vector<ZydisRegister> candidateGprRegs = {

		ZYDIS_REGISTER_RAX, ZYDIS_REGISTER_RCX, ZYDIS_REGISTER_RDX,
		ZYDIS_REGISTER_RBX, ZYDIS_REGISTER_RSI, ZYDIS_REGISTER_RDI,
		ZYDIS_REGISTER_R8,  ZYDIS_REGISTER_R9,  ZYDIS_REGISTER_R10,
		ZYDIS_REGISTER_R11, ZYDIS_REGISTER_R12, ZYDIS_REGISTER_R13,
		ZYDIS_REGISTER_R14, ZYDIS_REGISTER_R15
	
	};

	// List of XMM registers considered as candidates for junk/mutation during comparison.
	const std::vector<ZydisRegister> candidateXmmRegs = {

		ZYDIS_REGISTER_XMM0,  ZYDIS_REGISTER_XMM1,  ZYDIS_REGISTER_XMM2,  ZYDIS_REGISTER_XMM3,
		ZYDIS_REGISTER_XMM4,  ZYDIS_REGISTER_XMM5,  ZYDIS_REGISTER_XMM6,  ZYDIS_REGISTER_XMM7,
		ZYDIS_REGISTER_XMM8,  ZYDIS_REGISTER_XMM9,  ZYDIS_REGISTER_XMM10, ZYDIS_REGISTER_XMM11,
		ZYDIS_REGISTER_XMM12, ZYDIS_REGISTER_XMM13, ZYDIS_REGISTER_XMM14, ZYDIS_REGISTER_XMM15
	
	};

	m_unusedRegisters.clear();

	std::set<ZydisRegister> usedRegs;

	// Regardless of everything, the stack manipulation registers RSP and RBP will always be considered as used.
	usedRegs.insert(ZYDIS_REGISTER_RSP);
	usedRegs.insert(ZYDIS_REGISTER_RBP);

	for (const auto& block : m_proc.basic_blocks) {

		for (const auto& instr : block.instructions) {

			const auto& dinfo = instr.instruction.info;
			const uint8_t opcount = dinfo.operand_count;

			for (uint8_t i = 0; i < opcount; ++i) {
		
				const ZydisDecodedOperand& op = instr.instruction.operands[i];

				// Registers with explicit operands
				if (op.type == ZYDIS_OPERAND_TYPE_REGISTER) {

					ZydisRegister reg = op.reg.value;
					ZydisRegisterClass cls = ZydisRegisterGetClass(reg);

					// Normalizing GPRs to GPR64 registers
					if (cls == ZYDIS_REGCLASS_GPR8 || cls == ZYDIS_REGCLASS_GPR16 || cls == ZYDIS_REGCLASS_GPR32 || cls == ZYDIS_REGCLASS_GPR64) {

						int16_t id = ZydisRegisterGetId(reg);

						// Considering the lower-nibble registers
						if (cls == ZYDIS_REGCLASS_GPR8 && id >= 4 && id <= 7)
							id -= 4;

						ZydisRegister reg64 = ZydisRegisterEncode(ZYDIS_REGCLASS_GPR64, id);
						if (reg64 != ZYDIS_REGISTER_NONE) usedRegs.insert(reg64);

					}
					// Fetching XMM registers
					else if (cls == ZYDIS_REGCLASS_XMM)
						usedRegs.insert(reg);
					// Checking for segment registers
					else if (cls == ZYDIS_REGCLASS_SEGMENT)
						usedRegs.insert(reg);
				}
				// Registers in use with memory operands
				else if (op.type == ZYDIS_OPERAND_TYPE_MEMORY) {

					if (op.mem.base != ZYDIS_REGISTER_NONE) {

						ZydisRegister base = op.mem.base;
						ZydisRegisterClass cls = ZydisRegisterGetClass(base);

						if (cls == ZYDIS_REGCLASS_GPR8 || cls == ZYDIS_REGCLASS_GPR16 || cls == ZYDIS_REGCLASS_GPR32 || cls == ZYDIS_REGCLASS_GPR64) {

							int16_t id = ZydisRegisterGetId(base);
							ZydisRegister base64 = ZydisRegisterEncode(ZYDIS_REGCLASS_GPR64, id);
							if (base64 != ZYDIS_REGISTER_NONE) usedRegs.insert(base64);

						}
						else
							usedRegs.insert(base);

					}

					// Collecting index registers
					if (op.mem.index != ZYDIS_REGISTER_NONE) {

						ZydisRegister idx = op.mem.index;
						ZydisRegisterClass cls = ZydisRegisterGetClass(idx);

						if (cls == ZYDIS_REGCLASS_GPR8 || cls == ZYDIS_REGCLASS_GPR16 || cls == ZYDIS_REGCLASS_GPR32 || cls == ZYDIS_REGCLASS_GPR64) {

							int16_t id = ZydisRegisterGetId(idx);
							ZydisRegister idx64 = ZydisRegisterEncode(ZYDIS_REGCLASS_GPR64, id);
							if (idx64 != ZYDIS_REGISTER_NONE) usedRegs.insert(idx64);
						
						}
						else
							usedRegs.insert(idx);
					
					}

					// Hackfix for segment registers like: cs:[rax]
					if (op.mem.segment != ZYDIS_REGISTER_NONE)
						usedRegs.insert(op.mem.segment);

				}
			}
		}
	}

	/*
	   Based on the collected registers, compare each register with the list of used registers
	   so we can build the unique set of used registers.
	*/
	for (ZydisRegister r : candidateGprRegs)
		if (usedRegs.count(r) == 0)
			m_unusedRegisters.push_back(r);

	/*
	*  TEMPORARILY DISABLED until Ryujin implements support for multimedia registers.
	*
	*  Based on the collected XMM registers, compare each register with the list of used XMM registers
	*  to build the unique set of used XMM registers.
	*/
	//for (ZydisRegister r : candidateXmmRegs)
	//    if (usedRegs.count(r) == 0)
	//        m_unusedRegisters.push_back(r);

	// We need at least 2 registers in order for obfuscation to work.
	return (m_unusedRegisters.size() >= 2); // Seriously, Keowu? Yes. We need room to run some passes.
}

void RyujinObfuscationCore::addPaddingSpaces() {

	// Initializing AsmJit
	asmjit::JitRuntime runtime;

	for (auto& block : m_proc.basic_blocks) {

		// Vector to store the opcodes related to the current context basic block
		std::vector<std::vector<ZyanU8>> new_instructions;

		for (auto& opcode : block.opcodes) {

			// Saving all original opcodes of the basic block
			std::vector<ZyanU8> new_opcodes;

			for (auto individual_opcode : opcode)
				new_opcodes.push_back(individual_opcode);

			// Adding them to the main control vector
			new_instructions.push_back(new_opcodes);

			//Storing Nop-Spacing
			std::vector<ZyanU8> gen_opcodes;

			// Initializing AsmJit
			asmjit::CodeHolder code;
			code.init(runtime.environment());
			asmjit::x86::Assembler a(&code);

			// Inserting nop-spacing technique
			for (auto i = 0; i < MAX_PADDING_SPACE_INSTR; i++) a.nop();

			// Flush flatten
			code.flatten();

			// Getting the result from JIT
			auto section = code.sectionById(0);
			const auto buf = section->buffer().data();
			auto size = section->buffer().size();

			// Storing each new generated opcode
			for (auto i = 0; i < size; ++i) gen_opcodes.push_back(buf[i]);

			// Storing in the main vector of the block
			new_instructions.push_back(gen_opcodes);

		}

		//Overrite the original opcodes with new ones
		block.opcodes.clear();
		block.opcodes.assign(new_instructions.begin(), new_instructions.end());

	}

}

void RyujinObfuscationCore::obfuscateIat() {

	/*
		Unexpected Ryujin requires at least one unused register in the current procedure to deobfuscate the IAT during runtime
	*/
	if (m_unusedRegisters.size() == 0) return;

	for (auto& block : m_obfuscated_bb) {

		for (auto& instr : block.instructions) {

			if (instr.instruction.info.meta.category == ZYDIS_CATEGORY_CALL && instr.instruction.operands->type == ZYDIS_OPERAND_TYPE_MEMORY) {

				// Finding the block info related to the obfuscated opcode
				auto block_info = findBlockId(instr.instruction.info.opcode, instr.instruction.operands->mem.disp.value, 2, sizeof(uint32_t));

				// Call to an invalid IAT in the list of basic blocks
				if (block_info.first == -1 || block_info.second == -1) continue;

				// Retrieving the original opcodes where the opcodes have already been updated and obfuscated
				auto& data = m_proc.basic_blocks[block_info.first].opcodes[block_info.second];

				// Retrieving the "INSTRUCTION" from the basic block for our IAT call related to this context we're working with
				auto orInstr = m_proc.basic_blocks[block_info.first].instructions.back(); // A call [IAT] will always be the last entry

				/*
					Let's calculate the IAT address that stores the resolved address for the given CALL
				*/
				// Calculating the VA of the next instruction after the "CALL" to the IAT in the original section
				const uintptr_t next_instruction_address = orInstr.addressofinstruction + orInstr.instruction.info.length;

				// Calculating the target address of the IAT using the memory immediate from the original instruction
				uint32_t iat_target_rva = (next_instruction_address + orInstr.instruction.operands->mem.disp.value) - m_ProcImageBase;

				/*
					Let's obfuscate our RVA
				*/
				// Generating two random bytes for the key
				std::mt19937 rng(std::random_device{}());
				// A single random value of 2 bytes (uint16_t)
				std::uniform_int_distribution<uint16_t> dist(0, 0xFFFF);
				uint16_t xorKey = dist(rng);

				// Obfsucate the RVA with a XOR
				iat_target_rva ^= xorKey;

				// Obfuscate PEB offset from automatic scan
				unsigned char PebGsOffset  = 0x60 ^ (xorKey & 0xFF);
				unsigned char ImageBasePeb = 0x10 ^ (xorKey & 0xFF);

				// A new vector to store our corrected IAT
				std::vector<ZyanU8> new_iat_call;

				//Begin ASMJIT configuration
				asmjit::JitRuntime runtime;
				asmjit::CodeHolder code;
				code.init(runtime.environment());
				asmjit::x86::Assembler a(&code);

				// Breaking Decompilers
				insertBreakDecompilers(a);

				// Using `rdgsbase rax` to store the base address of the GS segment in RAX -> rdgsbase rax
				a.emit(asmjit::x86::Inst::kIdRdgsbase, asmjit::x86::rax);

				// Adding the obfuscated offset of the PEB in the GS segment -> add rax, PebGsOffset
				a.add(asmjit::x86::rax, PebGsOffset);

				// Undoing the XOR operation with the obfuscated RAX value and the XOR key -> xor rax, lastByteXorKey
				a.xor_(asmjit::x86::rax, asmjit::imm(xorKey & 0xFF));

				// Accessing the resulting address to retrieve the PEB instance -> mov rax, [rax]
				a.mov(asmjit::x86::rax, asmjit::x86::ptr(asmjit::x86::rax));

				// Adding the obfuscated offset of the ImageBase field in the PEB -> add rax, ImageBasePeb
				a.add(asmjit::x86::rax, ImageBasePeb);

				// Undoing the XOR operation with the obfuscated value and the XOR key -> xor rax, lastByteXorKey
				a.xor_(asmjit::x86::rax, asmjit::imm(xorKey & 0xFF));

				// Accessing the resulting address to retrieve the PEB+ImageBase instance -> mov rax, [rax]
				a.mov(asmjit::x86::rax, asmjit::x86::ptr(asmjit::x86::rax));

				// Adding the RVA that points to the entry in the IAT -> add rax, imm32 -> Adding the offset of the IAT entry
				a.add(asmjit::x86::rax, asmjit::imm(iat_target_rva));
				
				// Undoing the XOR operation with the obfuscated value and the XOR key -> xor rax, xorKey
				a.xor_(asmjit::x86::rax, asmjit::imm(xorKey));

				// mov rax, [rax] -> retrieving the resolved address for the IAT entry by the OS loader
				a.mov(asmjit::x86::rax, asmjit::x86::ptr(asmjit::x86::rax));

				// call rax -> Calling the IAT
				a.call(asmjit::x86::rax);

				// Breaking Decompilers
				insertBreakDecompilers(a);

				// Obtaining the new section buffer
				auto& opcodeBuffer = code.sectionById(0)->buffer();
				// Obtaining the pointer to the buffer of raw opcode data generated
				const auto pOpcodeBuffer = opcodeBuffer.data();
				// Reserving space in the IAT vector
				new_iat_call.reserve(opcodeBuffer.size());

				// Storing each opcode individually in the vector for our new IAT call
				for (auto i = 0; i < opcodeBuffer.size(); ++i) new_iat_call.push_back(static_cast<ZyanU8>(pOpcodeBuffer[i]));

				// Replacing opcodes of the call in question with the new ones
				data.assign(new_iat_call.begin(), new_iat_call.end());

				std::printf("[OK] Obfuscating IAT CALL: %s\n", instr.instruction.text);

			}

		}

	}

	return;
}

void RyujinObfuscationCore::insertJunkCode() {

	// Initializing AsmJit
	asmjit::JitRuntime runtime;
	
	for (auto& block : m_proc.basic_blocks) {

		// New vector to load the updated opcodes for the given block
		std::vector<std::vector<ZyanU8>> new_instructions;
		
		for (auto& opcode : block.opcodes) {

			// Saving all original opcodes of the basic block
			std::vector<ZyanU8> new_opcodes;

			// Storing the original opcodes of the procedure
			for (auto individual_opcode : opcode) new_opcodes.push_back(individual_opcode);

			// Inserting original opcodes into the control vector
			new_instructions.push_back(new_opcodes);

			// Generating junk code
			std::vector<ZyanU8> junk_opcodes;

			// Initializing AsmJit
			asmjit::CodeHolder code;
			code.init(runtime.environment());
			asmjit::x86::Assembler a(&code);

			// Let's iterate over all registers not used by the procedure to generate junk code
			for (auto reg : m_unusedRegisters) {

				// Nop-Spacing technique for alignment
				for (auto i = 0; i < MAX_PADDING_SPACE_INSTR; i++) a.nop();

				// Junk code insertion technique
				for (auto i = 0; i < MAX_JUNK_GENERATION_ITERATION; i++) {

					/*
						Converting ZydisRegister to GP Register based on it's own ID.
					*/
					// Only x64 registers
					if (ZydisRegisterGetClass(reg) != ZYDIS_REGCLASS_GPR64) continue;
					
					// Converting ZydisRegister to GB Register Index
					auto idx = ZydisRegisterGetId(reg);
					
					// Ignore stack unused registers, if the feature for extracting unused register fail
					if (idx == 4 /*RSP*/ || idx == 5 /*RBP*/) continue;
	
					// Converting GB Register Index to a GB Register
					auto regx = a.gpz(uint32_t(idx));

					/*
						Generating Junk Code instructions randomly
					*/

					// Generating random value for obfuscation
					std::random_device rd;
					std::mt19937 gen(rd());

					std::uniform_int_distribution<uint32_t> quantity_dist(0, 69);     // Instructions per block
					std::uniform_int_distribution<uint32_t> opcode_dist(0, 37);       // 37 supported instructions
					std::uniform_int_distribution<uint32_t> imm_dist(1, 100);         // Range for randomizing immediate values
					std::uniform_int_distribution<uint32_t> shift_dist(0, 69);        // Range for randomizing bitwise values

					// Junk Code In
					a.push(regx);
					a.pushf();

					// Generating number of instructions for the junk code block
					auto numInstructions = quantity_dist(gen);

					for (auto i = 0; i < numInstructions; ++i) {

						/*
							Generating random values for the opcode, immediate value, and displacement value (bitwise).
						*/
						auto opcode = opcode_dist(gen);
						auto value = imm_dist(gen);
						auto shift = shift_dist(gen);

						// Choosing an opcode to use for randomizing the junk code
						switch (opcode) {

							case 0:  a.add(regx, value); break;
							case 1:  a.sub(regx, value); break;
							case 2:  a.imul(regx, value); break;
							case 3:  a.xor_(regx, value); break;
							case 4:  a.or_(regx, value); break;
							case 5:  a.and_(regx, value); break;
							case 6:  a.not_(regx); break;
							case 7:  a.neg(regx); break;
							case 8:  a.shl(regx, shift); break;
							case 9:  a.shr(regx, shift); break;
							case 10: a.sar(regx, shift); break;
							case 11: a.rol(regx, shift); break;
							case 12: a.ror(regx, shift); break;
							case 13: a.inc(regx); break;
							case 14: a.dec(regx); break;
							case 15: a.test(regx, value); break;
							case 16: a.cmp(regx, value); break;
							case 17: a.lea(regx, asmjit::x86::ptr(regx, value)); break;
							case 18: a.nop(); break;
							case 19: a.add(regx, regx); break;

							/*
								Additional instructions contributions coming directly from VMProtect mutation
								(https://keowu.re/posts/Analyzing-Mutation-Coded-VM-Protect-and-Alcatraz-English/#analyzing-techniques-and-mutation-of-vm-protect)
							*/
							case 20: a.bt(regx, value); break;
							case 21: a.bts(regx, value); break;
							case 22: a.btc(regx, value); break;
							case 23: a.movzx(regx.r32(), regx.r8()); break;
							case 24: a.movsx(regx.r32(), regx.r8()); break;
							case 25: a.movsxd(regx, regx.r32()); break;
							case 26: a.cmovs(regx, regx); break;
							case 27: a.cmovp(regx, regx); break;
							case 28: a.sal(regx, shift); break;
							case 29: a.rcl(regx, 1); break;
							case 30: a.rcr(regx, 1); break;
							case 31: a.stc(); break;
							case 32: a.clc(); break;
							case 33: a.cmc(); break;

							//////////////////////////
							// Different logic for these registers because they overwrite RAX
							//--------------------------------------------------
							case 34: {
								a.push(asmjit::x86::rax);
								a.pushf();
								a.cdqe();
								a.popf();
								a.pop(asmjit::x86::rax);
								break;
							}
							case 35: {
								a.push(asmjit::x86::rax);
								a.pushf();
								a.cbw();
								a.popf();
								a.pop(asmjit::x86::rax);
								break;
							}
							///////////////////////////////
							case 36: a.sbb(regx, value); break;
							case 37: a.bsf(regx, regx); break;

							default: break;
						}

					}

					// Junk Code Out
					a.popf();
					a.pop(regx);

				}

			}

			// AsmJit Flush flatten
			code.flatten();

			// Getting the result of opcodes generated via JIT to add to our junk opcodes in the current iteration context
			auto section = code.sectionById(0);
			const auto buf = section->buffer().data();
			auto size = section->buffer().size();
			for (auto i = 0; i < size; ++i) junk_opcodes.push_back(buf[i]);

			// Adding the newly processed opcodes to the global instruction vector
			new_instructions.push_back(junk_opcodes);

		}

		// Overwriting opcodes with the new obfuscated ones
		block.opcodes.clear();
		block.opcodes.assign(new_instructions.begin(), new_instructions.end());
	
	}

}

void RyujinObfuscationCore::insertVirtualization() {

	/*
		1 - Convert the procedure's instructions and their basic blocks into the VM's bytecode (each instruction generates 8 bytes of bytecode).
		2 - Replace the instruction with a call to the VM's interpretation routine and pass the bytecodes via RCX. (Take into account saving the register and stack contexts.)
		3 - Be able to continue execution without issues, integrating the VM routine with the original code that is to be executed and not obfuscated.
		4 - This routine should insert only the VM stub and bytecode. After that, there will be a processing step before saving and fixing relocations, so we can identify the virtualization routine pattern and insert the real address of the VM interpreter to make it work.

		Basically, this is a single-VM that:
			Analyzes the instruction in question, extracts its opcode and maps it to the VM's opcode, extracts its immediates and stores everything in a single set.
		Example:
			0x48 -> mov -> bytecode
			rbx -> bytecode
			10 -> value

		Example output:
			0x112210

		Which will be assigned to the value of RCX:

			push rcx
			mov rcx, 112210h
			call vmentry (but a symbolic value, since the immediate offset wouldn't be inserted here)
			-> rax result goes to the register in question that would continue the execution flow or receive the result, in this example: rbx
			pop rcx

		In this way, the code would continue.
	*/

	/*
		Ryujin MiniVM Logic Begin
	*/
	// Is it a candidate instruction to be virtualized by the minivm?
	auto isValidToSRyujinMiniVm = [&](RyujinInstruction instr) {

		return instr.instruction.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER && instr.instruction.operands[1].type == ZYDIS_OPERAND_TYPE_IMMEDIATE &&
			// Ignoring registers and stack operations
			(instr.instruction.operands[0].reg.value != ZYDIS_REGISTER_RSP && instr.instruction.operands[0].reg.value != ZYDIS_REGISTER_RBP);
	};

	// Let's map the Zydis register to ASMJIT
	auto mapZydisToAsmjitGp = [&](ZydisRegister zydisReg) -> asmjit::x86::Gp {

		switch (zydisReg) {

			// RAX family
			case ZYDIS_REGISTER_AL:
			case ZYDIS_REGISTER_AH:
			case ZYDIS_REGISTER_AX:
			case ZYDIS_REGISTER_EAX:
			case ZYDIS_REGISTER_RAX: return asmjit::x86::rax;

			// RBX family
			case ZYDIS_REGISTER_BL:
			case ZYDIS_REGISTER_BH:
			case ZYDIS_REGISTER_BX:
			case ZYDIS_REGISTER_EBX:
			case ZYDIS_REGISTER_RBX: return asmjit::x86::rbx;

			// RCX family
			case ZYDIS_REGISTER_CL:
			case ZYDIS_REGISTER_CH:
			case ZYDIS_REGISTER_CX:
			case ZYDIS_REGISTER_ECX:
			case ZYDIS_REGISTER_RCX: return asmjit::x86::rcx;

			// RDX family
			case ZYDIS_REGISTER_DL:
			case ZYDIS_REGISTER_DH:
			case ZYDIS_REGISTER_DX:
			case ZYDIS_REGISTER_EDX:
			case ZYDIS_REGISTER_RDX: return asmjit::x86::rdx;

			// RSI family
			case ZYDIS_REGISTER_SIL:
			case ZYDIS_REGISTER_SI:
			case ZYDIS_REGISTER_ESI:
			case ZYDIS_REGISTER_RSI: return asmjit::x86::rsi;

			// RDI family
			case ZYDIS_REGISTER_DIL:
			case ZYDIS_REGISTER_DI:
			case ZYDIS_REGISTER_EDI:
			case ZYDIS_REGISTER_RDI: return asmjit::x86::rdi;

			// RBP family
			case ZYDIS_REGISTER_BPL:
			case ZYDIS_REGISTER_BP:
			case ZYDIS_REGISTER_EBP:
			case ZYDIS_REGISTER_RBP: return asmjit::x86::rbp;

			// RSP family
			case ZYDIS_REGISTER_SPL:
			case ZYDIS_REGISTER_SP:
			case ZYDIS_REGISTER_ESP:
			case ZYDIS_REGISTER_RSP: return asmjit::x86::rsp;

			// R8 family
			case ZYDIS_REGISTER_R8B:
			case ZYDIS_REGISTER_R8W:
			case ZYDIS_REGISTER_R8D:
			case ZYDIS_REGISTER_R8: return asmjit::x86::r8;

			// R9 family
			case ZYDIS_REGISTER_R9B:
			case ZYDIS_REGISTER_R9W:
			case ZYDIS_REGISTER_R9D:
			case ZYDIS_REGISTER_R9: return asmjit::x86::r9;

			// R10 family
			case ZYDIS_REGISTER_R10B:
			case ZYDIS_REGISTER_R10W:
			case ZYDIS_REGISTER_R10D:
			case ZYDIS_REGISTER_R10: return asmjit::x86::r10;

			// R11 family
			case ZYDIS_REGISTER_R11B:
			case ZYDIS_REGISTER_R11W:
			case ZYDIS_REGISTER_R11D:
			case ZYDIS_REGISTER_R11: return asmjit::x86::r11;

			// R12 family
			case ZYDIS_REGISTER_R12B:
			case ZYDIS_REGISTER_R12W:
			case ZYDIS_REGISTER_R12D:
			case ZYDIS_REGISTER_R12: return asmjit::x86::r12;

			// R13 family
			case ZYDIS_REGISTER_R13B:
			case ZYDIS_REGISTER_R13W:
			case ZYDIS_REGISTER_R13D:
			case ZYDIS_REGISTER_R13: return asmjit::x86::r13;

			// R14 family
			case ZYDIS_REGISTER_R14B:
			case ZYDIS_REGISTER_R14W:
			case ZYDIS_REGISTER_R14D:
			case ZYDIS_REGISTER_R14: return asmjit::x86::r14;

			// R15 family
			case ZYDIS_REGISTER_R15B:
			case ZYDIS_REGISTER_R15W:
			case ZYDIS_REGISTER_R15D:
			case ZYDIS_REGISTER_R15: return asmjit::x86::r15;

			default: break;
		}

	};

	// Let's translate an instruction to the MiniVm bytecode from Ryujin
	auto translateToMiniVmBytecode = [&](ZydisRegister reg, ZyanU8 op, ZyanU64 value) {

		ZyanU64 miniVmByteCode = 0;

		switch (reg) {

			case ZYDIS_REGISTER_EAX:
			case ZYDIS_REGISTER_RAX: {

				miniVmByteCode = 0x33; // reg = RAX
				miniVmByteCode <<= 8;
				miniVmByteCode |= op; // OP TYPE
				miniVmByteCode <<= 8;
				miniVmByteCode |= value; // valor

				break;
			}
			case ZYDIS_REGISTER_RBX: {

				miniVmByteCode = 0x34; // reg = RBX
				miniVmByteCode <<= 8;
				miniVmByteCode |= op; // OP TYPE
				miniVmByteCode <<= 8;
				miniVmByteCode |= value; // valor

				break;
			}
			case ZYDIS_REGISTER_RCX: {
			
				miniVmByteCode = 0x35; // reg = RCX
				miniVmByteCode <<= 8;
				miniVmByteCode |= op; // OP TYPE
				miniVmByteCode <<= 8;
				miniVmByteCode |= value; // valor

				break;
			}
			case ZYDIS_REGISTER_RDX: {
			
				miniVmByteCode = 0x36; // reg = RDX
				miniVmByteCode <<= 8;
				miniVmByteCode |= op; // OP TYPE
				miniVmByteCode <<= 8;
				miniVmByteCode |= value; // valor

				break;
			}
			case ZYDIS_REGISTER_RSI: {
			
				miniVmByteCode = 0x37; // reg = RSI
				miniVmByteCode <<= 8;
				miniVmByteCode |= op; // OP TYPE
				miniVmByteCode <<= 8;
				miniVmByteCode |= value; // valor

				break;
			}
			case ZYDIS_REGISTER_RDI: {
			
				miniVmByteCode = 0x38; // reg = RDI
				miniVmByteCode <<= 8;
				miniVmByteCode |= op; // OP TYPE
				miniVmByteCode <<= 8;
				miniVmByteCode |= value; // valor

				break;
			}
			case ZYDIS_REGISTER_RBP: {
			
				miniVmByteCode = 0x39; // reg = RBP
				miniVmByteCode <<= 8;
				miniVmByteCode |= op; // OP TYPE
				miniVmByteCode <<= 8;
				miniVmByteCode |= value; // valor

				break;
			}
			case ZYDIS_REGISTER_RSP: {
			
				miniVmByteCode = 0x40; // reg = RSP
				miniVmByteCode <<= 8;
				miniVmByteCode |= op; // OP TYPE
				miniVmByteCode <<= 8;
				miniVmByteCode |= value; // valor

				break;
			}
			case ZYDIS_REGISTER_R8: {

				miniVmByteCode = 0x41; // reg = R8
				miniVmByteCode <<= 8;
				miniVmByteCode |= op; // OP TYPE
				miniVmByteCode <<= 8;
				miniVmByteCode |= value; // valor

				break;
			}
			case ZYDIS_REGISTER_R9: { 

				miniVmByteCode = 0x42; // reg = R9
				miniVmByteCode <<= 8;
				miniVmByteCode |= op; // OP TYPE
				miniVmByteCode <<= 8;
				miniVmByteCode |= value; // valor

				break;
			}
			case ZYDIS_REGISTER_R10: { 

				miniVmByteCode = 0x43; // reg = R10
				miniVmByteCode <<= 8;
				miniVmByteCode |= op; // OP TYPE
				miniVmByteCode <<= 8;
				miniVmByteCode |= value; // valor

				break;
			}
			case ZYDIS_REGISTER_R11: { 
				
				miniVmByteCode = 0x44; // reg = R11
				miniVmByteCode <<= 8;
				miniVmByteCode |= op; // OP TYPE
				miniVmByteCode <<= 8;
				miniVmByteCode |= value; // valor

				break;
			}
			case ZYDIS_REGISTER_R12: { 
				
				miniVmByteCode = 0x45; // reg = R12
				miniVmByteCode <<= 8;
				miniVmByteCode |= op; // OP TYPE
				miniVmByteCode <<= 8;
				miniVmByteCode |= value; // valor

				break;
			}
			case ZYDIS_REGISTER_R13: { 
				
				miniVmByteCode = 0x46; // reg = R13
				miniVmByteCode <<= 8;
				miniVmByteCode |= op; // OP TYPE
				miniVmByteCode <<= 8;
				miniVmByteCode |= value; // valor

				break;
			}
			case ZYDIS_REGISTER_R14: { 
				
				miniVmByteCode = 0x47; // reg = R14
				miniVmByteCode <<= 8;
				miniVmByteCode |= op; // OP TYPE
				miniVmByteCode <<= 8;
				miniVmByteCode |= value; // valor

				break;
			}
			case ZYDIS_REGISTER_R15: { 
			
				miniVmByteCode = 0x48; // reg = R15
				miniVmByteCode <<= 8;
				miniVmByteCode |= op; // OP TYPE
				miniVmByteCode <<= 8;
				miniVmByteCode |= value; // valor

				break;
			}

			default: break;
		}

		return miniVmByteCode;
	};

	// Initializing the asmjit runtime
	asmjit::JitRuntime runtime;

	for (auto& block : m_proc.basic_blocks) {
		
		for (auto& instr : block.instructions) {
			
			// Vector to store the MiniVm opcodes from Ryujin
			std::vector<ZyanU8> minivm_enter;

			// Operand type
			ZyanU8 opType = 0;

			// Finding the block info for the current opcode
			auto block_info = findBlockId(instr.instruction.info.opcode, instr.instruction.operands[1].imm.value.u, 2, sizeof(unsigned char));

			// If not found
			if (block_info.first == -1 || block_info.second == -1) continue;

			// Retrieving the original opcodes of the instruction we're working on
			auto& data = m_proc.basic_blocks[block_info.first].opcodes[block_info.second];

			// Checking for operands that are candidates to be virtualized by the minivm
			if (instr.instruction.info.mnemonic == ZYDIS_MNEMONIC_ADD && isValidToSRyujinMiniVm(instr)) opType = 1;
			else if (instr.instruction.info.mnemonic == ZYDIS_MNEMONIC_SUB && isValidToSRyujinMiniVm(instr)) opType = 2;
			else if (instr.instruction.info.mnemonic == ZYDIS_MNEMONIC_IMUL && isValidToSRyujinMiniVm(instr)) opType = 3;
			else if (instr.instruction.info.mnemonic == ZYDIS_MNEMONIC_DIV && isValidToSRyujinMiniVm(instr)) opType = 4;

			// Is there a new VM Operator?
			if (opType != 0) {

				/*
					Encrypting the PEB acessing fields
				*/
				std::mt19937 rng(std::random_device{}());
				// A single random value of 2 bytes (uint16_t)
				std::uniform_int_distribution<uint16_t> dist(0, 0xFFFFF);
				uint16_t xorKey = dist(rng);

				// Obfuscate PEB offset from automatic scan
				// Xoring PEB Offset
				unsigned char PebGsOffset = 0x60 ^ (xorKey & 0xFF);
				// Xoring ImageBase offset
				unsigned char ImageBasePeb = 0x10 ^ (xorKey & 0xFF);
				// Xoring MiniVM Bytecode
				ZyanU64 vmByteCode = translateToMiniVmBytecode(instr.instruction.operands[0].reg.value, opType, instr.instruction.operands[1].imm.value.u) ^ xorKey;

				// Initializing asmjit to generate our minivm instructions
				asmjit::CodeHolder code;
				code.init(runtime.environment());
				asmjit::x86::Assembler a(&code);

				// Breaking Decompilers
				insertBreakDecompilers(a);
				
				// Saving the current value of RCX
				a.push(asmjit::x86::rcx);
				// Saving the current value of RDX
				a.push(asmjit::x86::rdx);
				// Setup stack for MS HV Code MiniVMm stub
				if (m_config.m_isHVPass) a.sub(asmjit::x86::rsp, 0x28);
				// Storing in the first argument RCX the value of the register from the first operand of the mathematical operation
				a.mov(asmjit::x86::rcx, mapZydisToAsmjitGp(instr.instruction.operands[0].reg.value));
				// Storing in the second argument RDX the value of the bytecode sequence to be interpreted by the Ryujin MiniVM
				a.mov(asmjit::x86::rdx, vmByteCode);
				// Xor key for mini vmbytecode
				a.xor_(asmjit::x86::rdx, asmjit::imm(xorKey));
				// Using `rdgsbase rax` to store the base address of the GS segment in RAX
				a.emit(asmjit::x86::Inst::kIdRdgsbase, asmjit::x86::rax);
				// Adding to RAX the offset value for the PEB Xored
				a.add(asmjit::x86::rax, PebGsOffset);
				// Undoing the XOR operation with the obfuscated RAX value and the XOR key -> xor rax, lastByteXorKey
				a.xor_(asmjit::x86::rax, asmjit::imm(xorKey & 0xFF));
				// Accessing the resulting address to retrieve the PEB instance -> mov rax, [rax]
				a.mov(asmjit::x86::rax, asmjit::x86::ptr(asmjit::x86::rax));
				// Adding the obfuscated offset of the ImageBase xored field in the PEB -> add rax, ImageBasePeb
				a.add(asmjit::x86::rax, ImageBasePeb);
				// Undoing the XOR operation with the obfuscated value and the XOR key -> xor rax, lastByteXorKey
				a.xor_(asmjit::x86::rax, asmjit::imm(xorKey & 0xFF));
				// Accessing the "ImageBase" address in the PEB to obtain the actual value
				a.mov(asmjit::x86::rax, asmjit::x86::ptr(asmjit::x86::rax));
				// Adding to the "ImageBase" value a "default" offset that will later be overwritten by the actual offset of the MiniVM enter
				a.add(asmjit::x86::rax, asmjit::imm(0x88));
				// Calling the MiniVMEnter procedure to execute
				a.call(asmjit::x86::rax);
				// Storing the result of the MiniVM execution stored in RAX into the correct register to continue the normal execution flow
				a.mov(mapZydisToAsmjitGp(instr.instruction.operands[0].reg.value), asmjit::x86::rax);
				// Setup stack for MS HV Code MiniVMm stub
				if (m_config.m_isHVPass) a.add(asmjit::x86::rsp, 0x28);
				// Restoring the original value of RDX
				a.pop(asmjit::x86::rdx);
				// Restoring the original value of RCX
				a.pop(asmjit::x86::rcx);

				// Breaking Decompilers
				insertBreakDecompilers(a);

				// Retrieving from ASMJIT’s JIT the resulting opcodes generated by our algorithm
				auto& opcodeBuffer = code.sectionById(0)->buffer();
				const auto pOpcodeBuffer = opcodeBuffer.data();
				minivm_enter.reserve(opcodeBuffer.size());

				// Storing each individual opcode in our minivm vector
				for (auto i = 0; i < opcodeBuffer.size(); ++i) minivm_enter.push_back(static_cast<ZyanU8>(pOpcodeBuffer[i]));

				// Overwriting old opcodes with the new ones
				data.assign(minivm_enter.begin(), minivm_enter.end());

				std::printf("[!] Inserting a new MiniVm ByteCode on %s\n", instr.instruction.text);

			}

		}
	
	}

}

void RyujinObfuscationCore::insertAntiDebug() {

	BOOL isInserted{ FALSE };

	for (auto& block : m_proc.basic_blocks) {

		for (auto& instr : block.instructions) {

			if (isInserted) break;

			if (!isInserted) {

				auto block_info = findBlockId(instr.instruction.info.opcode, instr.instruction.operands[1].imm.value.u, 2, sizeof(unsigned char));

				if (block_info.first == -1 || block_info.second == -1) continue;

				auto& data = m_proc.basic_blocks[block_info.first].opcodes[block_info.second];

				asmjit::JitRuntime runtime;

				asmjit::CodeHolder code;
				code.init(runtime.environment());
				asmjit::x86::Assembler a(&code);
				
				// First, saving the states

				// Push flags
				a.pushfq();

				// Push regs
				a.push(asmjit::x86::rax);
				a.push(asmjit::x86::rcx);
				a.push(asmjit::x86::rdx);
				a.push(asmjit::x86::rbx);
				a.push(asmjit::x86::rbp);
				a.push(asmjit::x86::rsi);
				a.push(asmjit::x86::rdi);
				a.push(asmjit::x86::r8);
				a.push(asmjit::x86::r9);
				a.push(asmjit::x86::r10);
				a.push(asmjit::x86::r11);
				a.push(asmjit::x86::r12);
				a.push(asmjit::x86::r13);
				a.push(asmjit::x86::r14);
				a.push(asmjit::x86::r15);

				// Inserting the technique selected by the user -> Anti-debug with the troll or conventional anti-debug
				if (this->m_config.m_isTrollRerversers) {

					// IstrollReversers is the conventional anti-debug but with the capability to trigger a blue screen via hard error

					std::printf("Run m_isAntiDebug + m_isTrollRerversers\n");

					std::vector<unsigned char> antidebugWithTrollShellcode = {

						/*
						#pragma optimize("", off)
						__declspec(noinline) __declspec(safebuffers) void detectWithTroll() {
						
							#ifdef _M_X64
								auto* peb = reinterpret_cast<PEB*>(__readgsqword(0x60));
							#else
								auto* peb =  reinterpret_cast<PEB*>(__readfsdword(0x30));
							#endif
						
							if (!peb || !peb->Ldr) return;
						
							char nameAdj[] { 'R','t','l','A','d','j','u','s','t','P','r','i','v','i','l','e','g','e',0 };
							char nameHard[] { 'N','t','R','a','i','s','e','H','a','r','d','E','r','r','o','r',0 };
							char nameDbg[] { 'N','t','S','y','s','t','e','m','D','e','b','u','g','C','o','n','t','r','o','l',0 };
							char nameQsi[] { 'N','t','Q','u','e','r','y','S','y','s','t','e','m','I','n','f','o','r','m','a','t','i','o','n',0 };
							wchar_t nameDll[] { 'n','t','d','l','l','.','d','l','l',0 };
						
						   auto* head = &peb->Ldr->InMemoryOrderModuleList;
							for (auto* link = head->Flink; link != head; link = link->Flink) {
						
								auto* entry = CONTAINING_RECORD(link, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
						
								auto* a = entry->BaseDllName.Buffer;
								auto* b = nameDll;
								bool matched = true;
						
								auto lenA = entry->BaseDllName.Length / sizeof(WCHAR);
								auto lenB = static_cast<USHORT>(wcslen(nameDll));
						
								if (lenA != lenB) continue;
						
								for (auto i = 0; i < lenB; i++) {
						
									auto ca = a[i], cb = b[i];
									if (ca >= 'A' && ca <= 'Z') ca += 0x20;
									if (cb >= 'A' && cb <= 'Z') cb += 0x20;
									if (ca != cb) { matched = false; break; }
						
								}
						
								if (!matched) continue;
						
								auto* base = reinterpret_cast<BYTE*>(entry->DllBase);
								auto* dos = reinterpret_cast<IMAGE_DOS_HEADER*>(base);
								auto* nt = reinterpret_cast<IMAGE_NT_HEADERS*>(base + dos->e_lfanew);
								auto& ed = nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
						
								if (!ed.VirtualAddress) return;
						
								auto* exp = reinterpret_cast<IMAGE_EXPORT_DIRECTORY*>(base + ed.VirtualAddress);
								auto* names = reinterpret_cast<DWORD*>(base + exp->AddressOfNames);
								auto* ords = reinterpret_cast<DWORD*>(base + exp->AddressOfNameOrdinals);
								auto* funcs = reinterpret_cast<DWORD*>(base + exp->AddressOfFunctions);
						
								RtlAdjustPrivilege_t pAdj = nullptr;
								NtRaiseHardError_t   pHard = nullptr;
								NtSystemDebugControl_t pDbgCtrl = nullptr;
								NtQuerySystemInformation_t pQsi = nullptr;
						
								for (auto i = 0; i < exp->NumberOfNames; i++) {
						
									auto* fn = reinterpret_cast<char*>(base + names[i]);
						
									bool matchAdj = true;
									for (auto j = 0; nameAdj[j] || fn[j]; j++)
										if (nameAdj[j] != fn[j]) { matchAdj = false; break; }
						
									if (matchAdj) pAdj = reinterpret_cast<RtlAdjustPrivilege_t>(base + funcs[ords[i]]);
						
									bool matchHard = true;
									for (auto j = 0; nameHard[j] || fn[j]; j++)
										if (nameHard[j] != fn[j]) { matchHard = false; break; }
						
									if (matchHard) pHard = reinterpret_cast<NtRaiseHardError_t>(base + funcs[ords[i]]);
						
									bool matchDbg = true;
									for (auto j = 0; nameDbg[j] || fn[j]; j++)
										if (nameDbg[j] != fn[j]) { matchDbg = false; break; }
						
									if (matchDbg) pDbgCtrl = reinterpret_cast<NtSystemDebugControl_t>(base + funcs[ords[i]]);
						
									bool matchQsi = true;
									for (auto j = 0; nameQsi[j] || fn[j]; j++)
										if (nameQsi[j] != fn[j]) { matchQsi = false; break; }
						
									if (matchQsi) pQsi = reinterpret_cast<NtQuerySystemInformation_t>(base + funcs[ords[i]]);
						
									if (pAdj && pHard && pDbgCtrl && pQsi) break;
						
								}
						
								if (!pAdj || !pHard || !pDbgCtrl || !pQsi) return;
						
								BOOLEAN enabled = FALSE;
								ULONG resp = 0;
						
								// Calling detections
						
								auto status = pDbgCtrl(SysDbgCheckLowMemory, 0, 0, 0, 0, 0);
						
								if (status != STATUS_DEBUGGER_INACTIVE && status != STATUS_NOT_IMPLEMENTED) goto detected;
						
								SYSTEM_KERNEL_DEBUGGER_INFORMATION KdDebuggerInfo;
								status = pQsi(SystemKernelDebuggerInformation, &KdDebuggerInfo, sizeof(SYSTEM_KERNEL_DEBUGGER_INFORMATION), NULL);
						
								if (NT_SUCCESS(status)) if (KdDebuggerInfo.KernelDebuggerEnabled || !KdDebuggerInfo.KernelDebuggerNotPresent) goto detected;
						
								if (peb->BeingDebugged) goto detected; // Is this a meme Keowu ? yes!
						
								goto no_detected;
						
						detected:
								if (NT_SUCCESS(pAdj(19, TRUE, FALSE, &enabled)))
									pHard(STATUS_FLOAT_MULTIPLE_FAULTS, 0, 0, nullptr, 6, &resp);
						
						no_detected:
								return;
							}
						}
						#pragma optimize("", on)
						*/
						0x48, 0x81, 0xEC, 0xC8, 0x01, 0x00, 0x00, 0x65, 0x48, 0x8B, 0x04, 0x25,
						0x60, 0x00, 0x00, 0x00, 0x48, 0x89, 0x84, 0x24, 0x20, 0x01, 0x00, 0x00,
						0x48, 0x83, 0xBC, 0x24, 0x20, 0x01, 0x00, 0x00, 0x00, 0x74, 0x0F, 0x48,
						0x8B, 0x84, 0x24, 0x20, 0x01, 0x00, 0x00, 0x48, 0x83, 0x78, 0x18, 0x00,
						0x75, 0x05, 0xE9, 0x1B, 0x0A, 0x00, 0x00, 0xC6, 0x84, 0x24, 0x98, 0x00,
						0x00, 0x00, 0x52, 0xC6, 0x84, 0x24, 0x99, 0x00, 0x00, 0x00, 0x74, 0xC6,
						0x84, 0x24, 0x9A, 0x00, 0x00, 0x00, 0x6C, 0xC6, 0x84, 0x24, 0x9B, 0x00,
						0x00, 0x00, 0x41, 0xC6, 0x84, 0x24, 0x9C, 0x00, 0x00, 0x00, 0x64, 0xC6,
						0x84, 0x24, 0x9D, 0x00, 0x00, 0x00, 0x6A, 0xC6, 0x84, 0x24, 0x9E, 0x00,
						0x00, 0x00, 0x75, 0xC6, 0x84, 0x24, 0x9F, 0x00, 0x00, 0x00, 0x73, 0xC6,
						0x84, 0x24, 0xA0, 0x00, 0x00, 0x00, 0x74, 0xC6, 0x84, 0x24, 0xA1, 0x00,
						0x00, 0x00, 0x50, 0xC6, 0x84, 0x24, 0xA2, 0x00, 0x00, 0x00, 0x72, 0xC6,
						0x84, 0x24, 0xA3, 0x00, 0x00, 0x00, 0x69, 0xC6, 0x84, 0x24, 0xA4, 0x00,
						0x00, 0x00, 0x76, 0xC6, 0x84, 0x24, 0xA5, 0x00, 0x00, 0x00, 0x69, 0xC6,
						0x84, 0x24, 0xA6, 0x00, 0x00, 0x00, 0x6C, 0xC6, 0x84, 0x24, 0xA7, 0x00,
						0x00, 0x00, 0x65, 0xC6, 0x84, 0x24, 0xA8, 0x00, 0x00, 0x00, 0x67, 0xC6,
						0x84, 0x24, 0xA9, 0x00, 0x00, 0x00, 0x65, 0xC6, 0x84, 0x24, 0xAA, 0x00,
						0x00, 0x00, 0x00, 0xC6, 0x84, 0x24, 0x80, 0x00, 0x00, 0x00, 0x4E, 0xC6,
						0x84, 0x24, 0x81, 0x00, 0x00, 0x00, 0x74, 0xC6, 0x84, 0x24, 0x82, 0x00,
						0x00, 0x00, 0x52, 0xC6, 0x84, 0x24, 0x83, 0x00, 0x00, 0x00, 0x61, 0xC6,
						0x84, 0x24, 0x84, 0x00, 0x00, 0x00, 0x69, 0xC6, 0x84, 0x24, 0x85, 0x00,
						0x00, 0x00, 0x73, 0xC6, 0x84, 0x24, 0x86, 0x00, 0x00, 0x00, 0x65, 0xC6,
						0x84, 0x24, 0x87, 0x00, 0x00, 0x00, 0x48, 0xC6, 0x84, 0x24, 0x88, 0x00,
						0x00, 0x00, 0x61, 0xC6, 0x84, 0x24, 0x89, 0x00, 0x00, 0x00, 0x72, 0xC6,
						0x84, 0x24, 0x8A, 0x00, 0x00, 0x00, 0x64, 0xC6, 0x84, 0x24, 0x8B, 0x00,
						0x00, 0x00, 0x45, 0xC6, 0x84, 0x24, 0x8C, 0x00, 0x00, 0x00, 0x72, 0xC6,
						0x84, 0x24, 0x8D, 0x00, 0x00, 0x00, 0x72, 0xC6, 0x84, 0x24, 0x8E, 0x00,
						0x00, 0x00, 0x6F, 0xC6, 0x84, 0x24, 0x8F, 0x00, 0x00, 0x00, 0x72, 0xC6,
						0x84, 0x24, 0x90, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x84, 0x24, 0xB0, 0x00,
						0x00, 0x00, 0x4E, 0xC6, 0x84, 0x24, 0xB1, 0x00, 0x00, 0x00, 0x74, 0xC6,
						0x84, 0x24, 0xB2, 0x00, 0x00, 0x00, 0x53, 0xC6, 0x84, 0x24, 0xB3, 0x00,
						0x00, 0x00, 0x79, 0xC6, 0x84, 0x24, 0xB4, 0x00, 0x00, 0x00, 0x73, 0xC6,
						0x84, 0x24, 0xB5, 0x00, 0x00, 0x00, 0x74, 0xC6, 0x84, 0x24, 0xB6, 0x00,
						0x00, 0x00, 0x65, 0xC6, 0x84, 0x24, 0xB7, 0x00, 0x00, 0x00, 0x6D, 0xC6,
						0x84, 0x24, 0xB8, 0x00, 0x00, 0x00, 0x44, 0xC6, 0x84, 0x24, 0xB9, 0x00,
						0x00, 0x00, 0x65, 0xC6, 0x84, 0x24, 0xBA, 0x00, 0x00, 0x00, 0x62, 0xC6,
						0x84, 0x24, 0xBB, 0x00, 0x00, 0x00, 0x75, 0xC6, 0x84, 0x24, 0xBC, 0x00,
						0x00, 0x00, 0x67, 0xC6, 0x84, 0x24, 0xBD, 0x00, 0x00, 0x00, 0x43, 0xC6,
						0x84, 0x24, 0xBE, 0x00, 0x00, 0x00, 0x6F, 0xC6, 0x84, 0x24, 0xBF, 0x00,
						0x00, 0x00, 0x6E, 0xC6, 0x84, 0x24, 0xC0, 0x00, 0x00, 0x00, 0x74, 0xC6,
						0x84, 0x24, 0xC1, 0x00, 0x00, 0x00, 0x72, 0xC6, 0x84, 0x24, 0xC2, 0x00,
						0x00, 0x00, 0x6F, 0xC6, 0x84, 0x24, 0xC3, 0x00, 0x00, 0x00, 0x6C, 0xC6,
						0x84, 0x24, 0xC4, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x84, 0x24, 0xC8, 0x00,
						0x00, 0x00, 0x4E, 0xC6, 0x84, 0x24, 0xC9, 0x00, 0x00, 0x00, 0x74, 0xC6,
						0x84, 0x24, 0xCA, 0x00, 0x00, 0x00, 0x51, 0xC6, 0x84, 0x24, 0xCB, 0x00,
						0x00, 0x00, 0x75, 0xC6, 0x84, 0x24, 0xCC, 0x00, 0x00, 0x00, 0x65, 0xC6,
						0x84, 0x24, 0xCD, 0x00, 0x00, 0x00, 0x72, 0xC6, 0x84, 0x24, 0xCE, 0x00,
						0x00, 0x00, 0x79, 0xC6, 0x84, 0x24, 0xCF, 0x00, 0x00, 0x00, 0x53, 0xC6,
						0x84, 0x24, 0xD0, 0x00, 0x00, 0x00, 0x79, 0xC6, 0x84, 0x24, 0xD1, 0x00,
						0x00, 0x00, 0x73, 0xC6, 0x84, 0x24, 0xD2, 0x00, 0x00, 0x00, 0x74, 0xC6,
						0x84, 0x24, 0xD3, 0x00, 0x00, 0x00, 0x65, 0xC6, 0x84, 0x24, 0xD4, 0x00,
						0x00, 0x00, 0x6D, 0xC6, 0x84, 0x24, 0xD5, 0x00, 0x00, 0x00, 0x49, 0xC6,
						0x84, 0x24, 0xD6, 0x00, 0x00, 0x00, 0x6E, 0xC6, 0x84, 0x24, 0xD7, 0x00,
						0x00, 0x00, 0x66, 0xC6, 0x84, 0x24, 0xD8, 0x00, 0x00, 0x00, 0x6F, 0xC6,
						0x84, 0x24, 0xD9, 0x00, 0x00, 0x00, 0x72, 0xC6, 0x84, 0x24, 0xDA, 0x00,
						0x00, 0x00, 0x6D, 0xC6, 0x84, 0x24, 0xDB, 0x00, 0x00, 0x00, 0x61, 0xC6,
						0x84, 0x24, 0xDC, 0x00, 0x00, 0x00, 0x74, 0xC6, 0x84, 0x24, 0xDD, 0x00,
						0x00, 0x00, 0x69, 0xC6, 0x84, 0x24, 0xDE, 0x00, 0x00, 0x00, 0x6F, 0xC6,
						0x84, 0x24, 0xDF, 0x00, 0x00, 0x00, 0x6E, 0xC6, 0x84, 0x24, 0xE0, 0x00,
						0x00, 0x00, 0x00, 0xB8, 0x6E, 0x00, 0x00, 0x00, 0x66, 0x89, 0x84, 0x24,
						0x40, 0x01, 0x00, 0x00, 0xB8, 0x74, 0x00, 0x00, 0x00, 0x66, 0x89, 0x84,
						0x24, 0x42, 0x01, 0x00, 0x00, 0xB8, 0x64, 0x00, 0x00, 0x00, 0x66, 0x89,
						0x84, 0x24, 0x44, 0x01, 0x00, 0x00, 0xB8, 0x6C, 0x00, 0x00, 0x00, 0x66,
						0x89, 0x84, 0x24, 0x46, 0x01, 0x00, 0x00, 0xB8, 0x6C, 0x00, 0x00, 0x00,
						0x66, 0x89, 0x84, 0x24, 0x48, 0x01, 0x00, 0x00, 0xB8, 0x2E, 0x00, 0x00,
						0x00, 0x66, 0x89, 0x84, 0x24, 0x4A, 0x01, 0x00, 0x00, 0xB8, 0x64, 0x00,
						0x00, 0x00, 0x66, 0x89, 0x84, 0x24, 0x4C, 0x01, 0x00, 0x00, 0xB8, 0x6C,
						0x00, 0x00, 0x00, 0x66, 0x89, 0x84, 0x24, 0x4E, 0x01, 0x00, 0x00, 0xB8,
						0x6C, 0x00, 0x00, 0x00, 0x66, 0x89, 0x84, 0x24, 0x50, 0x01, 0x00, 0x00,
						0x33, 0xC0, 0x66, 0x89, 0x84, 0x24, 0x52, 0x01, 0x00, 0x00, 0x48, 0x8B,
						0x84, 0x24, 0x20, 0x01, 0x00, 0x00, 0x48, 0x8B, 0x40, 0x18, 0x48, 0x83,
						0xC0, 0x28, 0x48, 0x89, 0x84, 0x24, 0x70, 0x01, 0x00, 0x00, 0x48, 0x8B,
						0x84, 0x24, 0x70, 0x01, 0x00, 0x00, 0x48, 0x8B, 0x00, 0x48, 0x89, 0x84,
						0x24, 0x38, 0x01, 0x00, 0x00, 0xEB, 0x13, 0x48, 0x8B, 0x84, 0x24, 0x38,
						0x01, 0x00, 0x00, 0x48, 0x8B, 0x00, 0x48, 0x89, 0x84, 0x24, 0x38, 0x01,
						0x00, 0x00, 0x48, 0x8B, 0x84, 0x24, 0x70, 0x01, 0x00, 0x00, 0x48, 0x39,
						0x84, 0x24, 0x38, 0x01, 0x00, 0x00, 0x0F, 0x84, 0xB6, 0x06, 0x00, 0x00,
						0x48, 0x8B, 0x84, 0x24, 0x38, 0x01, 0x00, 0x00, 0x48, 0x83, 0xE8, 0x10,
						0x48, 0x89, 0x84, 0x24, 0x58, 0x01, 0x00, 0x00, 0x48, 0x8B, 0x84, 0x24,
						0x58, 0x01, 0x00, 0x00, 0x48, 0x8B, 0x40, 0x60, 0x48, 0x89, 0x84, 0x24,
						0x88, 0x01, 0x00, 0x00, 0x48, 0x8D, 0x84, 0x24, 0x40, 0x01, 0x00, 0x00,
						0x48, 0x89, 0x84, 0x24, 0x90, 0x01, 0x00, 0x00, 0xC6, 0x44, 0x24, 0x30,
						0x01, 0x48, 0x8B, 0x84, 0x24, 0x58, 0x01, 0x00, 0x00, 0x0F, 0xB7, 0x40,
						0x58, 0x33, 0xD2, 0xB9, 0x02, 0x00, 0x00, 0x00, 0x48, 0xF7, 0xF1, 0x66,
						0x89, 0x84, 0x24, 0xE8, 0x00, 0x00, 0x00, 0x48, 0x8D, 0x84, 0x24, 0x40,
						0x01, 0x00, 0x00, 0x48, 0x89, 0x84, 0x24, 0x80, 0x01, 0x00, 0x00, 0x48,
						0xC7, 0x84, 0x24, 0xF8, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x48,
						0xFF, 0x84, 0x24, 0xF8, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x84, 0x24, 0x80,
						0x01, 0x00, 0x00, 0x48, 0x8B, 0x8C, 0x24, 0xF8, 0x00, 0x00, 0x00, 0x66,
						0x83, 0x3C, 0x48, 0x00, 0x75, 0xE1, 0x48, 0x8B, 0x84, 0x24, 0xF8, 0x00,
						0x00, 0x00, 0x66, 0x89, 0x44, 0x24, 0x5C, 0x0F, 0xB7, 0x84, 0x24, 0xE8,
						0x00, 0x00, 0x00, 0x0F, 0xB7, 0x4C, 0x24, 0x5C, 0x3B, 0xC1, 0x74, 0x05,
						0xE9, 0x1E, 0xFF, 0xFF, 0xFF, 0x33, 0xC0, 0x66, 0x89, 0x44, 0x24, 0x38,
						0xEB, 0x0D, 0x0F, 0xB7, 0x44, 0x24, 0x38, 0x66, 0xFF, 0xC0, 0x66, 0x89,
						0x44, 0x24, 0x38, 0x0F, 0xB7, 0x44, 0x24, 0x38, 0x0F, 0xB7, 0x4C, 0x24,
						0x5C, 0x3B, 0xC1, 0x0F, 0x8D, 0x88, 0x00, 0x00, 0x00, 0x0F, 0xB7, 0x44,
						0x24, 0x38, 0x48, 0x8B, 0x8C, 0x24, 0x88, 0x01, 0x00, 0x00, 0x0F, 0xB7,
						0x04, 0x41, 0x66, 0x89, 0x44, 0x24, 0x3C, 0x0F, 0xB7, 0x44, 0x24, 0x38,
						0x48, 0x8B, 0x8C, 0x24, 0x90, 0x01, 0x00, 0x00, 0x0F, 0xB7, 0x04, 0x41,
						0x66, 0x89, 0x44, 0x24, 0x40, 0x0F, 0xB7, 0x44, 0x24, 0x3C, 0x83, 0xF8,
						0x41, 0x7C, 0x17, 0x0F, 0xB7, 0x44, 0x24, 0x3C, 0x83, 0xF8, 0x5A, 0x7F,
						0x0D, 0x0F, 0xB7, 0x44, 0x24, 0x3C, 0x83, 0xC0, 0x20, 0x66, 0x89, 0x44,
						0x24, 0x3C, 0x0F, 0xB7, 0x44, 0x24, 0x40, 0x83, 0xF8, 0x41, 0x7C, 0x17,
						0x0F, 0xB7, 0x44, 0x24, 0x40, 0x83, 0xF8, 0x5A, 0x7F, 0x0D, 0x0F, 0xB7,
						0x44, 0x24, 0x40, 0x83, 0xC0, 0x20, 0x66, 0x89, 0x44, 0x24, 0x40, 0x0F,
						0xB7, 0x44, 0x24, 0x3C, 0x0F, 0xB7, 0x4C, 0x24, 0x40, 0x3B, 0xC1, 0x74,
						0x07, 0xC6, 0x44, 0x24, 0x30, 0x00, 0xEB, 0x05, 0xE9, 0x59, 0xFF, 0xFF,
						0xFF, 0x0F, 0xB6, 0x44, 0x24, 0x30, 0x85, 0xC0, 0x75, 0x05, 0xE9, 0x60,
						0xFE, 0xFF, 0xFF, 0x48, 0x8B, 0x84, 0x24, 0x58, 0x01, 0x00, 0x00, 0x48,
						0x8B, 0x40, 0x30, 0x48, 0x89, 0x44, 0x24, 0x68, 0x48, 0x8B, 0x44, 0x24,
						0x68, 0x48, 0x89, 0x84, 0x24, 0x98, 0x01, 0x00, 0x00, 0x48, 0x8B, 0x84,
						0x24, 0x98, 0x01, 0x00, 0x00, 0x48, 0x63, 0x40, 0x3C, 0x48, 0x8B, 0x4C,
						0x24, 0x68, 0x48, 0x03, 0xC8, 0x48, 0x8B, 0xC1, 0x48, 0x89, 0x84, 0x24,
						0xB0, 0x01, 0x00, 0x00, 0xB8, 0x08, 0x00, 0x00, 0x00, 0x48, 0x6B, 0xC0,
						0x00, 0x48, 0x8B, 0x8C, 0x24, 0xB0, 0x01, 0x00, 0x00, 0x48, 0x8D, 0x84,
						0x01, 0x88, 0x00, 0x00, 0x00, 0x48, 0x89, 0x84, 0x24, 0x68, 0x01, 0x00,
						0x00, 0x48, 0x8B, 0x84, 0x24, 0x68, 0x01, 0x00, 0x00, 0x83, 0x38, 0x00,
						0x75, 0x05, 0xE9, 0xCF, 0x04, 0x00, 0x00, 0x48, 0x8B, 0x84, 0x24, 0x68,
						0x01, 0x00, 0x00, 0x8B, 0x00, 0x48, 0x8B, 0x4C, 0x24, 0x68, 0x48, 0x03,
						0xC8, 0x48, 0x8B, 0xC1, 0x48, 0x89, 0x84, 0x24, 0x00, 0x01, 0x00, 0x00,
						0x48, 0x8B, 0x84, 0x24, 0x00, 0x01, 0x00, 0x00, 0x8B, 0x40, 0x20, 0x48,
						0x8B, 0x4C, 0x24, 0x68, 0x48, 0x03, 0xC8, 0x48, 0x8B, 0xC1, 0x48, 0x89,
						0x84, 0x24, 0xA0, 0x01, 0x00, 0x00, 0x48, 0x8B, 0x84, 0x24, 0x00, 0x01,
						0x00, 0x00, 0x8B, 0x40, 0x24, 0x48, 0x8B, 0x4C, 0x24, 0x68, 0x48, 0x03,
						0xC8, 0x48, 0x8B, 0xC1, 0x48, 0x89, 0x84, 0x24, 0x08, 0x01, 0x00, 0x00,
						0x48, 0x8B, 0x84, 0x24, 0x00, 0x01, 0x00, 0x00, 0x8B, 0x40, 0x1C, 0x48,
						0x8B, 0x4C, 0x24, 0x68, 0x48, 0x03, 0xC8, 0x48, 0x8B, 0xC1, 0x48, 0x89,
						0x84, 0x24, 0x10, 0x01, 0x00, 0x00, 0x48, 0xC7, 0x84, 0x24, 0x28, 0x01,
						0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0xC7, 0x84, 0x24, 0x30, 0x01,
						0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0xC7, 0x84, 0x24, 0x18, 0x01,
						0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0xC7, 0x84, 0x24, 0xF0, 0x00,
						0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC7, 0x44, 0x24, 0x44, 0x00, 0x00,
						0x00, 0x00, 0xEB, 0x0A, 0x8B, 0x44, 0x24, 0x44, 0xFF, 0xC0, 0x89, 0x44,
						0x24, 0x44, 0x48, 0x8B, 0x84, 0x24, 0x00, 0x01, 0x00, 0x00, 0x8B, 0x40,
						0x18, 0x39, 0x44, 0x24, 0x44, 0x0F, 0x83, 0xBE, 0x02, 0x00, 0x00, 0x8B,
						0x44, 0x24, 0x44, 0x48, 0x8B, 0x8C, 0x24, 0xA0, 0x01, 0x00, 0x00, 0x8B,
						0x04, 0x81, 0x48, 0x8B, 0x4C, 0x24, 0x68, 0x48, 0x03, 0xC8, 0x48, 0x8B,
						0xC1, 0x48, 0x89, 0x44, 0x24, 0x78, 0xC6, 0x44, 0x24, 0x31, 0x01, 0xC7,
						0x44, 0x24, 0x4C, 0x00, 0x00, 0x00, 0x00, 0xEB, 0x0A, 0x8B, 0x44, 0x24,
						0x4C, 0xFF, 0xC0, 0x89, 0x44, 0x24, 0x4C, 0x48, 0x63, 0x44, 0x24, 0x4C,
						0x0F, 0xBE, 0x84, 0x04, 0x98, 0x00, 0x00, 0x00, 0x85, 0xC0, 0x75, 0x12,
						0x48, 0x63, 0x44, 0x24, 0x4C, 0x48, 0x8B, 0x4C, 0x24, 0x78, 0x0F, 0xBE,
						0x04, 0x01, 0x85, 0xC0, 0x74, 0x28, 0x48, 0x63, 0x44, 0x24, 0x4C, 0x0F,
						0xBE, 0x84, 0x04, 0x98, 0x00, 0x00, 0x00, 0x48, 0x63, 0x4C, 0x24, 0x4C,
						0x48, 0x8B, 0x54, 0x24, 0x78, 0x0F, 0xBE, 0x0C, 0x0A, 0x3B, 0xC1, 0x74,
						0x07, 0xC6, 0x44, 0x24, 0x31, 0x00, 0xEB, 0x02, 0xEB, 0xAB, 0x0F, 0xB6,
						0x44, 0x24, 0x31, 0x85, 0xC0, 0x74, 0x2E, 0x8B, 0x44, 0x24, 0x44, 0x48,
						0x8B, 0x8C, 0x24, 0x08, 0x01, 0x00, 0x00, 0x0F, 0xB7, 0x04, 0x41, 0x48,
						0x8B, 0x8C, 0x24, 0x10, 0x01, 0x00, 0x00, 0x8B, 0x04, 0x81, 0x48, 0x8B,
						0x4C, 0x24, 0x68, 0x48, 0x03, 0xC8, 0x48, 0x8B, 0xC1, 0x48, 0x89, 0x84,
						0x24, 0x28, 0x01, 0x00, 0x00, 0xC6, 0x44, 0x24, 0x32, 0x01, 0xC7, 0x44,
						0x24, 0x50, 0x00, 0x00, 0x00, 0x00, 0xEB, 0x0A, 0x8B, 0x44, 0x24, 0x50,
						0xFF, 0xC0, 0x89, 0x44, 0x24, 0x50, 0x48, 0x63, 0x44, 0x24, 0x50, 0x0F,
						0xBE, 0x84, 0x04, 0x80, 0x00, 0x00, 0x00, 0x85, 0xC0, 0x75, 0x12, 0x48,
						0x63, 0x44, 0x24, 0x50, 0x48, 0x8B, 0x4C, 0x24, 0x78, 0x0F, 0xBE, 0x04,
						0x01, 0x85, 0xC0, 0x74, 0x28, 0x48, 0x63, 0x44, 0x24, 0x50, 0x0F, 0xBE,
						0x84, 0x04, 0x80, 0x00, 0x00, 0x00, 0x48, 0x63, 0x4C, 0x24, 0x50, 0x48,
						0x8B, 0x54, 0x24, 0x78, 0x0F, 0xBE, 0x0C, 0x0A, 0x3B, 0xC1, 0x74, 0x07,
						0xC6, 0x44, 0x24, 0x32, 0x00, 0xEB, 0x02, 0xEB, 0xAB, 0x0F, 0xB6, 0x44,
						0x24, 0x32, 0x85, 0xC0, 0x74, 0x2E, 0x8B, 0x44, 0x24, 0x44, 0x48, 0x8B,
						0x8C, 0x24, 0x08, 0x01, 0x00, 0x00, 0x0F, 0xB7, 0x04, 0x41, 0x48, 0x8B,
						0x8C, 0x24, 0x10, 0x01, 0x00, 0x00, 0x8B, 0x04, 0x81, 0x48, 0x8B, 0x4C,
						0x24, 0x68, 0x48, 0x03, 0xC8, 0x48, 0x8B, 0xC1, 0x48, 0x89, 0x84, 0x24,
						0x30, 0x01, 0x00, 0x00, 0xC6, 0x44, 0x24, 0x33, 0x01, 0xC7, 0x44, 0x24,
						0x54, 0x00, 0x00, 0x00, 0x00, 0xEB, 0x0A, 0x8B, 0x44, 0x24, 0x54, 0xFF,
						0xC0, 0x89, 0x44, 0x24, 0x54, 0x48, 0x63, 0x44, 0x24, 0x54, 0x0F, 0xBE,
						0x84, 0x04, 0xB0, 0x00, 0x00, 0x00, 0x85, 0xC0, 0x75, 0x12, 0x48, 0x63,
						0x44, 0x24, 0x54, 0x48, 0x8B, 0x4C, 0x24, 0x78, 0x0F, 0xBE, 0x04, 0x01,
						0x85, 0xC0, 0x74, 0x28, 0x48, 0x63, 0x44, 0x24, 0x54, 0x0F, 0xBE, 0x84,
						0x04, 0xB0, 0x00, 0x00, 0x00, 0x48, 0x63, 0x4C, 0x24, 0x54, 0x48, 0x8B,
						0x54, 0x24, 0x78, 0x0F, 0xBE, 0x0C, 0x0A, 0x3B, 0xC1, 0x74, 0x07, 0xC6,
						0x44, 0x24, 0x33, 0x00, 0xEB, 0x02, 0xEB, 0xAB, 0x0F, 0xB6, 0x44, 0x24,
						0x33, 0x85, 0xC0, 0x74, 0x2E, 0x8B, 0x44, 0x24, 0x44, 0x48, 0x8B, 0x8C,
						0x24, 0x08, 0x01, 0x00, 0x00, 0x0F, 0xB7, 0x04, 0x41, 0x48, 0x8B, 0x8C,
						0x24, 0x10, 0x01, 0x00, 0x00, 0x8B, 0x04, 0x81, 0x48, 0x8B, 0x4C, 0x24,
						0x68, 0x48, 0x03, 0xC8, 0x48, 0x8B, 0xC1, 0x48, 0x89, 0x84, 0x24, 0x18,
						0x01, 0x00, 0x00, 0xC6, 0x44, 0x24, 0x34, 0x01, 0xC7, 0x44, 0x24, 0x58,
						0x00, 0x00, 0x00, 0x00, 0xEB, 0x0A, 0x8B, 0x44, 0x24, 0x58, 0xFF, 0xC0,
						0x89, 0x44, 0x24, 0x58, 0x48, 0x63, 0x44, 0x24, 0x58, 0x0F, 0xBE, 0x84,
						0x04, 0xC8, 0x00, 0x00, 0x00, 0x85, 0xC0, 0x75, 0x12, 0x48, 0x63, 0x44,
						0x24, 0x58, 0x48, 0x8B, 0x4C, 0x24, 0x78, 0x0F, 0xBE, 0x04, 0x01, 0x85,
						0xC0, 0x74, 0x28, 0x48, 0x63, 0x44, 0x24, 0x58, 0x0F, 0xBE, 0x84, 0x04,
						0xC8, 0x00, 0x00, 0x00, 0x48, 0x63, 0x4C, 0x24, 0x58, 0x48, 0x8B, 0x54,
						0x24, 0x78, 0x0F, 0xBE, 0x0C, 0x0A, 0x3B, 0xC1, 0x74, 0x07, 0xC6, 0x44,
						0x24, 0x34, 0x00, 0xEB, 0x02, 0xEB, 0xAB, 0x0F, 0xB6, 0x44, 0x24, 0x34,
						0x85, 0xC0, 0x74, 0x2E, 0x8B, 0x44, 0x24, 0x44, 0x48, 0x8B, 0x8C, 0x24,
						0x08, 0x01, 0x00, 0x00, 0x0F, 0xB7, 0x04, 0x41, 0x48, 0x8B, 0x8C, 0x24,
						0x10, 0x01, 0x00, 0x00, 0x8B, 0x04, 0x81, 0x48, 0x8B, 0x4C, 0x24, 0x68,
						0x48, 0x03, 0xC8, 0x48, 0x8B, 0xC1, 0x48, 0x89, 0x84, 0x24, 0xF0, 0x00,
						0x00, 0x00, 0x48, 0x83, 0xBC, 0x24, 0x28, 0x01, 0x00, 0x00, 0x00, 0x74,
						0x23, 0x48, 0x83, 0xBC, 0x24, 0x30, 0x01, 0x00, 0x00, 0x00, 0x74, 0x18,
						0x48, 0x83, 0xBC, 0x24, 0x18, 0x01, 0x00, 0x00, 0x00, 0x74, 0x0D, 0x48,
						0x83, 0xBC, 0x24, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x74, 0x02, 0xEB, 0x05,
						0xE9, 0x23, 0xFD, 0xFF, 0xFF, 0x48, 0x83, 0xBC, 0x24, 0x28, 0x01, 0x00,
						0x00, 0x00, 0x74, 0x21, 0x48, 0x83, 0xBC, 0x24, 0x30, 0x01, 0x00, 0x00,
						0x00, 0x74, 0x16, 0x48, 0x83, 0xBC, 0x24, 0x18, 0x01, 0x00, 0x00, 0x00,
						0x74, 0x0B, 0x48, 0x83, 0xBC, 0x24, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x75,
						0x05, 0xE9, 0x10, 0x01, 0x00, 0x00, 0xC6, 0x44, 0x24, 0x48, 0x00, 0xC7,
						0x84, 0x24, 0x60, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC7, 0x84,
						0x24, 0xAC, 0x01, 0x00, 0x00, 0x54, 0x03, 0x00, 0xC0, 0xC7, 0x84, 0x24,
						0xA8, 0x01, 0x00, 0x00, 0x22, 0x00, 0x00, 0xC0, 0xC7, 0x84, 0x24, 0x78,
						0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0xC0, 0x48, 0xC7, 0x44, 0x24, 0x28,
						0x00, 0x00, 0x00, 0x00, 0xC7, 0x44, 0x24, 0x20, 0x00, 0x00, 0x00, 0x00,
						0x45, 0x33, 0xC9, 0x45, 0x33, 0xC0, 0x33, 0xD2, 0xB9, 0x14, 0x00, 0x00,
						0x00, 0xFF, 0x94, 0x24, 0x18, 0x01, 0x00, 0x00, 0x89, 0x44, 0x24, 0x70,
						0x81, 0x7C, 0x24, 0x70, 0x54, 0x03, 0x00, 0xC0, 0x74, 0x0E, 0x81, 0x7C,
						0x24, 0x70, 0x02, 0x00, 0x00, 0xC0, 0x74, 0x04, 0xEB, 0x55, 0xEB, 0x53,
						0x45, 0x33, 0xC9, 0x41, 0xB8, 0x02, 0x00, 0x00, 0x00, 0x48, 0x8D, 0x54,
						0x24, 0x60, 0xB9, 0x23, 0x00, 0x00, 0x00, 0xFF, 0x94, 0x24, 0xF0, 0x00,
						0x00, 0x00, 0x89, 0x44, 0x24, 0x70, 0x83, 0x7C, 0x24, 0x70, 0x00, 0x7C,
						0x16, 0x0F, 0xB6, 0x44, 0x24, 0x60, 0x85, 0xC0, 0x75, 0x09, 0x0F, 0xB6,
						0x44, 0x24, 0x61, 0x85, 0xC0, 0x75, 0x04, 0xEB, 0x1A, 0xEB, 0x18, 0x48,
						0x8B, 0x84, 0x24, 0x20, 0x01, 0x00, 0x00, 0x0F, 0xB6, 0x40, 0x02, 0x85,
						0xC0, 0x74, 0x04, 0xEB, 0x06, 0xEB, 0x04, 0xEB, 0x46, 0xEB, 0x44, 0x4C,
						0x8D, 0x4C, 0x24, 0x48, 0x45, 0x33, 0xC0, 0xB2, 0x01, 0xB9, 0x13, 0x00,
						0x00, 0x00, 0xFF, 0x94, 0x24, 0x28, 0x01, 0x00, 0x00, 0x85, 0xC0, 0x7C,
						0x2A, 0x48, 0x8D, 0x84, 0x24, 0x60, 0x01, 0x00, 0x00, 0x48, 0x89, 0x44,
						0x24, 0x28, 0xC7, 0x44, 0x24, 0x20, 0x06, 0x00, 0x00, 0x00, 0x45, 0x33,
						0xC9, 0x45, 0x33, 0xC0, 0x33, 0xD2, 0xB9, 0xB4, 0x02, 0x00, 0xC0, 0xFF,
						0x94, 0x24, 0x30, 0x01, 0x00, 0x00, 0x90, 0xEB, 0x05, 0xE9, 0x21, 0xF9,
						0xFF, 0xFF, 0x48, 0x81, 0xC4, 0xC8, 0x01, 0x00, 0x00

					};

					a.embed(antidebugWithTrollShellcode.data(), antidebugWithTrollShellcode.size());

				} else {

					// IsAntidebug is the conventional anti-debug that will only terminate the execution of the protected binary

					std::printf("Run m_isAntiDebug\n");

					std::vector<unsigned char> antidebugShellcode = {

						/*
						#pragma optimize("", off)
						__declspec(noinline) __declspec(safebuffers) void detectNormal() {

							#ifdef _M_X64
								auto* peb = reinterpret_cast<PEB*>(__readgsqword(0x60));
							#else
								auto* peb =  reinterpret_cast<PEB*>(__readfsdword(0x30));
							#endif
						
							if (!peb || !peb->Ldr) return;
							
							char nameTerm[] { 'N','t','T','e','r','m','i','n','a','t','e','P','r','o','c','e','s','s', 0 };
							char nameDbg[] { 'N','t','S','y','s','t','e','m','D','e','b','u','g','C','o','n','t','r','o','l',0 };
							char nameQsi[] { 'N','t','Q','u','e','r','y','S','y','s','t','e','m','I','n','f','o','r','m','a','t','i','o','n',0 };
							wchar_t nameDll[] { 'n','t','d','l','l','.','d','l','l',0 };
						
							auto* head = &peb->Ldr->InMemoryOrderModuleList;
							for (auto* link = head->Flink; link != head; link = link->Flink) {
						
								auto* entry = CONTAINING_RECORD(link, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
						
								auto* a = entry->BaseDllName.Buffer;
								auto* b = nameDll;
								bool matched = true;
						
								auto lenA = entry->BaseDllName.Length / sizeof(WCHAR);
								auto lenB = static_cast<USHORT>(wcslen(nameDll));
						
								if (lenA != lenB) continue;
						
								for (auto i = 0; i < lenB; i++) {
						
									auto ca = a[i], cb = b[i];
									if (ca >= 'A' && ca <= 'Z') ca += 0x20;
									if (cb >= 'A' && cb <= 'Z') cb += 0x20;
									if (ca != cb) { matched = false; break; }
						
								}
						
								if (!matched) continue;
						
								auto* base = reinterpret_cast<BYTE*>(entry->DllBase);
								auto* dos = reinterpret_cast<IMAGE_DOS_HEADER*>(base);
								auto* nt = reinterpret_cast<IMAGE_NT_HEADERS*>(base + dos->e_lfanew);
								auto& ed = nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
						
								if (!ed.VirtualAddress) return;
						
								auto* exp = reinterpret_cast<IMAGE_EXPORT_DIRECTORY*>(base + ed.VirtualAddress);
								auto* names = reinterpret_cast<DWORD*>(base + exp->AddressOfNames);
								auto* ords = reinterpret_cast<DWORD*>(base + exp->AddressOfNameOrdinals);
								auto* funcs = reinterpret_cast<DWORD*>(base + exp->AddressOfFunctions);
						
								RtlAdjustPrivilege_t pAdj = nullptr;
								NtRaiseHardError_t   pHard = nullptr;
								NtSystemDebugControl_t pDbgCtrl = nullptr;
								NtQuerySystemInformation_t pQsi = nullptr;
						
								for (auto i = 0; i < exp->NumberOfNames; i++) {
						
									auto* fn = reinterpret_cast<char*>(base + names[i]);
						
									bool matchDbg = true;
									for (auto j = 0; nameDbg[j] || fn[j]; j++)
										if (nameDbg[j] != fn[j]) { matchDbg = false; break; }
						
									if (matchDbg) pDbgCtrl = reinterpret_cast<NtSystemDebugControl_t>(base + funcs[ords[i]]);
						
									bool matchQsi = true;
									for (auto j = 0; nameQsi[j] || fn[j]; j++)
										if (nameQsi[j] != fn[j]) { matchQsi = false; break; }
						
									if (matchQsi) pQsi = reinterpret_cast<NtQuerySystemInformation_t>(base + funcs[ords[i]]);
									
									bool matchTerm = true;
									for (int j = 0; nameTerm[j] || fn[j]; j++)
										if (nameTerm[j] != fn[j]) { matchTerm = false; break; }
									
									if (matchTerm) pTerm = (NtTerminateProcess_t)(base + funcs[ords[i]]);
						
									if (pDbgCtrl && pQsi && pTerm) break;
						
								}
						
								if (!pDbgCtrl || !pQsi || !pTerm) return;
						
								BOOLEAN enabled = FALSE;
								ULONG resp = 0;
						
								// Calling detections
						
								auto status = pDbgCtrl(SysDbgCheckLowMemory, 0, 0, 0, 0, 0);
						
								if (status != STATUS_DEBUGGER_INACTIVE && status != STATUS_NOT_IMPLEMENTED) goto detected;
						
								SYSTEM_KERNEL_DEBUGGER_INFORMATION KdDebuggerInfo;
								status = pQsi(SystemKernelDebuggerInformation, &KdDebuggerInfo, sizeof(SYSTEM_KERNEL_DEBUGGER_INFORMATION), NULL);
						
								if (NT_SUCCESS(status)) if (KdDebuggerInfo.KernelDebuggerEnabled || !KdDebuggerInfo.KernelDebuggerNotPresent) goto detected;
						
								if (peb->BeingDebugged) goto detected; // Is this a meme Keowu ? yes!
						
								goto no_detected;
						    
							detected:
									pTerm(reinterpret_cast<HANDLE>(-1), 1);
						
							no_detected:
									return;
							
							}
						}
						#pragma optimize("", on)
						*/
						0x48, 0x81, 0xEC, 0x98, 0x01, 0x00, 0x00, 0x65, 0x48, 0x8B, 0x04, 0x25,
						0x60, 0x00, 0x00, 0x00, 0x48, 0x89, 0x84, 0x24, 0xF8, 0x00, 0x00, 0x00,
						0x48, 0x83, 0xBC, 0x24, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x74, 0x0F, 0x48,
						0x8B, 0x84, 0x24, 0xF8, 0x00, 0x00, 0x00, 0x48, 0x83, 0x78, 0x18, 0x00,
						0x75, 0x05, 0xE9, 0x78, 0x08, 0x00, 0x00, 0xC6, 0x44, 0x24, 0x68, 0x4E,
						0xC6, 0x44, 0x24, 0x69, 0x74, 0xC6, 0x44, 0x24, 0x6A, 0x54, 0xC6, 0x44,
						0x24, 0x6B, 0x65, 0xC6, 0x44, 0x24, 0x6C, 0x72, 0xC6, 0x44, 0x24, 0x6D,
						0x6D, 0xC6, 0x44, 0x24, 0x6E, 0x69, 0xC6, 0x44, 0x24, 0x6F, 0x6E, 0xC6,
						0x44, 0x24, 0x70, 0x61, 0xC6, 0x44, 0x24, 0x71, 0x74, 0xC6, 0x44, 0x24,
						0x72, 0x65, 0xC6, 0x44, 0x24, 0x73, 0x50, 0xC6, 0x44, 0x24, 0x74, 0x72,
						0xC6, 0x44, 0x24, 0x75, 0x6F, 0xC6, 0x44, 0x24, 0x76, 0x63, 0xC6, 0x44,
						0x24, 0x77, 0x65, 0xC6, 0x44, 0x24, 0x78, 0x73, 0xC6, 0x44, 0x24, 0x79,
						0x73, 0xC6, 0x44, 0x24, 0x7A, 0x00, 0xC6, 0x84, 0x24, 0x80, 0x00, 0x00,
						0x00, 0x4E, 0xC6, 0x84, 0x24, 0x81, 0x00, 0x00, 0x00, 0x74, 0xC6, 0x84,
						0x24, 0x82, 0x00, 0x00, 0x00, 0x53, 0xC6, 0x84, 0x24, 0x83, 0x00, 0x00,
						0x00, 0x79, 0xC6, 0x84, 0x24, 0x84, 0x00, 0x00, 0x00, 0x73, 0xC6, 0x84,
						0x24, 0x85, 0x00, 0x00, 0x00, 0x74, 0xC6, 0x84, 0x24, 0x86, 0x00, 0x00,
						0x00, 0x65, 0xC6, 0x84, 0x24, 0x87, 0x00, 0x00, 0x00, 0x6D, 0xC6, 0x84,
						0x24, 0x88, 0x00, 0x00, 0x00, 0x44, 0xC6, 0x84, 0x24, 0x89, 0x00, 0x00,
						0x00, 0x65, 0xC6, 0x84, 0x24, 0x8A, 0x00, 0x00, 0x00, 0x62, 0xC6, 0x84,
						0x24, 0x8B, 0x00, 0x00, 0x00, 0x75, 0xC6, 0x84, 0x24, 0x8C, 0x00, 0x00,
						0x00, 0x67, 0xC6, 0x84, 0x24, 0x8D, 0x00, 0x00, 0x00, 0x43, 0xC6, 0x84,
						0x24, 0x8E, 0x00, 0x00, 0x00, 0x6F, 0xC6, 0x84, 0x24, 0x8F, 0x00, 0x00,
						0x00, 0x6E, 0xC6, 0x84, 0x24, 0x90, 0x00, 0x00, 0x00, 0x74, 0xC6, 0x84,
						0x24, 0x91, 0x00, 0x00, 0x00, 0x72, 0xC6, 0x84, 0x24, 0x92, 0x00, 0x00,
						0x00, 0x6F, 0xC6, 0x84, 0x24, 0x93, 0x00, 0x00, 0x00, 0x6C, 0xC6, 0x84,
						0x24, 0x94, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x84, 0x24, 0x98, 0x00, 0x00,
						0x00, 0x4E, 0xC6, 0x84, 0x24, 0x99, 0x00, 0x00, 0x00, 0x74, 0xC6, 0x84,
						0x24, 0x9A, 0x00, 0x00, 0x00, 0x51, 0xC6, 0x84, 0x24, 0x9B, 0x00, 0x00,
						0x00, 0x75, 0xC6, 0x84, 0x24, 0x9C, 0x00, 0x00, 0x00, 0x65, 0xC6, 0x84,
						0x24, 0x9D, 0x00, 0x00, 0x00, 0x72, 0xC6, 0x84, 0x24, 0x9E, 0x00, 0x00,
						0x00, 0x79, 0xC6, 0x84, 0x24, 0x9F, 0x00, 0x00, 0x00, 0x53, 0xC6, 0x84,
						0x24, 0xA0, 0x00, 0x00, 0x00, 0x79, 0xC6, 0x84, 0x24, 0xA1, 0x00, 0x00,
						0x00, 0x73, 0xC6, 0x84, 0x24, 0xA2, 0x00, 0x00, 0x00, 0x74, 0xC6, 0x84,
						0x24, 0xA3, 0x00, 0x00, 0x00, 0x65, 0xC6, 0x84, 0x24, 0xA4, 0x00, 0x00,
						0x00, 0x6D, 0xC6, 0x84, 0x24, 0xA5, 0x00, 0x00, 0x00, 0x49, 0xC6, 0x84,
						0x24, 0xA6, 0x00, 0x00, 0x00, 0x6E, 0xC6, 0x84, 0x24, 0xA7, 0x00, 0x00,
						0x00, 0x66, 0xC6, 0x84, 0x24, 0xA8, 0x00, 0x00, 0x00, 0x6F, 0xC6, 0x84,
						0x24, 0xA9, 0x00, 0x00, 0x00, 0x72, 0xC6, 0x84, 0x24, 0xAA, 0x00, 0x00,
						0x00, 0x6D, 0xC6, 0x84, 0x24, 0xAB, 0x00, 0x00, 0x00, 0x61, 0xC6, 0x84,
						0x24, 0xAC, 0x00, 0x00, 0x00, 0x74, 0xC6, 0x84, 0x24, 0xAD, 0x00, 0x00,
						0x00, 0x69, 0xC6, 0x84, 0x24, 0xAE, 0x00, 0x00, 0x00, 0x6F, 0xC6, 0x84,
						0x24, 0xAF, 0x00, 0x00, 0x00, 0x6E, 0xC6, 0x84, 0x24, 0xB0, 0x00, 0x00,
						0x00, 0x00, 0xB8, 0x6E, 0x00, 0x00, 0x00, 0x66, 0x89, 0x84, 0x24, 0x00,
						0x01, 0x00, 0x00, 0xB8, 0x74, 0x00, 0x00, 0x00, 0x66, 0x89, 0x84, 0x24,
						0x02, 0x01, 0x00, 0x00, 0xB8, 0x64, 0x00, 0x00, 0x00, 0x66, 0x89, 0x84,
						0x24, 0x04, 0x01, 0x00, 0x00, 0xB8, 0x6C, 0x00, 0x00, 0x00, 0x66, 0x89,
						0x84, 0x24, 0x06, 0x01, 0x00, 0x00, 0xB8, 0x6C, 0x00, 0x00, 0x00, 0x66,
						0x89, 0x84, 0x24, 0x08, 0x01, 0x00, 0x00, 0xB8, 0x2E, 0x00, 0x00, 0x00,
						0x66, 0x89, 0x84, 0x24, 0x0A, 0x01, 0x00, 0x00, 0xB8, 0x64, 0x00, 0x00,
						0x00, 0x66, 0x89, 0x84, 0x24, 0x0C, 0x01, 0x00, 0x00, 0xB8, 0x6C, 0x00,
						0x00, 0x00, 0x66, 0x89, 0x84, 0x24, 0x0E, 0x01, 0x00, 0x00, 0xB8, 0x6C,
						0x00, 0x00, 0x00, 0x66, 0x89, 0x84, 0x24, 0x10, 0x01, 0x00, 0x00, 0x33,
						0xC0, 0x66, 0x89, 0x84, 0x24, 0x12, 0x01, 0x00, 0x00, 0x48, 0x8B, 0x84,
						0x24, 0xF8, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x40, 0x18, 0x48, 0x83, 0xC0,
						0x28, 0x48, 0x89, 0x84, 0x24, 0x30, 0x01, 0x00, 0x00, 0x48, 0x8B, 0x84,
						0x24, 0x30, 0x01, 0x00, 0x00, 0x48, 0x8B, 0x00, 0x48, 0x89, 0x84, 0x24,
						0xD0, 0x00, 0x00, 0x00, 0xEB, 0x13, 0x48, 0x8B, 0x84, 0x24, 0xD0, 0x00,
						0x00, 0x00, 0x48, 0x8B, 0x00, 0x48, 0x89, 0x84, 0x24, 0xD0, 0x00, 0x00,
						0x00, 0x48, 0x8B, 0x84, 0x24, 0x30, 0x01, 0x00, 0x00, 0x48, 0x39, 0x84,
						0x24, 0xD0, 0x00, 0x00, 0x00, 0x0F, 0x84, 0xD4, 0x05, 0x00, 0x00, 0x48,
						0x8B, 0x84, 0x24, 0xD0, 0x00, 0x00, 0x00, 0x48, 0x83, 0xE8, 0x10, 0x48,
						0x89, 0x84, 0x24, 0x18, 0x01, 0x00, 0x00, 0x48, 0x8B, 0x84, 0x24, 0x18,
						0x01, 0x00, 0x00, 0x48, 0x8B, 0x40, 0x60, 0x48, 0x89, 0x84, 0x24, 0x50,
						0x01, 0x00, 0x00, 0x48, 0x8D, 0x84, 0x24, 0x00, 0x01, 0x00, 0x00, 0x48,
						0x89, 0x84, 0x24, 0x58, 0x01, 0x00, 0x00, 0xC6, 0x44, 0x24, 0x30, 0x01,
						0x48, 0x8B, 0x84, 0x24, 0x18, 0x01, 0x00, 0x00, 0x0F, 0xB7, 0x40, 0x58,
						0x33, 0xD2, 0xB9, 0x02, 0x00, 0x00, 0x00, 0x48, 0xF7, 0xF1, 0x48, 0x89,
						0x84, 0x24, 0x48, 0x01, 0x00, 0x00, 0x48, 0x8D, 0x84, 0x24, 0x00, 0x01,
						0x00, 0x00, 0x48, 0x89, 0x84, 0x24, 0x68, 0x01, 0x00, 0x00, 0x48, 0xC7,
						0x84, 0x24, 0xC8, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x48, 0xFF,
						0x84, 0x24, 0xC8, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x84, 0x24, 0x68, 0x01,
						0x00, 0x00, 0x48, 0x8B, 0x8C, 0x24, 0xC8, 0x00, 0x00, 0x00, 0x66, 0x83,
						0x3C, 0x48, 0x00, 0x75, 0xE1, 0x48, 0x8B, 0x84, 0x24, 0xC8, 0x00, 0x00,
						0x00, 0x66, 0x89, 0x44, 0x24, 0x4C, 0x0F, 0xB7, 0x44, 0x24, 0x4C, 0x48,
						0x39, 0x84, 0x24, 0x48, 0x01, 0x00, 0x00, 0x74, 0x05, 0xE9, 0x20, 0xFF,
						0xFF, 0xFF, 0xC7, 0x44, 0x24, 0x54, 0x00, 0x00, 0x00, 0x00, 0xEB, 0x0A,
						0x8B, 0x44, 0x24, 0x54, 0xFF, 0xC0, 0x89, 0x44, 0x24, 0x54, 0x0F, 0xB7,
						0x44, 0x24, 0x4C, 0x39, 0x44, 0x24, 0x54, 0x0F, 0x8D, 0x88, 0x00, 0x00,
						0x00, 0x48, 0x63, 0x44, 0x24, 0x54, 0x48, 0x8B, 0x8C, 0x24, 0x50, 0x01,
						0x00, 0x00, 0x0F, 0xB7, 0x04, 0x41, 0x66, 0x89, 0x44, 0x24, 0x34, 0x48,
						0x63, 0x44, 0x24, 0x54, 0x48, 0x8B, 0x8C, 0x24, 0x58, 0x01, 0x00, 0x00,
						0x0F, 0xB7, 0x04, 0x41, 0x66, 0x89, 0x44, 0x24, 0x38, 0x0F, 0xB7, 0x44,
						0x24, 0x34, 0x83, 0xF8, 0x41, 0x7C, 0x17, 0x0F, 0xB7, 0x44, 0x24, 0x34,
						0x83, 0xF8, 0x5A, 0x7F, 0x0D, 0x0F, 0xB7, 0x44, 0x24, 0x34, 0x83, 0xC0,
						0x20, 0x66, 0x89, 0x44, 0x24, 0x34, 0x0F, 0xB7, 0x44, 0x24, 0x38, 0x83,
						0xF8, 0x41, 0x7C, 0x17, 0x0F, 0xB7, 0x44, 0x24, 0x38, 0x83, 0xF8, 0x5A,
						0x7F, 0x0D, 0x0F, 0xB7, 0x44, 0x24, 0x38, 0x83, 0xC0, 0x20, 0x66, 0x89,
						0x44, 0x24, 0x38, 0x0F, 0xB7, 0x44, 0x24, 0x34, 0x0F, 0xB7, 0x4C, 0x24,
						0x38, 0x3B, 0xC1, 0x74, 0x07, 0xC6, 0x44, 0x24, 0x30, 0x00, 0xEB, 0x05,
						0xE9, 0x5F, 0xFF, 0xFF, 0xFF, 0x0F, 0xB6, 0x44, 0x24, 0x30, 0x85, 0xC0,
						0x75, 0x05, 0xE9, 0x67, 0xFE, 0xFF, 0xFF, 0x48, 0x8B, 0x84, 0x24, 0x18,
						0x01, 0x00, 0x00, 0x48, 0x8B, 0x40, 0x30, 0x48, 0x89, 0x44, 0x24, 0x58,
						0x48, 0x8B, 0x44, 0x24, 0x58, 0x48, 0x89, 0x84, 0x24, 0x60, 0x01, 0x00,
						0x00, 0x48, 0x8B, 0x84, 0x24, 0x60, 0x01, 0x00, 0x00, 0x48, 0x63, 0x40,
						0x3C, 0x48, 0x8B, 0x4C, 0x24, 0x58, 0x48, 0x03, 0xC8, 0x48, 0x8B, 0xC1,
						0x48, 0x89, 0x84, 0x24, 0x80, 0x01, 0x00, 0x00, 0xB8, 0x08, 0x00, 0x00,
						0x00, 0x48, 0x6B, 0xC0, 0x00, 0x48, 0x8B, 0x8C, 0x24, 0x80, 0x01, 0x00,
						0x00, 0x48, 0x8D, 0x84, 0x01, 0x88, 0x00, 0x00, 0x00, 0x48, 0x89, 0x84,
						0x24, 0x38, 0x01, 0x00, 0x00, 0x48, 0x8B, 0x84, 0x24, 0x38, 0x01, 0x00,
						0x00, 0x83, 0x38, 0x00, 0x75, 0x05, 0xE9, 0xF4, 0x03, 0x00, 0x00, 0x48,
						0x8B, 0x84, 0x24, 0x38, 0x01, 0x00, 0x00, 0x8B, 0x00, 0x48, 0x8B, 0x4C,
						0x24, 0x58, 0x48, 0x03, 0xC8, 0x48, 0x8B, 0xC1, 0x48, 0x89, 0x84, 0x24,
						0xE0, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x84, 0x24, 0xE0, 0x00, 0x00, 0x00,
						0x8B, 0x40, 0x20, 0x48, 0x8B, 0x4C, 0x24, 0x58, 0x48, 0x03, 0xC8, 0x48,
						0x8B, 0xC1, 0x48, 0x89, 0x84, 0x24, 0x70, 0x01, 0x00, 0x00, 0x48, 0x8B,
						0x84, 0x24, 0xE0, 0x00, 0x00, 0x00, 0x8B, 0x40, 0x24, 0x48, 0x8B, 0x4C,
						0x24, 0x58, 0x48, 0x03, 0xC8, 0x48, 0x8B, 0xC1, 0x48, 0x89, 0x84, 0x24,
						0x20, 0x01, 0x00, 0x00, 0x48, 0x8B, 0x84, 0x24, 0xE0, 0x00, 0x00, 0x00,
						0x8B, 0x40, 0x1C, 0x48, 0x8B, 0x4C, 0x24, 0x58, 0x48, 0x03, 0xC8, 0x48,
						0x8B, 0xC1, 0x48, 0x89, 0x84, 0x24, 0x28, 0x01, 0x00, 0x00, 0x48, 0xC7,
						0x84, 0x24, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0xC7,
						0x84, 0x24, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0xC7,
						0x84, 0x24, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC7, 0x44,
						0x24, 0x3C, 0x00, 0x00, 0x00, 0x00, 0xEB, 0x0A, 0x8B, 0x44, 0x24, 0x3C,
						0xFF, 0xC0, 0x89, 0x44, 0x24, 0x3C, 0x48, 0x8B, 0x84, 0x24, 0xE0, 0x00,
						0x00, 0x00, 0x8B, 0x40, 0x18, 0x39, 0x44, 0x24, 0x3C, 0x0F, 0x83, 0x27,
						0x02, 0x00, 0x00, 0x8B, 0x44, 0x24, 0x3C, 0x48, 0x8B, 0x8C, 0x24, 0x70,
						0x01, 0x00, 0x00, 0x8B, 0x04, 0x81, 0x48, 0x8B, 0x4C, 0x24, 0x58, 0x48,
						0x03, 0xC8, 0x48, 0x8B, 0xC1, 0x48, 0x89, 0x84, 0x24, 0xC0, 0x00, 0x00,
						0x00, 0xC6, 0x44, 0x24, 0x31, 0x01, 0xC7, 0x44, 0x24, 0x40, 0x00, 0x00,
						0x00, 0x00, 0xEB, 0x0A, 0x8B, 0x44, 0x24, 0x40, 0xFF, 0xC0, 0x89, 0x44,
						0x24, 0x40, 0x48, 0x63, 0x44, 0x24, 0x40, 0x0F, 0xBE, 0x84, 0x04, 0x80,
						0x00, 0x00, 0x00, 0x85, 0xC0, 0x75, 0x15, 0x48, 0x63, 0x44, 0x24, 0x40,
						0x48, 0x8B, 0x8C, 0x24, 0xC0, 0x00, 0x00, 0x00, 0x0F, 0xBE, 0x04, 0x01,
						0x85, 0xC0, 0x74, 0x2B, 0x48, 0x63, 0x44, 0x24, 0x40, 0x0F, 0xBE, 0x84,
						0x04, 0x80, 0x00, 0x00, 0x00, 0x48, 0x63, 0x4C, 0x24, 0x40, 0x48, 0x8B,
						0x94, 0x24, 0xC0, 0x00, 0x00, 0x00, 0x0F, 0xBE, 0x0C, 0x0A, 0x3B, 0xC1,
						0x74, 0x07, 0xC6, 0x44, 0x24, 0x31, 0x00, 0xEB, 0x02, 0xEB, 0xA5, 0x0F,
						0xB6, 0x44, 0x24, 0x31, 0x85, 0xC0, 0x74, 0x2E, 0x8B, 0x44, 0x24, 0x3C,
						0x48, 0x8B, 0x8C, 0x24, 0x20, 0x01, 0x00, 0x00, 0x0F, 0xB7, 0x04, 0x41,
						0x48, 0x8B, 0x8C, 0x24, 0x28, 0x01, 0x00, 0x00, 0x8B, 0x04, 0x81, 0x48,
						0x8B, 0x4C, 0x24, 0x58, 0x48, 0x03, 0xC8, 0x48, 0x8B, 0xC1, 0x48, 0x89,
						0x84, 0x24, 0xE8, 0x00, 0x00, 0x00, 0xC6, 0x44, 0x24, 0x32, 0x01, 0xC7,
						0x44, 0x24, 0x44, 0x00, 0x00, 0x00, 0x00, 0xEB, 0x0A, 0x8B, 0x44, 0x24,
						0x44, 0xFF, 0xC0, 0x89, 0x44, 0x24, 0x44, 0x48, 0x63, 0x44, 0x24, 0x44,
						0x0F, 0xBE, 0x84, 0x04, 0x98, 0x00, 0x00, 0x00, 0x85, 0xC0, 0x75, 0x15,
						0x48, 0x63, 0x44, 0x24, 0x44, 0x48, 0x8B, 0x8C, 0x24, 0xC0, 0x00, 0x00,
						0x00, 0x0F, 0xBE, 0x04, 0x01, 0x85, 0xC0, 0x74, 0x2B, 0x48, 0x63, 0x44,
						0x24, 0x44, 0x0F, 0xBE, 0x84, 0x04, 0x98, 0x00, 0x00, 0x00, 0x48, 0x63,
						0x4C, 0x24, 0x44, 0x48, 0x8B, 0x94, 0x24, 0xC0, 0x00, 0x00, 0x00, 0x0F,
						0xBE, 0x0C, 0x0A, 0x3B, 0xC1, 0x74, 0x07, 0xC6, 0x44, 0x24, 0x32, 0x00,
						0xEB, 0x02, 0xEB, 0xA5, 0x0F, 0xB6, 0x44, 0x24, 0x32, 0x85, 0xC0, 0x74,
						0x2E, 0x8B, 0x44, 0x24, 0x3C, 0x48, 0x8B, 0x8C, 0x24, 0x20, 0x01, 0x00,
						0x00, 0x0F, 0xB7, 0x04, 0x41, 0x48, 0x8B, 0x8C, 0x24, 0x28, 0x01, 0x00,
						0x00, 0x8B, 0x04, 0x81, 0x48, 0x8B, 0x4C, 0x24, 0x58, 0x48, 0x03, 0xC8,
						0x48, 0x8B, 0xC1, 0x48, 0x89, 0x84, 0x24, 0xF0, 0x00, 0x00, 0x00, 0xC6,
						0x44, 0x24, 0x33, 0x01, 0xC7, 0x44, 0x24, 0x48, 0x00, 0x00, 0x00, 0x00,
						0xEB, 0x0A, 0x8B, 0x44, 0x24, 0x48, 0xFF, 0xC0, 0x89, 0x44, 0x24, 0x48,
						0x48, 0x63, 0x44, 0x24, 0x48, 0x0F, 0xBE, 0x44, 0x04, 0x68, 0x85, 0xC0,
						0x75, 0x15, 0x48, 0x63, 0x44, 0x24, 0x48, 0x48, 0x8B, 0x8C, 0x24, 0xC0,
						0x00, 0x00, 0x00, 0x0F, 0xBE, 0x04, 0x01, 0x85, 0xC0, 0x74, 0x28, 0x48,
						0x63, 0x44, 0x24, 0x48, 0x0F, 0xBE, 0x44, 0x04, 0x68, 0x48, 0x63, 0x4C,
						0x24, 0x48, 0x48, 0x8B, 0x94, 0x24, 0xC0, 0x00, 0x00, 0x00, 0x0F, 0xBE,
						0x0C, 0x0A, 0x3B, 0xC1, 0x74, 0x07, 0xC6, 0x44, 0x24, 0x33, 0x00, 0xEB,
						0x02, 0xEB, 0xAB, 0x0F, 0xB6, 0x44, 0x24, 0x33, 0x85, 0xC0, 0x74, 0x2E,
						0x8B, 0x44, 0x24, 0x3C, 0x48, 0x8B, 0x8C, 0x24, 0x20, 0x01, 0x00, 0x00,
						0x0F, 0xB7, 0x04, 0x41, 0x48, 0x8B, 0x8C, 0x24, 0x28, 0x01, 0x00, 0x00,
						0x8B, 0x04, 0x81, 0x48, 0x8B, 0x4C, 0x24, 0x58, 0x48, 0x03, 0xC8, 0x48,
						0x8B, 0xC1, 0x48, 0x89, 0x84, 0x24, 0xD8, 0x00, 0x00, 0x00, 0x48, 0x83,
						0xBC, 0x24, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x74, 0x18, 0x48, 0x83, 0xBC,
						0x24, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x74, 0x0D, 0x48, 0x83, 0xBC, 0x24,
						0xD8, 0x00, 0x00, 0x00, 0x00, 0x74, 0x02, 0xEB, 0x05, 0xE9, 0xBA, 0xFD,
						0xFF, 0xFF, 0x48, 0x83, 0xBC, 0x24, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x74,
						0x16, 0x48, 0x83, 0xBC, 0x24, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x74, 0x0B,
						0x48, 0x83, 0xBC, 0x24, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x75, 0x05, 0xE9,
						0xE3, 0x00, 0x00, 0x00, 0xC6, 0x84, 0x24, 0xB8, 0x00, 0x00, 0x00, 0x00,
						0xC7, 0x84, 0x24, 0x7C, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC7,
						0x84, 0x24, 0x78, 0x01, 0x00, 0x00, 0x54, 0x03, 0x00, 0xC0, 0xC7, 0x84,
						0x24, 0x40, 0x01, 0x00, 0x00, 0x22, 0x00, 0x00, 0xC0, 0xC7, 0x84, 0x24,
						0x44, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0xC0, 0x48, 0xC7, 0x44, 0x24,
						0x28, 0x00, 0x00, 0x00, 0x00, 0xC7, 0x44, 0x24, 0x20, 0x00, 0x00, 0x00,
						0x00, 0x45, 0x33, 0xC9, 0x45, 0x33, 0xC0, 0x33, 0xD2, 0xB9, 0x14, 0x00,
						0x00, 0x00, 0xFF, 0x94, 0x24, 0xE8, 0x00, 0x00, 0x00, 0x89, 0x44, 0x24,
						0x60, 0x81, 0x7C, 0x24, 0x60, 0x54, 0x03, 0x00, 0xC0, 0x74, 0x0E, 0x81,
						0x7C, 0x24, 0x60, 0x02, 0x00, 0x00, 0xC0, 0x74, 0x04, 0xEB, 0x55, 0xEB,
						0x53, 0x45, 0x33, 0xC9, 0x41, 0xB8, 0x02, 0x00, 0x00, 0x00, 0x48, 0x8D,
						0x54, 0x24, 0x50, 0xB9, 0x23, 0x00, 0x00, 0x00, 0xFF, 0x94, 0x24, 0xF0,
						0x00, 0x00, 0x00, 0x89, 0x44, 0x24, 0x60, 0x83, 0x7C, 0x24, 0x60, 0x00,
						0x7C, 0x16, 0x0F, 0xB6, 0x44, 0x24, 0x50, 0x85, 0xC0, 0x75, 0x09, 0x0F,
						0xB6, 0x44, 0x24, 0x51, 0x85, 0xC0, 0x75, 0x04, 0xEB, 0x1A, 0xEB, 0x18,
						0x48, 0x8B, 0x84, 0x24, 0xF8, 0x00, 0x00, 0x00, 0x0F, 0xB6, 0x40, 0x02,
						0x85, 0xC0, 0x74, 0x04, 0xEB, 0x06, 0xEB, 0x04, 0xEB, 0x16, 0xEB, 0x14,
						0xBA, 0x01, 0x00, 0x00, 0x00, 0x48, 0xC7, 0xC1, 0xFF, 0xFF, 0xFF, 0xFF,
						0xFF, 0x94, 0x24, 0xD8, 0x00, 0x00, 0x00, 0x90, 0xEB, 0x05, 0xE9, 0x03,
						0xFA, 0xFF, 0xFF, 0x48, 0x81, 0xC4, 0x98, 0x01, 0x00, 0x00

					};
				
					a.embed(antidebugShellcode.data(), antidebugShellcode.size());

				}

				// Restoring the register context
				// Pop flags
				a.pop(asmjit::x86::r15);
				a.pop(asmjit::x86::r14);
				a.pop(asmjit::x86::r13);
				a.pop(asmjit::x86::r12);
				a.pop(asmjit::x86::r11);
				a.pop(asmjit::x86::r10);
				a.pop(asmjit::x86::r9);
				a.pop(asmjit::x86::r8);
				a.pop(asmjit::x86::rdi);
				a.pop(asmjit::x86::rsi);
				a.pop(asmjit::x86::rbp);
				a.pop(asmjit::x86::rbx);
				a.pop(asmjit::x86::rdx);
				a.pop(asmjit::x86::rcx);
				a.pop(asmjit::x86::rax);

				// Breaking Decompilers
				insertBreakDecompilers(a);

				// pop RFLAGS
				a.popfq();

				// Getting new opcodes to insert in place of the old block
				std::vector<ZyanU8> antidebug_instructions;
				auto& opcodeBuffer = code.sectionById(0)->buffer();
				const auto pOpcodeBuffer = opcodeBuffer.data();
				antidebug_instructions.reserve(opcodeBuffer.size());

				// Storing our new opcodes for antidebug detection
				for (auto i = 0; i < opcodeBuffer.size(); ++i) antidebug_instructions.push_back(static_cast<ZyanU8>(pOpcodeBuffer[i]));

				// Saving the opcode block
				data.assign(antidebug_instructions.begin(), antidebug_instructions.end());

				// There’s no need to insert it more than once per function.
				isInserted = TRUE;

			}

		}
	
	}

}

void RyujinObfuscationCore::insertAntiDump() {
	
	BOOL isInserted{ FALSE };

	for (auto& block : m_proc.basic_blocks) {

		for (auto& instr : block.instructions) {

			if (isInserted) break;

			if (!isInserted) {

				auto block_info = findBlockId(instr.instruction.info.opcode, instr.instruction.operands[1].imm.value.u, 2, sizeof(unsigned char));

				if (block_info.first == -1 || block_info.second == -1) continue;

				auto& data = m_proc.basic_blocks[block_info.first].opcodes[block_info.second];

				asmjit::JitRuntime runtime;

				asmjit::CodeHolder code;
				code.init(runtime.environment());
				asmjit::x86::Assembler a(&code);

				// First, saving the states

				// Push flags
				a.pushfq();

				// Push regs
				a.push(asmjit::x86::rax);
				a.push(asmjit::x86::rcx);
				a.push(asmjit::x86::rdx);
				a.push(asmjit::x86::rbx);
				a.push(asmjit::x86::rbp);
				a.push(asmjit::x86::rsi);
				a.push(asmjit::x86::rdi);
				a.push(asmjit::x86::r8);
				a.push(asmjit::x86::r9);
				a.push(asmjit::x86::r10);
				a.push(asmjit::x86::r11);
				a.push(asmjit::x86::r12);
				a.push(asmjit::x86::r13);
				a.push(asmjit::x86::r14);
				a.push(asmjit::x86::r15);

				// Add the AntiDump stub
				std::vector<unsigned char> antiDumpShellcode = {

					/*
						#pragma optimize("", off)
						__declspec(noinline) __declspec(safebuffers) void AntiDumpShell() {
						
						    #ifdef _M_X64
						    auto* peb = reinterpret_cast<PEB*>(__readgsqword(0x60));
						    #else
						    auto* peb = reinterpret_cast<PEB*>(__readfsdword(0x30));
						    #endif
						    if (!peb || !peb->Ldr) return;
						
						    wchar_t ntdllStr[] { 'n','t','d','l','l','.','d','l','l', 0 };
						    char ntprotStr[] { 'N','t','P','r','o','t','e','c','t','V','i','r','t','u','a','l','M','e','m','o','r','y', 0 };
						
						    NtProtectVirtualMemory_t pNtProtect = nullptr;
						
						    auto* head = &peb->Ldr->InMemoryOrderModuleList;
						    for (auto* link = head->Flink; link != head; link = link->Flink) {
						
						        auto* entry = CONTAINING_RECORD(link, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
						        if (!entry->BaseDllName.Buffer) continue;
						
						        auto* modName = entry->BaseDllName.Buffer;
						        auto* target = ntdllStr;
						        bool matched = true;
						        for (; *target && *modName; ++target, ++modName) {
						
						            auto ca = (*modName >= 'A' && *modName <= 'Z') ? *modName + 0x20 : *modName;
						            auto cb = (*target >= 'A' && *target <= 'Z') ? *target + 0x20 : *target;
						            
						            if (ca != cb) { matched = false; break; }
						        
						        }
						        
						        if (!matched || *target || *modName) continue;
						
						        auto* base = reinterpret_cast<BYTE*>(entry->DllBase);
						        auto* dos = reinterpret_cast<IMAGE_DOS_HEADER*>(base);
						        auto* nt = reinterpret_cast<IMAGE_NT_HEADERS*>(base + dos->e_lfanew);
						        auto& ed = nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
						        if (!ed.VirtualAddress) return;
						
						        auto* exp = reinterpret_cast<IMAGE_EXPORT_DIRECTORY*>(base + ed.VirtualAddress);
						        auto* names = reinterpret_cast<DWORD*>(base + exp->AddressOfNames);
						        auto* ords = reinterpret_cast<WORD*>(base + exp->AddressOfNameOrdinals);
						        auto* funcs = reinterpret_cast<DWORD*>(base + exp->AddressOfFunctions);
						
						        for (auto i = 0; i < exp->NumberOfNames; i++) {
						    
						            auto* fn = reinterpret_cast<char*>(base + names[i]);
						
						            bool match = true;
						            for (auto j = 0; ntprotStr[j] || fn[j]; ++j)
						                if (ntprotStr[j] != fn[j]) { match = false; break; }
						            
						            if (match) {
						
						                pNtProtect = reinterpret_cast<NtProtectVirtualMemory_t>(base + funcs[ords[i]]);
						
						                break;
						            }
						
						        
						        }
						        break;
						    
						    }
						
						    if (!pNtProtect) return;
						
						    auto* imgDos = reinterpret_cast<IMAGE_DOS_HEADER*>(peb->ImageBaseAddress);
						    auto* ntHeaders = reinterpret_cast<IMAGE_NT_HEADERS*>(reinterpret_cast<uint8_t*>(imgDos) + imgDos->e_lfanew);
						    auto* sectionHeaders = IMAGE_FIRST_SECTION(ntHeaders);
						
						    auto headerSize = sizeof(IMAGE_DOS_HEADER);
						    ULONG oldProtect;
						    PVOID baseAddr = imgDos;
						
						    if (pNtProtect(reinterpret_cast<HANDLE>(-1), &baseAddr, &headerSize, PAGE_READWRITE, &oldProtect) == 0) {
						
						        for (auto i = 0; i < ntHeaders->FileHeader.NumberOfSections; ++i) {
						
						            auto* ptr = reinterpret_cast<uint8_t*>(&sectionHeaders[i]);
						
						            for (auto j = 0; j < sizeof(IMAGE_SECTION_HEADER); ++j)
						                *ptr++ = 0;
						
						        }
						
						        pNtProtect(reinterpret_cast<HANDLE>(-1), &baseAddr, &headerSize, oldProtect, &oldProtect);
						
						    }
						
						}
						#pragma optimize("", on)
					*/
					0x48, 0x81, 0xEC, 0x48, 0x01, 0x00, 0x00, 0x65, 0x48, 0x8B, 0x04, 0x25,
					0x60, 0x00, 0x00, 0x00, 0x48, 0x89, 0x84, 0x24, 0x98, 0x00, 0x00, 0x00,
					0x48, 0x83, 0xBC, 0x24, 0x98, 0x00, 0x00, 0x00, 0x00, 0x74, 0x0F, 0x48,
					0x8B, 0x84, 0x24, 0x98, 0x00, 0x00, 0x00, 0x48, 0x83, 0x78, 0x18, 0x00,
					0x75, 0x05, 0xE9, 0xF6, 0x05, 0x00, 0x00, 0xB8, 0x6E, 0x00, 0x00, 0x00,
					0x66, 0x89, 0x84, 0x24, 0xA8, 0x00, 0x00, 0x00, 0xB8, 0x74, 0x00, 0x00,
					0x00, 0x66, 0x89, 0x84, 0x24, 0xAA, 0x00, 0x00, 0x00, 0xB8, 0x64, 0x00,
					0x00, 0x00, 0x66, 0x89, 0x84, 0x24, 0xAC, 0x00, 0x00, 0x00, 0xB8, 0x6C,
					0x00, 0x00, 0x00, 0x66, 0x89, 0x84, 0x24, 0xAE, 0x00, 0x00, 0x00, 0xB8,
					0x6C, 0x00, 0x00, 0x00, 0x66, 0x89, 0x84, 0x24, 0xB0, 0x00, 0x00, 0x00,
					0xB8, 0x2E, 0x00, 0x00, 0x00, 0x66, 0x89, 0x84, 0x24, 0xB2, 0x00, 0x00,
					0x00, 0xB8, 0x64, 0x00, 0x00, 0x00, 0x66, 0x89, 0x84, 0x24, 0xB4, 0x00,
					0x00, 0x00, 0xB8, 0x6C, 0x00, 0x00, 0x00, 0x66, 0x89, 0x84, 0x24, 0xB6,
					0x00, 0x00, 0x00, 0xB8, 0x6C, 0x00, 0x00, 0x00, 0x66, 0x89, 0x84, 0x24,
					0xB8, 0x00, 0x00, 0x00, 0x33, 0xC0, 0x66, 0x89, 0x84, 0x24, 0xBA, 0x00,
					0x00, 0x00, 0xC6, 0x44, 0x24, 0x58, 0x4E, 0xC6, 0x44, 0x24, 0x59, 0x74,
					0xC6, 0x44, 0x24, 0x5A, 0x50, 0xC6, 0x44, 0x24, 0x5B, 0x72, 0xC6, 0x44,
					0x24, 0x5C, 0x6F, 0xC6, 0x44, 0x24, 0x5D, 0x74, 0xC6, 0x44, 0x24, 0x5E,
					0x65, 0xC6, 0x44, 0x24, 0x5F, 0x63, 0xC6, 0x44, 0x24, 0x60, 0x74, 0xC6,
					0x44, 0x24, 0x61, 0x56, 0xC6, 0x44, 0x24, 0x62, 0x69, 0xC6, 0x44, 0x24,
					0x63, 0x72, 0xC6, 0x44, 0x24, 0x64, 0x74, 0xC6, 0x44, 0x24, 0x65, 0x75,
					0xC6, 0x44, 0x24, 0x66, 0x61, 0xC6, 0x44, 0x24, 0x67, 0x6C, 0xC6, 0x44,
					0x24, 0x68, 0x4D, 0xC6, 0x44, 0x24, 0x69, 0x65, 0xC6, 0x44, 0x24, 0x6A,
					0x6D, 0xC6, 0x44, 0x24, 0x6B, 0x6F, 0xC6, 0x44, 0x24, 0x6C, 0x72, 0xC6,
					0x44, 0x24, 0x6D, 0x79, 0xC6, 0x44, 0x24, 0x6E, 0x00, 0x48, 0xC7, 0x84,
					0x24, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x84,
					0x24, 0x98, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x40, 0x18, 0x48, 0x83, 0xC0,
					0x28, 0x48, 0x89, 0x84, 0x24, 0xE0, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x84,
					0x24, 0xE0, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x00, 0x48, 0x89, 0x84, 0x24,
					0x88, 0x00, 0x00, 0x00, 0xEB, 0x13, 0x48, 0x8B, 0x84, 0x24, 0x88, 0x00,
					0x00, 0x00, 0x48, 0x8B, 0x00, 0x48, 0x89, 0x84, 0x24, 0x88, 0x00, 0x00,
					0x00, 0x48, 0x8B, 0x84, 0x24, 0xE0, 0x00, 0x00, 0x00, 0x48, 0x39, 0x84,
					0x24, 0x88, 0x00, 0x00, 0x00, 0x0F, 0x84, 0x2C, 0x03, 0x00, 0x00, 0x48,
					0x8B, 0x84, 0x24, 0x88, 0x00, 0x00, 0x00, 0x48, 0x83, 0xE8, 0x10, 0x48,
					0x89, 0x84, 0x24, 0xC0, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x84, 0x24, 0xC0,
					0x00, 0x00, 0x00, 0x48, 0x83, 0x78, 0x60, 0x00, 0x75, 0x02, 0xEB, 0xB2,
					0x48, 0x8B, 0x84, 0x24, 0xC0, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x40, 0x60,
					0x48, 0x89, 0x44, 0x24, 0x48, 0x48, 0x8D, 0x84, 0x24, 0xA8, 0x00, 0x00,
					0x00, 0x48, 0x89, 0x44, 0x24, 0x40, 0xC6, 0x44, 0x24, 0x30, 0x01, 0xEB,
					0x1C, 0x48, 0x8B, 0x44, 0x24, 0x40, 0x48, 0x83, 0xC0, 0x02, 0x48, 0x89,
					0x44, 0x24, 0x40, 0x48, 0x8B, 0x44, 0x24, 0x48, 0x48, 0x83, 0xC0, 0x02,
					0x48, 0x89, 0x44, 0x24, 0x48, 0x48, 0x8B, 0x44, 0x24, 0x40, 0x0F, 0xB7,
					0x00, 0x85, 0xC0, 0x0F, 0x84, 0xB5, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x44,
					0x24, 0x48, 0x0F, 0xB7, 0x00, 0x85, 0xC0, 0x0F, 0x84, 0xA5, 0x00, 0x00,
					0x00, 0x48, 0x8B, 0x44, 0x24, 0x48, 0x0F, 0xB7, 0x00, 0x83, 0xF8, 0x41,
					0x7C, 0x1E, 0x48, 0x8B, 0x44, 0x24, 0x48, 0x0F, 0xB7, 0x00, 0x83, 0xF8,
					0x5A, 0x7F, 0x11, 0x48, 0x8B, 0x44, 0x24, 0x48, 0x0F, 0xB7, 0x00, 0x83,
					0xC0, 0x20, 0x89, 0x44, 0x24, 0x7C, 0xEB, 0x0C, 0x48, 0x8B, 0x44, 0x24,
					0x48, 0x0F, 0xB7, 0x00, 0x89, 0x44, 0x24, 0x7C, 0x0F, 0xB7, 0x44, 0x24,
					0x7C, 0x66, 0x89, 0x44, 0x24, 0x70, 0x48, 0x8B, 0x44, 0x24, 0x40, 0x0F,
					0xB7, 0x00, 0x83, 0xF8, 0x41, 0x7C, 0x21, 0x48, 0x8B, 0x44, 0x24, 0x40,
					0x0F, 0xB7, 0x00, 0x83, 0xF8, 0x5A, 0x7F, 0x14, 0x48, 0x8B, 0x44, 0x24,
					0x40, 0x0F, 0xB7, 0x00, 0x83, 0xC0, 0x20, 0x89, 0x84, 0x24, 0x80, 0x00,
					0x00, 0x00, 0xEB, 0x0F, 0x48, 0x8B, 0x44, 0x24, 0x40, 0x0F, 0xB7, 0x00,
					0x89, 0x84, 0x24, 0x80, 0x00, 0x00, 0x00, 0x0F, 0xB7, 0x84, 0x24, 0x80,
					0x00, 0x00, 0x00, 0x66, 0x89, 0x44, 0x24, 0x74, 0x0F, 0xB7, 0x44, 0x24,
					0x70, 0x0F, 0xB7, 0x4C, 0x24, 0x74, 0x3B, 0xC1, 0x74, 0x07, 0xC6, 0x44,
					0x24, 0x30, 0x00, 0xEB, 0x05, 0xE9, 0x1F, 0xFF, 0xFF, 0xFF, 0x0F, 0xB6,
					0x44, 0x24, 0x30, 0x85, 0xC0, 0x74, 0x18, 0x48, 0x8B, 0x44, 0x24, 0x40,
					0x0F, 0xB7, 0x00, 0x85, 0xC0, 0x75, 0x0C, 0x48, 0x8B, 0x44, 0x24, 0x48,
					0x0F, 0xB7, 0x00, 0x85, 0xC0, 0x74, 0x05, 0xE9, 0x86, 0xFE, 0xFF, 0xFF,
					0x48, 0x8B, 0x84, 0x24, 0xC0, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x40, 0x30,
					0x48, 0x89, 0x44, 0x24, 0x50, 0x48, 0x8B, 0x44, 0x24, 0x50, 0x48, 0x89,
					0x84, 0x24, 0x08, 0x01, 0x00, 0x00, 0x48, 0x8B, 0x84, 0x24, 0x08, 0x01,
					0x00, 0x00, 0x48, 0x63, 0x40, 0x3C, 0x48, 0x8B, 0x4C, 0x24, 0x50, 0x48,
					0x03, 0xC8, 0x48, 0x8B, 0xC1, 0x48, 0x89, 0x84, 0x24, 0x10, 0x01, 0x00,
					0x00, 0xB8, 0x08, 0x00, 0x00, 0x00, 0x48, 0x6B, 0xC0, 0x00, 0x48, 0x8B,
					0x8C, 0x24, 0x10, 0x01, 0x00, 0x00, 0x48, 0x8D, 0x84, 0x01, 0x88, 0x00,
					0x00, 0x00, 0x48, 0x89, 0x84, 0x24, 0xE8, 0x00, 0x00, 0x00, 0x48, 0x8B,
					0x84, 0x24, 0xE8, 0x00, 0x00, 0x00, 0x83, 0x38, 0x00, 0x75, 0x05, 0xE9,
					0xE1, 0x02, 0x00, 0x00, 0x48, 0x8B, 0x84, 0x24, 0xE8, 0x00, 0x00, 0x00,
					0x8B, 0x00, 0x48, 0x8B, 0x4C, 0x24, 0x50, 0x48, 0x03, 0xC8, 0x48, 0x8B,
					0xC1, 0x48, 0x89, 0x84, 0x24, 0x90, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x84,
					0x24, 0x90, 0x00, 0x00, 0x00, 0x8B, 0x40, 0x20, 0x48, 0x8B, 0x4C, 0x24,
					0x50, 0x48, 0x03, 0xC8, 0x48, 0x8B, 0xC1, 0x48, 0x89, 0x84, 0x24, 0x18,
					0x01, 0x00, 0x00, 0x48, 0x8B, 0x84, 0x24, 0x90, 0x00, 0x00, 0x00, 0x8B,
					0x40, 0x24, 0x48, 0x8B, 0x4C, 0x24, 0x50, 0x48, 0x03, 0xC8, 0x48, 0x8B,
					0xC1, 0x48, 0x89, 0x84, 0x24, 0x20, 0x01, 0x00, 0x00, 0x48, 0x8B, 0x84,
					0x24, 0x90, 0x00, 0x00, 0x00, 0x8B, 0x40, 0x1C, 0x48, 0x8B, 0x4C, 0x24,
					0x50, 0x48, 0x03, 0xC8, 0x48, 0x8B, 0xC1, 0x48, 0x89, 0x84, 0x24, 0x28,
					0x01, 0x00, 0x00, 0xC7, 0x44, 0x24, 0x38, 0x00, 0x00, 0x00, 0x00, 0xEB,
					0x0A, 0x8B, 0x44, 0x24, 0x38, 0xFF, 0xC0, 0x89, 0x44, 0x24, 0x38, 0x48,
					0x8B, 0x84, 0x24, 0x90, 0x00, 0x00, 0x00, 0x8B, 0x40, 0x18, 0x39, 0x44,
					0x24, 0x38, 0x0F, 0x83, 0xC4, 0x00, 0x00, 0x00, 0x8B, 0x44, 0x24, 0x38,
					0x48, 0x8B, 0x8C, 0x24, 0x18, 0x01, 0x00, 0x00, 0x8B, 0x04, 0x81, 0x48,
					0x8B, 0x4C, 0x24, 0x50, 0x48, 0x03, 0xC8, 0x48, 0x8B, 0xC1, 0x48, 0x89,
					0x84, 0x24, 0xF0, 0x00, 0x00, 0x00, 0xC6, 0x44, 0x24, 0x31, 0x01, 0xC7,
					0x44, 0x24, 0x34, 0x00, 0x00, 0x00, 0x00, 0xEB, 0x0A, 0x8B, 0x44, 0x24,
					0x34, 0xFF, 0xC0, 0x89, 0x44, 0x24, 0x34, 0x48, 0x63, 0x44, 0x24, 0x34,
					0x0F, 0xBE, 0x44, 0x04, 0x58, 0x85, 0xC0, 0x75, 0x15, 0x48, 0x63, 0x44,
					0x24, 0x34, 0x48, 0x8B, 0x8C, 0x24, 0xF0, 0x00, 0x00, 0x00, 0x0F, 0xBE,
					0x04, 0x01, 0x85, 0xC0, 0x74, 0x28, 0x48, 0x63, 0x44, 0x24, 0x34, 0x0F,
					0xBE, 0x44, 0x04, 0x58, 0x48, 0x63, 0x4C, 0x24, 0x34, 0x48, 0x8B, 0x94,
					0x24, 0xF0, 0x00, 0x00, 0x00, 0x0F, 0xBE, 0x0C, 0x0A, 0x3B, 0xC1, 0x74,
					0x07, 0xC6, 0x44, 0x24, 0x31, 0x00, 0xEB, 0x02, 0xEB, 0xAB, 0x0F, 0xB6,
					0x44, 0x24, 0x31, 0x85, 0xC0, 0x74, 0x30, 0x8B, 0x44, 0x24, 0x38, 0x48,
					0x8B, 0x8C, 0x24, 0x20, 0x01, 0x00, 0x00, 0x0F, 0xB7, 0x04, 0x41, 0x48,
					0x8B, 0x8C, 0x24, 0x28, 0x01, 0x00, 0x00, 0x8B, 0x04, 0x81, 0x48, 0x8B,
					0x4C, 0x24, 0x50, 0x48, 0x03, 0xC8, 0x48, 0x8B, 0xC1, 0x48, 0x89, 0x84,
					0x24, 0xA0, 0x00, 0x00, 0x00, 0xEB, 0x05, 0xE9, 0x1D, 0xFF, 0xFF, 0xFF,
					0xEB, 0x05, 0xE9, 0xAB, 0xFC, 0xFF, 0xFF, 0x48, 0x83, 0xBC, 0x24, 0xA0,
					0x00, 0x00, 0x00, 0x00, 0x75, 0x05, 0xE9, 0x66, 0x01, 0x00, 0x00, 0x48,
					0x8B, 0x84, 0x24, 0x98, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x40, 0x10, 0x48,
					0x89, 0x84, 0x24, 0xC8, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x84, 0x24, 0xC8,
					0x00, 0x00, 0x00, 0x48, 0x63, 0x40, 0x3C, 0x48, 0x8B, 0x8C, 0x24, 0xC8,
					0x00, 0x00, 0x00, 0x48, 0x03, 0xC8, 0x48, 0x8B, 0xC1, 0x48, 0x89, 0x84,
					0x24, 0xD0, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x84, 0x24, 0xD0, 0x00, 0x00,
					0x00, 0x0F, 0xB7, 0x40, 0x14, 0x48, 0x8B, 0x8C, 0x24, 0xD0, 0x00, 0x00,
					0x00, 0x48, 0x8D, 0x44, 0x01, 0x18, 0x48, 0x89, 0x84, 0x24, 0x30, 0x01,
					0x00, 0x00, 0x48, 0xC7, 0x84, 0x24, 0xF8, 0x00, 0x00, 0x00, 0x40, 0x00,
					0x00, 0x00, 0x48, 0x8B, 0x84, 0x24, 0xC8, 0x00, 0x00, 0x00, 0x48, 0x89,
					0x84, 0x24, 0x00, 0x01, 0x00, 0x00, 0x48, 0x8D, 0x84, 0x24, 0x84, 0x00,
					0x00, 0x00, 0x48, 0x89, 0x44, 0x24, 0x20, 0x41, 0xB9, 0x04, 0x00, 0x00,
					0x00, 0x4C, 0x8D, 0x84, 0x24, 0xF8, 0x00, 0x00, 0x00, 0x48, 0x8D, 0x94,
					0x24, 0x00, 0x01, 0x00, 0x00, 0x48, 0xC7, 0xC1, 0xFF, 0xFF, 0xFF, 0xFF,
					0xFF, 0x94, 0x24, 0xA0, 0x00, 0x00, 0x00, 0x85, 0xC0, 0x0F, 0x85, 0xBA,
					0x00, 0x00, 0x00, 0xC7, 0x44, 0x24, 0x3C, 0x00, 0x00, 0x00, 0x00, 0xEB,
					0x0A, 0x8B, 0x44, 0x24, 0x3C, 0xFF, 0xC0, 0x89, 0x44, 0x24, 0x3C, 0x48,
					0x8B, 0x84, 0x24, 0xD0, 0x00, 0x00, 0x00, 0x0F, 0xB7, 0x40, 0x06, 0x39,
					0x44, 0x24, 0x3C, 0x7D, 0x60, 0x48, 0x63, 0x44, 0x24, 0x3C, 0x48, 0x6B,
					0xC0, 0x28, 0x48, 0x8B, 0x8C, 0x24, 0x30, 0x01, 0x00, 0x00, 0x48, 0x03,
					0xC8, 0x48, 0x8B, 0xC1, 0x48, 0x89, 0x84, 0x24, 0xD8, 0x00, 0x00, 0x00,
					0xC7, 0x44, 0x24, 0x78, 0x00, 0x00, 0x00, 0x00, 0xEB, 0x0A, 0x8B, 0x44,
					0x24, 0x78, 0xFF, 0xC0, 0x89, 0x44, 0x24, 0x78, 0x48, 0x63, 0x44, 0x24,
					0x78, 0x48, 0x83, 0xF8, 0x28, 0x73, 0x20, 0x48, 0x8B, 0x84, 0x24, 0xD8,
					0x00, 0x00, 0x00, 0xC6, 0x00, 0x00, 0x48, 0x8B, 0x84, 0x24, 0xD8, 0x00,
					0x00, 0x00, 0x48, 0xFF, 0xC0, 0x48, 0x89, 0x84, 0x24, 0xD8, 0x00, 0x00,
					0x00, 0xEB, 0xCB, 0xEB, 0x84, 0x48, 0x8D, 0x84, 0x24, 0x84, 0x00, 0x00,
					0x00, 0x48, 0x89, 0x44, 0x24, 0x20, 0x44, 0x8B, 0x8C, 0x24, 0x84, 0x00,
					0x00, 0x00, 0x4C, 0x8D, 0x84, 0x24, 0xF8, 0x00, 0x00, 0x00, 0x48, 0x8D,
					0x94, 0x24, 0x00, 0x01, 0x00, 0x00, 0x48, 0xC7, 0xC1, 0xFF, 0xFF, 0xFF,
					0xFF, 0xFF, 0x94, 0x24, 0xA0, 0x00, 0x00, 0x00, 0x90, 0x48, 0x81, 0xC4,
					0x48, 0x01, 0x00, 0x00

				};

				a.embed(antiDumpShellcode.data(), antiDumpShellcode.size());

				// Restoring the register context
				// Pop flags
				a.pop(asmjit::x86::r15);
				a.pop(asmjit::x86::r14);
				a.pop(asmjit::x86::r13);
				a.pop(asmjit::x86::r12);
				a.pop(asmjit::x86::r11);
				a.pop(asmjit::x86::r10);
				a.pop(asmjit::x86::r9);
				a.pop(asmjit::x86::r8);
				a.pop(asmjit::x86::rdi);
				a.pop(asmjit::x86::rsi);
				a.pop(asmjit::x86::rbp);
				a.pop(asmjit::x86::rbx);
				a.pop(asmjit::x86::rdx);
				a.pop(asmjit::x86::rcx);
				a.pop(asmjit::x86::rax);

				// Breaking Decompilers
				insertBreakDecompilers(a);

				// pop RFLAGS
				a.popfq();

				// Getting new opcodes to insert in place of the old block
				std::vector<ZyanU8> antidump_instructions;
				auto& opcodeBuffer = code.sectionById(0)->buffer();
				const auto pOpcodeBuffer = opcodeBuffer.data();
				antidump_instructions.reserve(opcodeBuffer.size());

				// Storing our new opcodes for antidump detection
				for (auto i = 0; i < opcodeBuffer.size(); ++i) antidump_instructions.push_back(static_cast<ZyanU8>(pOpcodeBuffer[i]));

				// Saving the opcode block
				data.assign(antidump_instructions.begin(), antidump_instructions.end());

				isInserted = TRUE;

			}
		}
	}

}

void RyujinObfuscationCore::insertMemoryProtection() {

	BOOL isInserted{ FALSE };

	for (auto& block : m_proc.basic_blocks) {

		for (auto& instr : block.instructions) {

			if (isInserted) break;

			if (!isInserted) {

				auto block_info = findBlockId(instr.instruction.info.opcode, instr.instruction.operands[1].imm.value.u, 2, sizeof(unsigned char));

				if (block_info.first == -1 || block_info.second == -1) continue;

				auto& data = m_proc.basic_blocks[block_info.first].opcodes[block_info.second];

				asmjit::JitRuntime runtime;

				asmjit::CodeHolder code;
				code.init(runtime.environment());
				asmjit::x86::Assembler a(&code);

				// First, saving the states

				// Push flags
				a.pushfq();

				// Push regs
				a.push(asmjit::x86::rax);
				a.push(asmjit::x86::rcx);
				a.push(asmjit::x86::rdx);
				a.push(asmjit::x86::rbx);
				a.push(asmjit::x86::rbp);
				a.push(asmjit::x86::rsi);
				a.push(asmjit::x86::rdi);
				a.push(asmjit::x86::r8);
				a.push(asmjit::x86::r9);
				a.push(asmjit::x86::r10);
				a.push(asmjit::x86::r11);
				a.push(asmjit::x86::r12);
				a.push(asmjit::x86::r13);
				a.push(asmjit::x86::r14);
				a.push(asmjit::x86::r15);

				std::vector<unsigned char> memoryProtectionShellcode = {
				
					/*
						#pragma optimize("", off)
						__declspec(noinline) __declspec(safebuffers) void RyujinMemoryCrc32Protection() {
						
							#ifdef _M_X64
							auto* peb = reinterpret_cast<PEB*>(__readgsqword(0x60));
							#else
							auto* peb = reinterpret_cast<PEB*>(__readfsdword(0x30));
							#endif
						
							if (!peb || !peb->ImageBaseAddress || !peb->Ldr) return;
						
							auto* base = reinterpret_cast<BYTE*>(peb->ImageBaseAddress);
							auto* dos = reinterpret_cast<IMAGE_DOS_HEADER*>(base);
						
							if (dos->e_magic != IMAGE_DOS_SIGNATURE) return;
						
							auto* nt = reinterpret_cast<IMAGE_NT_HEADERS*>(base + dos->e_lfanew);
							if (nt->Signature != IMAGE_NT_SIGNATURE) return;
						
							auto* section = IMAGE_FIRST_SECTION(nt);
						
							char ryujinName[8] { '.', 'R', 'y', 'u', 'j', 'i', 'n', 0 };
						
							IMAGE_SECTION_HEADER* ryujin = nullptr;
							for (int i = 0; i < nt->FileHeader.NumberOfSections; ++i, ++section) {
						
								bool isMatch = true;
						
								for (int j = 0; j < 8; ++j)
									if (section->Name[j] != ryujinName[j]) {
						
										isMatch = false;
						
										break;
									}
						
								if (isMatch) {
						
									ryujin = section;
						
									break;
								}
						
							}
						
							if (!ryujin) return;
						
							wchar_t ntdllStr[] { 'n','t','d','l','l','.','d','l','l', 0 };
							char ntTermStr[] { 'N','t','T','e','r','m','i','n','a','t','e','P','r','o','c','e','s','s', 0 };
						
							BYTE* ntdllBase = nullptr;
							for (auto* link = peb->Ldr->InMemoryOrderModuleList.Flink; link != &peb->Ldr->InMemoryOrderModuleList; link = link->Flink) {
						
								auto* entry = CONTAINING_RECORD(link, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
						
								if (!entry->BaseDllName.Buffer) continue;
						
								auto* modName = entry->BaseDllName.Buffer;
								auto* target = ntdllStr;
						
								bool match = true;
						
								for (; *target && *modName; ++target, ++modName) {
						
									wchar_t ca = (*modName >= 'A' && *modName <= 'Z') ? *modName + 0x20 : *modName;
									wchar_t cb = (*target >= 'A' && *target <= 'Z') ? *target + 0x20 : *target;
									if (ca != cb) { match = false; break; }
						
								}
						
								if (match && !*target && !*modName) {
						
									ntdllBase = reinterpret_cast<BYTE*>(entry->DllBase);
						
									break;
								}
						
							}
						
							if (!ntdllBase) return;
						
							auto* dosHdr = reinterpret_cast<IMAGE_DOS_HEADER*>(ntdllBase);
							auto* ntHdr = reinterpret_cast<IMAGE_NT_HEADERS*>(ntdllBase + dosHdr->e_lfanew);
							auto& dir = ntHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
						
							if (!dir.VirtualAddress) return;
						
							auto* exportDir = reinterpret_cast<IMAGE_EXPORT_DIRECTORY*>(ntdllBase + dir.VirtualAddress);
							auto* names = reinterpret_cast<DWORD*>(ntdllBase + exportDir->AddressOfNames);
							auto* ordinals = reinterpret_cast<WORD*>(ntdllBase + exportDir->AddressOfNameOrdinals);
							auto* functions = reinterpret_cast<DWORD*>(ntdllBase + exportDir->AddressOfFunctions);
						
							NtTerminateProcess_t pNtTerminate = nullptr;
						
							for (DWORD i = 0; i < exportDir->NumberOfNames; ++i) {
						
								const char* fname = reinterpret_cast<const char*>(ntdllBase + names[i]);
						
								bool match = true;
								for (int j = 0; ntTermStr[j] || fname[j]; ++j)
									if (ntTermStr[j] != fname[j]) { match = false; break; }
						
								if (match) {
						
									pNtTerminate = reinterpret_cast<NtTerminateProcess_t>(
										ntdllBase + functions[ordinals[i]]);
						
									break;
								}
						
							}
						
							if (pNtTerminate) {
						
								const uint8_t* data = base + ryujin->VirtualAddress;
						
								uint32_t crc = 0xFFFFFFFF;
								for (size_t i = 0; i < ryujin->NumberOfLinenumbers; ++i) {
						
									crc ^= data[i];
						
									for (int j = 0; j < 8; ++j) {
										if (crc & 1)
											crc = (crc >> 1) ^ 0xB0B0C400;
										else
											crc >>= 1;
									}
						
								}
						
								auto crcvalue = crc ^ 0xFFFFFFFF;
						
								if (ryujin->PointerToLinenumbers != crcvalue)
									pNtTerminate(reinterpret_cast<HANDLE>(-1), crcvalue);
							}
						
						}
						#pragma optimize("", on)
					*/
					0x48, 0x81, 0xEC, 0x58, 0x01, 0x00, 0x00, 0x65, 0x48, 0x8B, 0x04, 0x25,
					0x60, 0x00, 0x00, 0x00, 0x48, 0x89, 0x84, 0x24, 0x80, 0x00, 0x00, 0x00,
					0x48, 0x83, 0xBC, 0x24, 0x80, 0x00, 0x00, 0x00, 0x00, 0x74, 0x1E, 0x48,
					0x8B, 0x84, 0x24, 0x80, 0x00, 0x00, 0x00, 0x48, 0x83, 0x78, 0x10, 0x00,
					0x74, 0x0F, 0x48, 0x8B, 0x84, 0x24, 0x80, 0x00, 0x00, 0x00, 0x48, 0x83,
					0x78, 0x18, 0x00, 0x75, 0x05, 0xE9, 0x16, 0x07, 0x00, 0x00, 0x48, 0x8B,
					0x84, 0x24, 0x80, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x40, 0x10, 0x48, 0x89,
					0x84, 0x24, 0xE8, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x84, 0x24, 0xE8, 0x00,
					0x00, 0x00, 0x48, 0x89, 0x84, 0x24, 0x00, 0x01, 0x00, 0x00, 0x48, 0x8B,
					0x84, 0x24, 0x00, 0x01, 0x00, 0x00, 0x0F, 0xB7, 0x00, 0x3D, 0x4D, 0x5A,
					0x00, 0x00, 0x74, 0x05, 0xE9, 0xDB, 0x06, 0x00, 0x00, 0x48, 0x8B, 0x84,
					0x24, 0x00, 0x01, 0x00, 0x00, 0x48, 0x63, 0x40, 0x3C, 0x48, 0x8B, 0x8C,
					0x24, 0xE8, 0x00, 0x00, 0x00, 0x48, 0x03, 0xC8, 0x48, 0x8B, 0xC1, 0x48,
					0x89, 0x84, 0x24, 0xA0, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x84, 0x24, 0xA0,
					0x00, 0x00, 0x00, 0x81, 0x38, 0x50, 0x45, 0x00, 0x00, 0x74, 0x05, 0xE9,
					0xA4, 0x06, 0x00, 0x00, 0x48, 0x8B, 0x84, 0x24, 0xA0, 0x00, 0x00, 0x00,
					0x0F, 0xB7, 0x40, 0x14, 0x48, 0x8B, 0x8C, 0x24, 0xA0, 0x00, 0x00, 0x00,
					0x48, 0x8D, 0x44, 0x01, 0x18, 0x48, 0x89, 0x84, 0x24, 0xA8, 0x00, 0x00,
					0x00, 0x48, 0x8B, 0x84, 0x24, 0xA0, 0x00, 0x00, 0x00, 0x0F, 0xB7, 0x40,
					0x06, 0x89, 0x84, 0x24, 0xF8, 0x00, 0x00, 0x00, 0xC6, 0x44, 0x24, 0x50,
					0x2E, 0xC6, 0x44, 0x24, 0x51, 0x52, 0xC6, 0x44, 0x24, 0x52, 0x79, 0xC6,
					0x44, 0x24, 0x53, 0x75, 0xC6, 0x44, 0x24, 0x54, 0x6A, 0xC6, 0x44, 0x24,
					0x55, 0x69, 0xC6, 0x44, 0x24, 0x56, 0x6E, 0xC6, 0x44, 0x24, 0x57, 0x00,
					0x48, 0xC7, 0x84, 0x24, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
					0xC7, 0x44, 0x24, 0x78, 0x00, 0x00, 0x00, 0x00, 0xEB, 0x1E, 0x8B, 0x44,
					0x24, 0x78, 0xFF, 0xC0, 0x89, 0x44, 0x24, 0x78, 0x48, 0x8B, 0x84, 0x24,
					0xA8, 0x00, 0x00, 0x00, 0x48, 0x83, 0xC0, 0x28, 0x48, 0x89, 0x84, 0x24,
					0xA8, 0x00, 0x00, 0x00, 0x8B, 0x84, 0x24, 0xF8, 0x00, 0x00, 0x00, 0x39,
					0x44, 0x24, 0x78, 0x7D, 0x68, 0xC6, 0x44, 0x24, 0x20, 0x01, 0xC7, 0x44,
					0x24, 0x2C, 0x00, 0x00, 0x00, 0x00, 0xEB, 0x0A, 0x8B, 0x44, 0x24, 0x2C,
					0xFF, 0xC0, 0x89, 0x44, 0x24, 0x2C, 0x83, 0x7C, 0x24, 0x2C, 0x08, 0x7D,
					0x28, 0x48, 0x63, 0x44, 0x24, 0x2C, 0x48, 0x8B, 0x8C, 0x24, 0xA8, 0x00,
					0x00, 0x00, 0x0F, 0xB6, 0x04, 0x01, 0x48, 0x63, 0x4C, 0x24, 0x2C, 0x0F,
					0xBE, 0x4C, 0x0C, 0x50, 0x3B, 0xC1, 0x74, 0x07, 0xC6, 0x44, 0x24, 0x20,
					0x00, 0xEB, 0x02, 0xEB, 0xC7, 0x0F, 0xB6, 0x44, 0x24, 0x20, 0x85, 0xC0,
					0x74, 0x12, 0x48, 0x8B, 0x84, 0x24, 0xA8, 0x00, 0x00, 0x00, 0x48, 0x89,
					0x84, 0x24, 0x98, 0x00, 0x00, 0x00, 0xEB, 0x05, 0xE9, 0x6D, 0xFF, 0xFF,
					0xFF, 0x48, 0x83, 0xBC, 0x24, 0x98, 0x00, 0x00, 0x00, 0x00, 0x75, 0x05,
					0xE9, 0x8F, 0x05, 0x00, 0x00, 0xB8, 0x6E, 0x00, 0x00, 0x00, 0x66, 0x89,
					0x84, 0x24, 0xC8, 0x00, 0x00, 0x00, 0xB8, 0x74, 0x00, 0x00, 0x00, 0x66,
					0x89, 0x84, 0x24, 0xCA, 0x00, 0x00, 0x00, 0xB8, 0x64, 0x00, 0x00, 0x00,
					0x66, 0x89, 0x84, 0x24, 0xCC, 0x00, 0x00, 0x00, 0xB8, 0x6C, 0x00, 0x00,
					0x00, 0x66, 0x89, 0x84, 0x24, 0xCE, 0x00, 0x00, 0x00, 0xB8, 0x6C, 0x00,
					0x00, 0x00, 0x66, 0x89, 0x84, 0x24, 0xD0, 0x00, 0x00, 0x00, 0xB8, 0x2E,
					0x00, 0x00, 0x00, 0x66, 0x89, 0x84, 0x24, 0xD2, 0x00, 0x00, 0x00, 0xB8,
					0x64, 0x00, 0x00, 0x00, 0x66, 0x89, 0x84, 0x24, 0xD4, 0x00, 0x00, 0x00,
					0xB8, 0x6C, 0x00, 0x00, 0x00, 0x66, 0x89, 0x84, 0x24, 0xD6, 0x00, 0x00,
					0x00, 0xB8, 0x6C, 0x00, 0x00, 0x00, 0x66, 0x89, 0x84, 0x24, 0xD8, 0x00,
					0x00, 0x00, 0x33, 0xC0, 0x66, 0x89, 0x84, 0x24, 0xDA, 0x00, 0x00, 0x00,
					0xC6, 0x44, 0x24, 0x58, 0x4E, 0xC6, 0x44, 0x24, 0x59, 0x74, 0xC6, 0x44,
					0x24, 0x5A, 0x54, 0xC6, 0x44, 0x24, 0x5B, 0x65, 0xC6, 0x44, 0x24, 0x5C,
					0x72, 0xC6, 0x44, 0x24, 0x5D, 0x6D, 0xC6, 0x44, 0x24, 0x5E, 0x69, 0xC6,
					0x44, 0x24, 0x5F, 0x6E, 0xC6, 0x44, 0x24, 0x60, 0x61, 0xC6, 0x44, 0x24,
					0x61, 0x74, 0xC6, 0x44, 0x24, 0x62, 0x65, 0xC6, 0x44, 0x24, 0x63, 0x50,
					0xC6, 0x44, 0x24, 0x64, 0x72, 0xC6, 0x44, 0x24, 0x65, 0x6F, 0xC6, 0x44,
					0x24, 0x66, 0x63, 0xC6, 0x44, 0x24, 0x67, 0x65, 0xC6, 0x44, 0x24, 0x68,
					0x73, 0xC6, 0x44, 0x24, 0x69, 0x73, 0xC6, 0x44, 0x24, 0x6A, 0x00, 0x48,
					0xC7, 0x44, 0x24, 0x38, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x84, 0x24,
					0x80, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x40, 0x18, 0x48, 0x8B, 0x40, 0x28,
					0x48, 0x89, 0x84, 0x24, 0xB0, 0x00, 0x00, 0x00, 0xEB, 0x13, 0x48, 0x8B,
					0x84, 0x24, 0xB0, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x00, 0x48, 0x89, 0x84,
					0x24, 0xB0, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x84, 0x24, 0x80, 0x00, 0x00,
					0x00, 0x48, 0x8B, 0x40, 0x18, 0x48, 0x83, 0xC0, 0x28, 0x48, 0x39, 0x84,
					0x24, 0xB0, 0x00, 0x00, 0x00, 0x0F, 0x84, 0x6D, 0x01, 0x00, 0x00, 0x48,
					0x8B, 0x84, 0x24, 0xB0, 0x00, 0x00, 0x00, 0x48, 0x83, 0xE8, 0x10, 0x48,
					0x89, 0x84, 0x24, 0xE0, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x84, 0x24, 0xE0,
					0x00, 0x00, 0x00, 0x48, 0x83, 0x78, 0x60, 0x00, 0x75, 0x02, 0xEB, 0xAA,
					0x48, 0x8B, 0x84, 0x24, 0xE0, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x40, 0x60,
					0x48, 0x89, 0x44, 0x24, 0x48, 0x48, 0x8D, 0x84, 0x24, 0xC8, 0x00, 0x00,
					0x00, 0x48, 0x89, 0x44, 0x24, 0x40, 0xC6, 0x44, 0x24, 0x21, 0x01, 0xEB,
					0x1C, 0x48, 0x8B, 0x44, 0x24, 0x40, 0x48, 0x83, 0xC0, 0x02, 0x48, 0x89,
					0x44, 0x24, 0x40, 0x48, 0x8B, 0x44, 0x24, 0x48, 0x48, 0x83, 0xC0, 0x02,
					0x48, 0x89, 0x44, 0x24, 0x48, 0x48, 0x8B, 0x44, 0x24, 0x40, 0x0F, 0xB7,
					0x00, 0x85, 0xC0, 0x0F, 0x84, 0xBE, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x44,
					0x24, 0x48, 0x0F, 0xB7, 0x00, 0x85, 0xC0, 0x0F, 0x84, 0xAE, 0x00, 0x00,
					0x00, 0x48, 0x8B, 0x44, 0x24, 0x48, 0x0F, 0xB7, 0x00, 0x83, 0xF8, 0x41,
					0x7C, 0x21, 0x48, 0x8B, 0x44, 0x24, 0x48, 0x0F, 0xB7, 0x00, 0x83, 0xF8,
					0x5A, 0x7F, 0x14, 0x48, 0x8B, 0x44, 0x24, 0x48, 0x0F, 0xB7, 0x00, 0x83,
					0xC0, 0x20, 0x89, 0x84, 0x24, 0x88, 0x00, 0x00, 0x00, 0xEB, 0x0F, 0x48,
					0x8B, 0x44, 0x24, 0x48, 0x0F, 0xB7, 0x00, 0x89, 0x84, 0x24, 0x88, 0x00,
					0x00, 0x00, 0x0F, 0xB7, 0x84, 0x24, 0x88, 0x00, 0x00, 0x00, 0x66, 0x89,
					0x44, 0x24, 0x70, 0x48, 0x8B, 0x44, 0x24, 0x40, 0x0F, 0xB7, 0x00, 0x83,
					0xF8, 0x41, 0x7C, 0x21, 0x48, 0x8B, 0x44, 0x24, 0x40, 0x0F, 0xB7, 0x00,
					0x83, 0xF8, 0x5A, 0x7F, 0x14, 0x48, 0x8B, 0x44, 0x24, 0x40, 0x0F, 0xB7,
					0x00, 0x83, 0xC0, 0x20, 0x89, 0x84, 0x24, 0x8C, 0x00, 0x00, 0x00, 0xEB,
					0x0F, 0x48, 0x8B, 0x44, 0x24, 0x40, 0x0F, 0xB7, 0x00, 0x89, 0x84, 0x24,
					0x8C, 0x00, 0x00, 0x00, 0x0F, 0xB7, 0x84, 0x24, 0x8C, 0x00, 0x00, 0x00,
					0x66, 0x89, 0x44, 0x24, 0x74, 0x0F, 0xB7, 0x44, 0x24, 0x70, 0x0F, 0xB7,
					0x4C, 0x24, 0x74, 0x3B, 0xC1, 0x74, 0x07, 0xC6, 0x44, 0x24, 0x21, 0x00,
					0xEB, 0x05, 0xE9, 0x16, 0xFF, 0xFF, 0xFF, 0x0F, 0xB6, 0x44, 0x24, 0x21,
					0x85, 0xC0, 0x74, 0x2B, 0x48, 0x8B, 0x44, 0x24, 0x40, 0x0F, 0xB7, 0x00,
					0x85, 0xC0, 0x75, 0x1F, 0x48, 0x8B, 0x44, 0x24, 0x48, 0x0F, 0xB7, 0x00,
					0x85, 0xC0, 0x75, 0x13, 0x48, 0x8B, 0x84, 0x24, 0xE0, 0x00, 0x00, 0x00,
					0x48, 0x8B, 0x40, 0x30, 0x48, 0x89, 0x44, 0x24, 0x38, 0xEB, 0x05, 0xE9,
					0x62, 0xFE, 0xFF, 0xFF, 0x48, 0x83, 0x7C, 0x24, 0x38, 0x00, 0x75, 0x05,
					0xE9, 0xE3, 0x02, 0x00, 0x00, 0x48, 0x8B, 0x44, 0x24, 0x38, 0x48, 0x89,
					0x84, 0x24, 0x18, 0x01, 0x00, 0x00, 0x48, 0x8B, 0x84, 0x24, 0x18, 0x01,
					0x00, 0x00, 0x48, 0x63, 0x40, 0x3C, 0x48, 0x8B, 0x4C, 0x24, 0x38, 0x48,
					0x03, 0xC8, 0x48, 0x8B, 0xC1, 0x48, 0x89, 0x84, 0x24, 0x20, 0x01, 0x00,
					0x00, 0xB8, 0x08, 0x00, 0x00, 0x00, 0x48, 0x6B, 0xC0, 0x00, 0x48, 0x8B,
					0x8C, 0x24, 0x20, 0x01, 0x00, 0x00, 0x48, 0x8D, 0x84, 0x01, 0x88, 0x00,
					0x00, 0x00, 0x48, 0x89, 0x84, 0x24, 0x08, 0x01, 0x00, 0x00, 0x48, 0x8B,
					0x84, 0x24, 0x08, 0x01, 0x00, 0x00, 0x83, 0x38, 0x00, 0x75, 0x05, 0xE9,
					0x84, 0x02, 0x00, 0x00, 0x48, 0x8B, 0x84, 0x24, 0x08, 0x01, 0x00, 0x00,
					0x8B, 0x00, 0x48, 0x8B, 0x4C, 0x24, 0x38, 0x48, 0x03, 0xC8, 0x48, 0x8B,
					0xC1, 0x48, 0x89, 0x84, 0x24, 0xB8, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x84,
					0x24, 0xB8, 0x00, 0x00, 0x00, 0x8B, 0x40, 0x20, 0x48, 0x8B, 0x4C, 0x24,
					0x38, 0x48, 0x03, 0xC8, 0x48, 0x8B, 0xC1, 0x48, 0x89, 0x84, 0x24, 0x28,
					0x01, 0x00, 0x00, 0x48, 0x8B, 0x84, 0x24, 0xB8, 0x00, 0x00, 0x00, 0x8B,
					0x40, 0x24, 0x48, 0x8B, 0x4C, 0x24, 0x38, 0x48, 0x03, 0xC8, 0x48, 0x8B,
					0xC1, 0x48, 0x89, 0x84, 0x24, 0x30, 0x01, 0x00, 0x00, 0x48, 0x8B, 0x84,
					0x24, 0xB8, 0x00, 0x00, 0x00, 0x8B, 0x40, 0x1C, 0x48, 0x8B, 0x4C, 0x24,
					0x38, 0x48, 0x03, 0xC8, 0x48, 0x8B, 0xC1, 0x48, 0x89, 0x84, 0x24, 0x38,
					0x01, 0x00, 0x00, 0x48, 0xC7, 0x84, 0x24, 0xF0, 0x00, 0x00, 0x00, 0x00,
					0x00, 0x00, 0x00, 0xC7, 0x44, 0x24, 0x30, 0x00, 0x00, 0x00, 0x00, 0xEB,
					0x0A, 0x8B, 0x44, 0x24, 0x30, 0xFF, 0xC0, 0x89, 0x44, 0x24, 0x30, 0x48,
					0x8B, 0x84, 0x24, 0xB8, 0x00, 0x00, 0x00, 0x8B, 0x40, 0x18, 0x39, 0x44,
					0x24, 0x30, 0x0F, 0x83, 0xC4, 0x00, 0x00, 0x00, 0x8B, 0x44, 0x24, 0x30,
					0x48, 0x8B, 0x8C, 0x24, 0x28, 0x01, 0x00, 0x00, 0x8B, 0x04, 0x81, 0x48,
					0x8B, 0x4C, 0x24, 0x38, 0x48, 0x03, 0xC8, 0x48, 0x8B, 0xC1, 0x48, 0x89,
					0x84, 0x24, 0x10, 0x01, 0x00, 0x00, 0xC6, 0x44, 0x24, 0x22, 0x01, 0xC7,
					0x44, 0x24, 0x28, 0x00, 0x00, 0x00, 0x00, 0xEB, 0x0A, 0x8B, 0x44, 0x24,
					0x28, 0xFF, 0xC0, 0x89, 0x44, 0x24, 0x28, 0x48, 0x63, 0x44, 0x24, 0x28,
					0x0F, 0xBE, 0x44, 0x04, 0x58, 0x85, 0xC0, 0x75, 0x15, 0x48, 0x63, 0x44,
					0x24, 0x28, 0x48, 0x8B, 0x8C, 0x24, 0x10, 0x01, 0x00, 0x00, 0x0F, 0xBE,
					0x04, 0x01, 0x85, 0xC0, 0x74, 0x28, 0x48, 0x63, 0x44, 0x24, 0x28, 0x0F,
					0xBE, 0x44, 0x04, 0x58, 0x48, 0x63, 0x4C, 0x24, 0x28, 0x48, 0x8B, 0x94,
					0x24, 0x10, 0x01, 0x00, 0x00, 0x0F, 0xBE, 0x0C, 0x0A, 0x3B, 0xC1, 0x74,
					0x07, 0xC6, 0x44, 0x24, 0x22, 0x00, 0xEB, 0x02, 0xEB, 0xAB, 0x0F, 0xB6,
					0x44, 0x24, 0x22, 0x85, 0xC0, 0x74, 0x30, 0x8B, 0x44, 0x24, 0x30, 0x48,
					0x8B, 0x8C, 0x24, 0x30, 0x01, 0x00, 0x00, 0x0F, 0xB7, 0x04, 0x41, 0x48,
					0x8B, 0x8C, 0x24, 0x38, 0x01, 0x00, 0x00, 0x8B, 0x04, 0x81, 0x48, 0x8B,
					0x4C, 0x24, 0x38, 0x48, 0x03, 0xC8, 0x48, 0x8B, 0xC1, 0x48, 0x89, 0x84,
					0x24, 0xF0, 0x00, 0x00, 0x00, 0xEB, 0x05, 0xE9, 0x1D, 0xFF, 0xFF, 0xFF,
					0x48, 0x83, 0xBC, 0x24, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x84, 0x05,
					0x01, 0x00, 0x00, 0x48, 0x8B, 0x84, 0x24, 0x98, 0x00, 0x00, 0x00, 0x8B,
					0x40, 0x0C, 0x48, 0x8B, 0x8C, 0x24, 0xE8, 0x00, 0x00, 0x00, 0x48, 0x03,
					0xC8, 0x48, 0x8B, 0xC1, 0x48, 0x89, 0x84, 0x24, 0x40, 0x01, 0x00, 0x00,
					0xC7, 0x44, 0x24, 0x24, 0xFF, 0xFF, 0xFF, 0xFF, 0x48, 0xC7, 0x84, 0x24,
					0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEB, 0x13, 0x48, 0x8B,
					0x84, 0x24, 0xC0, 0x00, 0x00, 0x00, 0x48, 0xFF, 0xC0, 0x48, 0x89, 0x84,
					0x24, 0xC0, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x84, 0x24, 0x98, 0x00, 0x00,
					0x00, 0x0F, 0xB7, 0x40, 0x22, 0x48, 0x39, 0x84, 0x24, 0xC0, 0x00, 0x00,
					0x00, 0x73, 0x6D, 0x48, 0x8B, 0x84, 0x24, 0xC0, 0x00, 0x00, 0x00, 0x48,
					0x8B, 0x8C, 0x24, 0x40, 0x01, 0x00, 0x00, 0x48, 0x03, 0xC8, 0x48, 0x8B,
					0xC1, 0x0F, 0xB6, 0x00, 0x8B, 0x4C, 0x24, 0x24, 0x33, 0xC8, 0x8B, 0xC1,
					0x89, 0x44, 0x24, 0x24, 0xC7, 0x44, 0x24, 0x7C, 0x00, 0x00, 0x00, 0x00,
					0xEB, 0x0A, 0x8B, 0x44, 0x24, 0x7C, 0xFF, 0xC0, 0x89, 0x44, 0x24, 0x7C,
					0x83, 0x7C, 0x24, 0x7C, 0x08, 0x7D, 0x28, 0x8B, 0x44, 0x24, 0x24, 0x83,
					0xE0, 0x01, 0x85, 0xC0, 0x74, 0x11, 0x8B, 0x44, 0x24, 0x24, 0xD1, 0xE8,
					0x35, 0x00, 0xC4, 0xB0, 0xB0, 0x89, 0x44, 0x24, 0x24, 0xEB, 0x0A, 0x8B,
					0x44, 0x24, 0x24, 0xD1, 0xE8, 0x89, 0x44, 0x24, 0x24, 0xEB, 0xC7, 0xE9,
					0x6A, 0xFF, 0xFF, 0xFF, 0x8B, 0x44, 0x24, 0x24, 0x83, 0xF0, 0xFF, 0x89,
					0x84, 0x24, 0x90, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x84, 0x24, 0x98, 0x00,
					0x00, 0x00, 0x8B, 0x8C, 0x24, 0x90, 0x00, 0x00, 0x00, 0x39, 0x48, 0x1C,
					0x74, 0x16, 0x8B, 0x94, 0x24, 0x90, 0x00, 0x00, 0x00, 0x48, 0xC7, 0xC1,
					0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x94, 0x24, 0xF0, 0x00, 0x00, 0x00, 0x90,
					0x48, 0x81, 0xC4, 0x58, 0x01, 0x00, 0x00

				};

				a.embed(memoryProtectionShellcode.data(), memoryProtectionShellcode.size());

				// Restoring the register context
				// Pop flags
				a.pop(asmjit::x86::r15);
				a.pop(asmjit::x86::r14);
				a.pop(asmjit::x86::r13);
				a.pop(asmjit::x86::r12);
				a.pop(asmjit::x86::r11);
				a.pop(asmjit::x86::r10);
				a.pop(asmjit::x86::r9);
				a.pop(asmjit::x86::r8);
				a.pop(asmjit::x86::rdi);
				a.pop(asmjit::x86::rsi);
				a.pop(asmjit::x86::rbp);
				a.pop(asmjit::x86::rbx);
				a.pop(asmjit::x86::rdx);
				a.pop(asmjit::x86::rcx);
				a.pop(asmjit::x86::rax);

				// Breaking Decompilers
				insertBreakDecompilers(a);

				// pop RFLAGS
				a.popfq();

				// Getting new opcodes to insert in place of the old block
				std::vector<ZyanU8> memoryprotection_instructions;
				auto& opcodeBuffer = code.sectionById(0)->buffer();
				const auto pOpcodeBuffer = opcodeBuffer.data();
				memoryprotection_instructions.reserve(opcodeBuffer.size());

				// Storing our new opcodes for memory protection detection
				for (auto i = 0; i < opcodeBuffer.size(); ++i) memoryprotection_instructions.push_back(static_cast<ZyanU8>(pOpcodeBuffer[i]));

				// Saving the opcode block
				data.assign(memoryprotection_instructions.begin(), memoryprotection_instructions.end());

				isInserted = TRUE;

			}
		}
	}
}

void RyujinObfuscationCore::updateBasicBlocksContext() {

	auto new_obfuscated_opcodes = getProcessedProc().getUpdateOpcodes();
	auto bb = new RyujinBasicBlockerBuilder(ZYDIS_MACHINE_MODE_LONG_64, ZydisStackWidth_::ZYDIS_STACK_WIDTH_64);
	m_obfuscated_bb = bb->createBasicBlocks(new_obfuscated_opcodes.data(), static_cast<size_t>(new_obfuscated_opcodes.size()), m_proc.address);

}

void RyujinObfuscationCore::insertBreakDecompilers(asmjit::x86::Assembler& a) {

	//Inspired by Breaking Decompilers(https://youtu.be/6UlxrDYng88?t=1287)
	const std::vector<std::pair<asmjit::x86::Gp, std::vector<uint8_t>>> tricks = {
		
		{ asmjit::x86::rbx, { 0xEB, 0xFF, 0xC3 } },
		{ asmjit::x86::rdx, { 0xEB, 0xFF, 0xC2, 0x90, 0x90 } },
		{ asmjit::x86::rcx, { 0xEB, 0xFF, 0xC9 } },
		{ asmjit::x86::rax, { 0xEB, 0xFF, 0xC0, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 } }

	};

	static std::mt19937 rng(static_cast<unsigned>(std::time(nullptr)));
	std::uniform_int_distribution<size_t> dist(0, tricks.size() - 1);
	const auto& selected = tricks[dist(rng)];
	const auto& reg = selected.first;
	const auto& bytes = selected.second;

	a.push(reg);
	a.embed(bytes.data(), bytes.size());
	a.pop(reg);

}

BOOL RyujinObfuscationCore::Run(bool& RyujinRunOncePass) {

	//Add padding spaces
	addPaddingSpaces();

	/*
		RyujinRunOncePass only run once for the first function candidate to obfuscation.
		this is the better place to put unique logic code that is high volatily.
	*/
	if (RyujinRunOncePass) {

		/*
			There is no need to obfuscate the anti-dump stub code. the junk code/mutation itself will handle that during processing.
		*/
		if (this->m_config.m_isAntiDump) {

			// Insert AntiDump Protection
			this->insertAntiDump();

			// Update our basic blocks context to rela 1-1 for the new obfuscated opcodes.
			this->updateBasicBlocksContext();

		}

	}

	//Update basic blocks view based on the new obfuscated 
	this->updateBasicBlocksContext();

	if (m_config.m_isAntiDebug) {

		/*
			There is no need to obfuscate the anti-debug stub code. the junk code/mutation itself will handle that during processing.
		*/
		this->insertAntiDebug();

		// Update our basic blocks context to rela 1-1 for the new obfuscated opcodes.
		this->updateBasicBlocksContext();

	}

	if (m_config.m_isVirtualized) {

		// Insert Virtualization
		insertVirtualization();

		//Update our basic blocks context to rely 1-1 for the new obfuscated opcodes.
		this->updateBasicBlocksContext();

	}

	//Obfuscate IAT for the configured procedures
	if (m_config.m_isIatObfuscation) {

		// Obfuscate IAT
		obfuscateIat();

		//Update our basic blocks context to rely 1-1 for the new obfuscated opcodes.
		this->updateBasicBlocksContext();

	}

	if (m_config.m_isJunkCode) {

		// Insert junk code
		insertJunkCode();

		//Update our basic blocks context to rely 1-1 for the new obfuscated opcodes.
		this->updateBasicBlocksContext();

	}

	// Checking if we have any user-registered callbacks
	if (m_config.m_callbacks.callbackCount > 0)
		// Iterating over each registered callback
		for (auto i = 0; i < m_config.m_callbacks.callbackCount; i++)
			// If it's a valid address
			if (m_config.m_callbacks.callbacks[i]) {

				// We invoke the callback, passing the m_proc instance by reference to allow user modifications.
				m_config.m_callbacks.callbacks[i](&m_proc);

				// We update the Basic Blocks context to stay 1:1 with the user's modifications.
				this->updateBasicBlocksContext();

			}

	if (RyujinRunOncePass) {
	
		if (this->m_config.m_isMemoryProtection && (!this->m_config.m_isAntiDump || !this->m_config.m_isEncryptObfuscatedCode || !this->m_config.m_isRandomSection)) {

			//Insert stub for memory CRC protection
			this->insertMemoryProtection();

			// Update our basic blocks context to rela 1-1 for the new obfuscated opcodes.
			this->updateBasicBlocksContext();

		}

		RyujinRunOncePass = FALSE;
	
	}


	return TRUE;
}

std::vector<ZyanU8> RyujinObfuscationCore::RunMiniVmObfuscation() {

	// Copiando os basic blocks da MiniVm antes de ofusca-la e adicionar bytes padding..
	auto origBlocks = m_proc.basic_blocks;
	auto originalOpcodes = this->getProcessedProc().getUpdateOpcodes();

	// Ofuscando e adicionando bytes paddings..
	addPaddingSpaces();
	
	//mutateMiniVm();

	// Redesenhando os basic blocks
	this->updateBasicBlocksContext();

	// Obtendo os opcodes novos ofuscados para podermos corrigir
	auto newOpcodes = this->getProcessedProc().getUpdateOpcodes();

	// Calculando quantas instruçőes temos antes de cada instruçőes nos Basic Blocks originais sem ofuscaçăo
	std::vector<size_t> instGlobalOffsets;
	for (auto& blk : origBlocks) {

		for (auto& inst : blk.instructions) {

			size_t absOffset = blk.start_address + inst.addressofinstruction;
			instGlobalOffsets.push_back(absOffset);

		}

	}

	// Organizando os deslocamentos originais..
	std::sort(instGlobalOffsets.begin(), instGlobalOffsets.end());

	// Calculando as instruçőes antes de uma instruçăo inserida..
	auto countInstructionsBefore = [&](size_t offset) {
	
		return static_cast<int>(std::distance(instGlobalOffsets.begin(), std::lower_bound(instGlobalOffsets.begin(), instGlobalOffsets.end(), offset)));
	};

	// Criando novos Basic Blocks com base nos opcodes devidamente ofuscados..
	auto bb = new RyujinBasicBlockerBuilder(ZYDIS_MACHINE_MODE_LONG_64, ZydisStackWidth_::ZYDIS_STACK_WIDTH_64);
	m_obfuscated_bb = bb->createBasicBlocks(newOpcodes.data(), newOpcodes.size(), 0);

	// Lambda para vermos se o deslocamente cabe em um short..
	auto fits_int8 = [](int32_t v) { 
		
		return v >= -128 && v <= 127;
	};

	// Salvando os opcodes originais sem ofuscaçăo com base em um offset
	auto read_original_byte = [&](size_t off, uint8_t fallback)->uint8_t {
		
		if (off < originalOpcodes.size()) return originalOpcodes[off];
	
		return fallback;
	};

	for (auto& block : origBlocks) {

		for (auto& inst : block.instructions) {

			// Filtrando apenas por instruçőes de banch condicional ou incondicional(JE, JZ... jmp...)..
			if (!(inst.instruction.info.meta.category == ZYDIS_CATEGORY_COND_BR || inst.instruction.info.meta.category == ZYDIS_CATEGORY_UNCOND_BR)) continue;

			// Calculando offset RIP relative para salto PIC da instruçăo..
			size_t origJumpOffset = block.start_address + inst.addressofinstruction;
			int64_t origDisp = inst.instruction.operands[0].imm.value.s;
			size_t origTargetOffset = origJumpOffset + inst.instruction.info.length + origDisp;

			// Contando quantas instruçőes temos antes de cada instruçăo. antes de depois da mesma para podermos calcular o offset correto da branch ser feita: E8 [AQUI]..
			int instBeforeJump = countInstructionsBefore(origJumpOffset);
			int instBeforeTarget = countInstructionsBefore(origTargetOffset);

			// Calculando os novos offsets considerando o tamanho dos NOPS e JunkCode..
			size_t newJumpOffset = origJumpOffset + instBeforeJump * MAX_PADDING_SPACE_INSTR;
			size_t newTargetOffset = origTargetOffset + instBeforeTarget * MAX_PADDING_SPACE_INSTR;

			// Lendo os bytes originais para podermos calcular o devido deslocamento e sincronizar os basic blocks..
			uint8_t rawOpcode = read_original_byte(origJumpOffset, (uint8_t)inst.instruction.info.opcode);
			uint8_t rawOpcodeSpecificWithIntelPrefix = read_original_byte(origJumpOffset + 1, 0); // Opcode real para caso a instruçăo tenha algum prefixo como o 0x0F(pode variar essa merda) etc

			std::vector<uint8_t> opcodeBytes;
			int dispSize = 0;   // 1 or 4
			int32_t finalDisp = 0;

			// Temos uma lógica customizada de correçăo para cada Opcode para garantir que nada seja quebrada quando formos patchar na instruçăo ofuscada...
			if (inst.instruction.info.meta.category == ZYDIS_CATEGORY_UNCOND_BR) {
				
				// Lógica para saltos incondicionais..
				if (rawOpcode == 0xEB) {

					// Calculo para relocation short RIP-PIC: length = 2 (opcode + int8)
					int32_t d = static_cast<int32_t>(static_cast<int64_t>(newTargetOffset) - (static_cast<int64_t>(newJumpOffset) + 2));
					
					if (fits_int8(d)) {

						opcodeBytes.push_back(0xEB);
						dispSize = 1;
						finalDisp = d;

					}
					else {

						opcodeBytes.push_back(0xE9);
						dispSize = 4;
						finalDisp = static_cast<int32_t>(static_cast<int64_t>(newTargetOffset) - (static_cast<int64_t>(newJumpOffset) + 5));

					}

				}
				else if (rawOpcode == 0xE9) {

					opcodeBytes.push_back(0xE9);
					dispSize = 4;
					finalDisp = static_cast<int32_t>(static_cast<int64_t>(newTargetOffset) - (static_cast<int64_t>(newJumpOffset) + 5));

				}
				else {

					// fallback: Para preservar opcode original..
					opcodeBytes.push_back(rawOpcode);
					dispSize = 4;
					finalDisp = static_cast<int32_t>(static_cast<int64_t>(newTargetOffset) - (static_cast<int64_t>(newJumpOffset) + static_cast<int>(opcodeBytes.size()) + 4));

				}
			}
			else {

				// Lógica para as branchs condicionais..
				// Tem apenas dois algoritmos para eles RIP-PIC relative sendo o short (0x7x) => 2 bytes e o near (0F 8x) => 6 bytes.
				if (rawOpcode >= 0x70 && rawOpcode <= 0x7F) {

					// Calculando o short RIP-PIC
					int32_t d = static_cast<int32_t>(static_cast<int64_t>(newTargetOffset) - (static_cast<int64_t>(newJumpOffset) + 2));
					if (fits_int8(d)) {

						opcodeBytes.push_back(rawOpcode);
						dispSize = 1;
						finalDisp = d;

					}
					else {

						// Calculando a lógica para um near com prefixo como 0F 8x com base no rawOpcode recebido..
						uint8_t op2 = (rawOpcode & 0x0F) + 0x80;
						opcodeBytes.push_back(0x0F);
						opcodeBytes.push_back(op2);
						dispSize = 4;
						finalDisp = static_cast<int32_t>(static_cast<int64_t>(newTargetOffset) - (static_cast<int64_t>(newJumpOffset) + 6));

					}

				}
				else if (rawOpcode == 0x0F) {

					// Calculando lógica customizada para o prefixo de salto com 0x0F
					uint8_t second = rawOpcodeSpecificWithIntelPrefix;
					
					if (second == 0)
						second = static_cast<uint8_t>((inst.instruction.operands[0].imm.value.u >> 8) & 0xFF);
					
					opcodeBytes.push_back(0x0F);
					opcodeBytes.push_back(second);
					dispSize = 4;
					finalDisp = static_cast<int32_t>(static_cast<int64_t>(newTargetOffset) - (static_cast<int64_t>(newJumpOffset) + 6));

				}
				else {

					// Fallback para condicionais inesperadas(se isso for usado para algo diferente no futuro, é claro)...
					opcodeBytes.push_back(rawOpcode);
					dispSize = 4;
					finalDisp = static_cast<int32_t>(static_cast<int64_t>(newTargetOffset) - (static_cast<int64_t>(newJumpOffset) + static_cast<int>(opcodeBytes.size()) + 4));

				}
			}

			// Compondo os novos opcodes..
			std::vector<uint8_t> composed;
			composed.insert(composed.end(), opcodeBytes.begin(), opcodeBytes.end());
			if (dispSize == 1) 
				composed.push_back(static_cast<uint8_t>(finalDisp & 0xFF));
			else
				for (int i = 0; i < 4; ++i) composed.push_back(static_cast<uint8_t>((finalDisp >> (8 * i)) & 0xFF));

			if (newJumpOffset + composed.size() > newOpcodes.size()) 
				continue;

			// Escrevendo as novas instruçőes devidamente corrigidas..
			std::memcpy(newOpcodes.data() + newJumpOffset, composed.data(), composed.size());
		}
	}

	return newOpcodes;
}


uint32_t RyujinObfuscationCore::findOpcodeOffset(const uint8_t* data, size_t dataSize, const void* opcode, size_t opcodeSize) {

	if (opcodeSize == 0 || dataSize < opcodeSize) return 0;

	for (size_t i = 0; i <= dataSize - opcodeSize; ++i) if (std::memcmp(data + i, opcode, opcodeSize) == 0) return static_cast<uint32_t>(i);

	return 0;
}

std::vector<uint8_t> RyujinObfuscationCore::fix_branch_near_far_short(uint8_t original_opcode, uint64_t jmp_address, uint64_t target_address) {
	
	//  Opcodes form the range of short Jcc (0x7x) -> near Jcc (0x0F 8x)
	static const std::unordered_map<uint8_t, uint8_t> SHORT_TO_NEAR = {

		{ 0x70, 0x80 }, { 0x71, 0x81 }, { 0x72, 0x82 }, { 0x73, 0x83 },
		{ 0x74, 0x84 }, { 0x75, 0x85 }, { 0x76, 0x86 }, { 0x77, 0x87 },
		{ 0x78, 0x88 }, { 0x79, 0x89 }, { 0x7A, 0x8A }, { 0x7B, 0x8B },
		{ 0x7C, 0x8C }, { 0x7D, 0x8D }, { 0x7E, 0x8E }, { 0x7F, 0x8F }

	};

	std::vector<uint8_t> result;

	// Tries to handle as a short jump (2 bytes) -> (2 bytes: opcode + disp8)
	const int short_length = 2;
	const int64_t short_disp = static_cast<int64_t>(target_address) - (jmp_address + short_length);

	if (short_disp >= -128 && short_disp <= 127) {

		result.push_back(original_opcode);
		result.push_back(static_cast<uint8_t>(short_disp));

		return result;
	}

	// If it is not a conditional jump, returns the original -> Jcc 
	auto it = SHORT_TO_NEAR.find(original_opcode);
	if (it == SHORT_TO_NEAR.end()) {

		result.push_back(original_opcode);

		return result; // Does not apply conversion
	}

	// Handles as a near jump (6 bytes) -> NEAR jump (6 bytes: 0F 8x + disp32)
	const uint8_t near_opcode = it->second;
	const int near_length = 6;
	const int64_t near_disp = static_cast<int64_t>(target_address) - (jmp_address + near_length);

	if (near_disp < INT32_MIN || near_disp > INT32_MAX) throw std::exception("[X] Offset exceeds the limit of a 32-bit signed integer.");

	result.push_back(0x0F);
	result.push_back(near_opcode);

	const uint32_t raw_disp = static_cast<uint32_t>(near_disp);
	result.push_back((raw_disp >> 0) & 0xFF);
	result.push_back((raw_disp >> 8) & 0xFF);
	result.push_back((raw_disp >> 16) & 0xFF);
	result.push_back((raw_disp >> 24) & 0xFF);

	return result;
}

void RyujinObfuscationCore::applyRelocationFixupsToInstructions(uintptr_t imageBase, DWORD virtualAddress, std::vector<unsigned char>& new_opcodes) {

	/*
		Creating a new basic block for our obfuscated code
	*/
	auto bb = new RyujinBasicBlockerBuilder(ZYDIS_MACHINE_MODE_LONG_64, ZydisStackWidth_::ZYDIS_STACK_WIDTH_64);
	m_obfuscated_bb = bb->createBasicBlocks(new_opcodes.data(), static_cast<size_t>(new_opcodes.size()), imageBase + virtualAddress);

	//The current block id that we're working with
	int block_id = 0;

	for (auto& block : m_proc.basic_blocks) {

		for (auto& instruction : block.instructions) {

			// -------------------
			// Fixing all Call to a immediate(No IAT) values from our obfuscated opcodes -> CALL rel32 (no IAT)
			// -------------------
			if (instruction.instruction.info.meta.category == ZYDIS_CATEGORY_CALL && instruction.instruction.operands->type == ZYDIS_OPERAND_TYPE_IMMEDIATE) {

				//References for the data and size of the vector with the obfuscated opcodes
				auto size = new_opcodes.size();
				auto data = new_opcodes.data();

				//Getting the immediate value of the original "CALL"
				const uint32_t immediateValue = instruction.instruction.operands[0].imm.value.u;

				/*
					Creating a signature for the opcode from the original section so that we can
					scan the obfuscated region using the correct instruction offset and recalculate its displacement.
				*/
				unsigned char ucOpcodeSignature[5]{ instruction.instruction.info.opcode };
				std::memcpy(&*(ucOpcodeSignature + 1), &immediateValue, sizeof(immediateValue));

				//Finding the offset of the "CALL" using the opcode signature in the obfuscated section
				const uint32_t offset = findOpcodeOffset(data, size, &ucOpcodeSignature, 5);

				//Calculating the VA (Virtual Address) of the "CALL" in the obfuscated section
				uint32_t obfuscated_call_va = imageBase + virtualAddress + offset;

				/*
					Calculating the new immediate offset to fix the relocation of the new obfuscated "CALL" instruction
				*/
				// Calculate address of the next instruction (CALL instruction + its length)
				const uintptr_t next_instruction_address = instruction.addressofinstruction + instruction.instruction.info.length;

				// Get the relative displacement from the first operand (signed 32-bit integer)
				const int32_t displacement = static_cast<int32_t>(instruction.instruction.operands[0].imm.value.s);

				// Calculate absolute target address
				const uintptr_t target_address = next_instruction_address + displacement;

				//Calculating the new immediate value for the "CALL" instruction using the VA addresses of the obfuscated section
				uint32_t new_immediate_reloc = static_cast<uint32_t>(target_address) - (obfuscated_call_va + instruction.instruction.info.length); //length == 5

				//Fixing the relocation of the "CALL" instruction in the obfuscated region
				std::memcpy(&*(data + offset + 1), &new_immediate_reloc, sizeof(uint32_t));

				std::printf("[OK] Fixing CALL IMM -> %s from 0x%X to 0x%X\n", instruction.instruction.text, immediateValue, new_immediate_reloc);

			}
			//Fixing all Call to a memory(IAT) values from our obfuscated opcodes -> CALL [MEMORY] (IAT)
			else if (instruction.instruction.info.meta.category == ZYDIS_CATEGORY_CALL && instruction.instruction.operands->type == ZYDIS_OPERAND_TYPE_MEMORY && !m_config.m_isIatObfuscation) {

				// References for the vector's data and size with the obfuscated opcodes
				auto size = new_opcodes.size();
				auto data = new_opcodes.data();

				// Obtaining the memory immediate value for the "CALL"
				const uint32_t memmory_immediate = instruction.instruction.operands->mem.disp.value;

				// Creating a signature to search for the offset in the obfuscated opcodes
				unsigned char ucOpcodeSignature[6]{ 0xFF, 0x15 };
				std::memcpy(&*(ucOpcodeSignature + 2), &memmory_immediate, sizeof(memmory_immediate));

				// Finding the offset of the "CALL" memory using the opcode signature in the obfuscated section
				const uint32_t offset = findOpcodeOffset(data, size, &ucOpcodeSignature, 6);

				// If we don't find the signature, it might not be an IAT... requiring future handling.
				if (offset == 0) {

					std::printf("[X] Invalid IAT call or call to a custom address detected.....\n");

					continue;
				}

				// Calculating the VA (Virtual Address) of the "CALL" instruction to the IAT in the obfuscated section
				const uintptr_t obfuscated_call_iat_va = ((imageBase + virtualAddress + offset));

				// Calculating the VA of the next instruction after the "CALL" to the IAT in the original section
				const uintptr_t next_instruction_address = instruction.addressofinstruction + instruction.instruction.info.length;

				// Calculating the target address of the IAT using the memory immediate from the original instruction
				const uintptr_t iat_target_address = next_instruction_address + memmory_immediate;

				// Calculating new RIP (Instruction Pointer) for the obfuscated instruction
				uintptr_t new_rip = obfuscated_call_iat_va + instruction.instruction.info.length;

				// Calculating the displacement from the new position to the IAT address
				const uint32_t new_memory_immediate_iat = iat_target_address - new_rip;

				// Fixing the relocation of the "CALL" instruction in the obfuscated region to the new memory immediate
				std::memcpy(&*(data + offset + 2), &new_memory_immediate_iat, sizeof(uint32_t));

				std::printf("[OK] Fixing IAT Call -> %s from 0x%X to 0x%X\n", instruction.instruction.text, obfuscated_call_iat_va, new_memory_immediate_iat);

			}
			// Searching for MOV and LEA instructions that have the second operand as memory-relative -> LEA / MOV reg, [RIP+disp]
			else if ((instruction.instruction.info.mnemonic == ZYDIS_MNEMONIC_LEA || instruction.instruction.info.mnemonic == ZYDIS_MNEMONIC_MOV) && instruction.instruction.operands[1].type == ZYDIS_OPERAND_TYPE_MEMORY) {

				const ZydisDecodedOperandMem* mem = &instruction.instruction.operands[1].mem;

				//Looking for: lea reg, [MEMORY] and mov reg, [MEMORY]
				if (mem->base == ZYDIS_REGISTER_RIP && mem->index == ZYDIS_REGISTER_NONE && mem->disp.has_displacement) {

					// References for data and vector size with obfuscated opcodes
					auto size = new_opcodes.size();
					auto data = new_opcodes.data();

					//Avoid memory op for stack
					if (instruction.instruction.operands->mem.base == ZYDIS_REGISTER_RSP || instruction.instruction.operands->mem.base == ZYDIS_REGISTER_RBP) {

						std::printf("Invalid relocation fix candidate for -> %s\n", instruction.instruction.text);

						continue;
					}

					// Getting the memory immediate offset value to build the signature
					const uint32_t memmory_immediate_offset = mem->disp.value;

					ZyanI64 offset = 0;
					unsigned char ucOpcodeSignature[7]{ 0 };

					// If original instruction is not a mov reg, cs[](beacuse it has 6 not 7 bytes)
					if (*reinterpret_cast<unsigned char*>(instruction.addressofinstruction) != 0x8B) {

						// Creating a signature to search for the offset in the obfuscated opcodes
						std::memcpy(&ucOpcodeSignature, reinterpret_cast<void*>(instruction.addressofinstruction), 3); // 3 BYTES do opcode relativo ao LEA ou MOV
						std::memcpy(&*(ucOpcodeSignature + 3), &memmory_immediate_offset, sizeof(memmory_immediate_offset));

						// Finding the offset of the "LEA" or "MOV" that uses memory-relative addressing
						offset = findOpcodeOffset(data, size, &ucOpcodeSignature, 7);

					}
					else {

						// Creating a signature to search for the offset in the obfuscated opcodes
						std::memcpy(&ucOpcodeSignature, reinterpret_cast<void*>(instruction.addressofinstruction), 6); // 6 bytes do opcode relativo MOV CODE SEGMENT: mov reg, cs:addr

						// Finding the offset of the "MOV reg, cs:addr" that uses memory-relative addressing
						offset = findOpcodeOffset(data, size, &ucOpcodeSignature, 6);

					}

					// If we don't find any offset, there may be an issue or bug.
					if (offset == 0) {

						std::printf("[X] Invalid lea/mov reference or uknown lea/mov detected.....\n");

						continue;
					}

					// Retrieving the instruction address in the original section
					const uintptr_t original_address = instruction.addressofinstruction;

					// Calculating new address in the obfuscated section
					const uintptr_t obfuscated_va_address = ((imageBase + virtualAddress + offset));

					/*
						Calculating new displacement for the immediate value
					*/
					// Calculating the address of the instruction following the original instruction
					const uintptr_t original_rip = original_address + instruction.instruction.info.length;

					// Calculating the original target address of the original instruction
					const uintptr_t target_original = original_rip + memmory_immediate_offset;

					// Calculating the address of the instruction following the obfuscated instruction
					const uintptr_t new_obfuscated_rip = obfuscated_va_address + instruction.instruction.info.length;

					// New memory immediate value for the instruction
					const uintptr_t new_memory_immediate = target_original - new_obfuscated_rip;

					// Fixing the immediate value for the "LEA" or "MOV" instruction with the corrected relative immediate value
					if (*reinterpret_cast<unsigned char*>(instruction.addressofinstruction) != 0x8B)
						std::memcpy(&*(data + offset + 3), &new_memory_immediate, sizeof(uint32_t)); // 3 bytes for the size of the LEA or MOV opcode
					else
						std::memcpy(&*(data + offset + 2), &new_memory_immediate, sizeof(uint32_t)); // 3 bytes for the size of the LEA or MOV opcode

					std::printf("[OK] Fixing -> %s - from %X to %X\n", instruction.instruction.text, mem->disp.value, new_memory_immediate);

				}

			}
			// Fixing displacements on left side aka read memory -> MOV / LEA [memory], reg 
			else if ((instruction.instruction.info.mnemonic == ZYDIS_MNEMONIC_MOV || instruction.instruction.info.mnemonic == ZYDIS_MNEMONIC_LEA) && instruction.instruction.operands->type == ZYDIS_OPERAND_TYPE_MEMORY && instruction.instruction.operands->mem.type == ZYDIS_MEMOP_TYPE_MEM) {

				if (instruction.instruction.info.length > 5) {

					// References for data and vector size with obfuscated opcodes
					auto size = new_opcodes.size();
					auto data = new_opcodes.data();

					const ZydisDecodedOperandMem* mem = &instruction.instruction.operands[0].mem;

					//Avoid memory op for stack
					if (instruction.instruction.operands->mem.base == ZYDIS_REGISTER_RSP || instruction.instruction.operands->mem.base == ZYDIS_REGISTER_RBP) {

						//std::printf("Invalid relocation fix candidate for -> %s\n", instruction.instruction.text);

						continue;
					}

					// Getting the memory immediate offset value to build the signature
					const uint32_t memmory_immediate_offset = mem->disp.value;

					ZyanI64 offset = 0, fix_byte = 0;
					unsigned char ucOpcodeSignature[11]{ 0 };

					if (instruction.instruction.info.length == 6) {

						std::memcpy(&ucOpcodeSignature, reinterpret_cast<void*>(instruction.addressofinstruction), 6);

						offset = findOpcodeOffset(data, size, &ucOpcodeSignature, 6);

						fix_byte = 2;

					}
					else if (instruction.instruction.info.length == 7) {

						std::memcpy(&ucOpcodeSignature, reinterpret_cast<void*>(instruction.addressofinstruction), 7);

						offset = findOpcodeOffset(data, size, &ucOpcodeSignature, 7);

						fix_byte = 3;

					}
					else if (instruction.instruction.info.length == 10) {

						std::memcpy(&ucOpcodeSignature, reinterpret_cast<void*>(instruction.addressofinstruction), 10);

						offset = findOpcodeOffset(data, size, &ucOpcodeSignature, 10);

						fix_byte = 2;

					}
					else {

						std::printf("ERROR Unexpected Instruction mov cs[], reg/imm -> %s - %d\n", instruction.instruction.text, instruction.instruction.info.length);

						continue;
					}

					// Retrieving the instruction address in the original section
					const uintptr_t original_address = instruction.addressofinstruction;

					// Calculating new address in the obfuscated section
					const uintptr_t obfuscated_va_address = ((imageBase + virtualAddress + offset));

					/*
						Calculating new displacement for the immediate value
					*/
					// Calculating the address of the instruction following the original instruction
					const uintptr_t original_rip = original_address + instruction.instruction.info.length;

					// Calculating the original target address of the original instruction
					const uintptr_t target_original = original_rip + memmory_immediate_offset;

					// Calculating the address of the instruction following the obfuscated instruction
					const uintptr_t new_obfuscated_rip = obfuscated_va_address + instruction.instruction.info.length;

					// New memory immediate value for the instruction
					const uintptr_t new_memory_immediate = target_original - new_obfuscated_rip;

					// Fixing the immediate value for the "LEA" or "MOV" instruction with the corrected relative immediate value
					std::memcpy(&*(data + offset + fix_byte), &new_memory_immediate, sizeof(uint32_t));

					std::printf("[OK] Fixing -> %s - from %X to %X\n", instruction.instruction.text, mem->disp.value, new_memory_immediate);
				}

			}
			// Fixing disp32 mem access -> ADD / SUB / XOR [mem], reg  (ou reg, [mem])
			else if ((instruction.instruction.info.mnemonic == ZYDIS_MNEMONIC_ADD || instruction.instruction.info.mnemonic == ZYDIS_MNEMONIC_SUB || instruction.instruction.info.mnemonic == ZYDIS_MNEMONIC_XOR) && (instruction.instruction.operands[0].type == ZYDIS_OPERAND_TYPE_MEMORY || instruction.instruction.operands[1].type == ZYDIS_OPERAND_TYPE_MEMORY)) {


					// References for data and vector size with obfuscated opcodes
					auto size = new_opcodes.size();
					auto data = new_opcodes.data();

					//Avoid memory op for stack
					if (instruction.instruction.operands->mem.base == ZYDIS_REGISTER_RSP || instruction.instruction.operands->mem.base == ZYDIS_REGISTER_RBP) {

						std::printf("Invalid relocation fix candidate for -> %s\n", instruction.instruction.text);

						continue;
					}

					ZydisDecodedOperandMem* mem;
					if (instruction.instruction.operands[0].type == ZYDIS_OPERAND_TYPE_MEMORY)
						mem = &instruction.instruction.operands[0].mem;
					else
						mem = &instruction.instruction.operands[1].mem;

					// Getting the memory immediate offset value to build the signature
					const uint32_t memmory_immediate_offset = mem->disp.value;

					ZyanI64 offset = 0, fix_byte = 0;
					unsigned char ucOpcodeSignature[11]{ 0 };
					

					if (instruction.instruction.info.length == 6) {

						std::memcpy(&ucOpcodeSignature, reinterpret_cast<void*>(instruction.addressofinstruction), 6);

						offset = findOpcodeOffset(data, size, &ucOpcodeSignature, 6);

						fix_byte = 2;

					}
					else if (instruction.instruction.info.length == 7) {

						std::memcpy(&ucOpcodeSignature, reinterpret_cast<void*>(instruction.addressofinstruction), 7);

						offset = findOpcodeOffset(data, size, &ucOpcodeSignature, 7);

						fix_byte = 3;

					}
					else {

						std::printf("ERROR Unexpected Instruction bitwise/math [], reg or bitwise/math reg, [] -> %s - %d\n", instruction.instruction.text, instruction.instruction.info.length);

						continue;
					}

					// Retrieving the instruction address in the original section
					const uintptr_t original_address = instruction.addressofinstruction;

					// Calculating new address in the obfuscated section
					const uintptr_t obfuscated_va_address = ((imageBase + virtualAddress + offset));

					/*
						Calculating new displacement for the immediate value
					*/
					// Calculating the address of the instruction following the original instruction
					const uintptr_t original_rip = original_address + instruction.instruction.info.length;

					// Calculating the original target address of the original instruction
					const uintptr_t target_original = original_rip + memmory_immediate_offset;

					// Calculating the address of the instruction following the obfuscated instruction
					const uintptr_t new_obfuscated_rip = obfuscated_va_address + instruction.instruction.info.length;

					// New memory immediate value for the instruction
					const uintptr_t new_memory_immediate = target_original - new_obfuscated_rip;

					// Fixing the immediate value for the "LEA" or "MOV" instruction with the corrected relative immediate value
					std::memcpy(&*(data + offset + fix_byte), &new_memory_immediate, sizeof(uint32_t));

					std::printf("[OK] Fixing Math/Bitwise Operators -> %s | %d\n", instruction.instruction.text, instruction.instruction.info.length);

			}
			// Fixing unconditional memory jumps and conditional linking each basic block offset for near/far procs -> Jumps [REG]
			else if (instruction.instruction.info.meta.category == ZYDIS_CATEGORY_COND_BR || instruction.instruction.info.meta.category == ZYDIS_CATEGORY_UNCOND_BR) {

				// References for data and vector size with obfuscated opcodes
				auto size = new_opcodes.size();
				auto data = new_opcodes.data();

				/*
					Finding the address of the currently analyzed branch instruction within the set of obfuscated basic blocks
				*/
				uintptr_t obfuscated_jmp_address = 0;
				auto basic_block_obfuscated_ctx = m_obfuscated_bb.at(block_id);
				for (auto& inst : basic_block_obfuscated_ctx.instructions)

					if (inst.instruction.info.opcode == instruction.instruction.info.opcode && inst.instruction.operands[0].imm.value.u == instruction.instruction.operands[0].imm.value.u) {
						obfuscated_jmp_address = inst.addressofinstruction;
						break;
					}

				/*
					Based on the branch's destination address, we’ll search for the block ID in our vector so that we can
					synchronize both the obfuscated and original blocks to work on a fix.
				*/
				auto address_branch = instruction.addressofinstruction + instruction.instruction.info.length + instruction.instruction.operands[0].imm.value.u;
				uint32_t local_block_id = 0;
				for (auto& block : m_proc.basic_blocks) {

					if (address_branch >= block.start_address && address_branch <= block.end_address)
						break;

					local_block_id++;
				}

				//Calculating our new branch immediate offset
				auto basic_block_original = m_proc.basic_blocks.at(local_block_id);
				auto basic_block_obfuscated = m_obfuscated_bb.at(local_block_id);

				/*
					Normally, obfuscated and deobfuscated blocks are 1-to-1, and we just need to get the address relative
					to the first instruction of the block in question so we can determine the jump address for the new obfuscated region.
				*/
				auto obfuscated_target_address = basic_block_obfuscated.instructions.at(0).addressofinstruction;

				/*
					Preventing problems.
					When IAT is obfuscated. theres no JUMP Address(it's always "0")! because it is solved during runtime. so the reloc is fixed, let's advance to the next blog!
				*/
				if (obfuscated_jmp_address == 0 && m_config.m_isIatObfuscation) continue;

				/*
					Let's fix our new branch. Previously it was a "near" jump, but now it will be "far" depending on the jump length.
					This procedure will perform the calculation and generate a far or near branch depending on the need
					and the output of the obfuscated code.
				*/
				auto corrected = fix_branch_near_far_short(instruction.instruction.info.opcode, obfuscated_jmp_address, obfuscated_target_address);

				// Creating a signature for the original branch in the obfuscated opcode to be fixed
				unsigned char ucSignature[2]{ 0, 0 };
				std::memcpy(ucSignature, reinterpret_cast<void*>(instruction.addressofinstruction), 2);
				// Finding the correct offset of the opcode to apply the patch
				const uint32_t offset = findOpcodeOffset(data, size, &ucSignature, 2);

				// Clearing the branch so we can insert the new branch with the corrected opcode and its offset
				std::memset(&*(data + offset), 0x90, 9); // Equivalent to -> branch + offset and possibly some add reg, value -> we have space because "addPaddingSpaces" into this section.

				// Patching the cleared region with the new branch, now fully fixed and with the newly calculated jump displacement
				std::memcpy(&*(data + offset), corrected.data(), corrected.size());

				std::printf("[OK] Fixing %s -> %X -> id: %X\n", instruction.instruction.text, instruction.instruction.operands[0].imm.value.u, block_id);

			}

		}

		//Increment block index
		block_id++;

	}

}

void RyujinObfuscationCore::InsertMiniVmEnterProcedureAddress(uintptr_t imageBase, uintptr_t virtualAddress, std::vector<unsigned char>& new_opcodes) {

	//Inserting Ryujin MiniVm Address on each vm entry reference
	if (m_config.m_isVirtualized) {
		
		// Data and sizes of the opcodes to be worked on
		auto size = new_opcodes.size();
		auto data = new_opcodes.data();

		// Signature of the pattern that we must replace with the referenced RVA of our MiniVmEntry
		unsigned char ucSignature[]{ 0x48, 0x05, 0x88, 0x00, 0x00, 0x00 };

		// Let's search for the pattern to replace
		for (auto i = 0; i < size; i++)

			// If we find it
			if (std::memcmp(&*(data + i), ucSignature, 6) == 0) {

				// Just log it
				std::printf("[OK] Inserting MiniVmEnter at %llx\n", imageBase + virtualAddress + i);
				
				// We will remove the value 0x88 and ensure there are no other offsets
				std::memset(&*(data + i + 2), 0, 4);

				// Finally, we will insert our new RVA for the MiniVmEntry procedure
				std::memcpy(&*(data + i + 2), &virtualAddress, sizeof(uint32_t));
			
			}
	
	}

}

void RyujinObfuscationCore::removeOldOpcodeRedirect(uintptr_t newMappedPE, std::size_t szMapped, uintptr_t newObfuscatedAddress, bool isIgnoreOriginalCodeRemove) {

	/*
		Creating signatures to search for the opcode in the PE mapped from disk.
		We will use findOpcodeOffset to find the exact offset of the procedure's start
		in the unmapped region with the SEC_IMAGE flag.
	*/
	unsigned char* ucSigature = new unsigned char[m_proc.size] { 0 };
	std::memcpy(ucSigature, reinterpret_cast<void*>(m_proc.address), m_proc.size);
	auto offsetz = findOpcodeOffset(reinterpret_cast<unsigned char*>(newMappedPE), szMapped, ucSigature, m_proc.size);

	delete[] ucSigature;

	/*
	* Future assert
	if (!offsetz) {
		std::printf("[X] Fatal Error on removeOldOpcodeRedirect -> %s\n", m_proc.name);
		exit(-1);
	}*/

	// Based on the obfuscation configuration, some users can decide to not remove the original code from the original procedure after obfuscation.
	if (!isIgnoreOriginalCodeRemove) std::memset(reinterpret_cast<void*>(newMappedPE + offsetz), 0x90, m_proc.size); // Removing all the opcodes from the original procedure and replacing them with NOP instructions.

	/*
		Creating a new JMP opcode in such a way that it can be added to the old region that was completely replaced by NOP,
		thus redirecting execution to the new obfuscated code.
	*/
	unsigned char ucOpcodeJmp[5]{
		0xE9, 0, 0, 0, 0, //JMP imm
	};

	/*
		Calculating the new displacement between the original code region and the target obfuscated opcode,
		calculating the relative immediate offset.
	*/
	const uint32_t offset = newObfuscatedAddress - (m_proc.address + 5);

	//Replacing the jump opcode with the new relative immediate displacement value.
	std::memcpy(&*(ucOpcodeJmp + 1), &offset, sizeof(uint32_t));

	//Inserting the new jump opcode into the original cleaned function to redirect execution to the fully obfuscated code.
	std::memcpy(reinterpret_cast<void*>(newMappedPE + offsetz), ucOpcodeJmp, 5);

}

RyujinObfuscationCore::~RyujinObfuscationCore() {

}