PPH_BYTES VirusTotalGetCachedDbHash( VOID ) { ULONG length; PUCHAR buffer; PPH_BYTES string; length = (ULONG)ProcessObjectDbHash.Length / sizeof(WCHAR) / 2; buffer = PhAllocate(length + 1); memset(buffer, 0, length + 1); PhHexStringToBuffer(&ProcessObjectDbHash, buffer); string = PhCreateBytes(buffer); for (SIZE_T i = 0; i < string->Length; i++) string->Buffer[i] = string->Buffer[i] ^ 0x0D06F00D; PhFree(buffer); return string; }
NTSTATUS NTAPI VirusTotalProcessApiThread( _In_ PVOID Parameter ) { LONG priority; IO_PRIORITY_HINT ioPriority; // TODO: Workqueue support. priority = THREAD_PRIORITY_LOWEST; ioPriority = IoPriorityVeryLow; NtSetInformationThread(NtCurrentThread(), ThreadBasePriority, &priority, sizeof(LONG)); NtSetInformationThread(NtCurrentThread(), ThreadIoPriority, &ioPriority, sizeof(IO_PRIORITY_HINT)); Sleep(10 * 1000); do { ULONG i; INT64 resultLength; PSTR jsonArrayToSendString; PSTR jsonApiResult = NULL; PVOID jsonArray; PVOID rootJsonObject = NULL; PVOID dataJsonObject; PPH_LIST resultTempList = NULL; PPH_LIST virusTotalResults = NULL; jsonArray = CreateJsonArray(); resultTempList = PhCreateList(30); PhAcquireQueuedLockExclusive(&ProcessListLock); for (i = 0; i < VirusTotalList->Count; i++) { PVIRUSTOTAL_FILE_HASH_ENTRY extension = VirusTotalList->Items[i]; if (resultTempList->Count >= 30) break; if (!extension->Stage1) { extension->Stage1 = TRUE; PhAddItemList(resultTempList, extension); } } PhReleaseQueuedLockExclusive(&ProcessListLock); if (resultTempList->Count == 0) { Sleep(30 * 1000); // Wait 30 seconds goto CleanupExit; } for (i = 0; i < resultTempList->Count; i++) { VirusTotalBuildJsonArray(resultTempList->Items[i], jsonArray); } if (!(jsonArrayToSendString = GetJsonArrayString(jsonArray))) goto CleanupExit; if (!(jsonApiResult = VirusTotalSendHttpRequest(PhCreateBytes(jsonArrayToSendString)))) goto CleanupExit; if (!(rootJsonObject = CreateJsonParser(jsonApiResult))) goto CleanupExit; if (!(dataJsonObject = JsonGetObject(rootJsonObject, "data"))) goto CleanupExit; if (!(resultLength = GetJsonValueAsUlong(rootJsonObject, "result"))) goto CleanupExit; if (virusTotalResults = VirusTotalJsonToResultList(dataJsonObject)) { for (i = 0; i < virusTotalResults->Count; i++) { PVIRUSTOTAL_API_RESULT result = virusTotalResults->Items[i]; if (result->Found) { PVIRUSTOTAL_FILE_HASH_ENTRY entry = VirusTotalGetCachedResultFromHash(result->FileHash); if (entry && !entry->Processed) { entry->Processed = TRUE; entry->Found = result->Found; entry->Positives = result->Positives; entry->Total = result->Total; if (!FindProcessDbObject(&entry->FileName->sr)) { CreateProcessDbObject( entry->FileName, entry->Positives, entry->Total, result->FileHash ); } } } } } CleanupExit: if (virusTotalResults) { for (i = 0; i < virusTotalResults->Count; i++) { PVIRUSTOTAL_API_RESULT result = virusTotalResults->Items[i]; // PhClearReference(&result->Permalink); // PhClearReference(&result->FileHash); // PhClearReference(&result->DetectionRatio); // PhFree(result); } PhDereferenceObject(virusTotalResults); } if (rootJsonObject) { CleanupJsonParser(rootJsonObject); } if (jsonArray) { CleanupJsonParser(jsonArray); } if (jsonApiResult) { PhFree(jsonApiResult); } if (resultTempList) { // Re-queue items without any results from VirusTotal. //for (i = 0; i < resultTempList->Count; i++) //{ // PVIRUSTOTAL_FILE_HASH_ENTRY result = resultTempList->Items[i]; // PPROCESS_EXTENSION extension = result->Extension; // // if (extension->Retries > 3) // continue; // // if (PhIsNullOrEmptyString(result->FileResult)) // { // extension->Stage1 = FALSE; // } // // extension->Retries++; //} PhDereferenceObject(resultTempList); } Sleep(5 * 1000); // Wait 5 seconds } while (VirusTotalHandle); return STATUS_SUCCESS; }