/** @file		P2PThreat.cpp
 *  @brief	Detect bad apps (virus/worms) that could threaten file sharing
 *  @author	netfinity
 */
#include "StdAfx.h"
#include "emule.h"
#include "OtherFunctions.h"
#include "P2PThreat.h"
 
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

CP2PThreat	theP2PThreat;

/**
 *  @brief	Detect if a bad app (virus/worm), is present, that could threaten file sharing
 */
bool CP2PThreat::IsMachineInfected()
{
	/**
	*  @brief	Internal list of bad software
	*/
	struct Threat
	{
		CString		threat_name;
		CString		file_name;
		CString		install_path;
		CString		run_registry_key_name;
		CString		run_registry_key_value;
		CString		created_dir;
	} Threats[] = {
		{L"W32.Tibick Worm",		L"svcnet.exe",		L"%System%",		L"System Restore",			L"svcnet.exe",					L"%Windir%\\msview"},
		{L"W32.Tibick Worm",		L"svcnet.exe",		L"%System%",		L"shellapi32",				L"svcnet",						L"%Windir%\\msview"},
		{L"W32.HLLW.Reur Worm",		L"",				L"%System%",		L"########",				L"%Sysdir%\\########.exe",		L""},
		{L"W32.HLLW.Cayam@mm Worm", L"Msfind32.exe",	L"%Windir%",		L"MSFind32",				L"c:\\windows\\msfind32.exe",	L""},
		{L"W32.Saros@mm Worm",		L"NonYou.exe",		L"%System%",		L"nldr32\\default",			L"WINDOWS\\system32\\NonYou.exe", L""},
		{L"W32.Netsky.S@mm Worm",	L"EasyAV.exe",		L"%Windir%",		L"EasyAV",					L"%Windir%\\EasyAV.exe",		L""},
		{L"W32.Netsky.T@mm Worm",	L"EasyAV.exe",		L"%Windir%",		L"EasyAV",					L"%Windir%\\EasyAV.exe",		L""},
		{L"W32.Netsky.U@mm Worm",	L"SymAV.exe",		L"%Windir%",		L"SymAV",					L"%Windir%\\SymAV.exe",			L""},
		{L"W32.Netsky.V@mm Worm",	L"Kasperskyaveng.exe", L"%Windir%",		L"KasperskyAVEng",			L"%Windir%\\Kasperskyaveng.exe", L""},
		{L"W32.Netsky.Q@mm Worm",	L"SysMonXP.exe",	L"%Windir%",		L"SysMonXP",				L"%Windir%\\SysMonXP.exe",		L""}
	};

	TCHAR	buffer[MAX_PATH];
	TCHAR	system_dir[MAX_PATH];
	TCHAR	windows_dir[MAX_PATH];
	bool	bInfected = false;
	//FILE*	fout;
	//fout = fopen("P2PThreat_debug.txt","wb");
	// Get system paths
	GetSystemDirectory(system_dir,MAX_PATH);
	GetWindowsDirectory(windows_dir,MAX_PATH);
	// Save path
	GetCurrentDirectory(MAX_PATH, buffer);
	int i = 0;
	for (i = 0; i < _countof(Threats); ++i)
	{
		//fprintf(fout,"%d:\n",i);
		bInfected = true;
		// Check if bad file is present on disk
		if (!Threats[i].file_name.IsEmpty() && !Threats[i].install_path.IsEmpty())
		{
			CString	install_path = Threats[i].install_path;
			//install_path.Preallocate(MAX_PATH);
			//TCHAR install_path[MAX_PATH];
			//PathUnExpandEnvStringsW(Threats[i].install_path, install_path.GetBuffer(), MAX_PATH);
			//install_path.ReleaseBuffer();
			install_path.Replace(L"%System%", system_dir);
			install_path.Replace(L"%Windir%", windows_dir);
			if (SetCurrentDirectory(install_path))
			{
				HANDLE hFile; 
 
				hFile = CreateFile(Threats[i].file_name,    // file to open
						GENERIC_READ,          // open for reading
						FILE_SHARE_READ,       // share for reading
						NULL,                  // default security
						OPEN_EXISTING,         // existing file only
						FILE_ATTRIBUTE_NORMAL, // normal file
						NULL);                 // no attr. template
 
				if (hFile == INVALID_HANDLE_VALUE)
				{
					if (GetLastError() == ERROR_FILE_NOT_FOUND)
					{
						bInfected = false;
						//fprintf(fout,"No suspicious file detected!\n");
					}
				}
				else
					CloseHandle(hFile);
			}
			else
			{
				bInfected = false;
				//fprintf(fout,"No suspicious file detected!\n");
			}
		}
		// Check if bad folder is present on disk
		if (!Threats[i].created_dir.IsEmpty())
		{
			CString created_dir = Threats[i].created_dir;
			//created_dir.Preallocate(MAX_PATH);
			//TCHAR created_dir[MAX_PATH];
			//PathUnExpandEnvStrings(Threats[i].created_dir, created_dir.GetBuffer(), MAX_PATH);
			//created_dir.ReleaseBuffer();
			created_dir.Replace(L"%System%", system_dir);
			created_dir.Replace(L"%Windir%", windows_dir);
			if (!SetCurrentDirectory(created_dir))
			{
				bInfected = false;
				//fprintf(fout,"No suspicious directory detected!\n");
			}
		}
		// Check if bad registry key is present
		if (!Threats[i].run_registry_key_name.IsEmpty())
		{
			if (!TestRegistryKey(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", Threats[i].run_registry_key_name, Threats[i].run_registry_key_value))
			{
				if (!TestRegistryKey(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Run", Threats[i].run_registry_key_name, Threats[i].run_registry_key_value))
				{
					bInfected = false;
					//fprintf(fout,"Registry is clean!\n");
				}
			}
		}
		// Is the system infected?
		if (bInfected)
			break;
	}
	//fclose(fout);
	// Restore path
	SetCurrentDirectory(buffer);
	// Notify user about the infection!
	if (bInfected)
	{
		CString	notification;
		CString	caption;
		notification.Format(
			L"WARNING!!! Your computer has been compromised.\n"
			L"The '%s' was detected on your system.\n\n"
			L"Please, update your antivirus software, scan&clean your machine and restart eMule.",
			Threats[i].threat_name
			);
		AfxMessageBox(notification, MB_ICONSTOP | MB_SYSTEMMODAL | MB_SETFOREGROUND);
	}
	return bInfected;
}

bool CP2PThreat::TestRegistryKey(HKEY hParent, LPCTSTR pszKey, LPCTSTR pszName, LPCTSTR pszValue)
{
	bool bFound = false;
	CRegKey regkey;
	if (regkey.Open(hParent, pszKey) == ERROR_SUCCESS)
	{
		TCHAR pszTempName[500], pszTempValue[500];
		DWORD dwNameLen, dwValueLen, idx = 0;
		if (CString(pszName) == L"*")
		{
			while (!bFound)
			{
				dwNameLen = _countof(pszTempName);
				dwValueLen = _countof(pszTempValue);
				if (regkey.EnumKey(idx++, pszTempName, &dwNameLen) != ERROR_SUCCESS)
					break;
				regkey.QueryStringValue(pszTempName, pszTempValue, &dwValueLen);
				CString strValue = pszTempValue;
				strValue.Replace(pszTempName, L"*");
	
				if (_tcscmp(pszTempValue, pszValue) == 0)
					bFound = true;
			}
		}
		else if (CString(pszName) == L"########")
		{
			while (!bFound)
			{
				dwNameLen = _countof(pszTempName);
				dwValueLen = _countof(pszTempValue);
				if (regkey.EnumKey(idx++, pszTempName, &dwNameLen) != ERROR_SUCCESS)
					break;
				regkey.QueryStringValue(pszTempName, pszTempValue, &dwValueLen);
				if (_tcslen(pszTempName) == 8)
				{
					bool bIsHex = true;
					for (int i = 0; i < 8 && bIsHex; ++i)
					{
						if(!IsHexDigit(pszTempName[i]))
							bIsHex = false;
					}
					CString strValue = pszTempValue;
					strValue.Replace(pszTempName, L"########");
	
					if (bIsHex && _tcscmp(pszTempValue, pszValue) == 0)
						bFound = true;
				}
			}
		}
		else
		{
			dwValueLen = _countof(pszTempValue);
			regkey.QueryStringValue(pszName, pszTempValue, &dwValueLen);

			if (_tcscmp(pszTempValue, pszValue) == 0)
				bFound = true;
		}

		regkey.Close();
	}
	return bFound;
}