
#include <Windows.h>
#include <stdio.h>
#include <fstream>

#include "Windas.h"
#include "XedWrap.h"
#include "NativeCode.h"
#include "Obfuscator.h"
#include "Random.h"

__declspec(dllexport) VOID CvInit()
{
	XedTablesInit();
	srand(time(NULL));
}

__declspec(dllexport) PVOID CvDriverFunctionObfuscate(PVOID Code, ULONG CodeSize, PULONG OutSize, ULONG BranchCount, FLOAT MaxBranchSizePercentage)
{
	//trip 0xCC alignment at end of code
	while (((PUCHAR)Code)[CodeSize - 1] == 0xCC)
	{
		//printf("%X", ((PUCHAR)Code)[CodeSize - 1]);
		--CodeSize;
	}

	NATIVE_CODE_BLOCK CodeBlock;
	if (!NcDisassemble(&CodeBlock, Code, CodeSize))
	{
		return NULL;
	}
	//printf("Dissasembled.\n");

	if (!NcPromoteAllRelJmpTo32(&CodeBlock))
	{
		return NULL;
	}
	//printf("Jmps Fixed.\n");

	/*OPBR_SETS Obf;
	Obf.Flags = 0;
	Obf.ParentBlock = &CodeBlock;
	Obf.MinBranchLength = InstructionCount / 5 ;
	Obf.BranchLengthChangeAmount = 4;
	Obf.SpaceBetweenBranches = 10;
	Obf.BranchLengthChangeAmount = 4;
	Obf.BranchImmediately = FALSE;
	Obf.RandomizeBranchChangeAmount = TRUE;
	Obf.RandomizeSpaceBetweenBranches = TRUE;
	Obf.BranchRemainingInstructions = TRUE;
	Obf.BranchChance = 75;
	ULONG BranchesMade = */

	while (BranchCount)
	{
		ObfGenOpaqueBranch(&CodeBlock, RndGetRandomFloat(0.F, MaxBranchSizePercentage));
		BranchCount--;
	}

	//if (MutSettings)
	//	ObfMutateInstructions(MutSettings, &CodeBlock);

	return NcAssembleEx(&CodeBlock, OutSize);
}

__declspec(dllexport) VOID CvDeleteCode(PVOID Code)
{
	if (Code)
		delete[] Code;
}


VOID PrintByteArr(PVOID Buff, ULONG BufSize)
{
	for (uint32_t i = 0; i < BufSize; i++)
	{
		std::cout << std::hex << std::setw(2) << std::setfill('0') << (int)((PUCHAR)Buff)[i] << ' ';
	}
}

