PPH_UPDATER_CONTEXT CreateUpdateContext( _In_ BOOLEAN StartupCheck ) { PPH_UPDATER_CONTEXT context; context = (PPH_UPDATER_CONTEXT)PhCreateAlloc(sizeof(PH_UPDATER_CONTEXT)); memset(context, 0, sizeof(PH_UPDATER_CONTEXT)); context->CurrentVersionString = PhGetPhVersion(); context->StartupCheck = StartupCheck; return context; }
VOID PhWritePhTextHeader( __inout PPH_FILE_STREAM FileStream ) { PPH_STRING version; LARGE_INTEGER time; SYSTEMTIME systemTime; PPH_STRING dateString; PPH_STRING timeString; PhWriteStringAsAnsiFileStream2(FileStream, L"Process Hacker "); if (version = PhGetPhVersion()) { PhWriteStringAsAnsiFileStream(FileStream, &version->sr); PhDereferenceObject(version); } PhWriteStringFormatFileStream(FileStream, L"\r\nWindows NT %u.%u", PhOsVersion.dwMajorVersion, PhOsVersion.dwMinorVersion); if (PhOsVersion.szCSDVersion[0] != 0) PhWriteStringFormatFileStream(FileStream, L" %s", PhOsVersion.szCSDVersion); #ifdef _M_IX86 PhWriteStringAsAnsiFileStream2(FileStream, L" (32-bit)"); #else PhWriteStringAsAnsiFileStream2(FileStream, L" (64-bit)"); #endif PhQuerySystemTime(&time); PhLargeIntegerToLocalSystemTime(&systemTime, &time); dateString = PhFormatDate(&systemTime, NULL); timeString = PhFormatTime(&systemTime, NULL); PhWriteStringFormatFileStream(FileStream, L"\r\n%s %s\r\n\r\n", dateString->Buffer, timeString->Buffer); PhDereferenceObject(dateString); PhDereferenceObject(timeString); }
PVIRUSTOTAL_API_RESPONSE VirusTotalRequestIpAddressReport( _In_ PPH_STRING IpAddress ) { PVIRUSTOTAL_API_RESPONSE result = NULL; PPH_BYTES jsonString = NULL; PPH_HTTP_CONTEXT httpContext = NULL; PPH_STRING versionString = NULL; PPH_STRING userAgentString = NULL; PPH_STRING urlPathString = NULL; PVOID jsonRootObject = NULL; versionString = PhGetPhVersion(); userAgentString = PhConcatStrings2(L"ProcessHacker_", versionString->Buffer); if (!PhHttpSocketCreate( &httpContext, PhGetString(userAgentString) )) { goto CleanupExit; } if (!PhHttpSocketConnect( httpContext, L"www.virustotal.com", PH_HTTP_DEFAULT_HTTPS_PORT )) { goto CleanupExit; } { PPH_BYTES resourceString = VirusTotalGetCachedDbHash(); urlPathString = PhFormatString( L"%s%s%s%s%s%S%s%s", L"/vtapi", L"/v2", L"/ip-address", L"/report", L"?\x0061\x0070\x0069\x006B\x0065\x0079=", resourceString->Buffer, L"&ip=", IpAddress->Buffer ); PhClearReference(&resourceString); } if (!PhHttpSocketBeginRequest( httpContext, L"POST", PhGetString(urlPathString), PH_HTTP_FLAG_REFRESH | PH_HTTP_FLAG_SECURE )) { goto CleanupExit; } if (!PhHttpSocketAddRequestHeaders(httpContext, L"Content-Type: application/json", 0)) goto CleanupExit; if (!PhHttpSocketSendRequest(httpContext, NULL, 0)) goto CleanupExit; if (!PhHttpSocketEndRequest(httpContext)) goto CleanupExit; if (!(jsonString = PhHttpSocketDownloadString(httpContext, FALSE))) goto CleanupExit; if (!(jsonRootObject = PhCreateJsonParser(jsonString->Buffer))) goto CleanupExit; result = PhAllocate(sizeof(VIRUSTOTAL_API_RESPONSE)); memset(result, 0, sizeof(VIRUSTOTAL_API_RESPONSE)); //result->ResponseCode = PhGetJsonValueAsLong64(jsonRootObject, "response_code"); //result->StatusMessage = PhGetJsonValueAsString(jsonRootObject, "verbose_msg"); //result->PermaLink = PhGetJsonValueAsString(jsonRootObject, "permalink"); //result->ScanId = PhGetJsonValueAsString(jsonRootObject, "scan_id"); CleanupExit: if (httpContext) PhHttpSocketDestroy(httpContext); if (jsonRootObject) PhFreeJsonParser(jsonRootObject); PhClearReference(&jsonString); PhClearReference(&versionString); PhClearReference(&userAgentString); return result; }
PVIRUSTOTAL_FILE_REPORT VirusTotalRequestFileReport( _In_ PPH_STRING FileHash ) { PVIRUSTOTAL_FILE_REPORT result = NULL; PPH_BYTES jsonString = NULL; PPH_HTTP_CONTEXT httpContext = NULL; PPH_STRING versionString = NULL; PPH_STRING userAgentString = NULL; PPH_STRING urlPathString = NULL; PVOID jsonRootObject = NULL; PVOID jsonScanObject; versionString = PhGetPhVersion(); userAgentString = PhConcatStrings2(L"ProcessHacker_", versionString->Buffer); if (!PhHttpSocketCreate( &httpContext, PhGetString(userAgentString) )) { goto CleanupExit; } if (!PhHttpSocketConnect( httpContext, L"www.virustotal.com", PH_HTTP_DEFAULT_HTTPS_PORT )) { goto CleanupExit; } { PPH_BYTES resourceString = VirusTotalGetCachedDbHash(); urlPathString = PhFormatString( L"%s%s%s%s%s%S%s%s", L"/vtapi", L"/v2", L"/file", L"/report", L"?\x0061\x0070\x0069\x006B\x0065\x0079=", resourceString->Buffer, L"&resource=", FileHash->Buffer ); PhClearReference(&resourceString); } if (!PhHttpSocketBeginRequest( httpContext, L"POST", PhGetString(urlPathString), PH_HTTP_FLAG_REFRESH | PH_HTTP_FLAG_SECURE )) { goto CleanupExit; } if (!PhHttpSocketAddRequestHeaders(httpContext, L"Content-Type: application/json", 0)) goto CleanupExit; if (!PhHttpSocketSendRequest(httpContext, NULL, 0)) goto CleanupExit; if (!PhHttpSocketEndRequest(httpContext)) goto CleanupExit; if (!(jsonString = PhHttpSocketDownloadString(httpContext, FALSE))) goto CleanupExit; if (!(jsonRootObject = PhCreateJsonParser(jsonString->Buffer))) goto CleanupExit; result = PhAllocate(sizeof(VIRUSTOTAL_FILE_REPORT)); memset(result, 0, sizeof(VIRUSTOTAL_FILE_REPORT)); result->ResponseCode = PhGetJsonValueAsLong64(jsonRootObject, "response_code"); result->StatusMessage = PhGetJsonValueAsString(jsonRootObject, "verbose_msg"); result->PermaLink = PhGetJsonValueAsString(jsonRootObject, "permalink"); result->ScanDate = PhGetJsonValueAsString(jsonRootObject, "scan_date"); result->ScanId = PhGetJsonValueAsString(jsonRootObject, "scan_id"); result->Total = PhFormatUInt64(PhGetJsonValueAsLong64(jsonRootObject, "total"), FALSE); result->Positives = PhFormatUInt64(PhGetJsonValueAsLong64(jsonRootObject, "positives"), FALSE); //result->Md5 = PhGetJsonValueAsString(jsonRootObject, "md5"); //result->Sha1 = PhGetJsonValueAsString(jsonRootObject, "sha1"); //result->Sha256 = PhGetJsonValueAsString(jsonRootObject, "sha256"); if (jsonScanObject = PhGetJsonObject(jsonRootObject, "scans")) { PPH_LIST jsonArrayList; if (jsonArrayList = PhGetJsonObjectAsArrayList(jsonScanObject)) { result->ScanResults = PhCreateList(jsonArrayList->Count); for (ULONG i = 0; i < jsonArrayList->Count; i++) { PVIRUSTOTAL_FILE_REPORT_RESULT entry; PJSON_ARRAY_LIST_OBJECT object = jsonArrayList->Items[i]; entry = PhAllocate(sizeof(VIRUSTOTAL_FILE_REPORT_RESULT)); memset(entry, 0, sizeof(VIRUSTOTAL_FILE_REPORT_RESULT)); entry->Vendor = PhConvertUtf8ToUtf16(object->Key); entry->Detected = PhGetJsonObjectBool(object->Entry, "detected"); entry->EngineVersion = PhGetJsonValueAsString(object->Entry, "version"); entry->DetectionName = PhGetJsonValueAsString(object->Entry, "result"); entry->DatabaseDate = PhGetJsonValueAsString(object->Entry, "update"); PhAddItemList(result->ScanResults, entry); PhFree(object); } PhDereferenceObject(jsonArrayList); } } CleanupExit: if (httpContext) PhHttpSocketDestroy(httpContext); if (jsonRootObject) PhFreeJsonParser(jsonRootObject); PhClearReference(&jsonString); PhClearReference(&versionString); PhClearReference(&userAgentString); return result; }
PPH_BYTES VirusTotalSendHttpRequest( _In_ PPH_BYTES JsonArray ) { PPH_BYTES subRequestBuffer = NULL; PPH_HTTP_CONTEXT httpContext = NULL; PPH_STRING versionString = NULL; PPH_STRING userAgentString = NULL; PPH_STRING urlPathString = NULL; versionString = PhGetPhVersion(); userAgentString = PhConcatStrings2(L"ProcessHacker_", versionString->Buffer); if (!PhHttpSocketCreate(&httpContext, PhGetString(userAgentString))) goto CleanupExit; if (!PhHttpSocketConnect(httpContext, L"www.virustotal.com", PH_HTTP_DEFAULT_HTTPS_PORT)) goto CleanupExit; { PPH_BYTES resourceString = VirusTotalGetCachedDbHash(); urlPathString = PhFormatString( L"%s%s%s%s%S", L"/partners", L"/sysinternals", L"/file-reports", L"?\x0061\x0070\x0069\x006B\x0065\x0079=", resourceString->Buffer ); PhClearReference(&resourceString); } if (!PhHttpSocketBeginRequest( httpContext, L"POST", urlPathString->Buffer, PH_HTTP_FLAG_REFRESH | PH_HTTP_FLAG_SECURE )) { goto CleanupExit; } if (!PhHttpSocketAddRequestHeaders(httpContext, L"Content-Type: application/json", 0)) goto CleanupExit; if (!PhHttpSocketSendRequest(httpContext, JsonArray->Buffer, (ULONG)JsonArray->Length)) goto CleanupExit; if (!PhHttpSocketEndRequest(httpContext)) goto CleanupExit; if (!(subRequestBuffer = PhHttpSocketDownloadString(httpContext, FALSE))) goto CleanupExit; CleanupExit: if (httpContext) PhHttpSocketDestroy(httpContext); PhClearReference(&urlPathString); PhClearReference(&versionString); PhClearReference(&userAgentString); if (JsonArray) PhDereferenceObject(JsonArray); return subRequestBuffer; }
static NTSTATUS DownloadUpdateThreadStart( __in PVOID Parameter ) { PPH_STRING downloadUrlPath = NULL; HANDLE tempFileHandle = NULL; HINTERNET hInitialize = NULL, hConnection = NULL, hRequest = NULL; NTSTATUS status = STATUS_UNSUCCESSFUL; HWND hwndDlg = (HWND)Parameter; Button_Enable(GetDlgItem(hwndDlg, IDC_DOWNLOAD), FALSE); SetDlgItemText(hwndDlg, IDC_STATUS, L"Initializing"); // Reset the progress state on Vista and above. if (WindowsVersion > WINDOWS_XP) SendDlgItemMessage(hwndDlg, IDC_PROGRESS, PBM_SETSTATE, PBST_NORMAL, 0L); if (!ConnectionAvailable()) return status; __try { // Get temp dir. WCHAR tempPathString[MAX_PATH]; DWORD tempPathLength = GetTempPath(MAX_PATH, tempPathString); if (tempPathLength == 0 || tempPathLength > MAX_PATH) { LogEvent(hwndDlg, PhFormatString(L"CreateFile failed (%d)", GetLastError())); __leave; } // create the download path string. downloadUrlPath = PhFormatString( L"/projects/processhacker/files/processhacker2/processhacker-%u.%u-setup.exe/download?use_mirror=autoselect", /* ?use_mirror=waix" */ UpdateData.MajorVersion, UpdateData.MinorVersion ); // Append the tempath to our string: %TEMP%processhacker-%u.%u-setup.exe // Example: C:\\Users\\dmex\\AppData\\Temp\\processhacker-2.10-setup.exe SetupFilePath = PhFormatString( L"%sprocesshacker-%u.%u-setup.exe", tempPathString, UpdateData.MajorVersion, UpdateData.MinorVersion ); // Create output file status = PhCreateFileWin32( &tempFileHandle, SetupFilePath->Buffer, FILE_GENERIC_READ | FILE_GENERIC_WRITE, FILE_ATTRIBUTE_NOT_CONTENT_INDEXED | FILE_ATTRIBUTE_TEMPORARY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OVERWRITE_IF, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT ); if (!NT_SUCCESS(status)) { LogEvent(hwndDlg, PhFormatString(L"PhCreateFileWin32 failed (%s)", ((PPH_STRING)PHA_DEREFERENCE(PhGetNtMessage(status)))->Buffer)); __leave; } { // Create a user agent string. PPH_STRING phVersion = PhGetPhVersion(); PPH_STRING userAgent = PhConcatStrings2(L"PH Updater v", phVersion->Buffer); // Initialize the wininet library. if (!(hInitialize = InternetOpen( userAgent->Buffer, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0 ))) { LogEvent(hwndDlg, PhFormatString(L"Updater: (InitializeConnection) InternetOpen failed (%d)", GetLastError())); PhDereferenceObject(userAgent); PhDereferenceObject(phVersion); __leave; } PhDereferenceObject(userAgent); PhDereferenceObject(phVersion); } // Connect to the server. if (!(hConnection = InternetConnect( hInitialize, L"sourceforge.net", INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0))) { LogEvent(hwndDlg, PhFormatString(L"InternetConnect failed (%d)", GetLastError())); __leave; } // Open the HTTP request. if (!(hRequest = HttpOpenRequest( hConnection, NULL, downloadUrlPath->Buffer, NULL, NULL, NULL, INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_RESYNCHRONIZE, 0 ))) { LogEvent(hwndDlg, PhFormatString(L"HttpOpenRequest failed (%d)", GetLastError())); __leave; } SetDlgItemText(hwndDlg, IDC_STATUS, L"Connecting"); // Send the HTTP request. if (!HttpSendRequest(hRequest, NULL, 0, NULL, 0)) { LogEvent(hwndDlg, PhFormatString(L"HttpSendRequest failed (%d)", GetLastError())); // Enable the 'Retry' button. Button_Enable(GetDlgItem(hwndDlg, IDC_DOWNLOAD), TRUE); SetDlgItemText(hwndDlg, IDC_DOWNLOAD, L"Retry"); // Reset the state and let user retry the download. PhUpdaterState = Download; } else { BYTE hashBuffer[20]; DWORD contentLengthSize = sizeof(DWORD); PH_HASH_CONTEXT hashContext; // Initialize hash algorithm. PhInitializeHash(&hashContext, Sha1HashAlgorithm); if (!HttpQueryInfoW(hRequest, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &contentLength, &contentLengthSize, 0)) { // No content length...impossible to calculate % complete... // we can read the data, BUT in this instance Sourceforge always returns the content length // so instead we'll exit here instead of downloading the file. LogEvent(hwndDlg, PhFormatString(L"HttpQueryInfo failed (%d)", GetLastError())); __leave; } else { BYTE buffer[PAGE_SIZE]; DWORD bytesRead = 0, startTick = 0; IO_STATUS_BLOCK isb; // Zero the buffer. ZeroMemory(buffer, PAGE_SIZE); // Reset the counters. bytesDownloaded = 0, timeTransferred = 0, LastUpdateTime = 0; IsUpdating = FALSE; // Start the clock. startTick = GetTickCount(); timeTransferred = startTick; // Download the data. while (InternetReadFile(hRequest, buffer, PAGE_SIZE, &bytesRead)) { // If we get zero bytes, the file was uploaded or there was an error. if (bytesRead == 0) break; // If window closed and thread handle was closed, just dispose and exit. // (This also skips error checking/prompts and updating the disposed UI) if (!DownloadThreadHandle) __leave; // Update the hash of bytes we downloaded. PhUpdateHash(&hashContext, buffer, bytesRead); // Write the downloaded bytes to disk. status = NtWriteFile( tempFileHandle, NULL, NULL, NULL, &isb, buffer, bytesRead, NULL, NULL ); if (!NT_SUCCESS(status)) { PPH_STRING message = PhGetNtMessage(status); LogEvent(hwndDlg, PhFormatString(L"NtWriteFile failed (%s)", message->Buffer)); PhDereferenceObject(message); break; } // Check dwBytesRead are the same dwBytesWritten length returned by WriteFile. if (bytesRead != isb.Information) { PPH_STRING message = PhGetNtMessage(status); LogEvent(hwndDlg, PhFormatString(L"NtWriteFile failed (%s)", message->Buffer)); PhDereferenceObject(message); break; } // Update our total bytes downloaded PhAcquireQueuedLockExclusive(&Lock); bytesDownloaded += (DWORD)isb.Information; PhReleaseQueuedLockExclusive(&Lock); AsyncUpdate(); } // Check if we downloaded the entire file. assert(bytesDownloaded == contentLength); // Compute our hash result. if (PhFinalHash(&hashContext, &hashBuffer, 20, NULL)) { // Allocate our hash string, hex the final hash result in our hashBuffer. PPH_STRING hexString = PhBufferToHexString(hashBuffer, 20); if (PhEqualString(hexString, UpdateData.Hash, TRUE)) { // If PH is not elevated, set the UAC shield for the install button as the setup requires elevation. if (!PhElevated) SendMessage(GetDlgItem(hwndDlg, IDC_DOWNLOAD), BCM_SETSHIELD, 0, TRUE); // Set the download result, don't include hash status since it succeeded. //SetDlgItemText(hwndDlg, IDC_STATUS, L"Download Complete"); // Set button text for next action Button_SetText(GetDlgItem(hwndDlg, IDC_DOWNLOAD), L"Install"); // Enable the Install button Button_Enable(GetDlgItem(hwndDlg, IDC_DOWNLOAD), TRUE); // Hash succeeded, set state as ready to install. PhUpdaterState = Install; } else { if (WindowsVersion > WINDOWS_XP) SendDlgItemMessage(hwndDlg, IDC_PROGRESS, PBM_SETSTATE, PBST_ERROR, 0L); SetDlgItemText(hwndDlg, IDC_STATUS, L"Download complete, SHA1 Hash failed."); // Set button text for next action Button_SetText(GetDlgItem(hwndDlg, IDC_DOWNLOAD), L"Retry"); // Enable the Install button Button_Enable(GetDlgItem(hwndDlg, IDC_DOWNLOAD), TRUE); // Hash failed, reset state to downloading so user can redownload the file. PhUpdaterState = Download; } PhDereferenceObject(hexString); } else { //SetDlgItemText(hwndDlg, IDC_STATUS, L"PhFinalHash failed"); // Show fancy Red progressbar if hash failed on Vista and above. if (WindowsVersion > WINDOWS_XP) SendDlgItemMessage(hwndDlg, IDC_PROGRESS, PBM_SETSTATE, PBST_ERROR, 0L); } } } status = STATUS_SUCCESS; } __finally { if (hInitialize) { InternetCloseHandle(hInitialize); hInitialize = NULL; } if (hConnection) { InternetCloseHandle(hConnection); hConnection = NULL; } if (hRequest) { InternetCloseHandle(hRequest); hRequest = NULL; } if (tempFileHandle) { NtClose(tempFileHandle); tempFileHandle = NULL; } if (downloadUrlPath) { PhDereferenceObject(downloadUrlPath); downloadUrlPath = NULL; } } return status; }
static BOOL QueryXmlData( VOID ) { PCHAR data = NULL; BOOL isSuccess = FALSE; HINTERNET netInitialize = NULL, netConnection = NULL, netRequest = NULL; mxml_node_t *xmlDoc = NULL, *xmlNodeVer = NULL, *xmlNodeRelDate = NULL, *xmlNodeSize = NULL, *xmlNodeHash = NULL; // Create a user agent string. PPH_STRING phVersion = PhGetPhVersion(); PPH_STRING userAgent = PhConcatStrings2(L"PH Updater v", phVersion->Buffer); __try { // Initialize the wininet library. if (!(netInitialize = InternetOpen( userAgent->Buffer, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0 ))) { LogEvent(NULL, PhFormatString(L"Updater: (InitializeConnection) InternetOpen failed (%d)", GetLastError())); __leave; } // Connect to the server. if (!(netConnection = InternetConnect( netInitialize, UPDATE_URL, INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0 ))) { LogEvent(NULL, PhFormatString(L"Updater: (InitializeConnection) InternetConnect failed (%d)", GetLastError())); __leave; } // Open the HTTP request. if (!(netRequest = HttpOpenRequest( netConnection, L"GET", UPDATE_FILE, NULL, NULL, NULL, // wj32: do NOT cache --------------------------- Old - "Always cache the update xml, it can be cleared by deleting IE history, we configured the file to cache locally for two days." INTERNET_FLAG_RELOAD, 0 ))) { LogEvent(NULL, PhFormatString(L"Updater: (InitializeConnection) HttpOpenRequest failed (%d)", GetLastError())); __leave; } // Send the HTTP request. if (!HttpSendRequest(netRequest, NULL, 0, NULL, 0)) { LogEvent(NULL, PhFormatString(L"HttpSendRequest failed (%d)", GetLastError())); __leave; } // Read the resulting xml into our buffer. if (!ReadRequestString(netRequest, &data, NULL)) { // We don't need to log this. __leave; } // Load our XML. xmlDoc = mxmlLoadString(NULL, data, QueryXmlDataCallback); // Check our XML. if (xmlDoc == NULL || xmlDoc->type != MXML_ELEMENT) { LogEvent(NULL, PhCreateString(L"Updater: (WorkerThreadStart) mxmlLoadString failed.")); __leave; } // Find the ver node. xmlNodeVer = mxmlFindElement(xmlDoc, xmlDoc, "ver", NULL, NULL, MXML_DESCEND); // Find the reldate node. xmlNodeRelDate = mxmlFindElement(xmlDoc, xmlDoc, "reldate", NULL, NULL, MXML_DESCEND); // Find the size node. xmlNodeSize = mxmlFindElement(xmlDoc, xmlDoc, "size", NULL, NULL, MXML_DESCEND); // Find the hash node. xmlNodeHash = mxmlFindElement(xmlDoc, xmlDoc, "sha1", NULL, NULL, MXML_DESCEND); // Format strings into unicode PPH_STRING's UpdateData.Version = PhGetOpaqueXmlNodeText(xmlNodeVer); UpdateData.RelDate = PhGetOpaqueXmlNodeText(xmlNodeRelDate); UpdateData.Size = PhGetOpaqueXmlNodeText(xmlNodeSize); UpdateData.Hash = PhGetOpaqueXmlNodeText(xmlNodeHash); // parse and check string //if (!ParseVersionString(XmlData->Version->Buffer, &XmlData->MajorVersion, &XmlData->MinorVersion)) // __leave; if (!PhIsNullOrEmptyString(UpdateData.Version)) { PH_STRINGREF sr, majorPart, minorPart; ULONG64 majorInteger = 0, minorInteger = 0; PhInitializeStringRef(&sr, UpdateData.Version->Buffer); if (PhSplitStringRefAtChar(&sr, '.', &majorPart, &minorPart)) { PhStringToInteger64(&majorPart, 10, &majorInteger); PhStringToInteger64(&minorPart, 10, &minorInteger); UpdateData.MajorVersion = (ULONG)majorInteger; UpdateData.MinorVersion = (ULONG)minorInteger; isSuccess = TRUE; } } } __finally { if (xmlDoc) { mxmlDelete(xmlDoc); xmlDoc = NULL; } if (netInitialize) { InternetCloseHandle(netInitialize); netInitialize = NULL; } if (netConnection) { InternetCloseHandle(netConnection); netConnection = NULL; } if (netRequest) { InternetCloseHandle(netRequest); netRequest = NULL; } if (userAgent) { PhDereferenceObject(userAgent); userAgent = NULL; } if (phVersion) { PhDereferenceObject(phVersion); phVersion = NULL; } } return isSuccess; }
PVIRUSTOTAL_FILE_REPORT_RESULT VirusTotalSendHttpFileReportRequest( _In_ PPH_STRING FileHash ) { NTSTATUS status = STATUS_SUCCESS; HANDLE fileHandle = INVALID_HANDLE_VALUE; HINTERNET httpSessionHandle = NULL; HINTERNET connectHandle = NULL; HINTERNET requestHandle = NULL; PSTR subRequestBuffer = NULL; PPH_STRING phVersion = NULL; PPH_STRING userAgent = NULL; PPH_STRING urlString = NULL; phVersion = PhGetPhVersion(); userAgent = PhConcatStrings2(L"ProcessHacker_", phVersion->Buffer); if (!(httpSessionHandle = WinHttpOpen( userAgent->Buffer, WindowsVersion >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0 ))) { goto CleanupExit; } if (WindowsVersion >= WINDOWS_8_1) { WinHttpSetOption( httpSessionHandle, WINHTTP_OPTION_DECOMPRESSION, &(ULONG){ WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE }, sizeof(ULONG) ); } if (!(connectHandle = WinHttpConnect( httpSessionHandle, L"www.virustotal.com", INTERNET_DEFAULT_HTTPS_PORT, 0 ))) { goto CleanupExit; } PPH_BYTES resourceString = VirusTotalGetCachedDbHash(); urlString = PhFormatString( L"%s%s%s%s%S%s%s", L"/vtapi", L"/v2", L"/file", L"/report", L"?apikey=", resourceString->Buffer, L"&resource=", PhGetString(FileHash) ); PhClearReference(&resourceString); if (!(requestHandle = WinHttpOpenRequest( connectHandle, L"POST", PhGetString(urlString), NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE ))) { goto CleanupExit; } if (!WinHttpAddRequestHeaders(requestHandle, L"Content-Type: application/json", -1L, 0)) goto CleanupExit; if (!WinHttpSendRequest( requestHandle, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH, 0 )) { goto CleanupExit; } if (WinHttpReceiveResponse(requestHandle, NULL)) { BYTE buffer[PAGE_SIZE]; ULONG allocatedLength; ULONG dataLength; ULONG returnLength; allocatedLength = sizeof(buffer); subRequestBuffer = PhAllocate(allocatedLength); dataLength = 0; while (WinHttpReadData(requestHandle, buffer, PAGE_SIZE, &returnLength)) { if (returnLength == 0) break; if (allocatedLength < dataLength + returnLength) { allocatedLength *= 2; subRequestBuffer = PhReAllocate(subRequestBuffer, allocatedLength); } memcpy(subRequestBuffer + dataLength, buffer, returnLength); dataLength += returnLength; } if (allocatedLength < dataLength + 1) { allocatedLength++; subRequestBuffer = PhReAllocate(subRequestBuffer, allocatedLength); } subRequestBuffer[dataLength] = 0; } CleanupExit: PhClearReference(&urlString); if (requestHandle) WinHttpCloseHandle(requestHandle); if (connectHandle) WinHttpCloseHandle(connectHandle); if (httpSessionHandle) WinHttpCloseHandle(httpSessionHandle); PVOID jsonRootObject; //PVOID jsonScanObject; PVIRUSTOTAL_FILE_REPORT_RESULT result; if (!(jsonRootObject = CreateJsonParser(subRequestBuffer))) goto CleanupExit; if (!GetJsonValueAsUlong(jsonRootObject, "response_code")) goto CleanupExit; result = PhAllocate(sizeof(VIRUSTOTAL_FILE_REPORT_RESULT)); memset(result, 0, sizeof(VIRUSTOTAL_FILE_REPORT_RESULT)); result->Total = PhFormatUInt64(GetJsonValueAsUlong(jsonRootObject, "total"), FALSE); result->Positives = PhFormatUInt64(GetJsonValueAsUlong(jsonRootObject, "positives"), FALSE); result->Resource = PhZeroExtendToUtf16(GetJsonValueAsString(jsonRootObject, "resource")); result->ScanId = PhZeroExtendToUtf16(GetJsonValueAsString(jsonRootObject, "scan_id")); result->Md5 = PhZeroExtendToUtf16(GetJsonValueAsString(jsonRootObject, "md5")); result->Sha1 = PhZeroExtendToUtf16(GetJsonValueAsString(jsonRootObject, "sha1")); result->Sha256 = PhZeroExtendToUtf16(GetJsonValueAsString(jsonRootObject, "sha256")); result->ScanDate = PhZeroExtendToUtf16(GetJsonValueAsString(jsonRootObject, "scan_date")); result->Permalink = PhZeroExtendToUtf16(GetJsonValueAsString(jsonRootObject, "permalink")); result->StatusMessage = PhZeroExtendToUtf16(GetJsonValueAsString(jsonRootObject, "verbose_msg")); //if (jsonScanObject = JsonGetObject(jsonRootObject, "scans")) //{ // PPH_LIST jsonArrayList; // // if (jsonArrayList = JsonGetObjectArrayList(jsonScanObject)) // { // result->ScanResults = PhCreateList(jsonArrayList->Count); // // for (ULONG i = 0; i < jsonArrayList->Count; i++) // { // PJSON_ARRAY_LIST_OBJECT object = jsonArrayList->Items[i]; // //BOOLEAN detected = GetJsonValueAsBool(object->Entry, "detected") == TRUE; // //PSTR version = GetJsonValueAsString(object->Entry, "version"); // //PSTR result = GetJsonValueAsString(object->Entry, "result"); // //PSTR update = GetJsonValueAsString(object->Entry, "update"); // // PhFree(object); // } // // PhDereferenceObject(jsonArrayList); // } //} return result; }
PSTR VirusTotalSendHttpRequest( _In_ PPH_BYTES JsonArray ) { HANDLE fileHandle = INVALID_HANDLE_VALUE; HINTERNET httpSessionHandle = NULL; HINTERNET connectHandle = NULL; HINTERNET requestHandle = NULL; PSTR subRequestBuffer = NULL; PPH_STRING phVersion = NULL; PPH_STRING userAgent = NULL; PPH_STRING urlString = NULL; phVersion = PhGetPhVersion(); userAgent = PhConcatStrings2(L"ProcessHacker_", phVersion->Buffer); if (!(httpSessionHandle = WinHttpOpen( userAgent->Buffer, WindowsVersion >= WINDOWS_8_1 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0 ))) { goto CleanupExit; } if (WindowsVersion >= WINDOWS_8_1) { WinHttpSetOption( httpSessionHandle, WINHTTP_OPTION_DECOMPRESSION, &(ULONG){ WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE }, sizeof(ULONG) ); } if (!(connectHandle = WinHttpConnect( httpSessionHandle, L"www.virustotal.com", INTERNET_DEFAULT_HTTPS_PORT, 0 ))) { goto CleanupExit; } PPH_BYTES resourceString = VirusTotalGetCachedDbHash(); urlString = PhFormatString( L"%s%s%s%s%S", L"/partners", L"/sysinternals", L"/file-reports", L"?apikey=", resourceString->Buffer ); PhClearReference(&resourceString); if (!(requestHandle = WinHttpOpenRequest( connectHandle, L"POST", PhGetString(urlString), NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE ))) { PhClearReference(&urlString); goto CleanupExit; } PhClearReference(&urlString); if (!WinHttpAddRequestHeaders(requestHandle, L"Content-Type: application/json", -1L, 0)) { goto CleanupExit; } if (!WinHttpSendRequest( requestHandle, WINHTTP_NO_ADDITIONAL_HEADERS, 0, JsonArray->Buffer, (ULONG)JsonArray->Length, (ULONG)JsonArray->Length, 0 )) { goto CleanupExit; } if (WinHttpReceiveResponse(requestHandle, NULL)) { BYTE buffer[PAGE_SIZE]; ULONG allocatedLength; ULONG dataLength; ULONG returnLength; allocatedLength = sizeof(buffer); subRequestBuffer = PhAllocate(allocatedLength); dataLength = 0; while (WinHttpReadData(requestHandle, buffer, PAGE_SIZE, &returnLength)) { if (returnLength == 0) break; if (allocatedLength < dataLength + returnLength) { allocatedLength *= 2; subRequestBuffer = PhReAllocate(subRequestBuffer, allocatedLength); } memcpy(subRequestBuffer + dataLength, buffer, returnLength); dataLength += returnLength; } if (allocatedLength < dataLength + 1) { allocatedLength++; subRequestBuffer = PhReAllocate(subRequestBuffer, allocatedLength); } // Ensure that the buffer is null-terminated. subRequestBuffer[dataLength] = 0; } CleanupExit: if (requestHandle) WinHttpCloseHandle(requestHandle); if (connectHandle) WinHttpCloseHandle(connectHandle); if (httpSessionHandle) WinHttpCloseHandle(httpSessionHandle); if (JsonArray) PhDereferenceObject(JsonArray); return subRequestBuffer; }
NTSTATUS NetworkPingThreadStart( _In_ PVOID Parameter ) { HANDLE icmpHandle = INVALID_HANDLE_VALUE; ULONG icmpCurrentPingMs = 0; ULONG icmpReplyCount = 0; ULONG icmpReplyLength = 0; PVOID icmpReplyBuffer = NULL; PPH_BYTES icmpEchoBuffer = NULL; IP_OPTION_INFORMATION pingOptions = { 255, // Time To Live 0, // Type Of Service IP_FLAG_DF, // IP header flags 0 // Size of options data }; PNETWORK_OUTPUT_CONTEXT context = (PNETWORK_OUTPUT_CONTEXT)Parameter; __try { // Create ICMP echo buffer. if (context->PingSize > 0 && context->PingSize != 32) { PPH_STRING randString; randString = PhCreateStringEx(NULL, context->PingSize * 2 + 2); // Create a random string to fill the buffer. PhGenerateRandomAlphaString(randString->Buffer, (ULONG)randString->Length / sizeof(WCHAR)); icmpEchoBuffer = PhConvertUtf16ToMultiByte(randString->Buffer); PhDereferenceObject(randString); } else { PPH_STRING version; // We're using a default length, query the PH version and use the previous buffer format. version = PhGetPhVersion(); if (version) { icmpEchoBuffer = FormatAnsiString("processhacker_%S_0x0D06F00D_x1", version->Buffer); PhDereferenceObject(version); } } if (context->IpAddress.Type == PH_IPV6_NETWORK_TYPE) { SOCKADDR_IN6 icmp6LocalAddr = { 0 }; SOCKADDR_IN6 icmp6RemoteAddr = { 0 }; PICMPV6_ECHO_REPLY2 icmp6ReplyStruct = NULL; // Create ICMPv6 handle. if ((icmpHandle = Icmp6CreateFile()) == INVALID_HANDLE_VALUE) __leave; // Set Local IPv6-ANY address. icmp6LocalAddr.sin6_addr = in6addr_any; icmp6LocalAddr.sin6_family = AF_INET6; // Set Remote IPv6 address. icmp6RemoteAddr.sin6_addr = context->IpAddress.In6Addr; icmp6RemoteAddr.sin6_port = _byteswap_ushort((USHORT)context->NetworkItem->RemoteEndpoint.Port); // Allocate ICMPv6 message. icmpReplyLength = ICMP_BUFFER_SIZE(sizeof(ICMPV6_ECHO_REPLY), icmpEchoBuffer); icmpReplyBuffer = PhAllocate(icmpReplyLength); memset(icmpReplyBuffer, 0, icmpReplyLength); InterlockedIncrement(&context->PingSentCount); // Send ICMPv6 ping... icmpReplyCount = Icmp6SendEcho2( icmpHandle, NULL, NULL, NULL, &icmp6LocalAddr, &icmp6RemoteAddr, icmpEchoBuffer->Buffer, (USHORT)icmpEchoBuffer->Length, &pingOptions, icmpReplyBuffer, icmpReplyLength, context->MaxPingTimeout ); icmp6ReplyStruct = (PICMPV6_ECHO_REPLY2)icmpReplyBuffer; if (icmpReplyCount > 0 && icmp6ReplyStruct) { BOOLEAN icmpPacketSignature = FALSE; if (icmp6ReplyStruct->Status != IP_SUCCESS) { InterlockedIncrement(&context->PingLossCount); } if (_memicmp( icmp6ReplyStruct->Address.sin6_addr, context->IpAddress.In6Addr.u.Word, sizeof(icmp6ReplyStruct->Address.sin6_addr) ) != 0) { InterlockedIncrement(&context->UnknownAddrCount); } icmpPacketSignature = _memicmp( icmpEchoBuffer->Buffer, icmp6ReplyStruct->Data, icmpEchoBuffer->Length ) == 0; if (!icmpPacketSignature) { InterlockedIncrement(&context->HashFailCount); } icmpCurrentPingMs = icmp6ReplyStruct->RoundTripTime; } else { InterlockedIncrement(&context->PingLossCount); } } else { IPAddr icmpLocalAddr = 0; IPAddr icmpRemoteAddr = 0; PICMP_ECHO_REPLY icmpReplyStruct = NULL; // Create ICMPv4 handle. if ((icmpHandle = IcmpCreateFile()) == INVALID_HANDLE_VALUE) __leave; // Set Local IPv4-ANY address. icmpLocalAddr = in4addr_any.s_addr; // Set Remote IPv4 address. icmpRemoteAddr = context->IpAddress.InAddr.s_addr; // Allocate ICMPv4 message. icmpReplyLength = ICMP_BUFFER_SIZE(sizeof(ICMP_ECHO_REPLY), icmpEchoBuffer); icmpReplyBuffer = PhAllocate(icmpReplyLength); memset(icmpReplyBuffer, 0, icmpReplyLength); InterlockedIncrement(&context->PingSentCount); // Send ICMPv4 ping... icmpReplyCount = IcmpSendEcho2Ex( icmpHandle, NULL, NULL, NULL, icmpLocalAddr, icmpRemoteAddr, icmpEchoBuffer->Buffer, (USHORT)icmpEchoBuffer->Length, &pingOptions, icmpReplyBuffer, icmpReplyLength, context->MaxPingTimeout ); icmpReplyStruct = (PICMP_ECHO_REPLY)icmpReplyBuffer; if (icmpReplyStruct && icmpReplyCount > 0) { BOOLEAN icmpPacketSignature = FALSE; if (icmpReplyStruct->Status != IP_SUCCESS) { InterlockedIncrement(&context->PingLossCount); } if (icmpReplyStruct->Address != context->IpAddress.InAddr.s_addr) { InterlockedIncrement(&context->UnknownAddrCount); } if (icmpReplyStruct->DataSize == icmpEchoBuffer->Length) { icmpPacketSignature = _memicmp( icmpEchoBuffer->Buffer, icmpReplyStruct->Data, icmpReplyStruct->DataSize ) == 0; } icmpCurrentPingMs = icmpReplyStruct->RoundTripTime; if (!icmpPacketSignature) { InterlockedIncrement(&context->HashFailCount); } } else { InterlockedIncrement(&context->PingLossCount); } } InterlockedIncrement(&context->PingRecvCount); if (context->PingMinMs == 0 || icmpCurrentPingMs < context->PingMinMs) context->PingMinMs = icmpCurrentPingMs; if (icmpCurrentPingMs > context->PingMaxMs) context->PingMaxMs = icmpCurrentPingMs; context->CurrentPingMs = icmpCurrentPingMs; PhAddItemCircularBuffer_ULONG(&context->PingHistory, icmpCurrentPingMs); } __finally { if (icmpEchoBuffer) { PhDereferenceObject(icmpEchoBuffer); } if (icmpHandle != INVALID_HANDLE_VALUE) { IcmpCloseHandle(icmpHandle); } if (icmpReplyBuffer) { PhFree(icmpReplyBuffer); } } PostMessage(context->WindowHandle, WM_PING_UPDATE, 0, 0); return STATUS_SUCCESS; }
static NTSTATUS PhNetworkPingThreadStart( _In_ PVOID Parameter ) { HANDLE icmpHandle = INVALID_HANDLE_VALUE; ULONG icmpCurrentPingMs = 0; ULONG icmpCurrentPingTtl = 0; ULONG icmpReplyCount = 0; ULONG icmpReplyLength = 0; PVOID icmpReplyBuffer = NULL; PPH_STRING phVersion = NULL; PPH_BYTES icmpEchoBuffer = NULL; IP_OPTION_INFORMATION pingOptions = { 255, // Time To Live 0, // Type Of Service IP_FLAG_DF, // IP header flags 0 // Size of options data }; PNETWORK_OUTPUT_CONTEXT context = (PNETWORK_OUTPUT_CONTEXT)Parameter; __try { // Query PH version. if ((phVersion = PhGetPhVersion()) == NULL) __leave; // Create ICMP echo buffer. if ((icmpEchoBuffer = PhFormatAnsiString("processhacker_%S_0x0D06F00D_x1", phVersion->Buffer)) == NULL) __leave; if (context->IpAddress.Type == PH_IPV6_NETWORK_TYPE) { SOCKADDR_IN6 icmp6LocalAddr = { 0 }; SOCKADDR_IN6 icmp6RemoteAddr = { 0 }; PICMPV6_ECHO_REPLY icmp6ReplyStruct = NULL; // Create ICMPv6 handle. if ((icmpHandle = Icmp6CreateFile()) == INVALID_HANDLE_VALUE) __leave; // Set Local IPv6-ANY address. icmp6LocalAddr.sin6_addr = in6addr_any; icmp6LocalAddr.sin6_family = AF_INET6; // Set Remote IPv6 address. icmp6RemoteAddr.sin6_addr = context->IpAddress.In6Addr; icmp6RemoteAddr.sin6_port = _byteswap_ushort((USHORT)context->NetworkItem->RemoteEndpoint.Port); // Allocate ICMPv6 message. icmpReplyLength = ICMP_BUFFER_SIZE(sizeof(ICMPV6_ECHO_REPLY), icmpEchoBuffer); icmpReplyBuffer = PhAllocate(icmpReplyLength); memset(icmpReplyBuffer, 0, icmpReplyLength); InterlockedIncrement(&context->PingSentCount); // Send ICMPv6 ping... icmpReplyCount = Icmp6SendEcho2( icmpHandle, NULL, NULL, NULL, &icmp6LocalAddr, &icmp6RemoteAddr, icmpEchoBuffer->Buffer, (USHORT)icmpEchoBuffer->Length, &pingOptions, icmpReplyBuffer, icmpReplyLength, context->MaxPingTimeout ); icmp6ReplyStruct = (PICMPV6_ECHO_REPLY)icmpReplyBuffer; if (icmpReplyCount > 0 && icmp6ReplyStruct) { BOOLEAN icmpPacketSignature = FALSE; if (icmp6ReplyStruct->Status != IP_SUCCESS) { InterlockedIncrement(&context->PingLossCount); } if (_memicmp( icmp6ReplyStruct->Address.sin6_addr, context->IpAddress.In6Addr.u.Word, sizeof(icmp6ReplyStruct->Address.sin6_addr) ) != 0) { InterlockedIncrement(&context->UnknownAddrCount); } //if (icmp6ReplyStruct->DataSize == icmpEchoBuffer->MaximumLength) //{ // icmpPacketSignature = (_memicmp( // icmpEchoBuffer->Buffer, // icmp6ReplyStruct->Data, // icmp6ReplyStruct->DataSize // ) == 0); //} //if (icmpPacketSignature != TRUE) //{ // InterlockedIncrement(&context->HashFailCount); //} icmpCurrentPingMs = icmp6ReplyStruct->RoundTripTime; //icmpCurrentPingTtl = icmp6ReplyStruct->Options.Ttl; } else { InterlockedIncrement(&context->PingLossCount); } } else { IPAddr icmpLocalAddr = 0; IPAddr icmpRemoteAddr = 0; PICMP_ECHO_REPLY icmpReplyStruct = NULL; // Create ICMPv4 handle. if ((icmpHandle = IcmpCreateFile()) == INVALID_HANDLE_VALUE) __leave; // Set Local IPv4-ANY address. icmpLocalAddr = in4addr_any.s_addr; // Set Remote IPv4 address. icmpRemoteAddr = context->IpAddress.InAddr.s_addr; // Allocate ICMPv4 message. icmpReplyLength = ICMP_BUFFER_SIZE(sizeof(ICMP_ECHO_REPLY), icmpEchoBuffer); icmpReplyBuffer = PhAllocate(icmpReplyLength); memset(icmpReplyBuffer, 0, icmpReplyLength); InterlockedIncrement(&context->PingSentCount); // Send ICMPv4 ping... //if (WindowsVersion > WINDOWS_VISTA) //{ // // Vista SP1 and up we can specify the source address: // icmpReplyCount = IcmpSendEcho2Ex( // icmpHandle, // NULL, // NULL, // NULL, // icmpLocalAddr, // icmpRemoteAddr, // icmpEchoBuffer->Buffer, // icmpEchoBuffer->MaximumLength, // &pingOptions, // icmpReplyBuffer, // icmpReplyLength, // context->MaxPingTimeout // ); //} icmpReplyCount = IcmpSendEcho2( icmpHandle, NULL, NULL, NULL, icmpRemoteAddr, icmpEchoBuffer->Buffer, (USHORT)icmpEchoBuffer->Length, &pingOptions, icmpReplyBuffer, icmpReplyLength, context->MaxPingTimeout ); icmpReplyStruct = (PICMP_ECHO_REPLY)icmpReplyBuffer; if (icmpReplyStruct && icmpReplyCount > 0) { BOOLEAN icmpPacketSignature = FALSE; if (icmpReplyStruct->Status != IP_SUCCESS) { InterlockedIncrement(&context->PingLossCount); } if (icmpReplyStruct->Address != context->IpAddress.InAddr.s_addr) { InterlockedIncrement(&context->UnknownAddrCount); } if (icmpReplyStruct->DataSize == icmpEchoBuffer->Length) { icmpPacketSignature = (_memicmp( icmpEchoBuffer->Buffer, icmpReplyStruct->Data, icmpReplyStruct->DataSize ) == 0); } icmpCurrentPingMs = icmpReplyStruct->RoundTripTime; icmpCurrentPingTtl = icmpReplyStruct->Options.Ttl; if (!icmpPacketSignature) { InterlockedIncrement(&context->HashFailCount); } } else { InterlockedIncrement(&context->PingLossCount); } } InterlockedIncrement(&context->PingRecvCount); if (context->PingMinMs == 0 || icmpCurrentPingMs < context->PingMinMs) context->PingMinMs = icmpCurrentPingMs; if (icmpCurrentPingMs > context->PingMaxMs) context->PingMaxMs = icmpCurrentPingMs; context->CurrentPingMs = icmpCurrentPingMs; PhAddItemCircularBuffer_ULONG(&context->PingHistory, icmpCurrentPingMs); } __finally { if (phVersion) { PhDereferenceObject(phVersion); } if (icmpEchoBuffer) { PhDereferenceObject(icmpEchoBuffer); } if (icmpHandle != INVALID_HANDLE_VALUE) { IcmpCloseHandle(icmpHandle); } if (icmpReplyBuffer) { PhFree(icmpReplyBuffer); } } PostMessage(context->WindowHandle, WM_PING_UPDATE, 0, 0); return STATUS_SUCCESS; }