#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() {

	std::vector<ZydisRegister> candidateRegs = {

			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,

	};

	std::set<ZydisRegister> usedRegs;

	for (auto blocks : m_proc.basic_blocks) {

		for (auto instr : blocks.instructions) {

			for (auto i = 0; i < instr.instruction.info.operand_count; ++i) {

				const ZydisDecodedOperand& op = instr.instruction.operands[i];

				if (op.type == ZYDIS_OPERAND_TYPE_REGISTER) usedRegs.insert(op.reg.value);
				else if (op.type == ZYDIS_OPERAND_TYPE_POINTER) {

					if (op.mem.base != ZYDIS_REGISTER_NONE) usedRegs.insert(op.mem.base);
					if (op.mem.index != ZYDIS_REGISTER_NONE) usedRegs.insert(op.mem.index);

				}

			}

		}

	}

	ZydisRegister freeReg = ZYDIS_REGISTER_NONE;
	for (auto reg : candidateRegs)
		if (usedRegs.count(reg) == 0) m_unusedRegisters.push_back(reg);

	return m_unusedRegisters.size() >= 2; //Theres unused regs for be used by us ?
}

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;
							case 34: a.cdqe(); break;
							case 35: a.cbw(); 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);
				// 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);
				// 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 antidebug 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() {

	unsigned char ucTest[]{ 0xDE, 0xAD, 0xBE, 0xEF };

	RyujinCRC32Utils crcTest;
	std::printf("RyujinObfuscationCore::insertMemoryProtection.TEST: 0x%X\n", crcTest.crc32(ucTest, 4));

}

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.
		*/
		this->insertAntiDump();

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

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

		RyujinRunOncePass = FALSE;

	}

	//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();

	}

	return TRUE;
}

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) {

	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)
	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
	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)
	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 IMM
			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]
			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
			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();

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

					// Creating a signature to search for the offset in the obfuscated opcodes
					unsigned char ucOpcodeSignature[7]{ 0 };
					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
					const ZyanI64 offset = findOpcodeOffset(data, size, &ucOpcodeSignature, 7);

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

						std::printf("[X] Invalid lea reference or uknown lea 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
					std::memcpy(&*(data + offset + 3), &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);

				}

			}
			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;

				/*
					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[10]{ 0 };
	std::memcpy(ucSigature, reinterpret_cast<void*>(m_proc.address), 10);
	auto offsetz = findOpcodeOffset(reinterpret_cast<unsigned char*>(newMappedPE), szMapped, &ucSigature, 10);

	// 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() {

}