#include "stdafx.h" #include #include #include #include #pragma comment(lib, "Wininet.lib") CProjectSupport::CProjectSupport() : m_SupportInfo({0}) { LoadSupportInfo(); } bool CProjectSupport::RequestCode(const char * Email) { stdstr_f PostData("task=RequestCode&email=%s&machine=%s", Email, MachineID()); std::vector Headers; DWORD StatusCode; if (!PerformRequest(L"/index.php?option=com_project64", PostData, StatusCode, Headers)) { return false; } if (StatusCode == 200) { for (size_t i = 0, n = Headers.size(); i < n; i++) { if (strcmp(Headers[i].c_str(), "Email: Sent") == 0) { return true; } } } return false; } bool CProjectSupport::ValidateCode(const char * Code) { stdstr_f PostData("task=ValidateCode&code=%s&machine=%s", Code, MachineID()); std::vector Headers; DWORD StatusCode; if (PerformRequest(L"/index.php?option=com_project64", PostData, StatusCode, Headers) && StatusCode == 200) { std::string Name, Email; struct { const char * Key; std::string & Value; } Test[] = { { "SupporterName: ", Name }, { "SupporterEmail: ", Email }, }; for (size_t i = 0, n = Headers.size(); i < n; i++) { for (size_t t = 0; t < sizeof(Test) / sizeof(Test[0]); t++) { size_t KeyLen = strlen(Test[t].Key); if (strncmp(Headers[i].c_str(), Test[t].Key, KeyLen) == 0) { Test[t].Value = stdstr(&Headers[i][KeyLen]).Trim(); break; } } } if (Name.length() > 0 && Email.length() > 0) { strncpy(m_SupportInfo.Code, Code, sizeof(m_SupportInfo.Code)); strncpy(m_SupportInfo.Email, Email.c_str(), sizeof(m_SupportInfo.Email)); strncpy(m_SupportInfo.Name, Name.c_str(), sizeof(m_SupportInfo.Name)); m_SupportInfo.Validated = true; SaveSupportInfo(); } } return m_SupportInfo.Validated; } std::string CProjectSupport::GenerateMachineID(void) { wchar_t ComputerName[256]; DWORD Length = sizeof(ComputerName) / sizeof(ComputerName[0]); GetComputerName(ComputerName, &Length); wchar_t SysPath[MAX_PATH] = { 0 }, VolumePath[MAX_PATH] = { 0 }; GetSystemDirectory(SysPath, sizeof(SysPath) / sizeof(SysPath[0])); GetVolumePathName(SysPath, VolumePath, sizeof(VolumePath) / sizeof(VolumePath[0])); DWORD SerialNumber = 0; GetVolumeInformation(VolumePath, NULL, NULL, &SerialNumber, NULL, NULL, NULL, NULL); wchar_t MachineGuid[200] = { 0 }; HKEY hKey; if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Cryptography", 0, KEY_QUERY_VALUE | KEY_WOW64_64KEY, &hKey) == ERROR_SUCCESS) { DWORD Type, dwDataSize = sizeof(MachineGuid); RegQueryValueEx(hKey, L"MachineGuid", nullptr, &Type, (LPBYTE)MachineGuid, &dwDataSize); RegCloseKey(hKey); } stdstr_f Machine("%s.%ud.%s", stdstr().FromUTF16(ComputerName).c_str(), SerialNumber, stdstr().FromUTF16(MachineGuid).c_str()); return std::string(MD5((const unsigned char *)Machine.c_str(), Machine.size()).hex_digest()); } void CProjectSupport::IncrementRunCount() { time_t now = time(nullptr); if (m_SupportInfo.LastUpdated <= now && ((now - m_SupportInfo.LastUpdated) / 60) < 60) { return; } m_SupportInfo.RunCount += 1; m_SupportInfo.LastUpdated = now; SaveSupportInfo(); } bool CProjectSupport::ShowSuppotWindow() { time_t now = time(nullptr); if (m_SupportInfo.LastShown <= now && ((now - m_SupportInfo.LastShown) / 60) < 60) { return false; } m_SupportInfo.LastShown = now; SaveSupportInfo(); return true; } bool CProjectSupport::PerformRequest(const wchar_t * Url, const std::string & PostData, DWORD & StatusCode, std::vector & Headers) { StatusCode = 0; Headers.clear(); HINTERNET hSession = InternetOpen(L"Project64", INTERNET_OPEN_TYPE_PRECONFIG, nullptr, nullptr, 0); if (hSession == nullptr) { return false; } HINTERNET hConnect = InternetConnect(hSession, L"www.pj64-emu.com", INTERNET_DEFAULT_HTTPS_PORT, L"", L"", INTERNET_SERVICE_HTTP, 0, 0); if (hConnect == nullptr) { return false; } LPCWSTR lpszAcceptTypes[] = { L"text/*", nullptr }; HINTERNET hRequest = HttpOpenRequest(hConnect, L"POST", Url, NULL, NULL, lpszAcceptTypes, INTERNET_FLAG_SECURE | INTERNET_FLAG_NO_AUTO_REDIRECT | INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_NO_CACHE_WRITE, (LPARAM)0); if (hRequest == nullptr) { InternetCloseHandle(hRequest); return false; } wchar_t hdheaders[] = _T("Content-Type: application/x-www-form-urlencoded\r\n"); BOOL Success = HttpSendRequest(hRequest, hdheaders, _tcslen(hdheaders), (LPVOID)PostData.c_str(), PostData.length()); if (!Success) { InternetCloseHandle(hRequest); return false; } DWORD StatusCodeSize = sizeof(StatusCode); if (!HttpQueryInfo(hRequest, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &StatusCode, &StatusCodeSize, NULL)) { InternetCloseHandle(hRequest); return false; } DWORD dwSize = 0; if (!HttpQueryInfo(hRequest, HTTP_QUERY_RAW_HEADERS_CRLF, NULL, &dwSize, NULL) && GetLastError() == ERROR_INSUFFICIENT_BUFFER) { std::vector RawHeaderData(dwSize); if (!HttpQueryInfo(hRequest, HTTP_QUERY_RAW_HEADERS_CRLF, RawHeaderData.data(), &dwSize, NULL)) { InternetCloseHandle(hRequest); return false; } strvector RawHeader = stdstr().FromUTF16((wchar_t *)RawHeaderData.data()).Tokenize("\n"); for (size_t i = 0, n = RawHeader.size(); i < n; i++) { RawHeader[i].Replace("\r", ""); RawHeader[i].Trim(); if (RawHeader[i].length() > 0) { Headers.push_back(RawHeader[i]); } } } return true; } void CProjectSupport::SaveSupportInfo(void) { std::string hash = MD5((const unsigned char *)&m_SupportInfo, sizeof(m_SupportInfo)).hex_digest(); std::vector InData(sizeof(m_SupportInfo) + hash.length()); memcpy(InData.data(), (const unsigned char *)&m_SupportInfo, sizeof(m_SupportInfo)); memcpy(InData.data() + sizeof(m_SupportInfo), hash.data(), hash.length()); std::vector OutData(InData.size()); z_stream defstream; defstream.zalloc = Z_NULL; defstream.zfree = Z_NULL; defstream.opaque = Z_NULL; defstream.avail_in = (uInt)InData.size(); defstream.next_in = (Bytef *)InData.data(); defstream.avail_out = (uInt)OutData.size(); defstream.next_out = (Bytef *)OutData.data(); deflateInit(&defstream, Z_BEST_COMPRESSION); deflate(&defstream, Z_FINISH); deflateEnd(&defstream); OutData.resize(defstream.total_out); for (size_t i = 0, n = OutData.size(); i < n; i++) { OutData[i] ^= 0xAA; } HKEY hKeyResults = 0; DWORD Disposition = 0; long lResult = RegCreateKeyEx(HKEY_CURRENT_USER, L"SOFTWARE\\Project64", 0, L"", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKeyResults, &Disposition); if (lResult == ERROR_SUCCESS) { RegSetValueEx(hKeyResults, L"user", 0, REG_BINARY, (BYTE *)OutData.data(), OutData.size()); RegCloseKey(hKeyResults); } } void CProjectSupport::LoadSupportInfo(void) { std::string MachineID = GenerateMachineID(); std::vector InData; HKEY hKeyResults = 0; long lResult = RegOpenKeyEx(HKEY_CURRENT_USER, L"SOFTWARE\\Project64", 0, KEY_READ, &hKeyResults); if (lResult == ERROR_SUCCESS) { DWORD DataSize = 0; if (RegQueryValueEx(hKeyResults, L"user", NULL, NULL, NULL, &DataSize) == ERROR_SUCCESS) { InData.resize(DataSize); if (RegQueryValueEx(hKeyResults, L"user", NULL, NULL, InData.data(), &DataSize) != ERROR_SUCCESS) { InData.clear(); } } } if (hKeyResults != NULL) { RegCloseKey(hKeyResults); NULL; } std::vector OutData; if (InData.size() > 0) { for (size_t i = 0, n = InData.size(); i < n; i++) { InData[i] ^= 0xAA; } OutData.resize(sizeof(m_SupportInfo) + 100); uLongf DestLen = OutData.size(); if (uncompress(OutData.data(), &DestLen, InData.data(), InData.size()) >= 0) { OutData.resize(DestLen); } else { OutData.clear(); } } if (OutData.size() == sizeof(SupportInfo) + 32) { SupportInfo * Info = (SupportInfo *)OutData.data(); const char * CurrentHash = (const char *)(OutData.data() + sizeof(SupportInfo)); std::string hash = MD5((const unsigned char *)Info, sizeof(SupportInfo)).hex_digest(); if (strcmp(hash.c_str(), CurrentHash) == 0 && strcmp(Info->MachineID, MachineID.c_str()) == 0) { memcpy(&m_SupportInfo, Info, sizeof(SupportInfo)); } } strcpy(m_SupportInfo.MachineID, MachineID.c_str()); }