PVOID MakeExecutableBuffer(PVOID Buffer, ULONG BufferSize)
{
	PVOID ExecBuffer = VirtualAlloc(nullptr, BufferSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	if (!ExecBuffer)
	{
		printf("allocate failed.\n");
		return NULL;
	}
	RtlCopyMemory(ExecBuffer, Buffer, BufferSize);
	return ExecBuffer;
}

VOID PutToFile(PVOID Buffer, ULONG BufferSize)
{
	std::ofstream fout;
	//
	//fout.open("C:\\Users\\James\\Desktop\\fantern\\Test.m", std::ios::binary | std::ios::out);
	fout.open("C:\\Users\\Iizerd\\Desktop\\Leeg Hake\\Test.m", std::ios::binary | std::ios::out);
	fout.write((PCHAR)Buffer, BufferSize);
	fout.close();
}

ULONG64 TestShelcode(ULONG64 v1, ULONG64 v2, ULONG64 v3, ULONG64 v4)
{
	if (v4 == 0)
		v4 = 2;

	ULONG64 Value = 1;
	for (int i = 1; i <= v1; i++)
	{
		Value *= i;
		Value += v3;
		Value /= v4;
		for (int i = 1; i <= v4; i++)
			Value += v2 = i;
	}
	return Value;
}

ULONG64 Nextfunction(ULONG64 v1)
{
	return v1 + 1;
}

UCHAR TestBuffer[] = {
	0x48, 0x33, 0xC0,
	0x48, 0x33, 0xC0,
	//0xEB, 0x0E,
	0x48, 0x33, 0xC0,
	0x48, 0x33, 0xC0,
	//0x7E, 0x06,
	0x48, 0x33, 0xC0,
	0x48, 0x33, 0xC0,
	0x48, 0x33, 0xC0,
	0x48, 0x33, 0xC0,
	//0xEB, 0xF8,
	0x50,
	0x48, 0xB8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F,
	0x48, 0x87, 0x04, 0x24,
	0xC3,
};
ULONG TestBufferSize = sizeof(TestBuffer);

UCHAR meme1[] = { 
	0x31, 0xc0, 
	0x83, 0xc0, 0x01,
	0x83, 0xc0, 0x01,
0x83, 0xc0, 0x01, 
0x83, 0xc0, 0x01, 
0x83, 0xc0, 0x01,
0x83, 0xc0, 0x01,
0x83, 0xc0, 0x01,
0x83, 0xc0, 0x01,
0x83, 0xc0, 0x01,
0x83, 0xc0, 0x01,
0x83, 0xc0, 0x01,
0x83, 0xc0, 0x01,
0x83, 0xc0, 0x01,
0x83, 0xc0, 0x01,
0x83, 0xc0, 0x01,
0xc3,
};

UCHAR RetNumCode[] = {
	0x33, 0xC0
	, 0x48, 0x83, 0xC0, 0x01
	, 0x48, 0x83, 0xE9, 0x01
	, 0x48, 0x83, 0xC1, 0x01
	, 0x48, 0x83, 0xC0, 0x02
	, 0x48, 0x83, 0xE8, 0x02
	, 0x48, 0x83, 0xE9, 0x01
	, 0x75, 0xE6
	, 0xC3
};

UCHAR IsEvenCode[]{
	0xF6, 0xC1, 0x01,
	0x75, 0x05,
	0x66, 0xB8, 0x01, 0x00,
	0xC3,
	0x33, 0xC0,
	0xC3,
};

//EXTERN_C ULONG64 RetNum(ULONG64 Num);
//EXTERN_C BOOL IsEven(ULONG64 Num);

int main()
{
	CvInit();

	//ULONG Delta = (*((PULONG)((PUCHAR)TestShelcode + 1))) + 5;
	//printf("Delta: %X\n", Delta);
	PVOID ActualFunction = TestShelcode; // (PVOID)((ULONG64)TestShelcode + Delta);

	printf("%llu %llu %llu %llu\n", TestShelcode(1, 2, 3, 4), TestShelcode(20, 20, 20, 4), TestShelcode(50, 50, 50, 0), Nextfunction(12));
	system("pause");

	PUCHAR MemeBlock = new UCHAR[110];
	memcpy(MemeBlock, ActualFunction, 110);

	PrintByteArr(MemeBlock, 110);
	system("pause");



	//NATIVE_CODE_BLOCK RetNumBlock;
	////NcDisassemble(&RetNumBlock, RetNumCode, sizeof(RetNumCode));
	//NcDisassemble(&RetNumBlock, MemeBlock, 110);
	//if (!NcPromoteAllRelJmpTo32(&RetNumBlock))
	//{
	//	printf("failed to promote all jmps.\n");
	//}
	//OPBR_SETS Obf;
	//Obf.Flags = 0;
	//Obf.ParentBlock = &RetNumBlock;
	//Obf.Divisor = 1.7F;
	//Obf.MaxDepth = 10;
	//Obf.MinBranchSize = 5;
	//Obf.ChanceForBranch = 80;
	//Obf.MinDepthForBranch = 0;
	//ObfGenerateOpaqueBranches(&Obf, &RetNumBlock);
	//INSTMUT_SETS Obf2;
	//Obf2.MutateChance = 100;
	////ObfMutateInstructions(&Obf2, &RetNumBlock);
	//Obf.MinBranchSize = 40;
	//printf("Size = %u\n", NcCountInstructions(&RetNumBlock, TRUE));
	//Obf.ChanceForBranch = 100;
	//ObfGenerateOpaqueBranches(&Obf, &RetNumBlock);

	//printf("Assembling %u %u", NcCountInstructions(&RetNumBlock), NcCalcBlockSizeInBytes(&RetNumBlock));
	//ULONG AsmSize;
	//PVOID Asm = NcAssemble(&RetNumBlock, &AsmSize);
	//if (!Asm)
	//{
	//	printf("failed to assemble\n");
	//	system("pause");
	//	return 1;
	//}
	//PutToFile(Asm, AsmSize);
	//system("pause");

	ULONG AsmSize;
	PVOID Asm = CvDriverFunctionObfuscate(MemeBlock, 110, &AsmSize, 5, 0.5);
	if (!Asm)
	{
		printf("failed to obfuscate ngiga\n");
		system("pause");
		return 2;
	}
	PutToFile(Asm, AsmSize);


	typedef ULONG64(*FnTestShelcode)(ULONG64, ULONG64, ULONG64, ULONG64);
	PVOID Exec = NULL;
	Exec = MakeExecutableBuffer(Asm, AsmSize);
	if (!Exec)
	{
		printf("Failed to make buffer\n");
		return 1;
	}
	printf("%llu %llu %llu %llu\n", ((FnTestShelcode)Exec)(1, 2, 3, 4), ((FnTestShelcode)Exec)(20, 20, 20, 4), ((FnTestShelcode)Exec)(50, 50, 50, 0), Nextfunction(12));



	/*PVOID Exec = MakeExecutableBuffer(Asm, AsmSize);
	typedef ULONG64(*FnRetNum)(ULONG Num);

	printf("\n\nSize: %u   Obfuscated: %llu    Original: %llu\n\n", NcCountInstructions(&RetNumBlock), ((FnRetNum)Exec)(1776), ((FnRetNum)Exec)(1776));
	NcDeleteBlock(&RetNumBlock);
	system("pause");*/


	/*NATIVE_CODE_BLOCK Block;
	NcDisassemble(&Block, meme1, sizeof(meme1));
	OBFUSCATOR Obf;
	Obf.Flags = 0;
	Obf.MinSizeForOpaqueBranch = 12;
	Obf.GlobalBlock = &Block;
	ObfObfuscate(&Obf, &Block);
	Obf.MinSizeForOpaqueBranch = 4;
	ObfObfuscate(&Obf, &Block);
	NcDebugPrint(&Block);

	ULONG ByteSize = NcCalcBlockSizeInBytes(&Block);
	ULONG InstSize = NcCountInstructions(&Block);

	printf("Bytes: %u, Insts: %u, FlagsMeme: %u.\n", ByteSize, InstSize, Obf.Flags);

	ULONG AsmSize;
	PVOID Asm = NcAssemble(&Block, &AsmSize);
	PVOID Exec = MakeExecutableBuffer(Asm, AsmSize);
	typedef ULONG(*FnGetFour)();
	printf("numba is: %u size is %u\n\n", ((FnGetFour)Exec)(), AsmSize);
	PutToFile(Asm, AsmSize);*/


	//PNATIVE_CODE_LINK Return1776 = new NATIVE_CODE_LINK(CODE_FLAG_IS_INST, meme1, sizeof(meme1));
	//PNATIVE_CODE_LINK RetInst = new NATIVE_CODE_LINK(CODE_FLAG_IS_INST, meme2, sizeof(meme2));
	//PNATIVE_CODE_BLOCK Pre1 = JitEmitPreRipMov(Return1776);
	//PNATIVE_CODE_BLOCK Post1 = JitEmitPostRipMov(Return1776);
	//PNATIVE_CODE_BLOCK Pre2 = JitEmitPreRipMov(RetInst);
	//PNATIVE_CODE_BLOCK Post2 = JitEmitPostRipMov(RetInst);

	//NcAppendToBlock(Pre1, Return1776);
	//NcInsertBlockAfter(Pre1->End, Post1, 0);
	//Pre1->End = Post1->End;
	//NcInsertBlockAfter(Pre1->End, Pre2, 0);
	//Pre1->End = Pre2->End;
	//NcAppendToBlock(Pre1, RetInst);
	//NcInsertBlockAfter(Pre1->End, Post2, 0);
	//Pre1->End = Post2->End;

	///*Pre->Start = Return1776;
	//Pre->End = Return1776;*/

	//for (ULONG i = 0; i < Return1776->RawDataSize; i++)
	//	Return1776->RawData[i] = (UCHAR)rand();
	//for (ULONG i = 0; i < RetInst->RawDataSize; i++)
	//	RetInst->RawData[i] = (UCHAR)rand();



	//ULONG AsmLen;
	//PVOID Asm = NcAssemble(Pre1, &AsmLen);
	//PUCHAR Tb = (PUCHAR)Asm;
	//for (uint32_t i = 0; i < AsmLen; i++)
	//{
	//	std::cout << std::hex << std::setw(2) << std::setfill('0') << (int)Tb[i] << ' ';
	//}

	//system("pause");

	//typedef ULONG64(*FnGet1776)();
	//FnGet1776 ExecBuffer = (FnGet1776)MakeExecutableBuffer(Asm, AsmLen);
	//if (ExecBuffer)
	//{
	//	printf("The numba was: %X\n", ExecBuffer());
	//	printf("The numba was: %X\n", ExecBuffer());

	//	printf("The numba was: %X\n", ExecBuffer());

	//	printf("The numba was: %X\n", ExecBuffer());

	//}


	//NcDebugPrint(Post);



	/*NATIVE_CODE_BLOCK Block;
	NcDisassemble(&Block, TestBuffer, TestBufferSize);
	PNATIVE_CODE_LINK NewLink = new NATIVE_CODE_LINK(CODE_FLAG_IS_INST, meme1, sizeof(meme1));

	NcInsertLinkBefore(Block.End->Prev->Prev->Prev->Prev, NewLink);
	ULONG AssembledSize;
	PVOID AssembledBlock = NcAssemble(&Block, &AssembledSize);
	if (!AssembledBlock || !AssembledSize)
	{
		printf("Something failed nicka.\n");
		system("pause");
		return -1;
	}
	PUCHAR Tb = (PUCHAR)AssembledBlock;
	for (uint32_t i = 0; i < AssembledSize; i++)
	{
		std::cout << std::hex << std::setw(2) << std::setfill('0') << (int)Tb[i] << ' ';
	}
	*/


	//PNATIVE_CODE_BLOCK OpaqueBranch = ObfGenOpaqueBranch(Block.Start, Block.End);
	//NcDebugPrint(OpaqueBranch);



	/*NATIVE_CODE_LINK T;
	T.RawDataSize = 10;
	T.RawData = new UCHAR[10];
	memset(T.RawData, 0xAA, 10);
	JIT_BITWISE_DATA Data;
	RtlSecureZeroMemory(&Data, sizeof(JIT_BITWISE_DATA));
	PNATIVE_CODE_BLOCK NewBlock = JitEmitPreRipMov(&T);
	if (NewBlock)
	{
		printf("\n");
		NcDebugPrint(NewBlock);
		printf("\n");
		NcPrintBlockCode(NewBlock);
	}
	system("pause");*/
	
}

