int CTimer::RandomSeed() { #ifdef _WIN32 return GetPerformanceCount() / GetFrequency(); #else return 0; #endif }
DWORD WINAPI ep_DriverService(void *arg) { const CONFIG_DATA *cd = GetConfigData(); SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); // Build the threadpool POOL_DATA pd; ZeroMemory(&pd, sizeof(POOL_DATA)); pd.hSharedDriverHandle = g_hDriver; const DWORD dwNumChannels = NUM_EVENTTYPES-1; // -1 to ignore EVENT_NONE THREADPOOL *tp = ThreadPoolAlloc(cd->dThreadPoolSize, dwNumChannels, PfWorkerInit, PfWorkerWork, PfWorkerDestroy, &pd, sizeof(WORKER_DATA), THREAD_PRIORITY_NORMAL); if (!tp) Die("Unable to allocate threadpool"); // Create the read file event for use with overlapped I/O HANDLE hReadFileEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (hReadFileEvent == NULL) Die("Unable to create read file event"); // Allocate memory for the buffer to be read from the kernel PROCFILTER_REQUEST *req = (PROCFILTER_REQUEST*)_malloca(PROCFILTER_REQUEST_SIZE); while (true) { if (WaitForSingleObject(g_hStopTheadEvent, 0) == WAIT_OBJECT_0) break; // Read request from driver using synch/asynch calls according to https://support.microsoft.com/en-us/kb/156932 DWORD dwBytesRead = 0; OVERLAPPED overlapped; ZeroMemory(&overlapped, sizeof(OVERLAPPED)); ResetEvent(hReadFileEvent); overlapped.hEvent = hReadFileEvent; BOOL rc = ReadFile(g_hDriver, req, PROCFILTER_REQUEST_SIZE, &dwBytesRead, &overlapped); DWORD dwErrorCode = GetLastError(); if (rc) { // Successfully completed a synchronous read, do nothing } else if (dwErrorCode == ERROR_IO_PENDING) { // Successfully completed an asynchronous read, so wait for it DWORD dwNumberOfBytesTransferred = 0; if (!GetOverlappedResult(g_hDriver, &overlapped, &dwNumberOfBytesTransferred, TRUE)) { dwErrorCode = GetLastError(); if (dwErrorCode == ERROR_OPERATION_ABORTED || dwErrorCode == ERROR_INVALID_HANDLE) break; // Cancel the pending IO to ensure the IO operation does not complete after this function ends // and the result is stored to an invalid location CancelIo(g_hDriver); Die("GetOverlappedResult() failure in reader: %d", dwErrorCode); } dwErrorCode = GetLastError(); dwBytesRead = dwNumberOfBytesTransferred; } else if (dwErrorCode == ERROR_OPERATION_ABORTED || dwErrorCode == ERROR_INVALID_HANDLE) { break; } else { Die("Unable to read data from driver: %d / %ls", dwErrorCode, ErrorText(dwErrorCode)); } LogDebugFmt("Read event from driver: PID:%u Event:%u", req->dwProcessId, req->dwEventType); ULONG64 ulStartPerformanceCount = GetPerformanceCount(); // Validate the size of data read if (dwBytesRead < sizeof(PROCFILTER_REQUEST) || dwBytesRead > PROCFILTER_REQUEST_SIZE) { Die("Read invalid size from driver device: %u < %u || %u > %u ReadFile:%hs ErrorCode:%d", dwBytesRead, sizeof(PROCFILTER_REQUEST), dwBytesRead, PROCFILTER_REQUEST_SIZE, rc ? "TRUE" : "FALSE", dwErrorCode); } if (dwBytesRead != req->dwRequestSize) { Die("Read partial packet from driver device: Read:%u PacketSize:%u", dwBytesRead, req->dwRequestSize); } // Post a copy of the retrieved data to a worker thread LogDebug("Posting work task to worker"); // Allocate memory for the task data, the structure of which includes only the header portion of the procfilter request, // so allocate only the exact size needed WORKER_TASK_DATA *wtd = (WORKER_TASK_DATA*)malloc(sizeof(WORKER_TASK_DATA) + (dwBytesRead - sizeof(PROCFILTER_REQUEST))); if (!wtd) Die("Memory allocation failure for ProcFilter request"); memcpy(&wtd->peProcFilterRequest, req, dwBytesRead); wtd->ulStartPerformanceCount = ulStartPerformanceCount; LogDebugFmt("Posting to threadpool: PID:%u Event:%u", req->dwProcessId, req->dwEventType); if (ThreadPoolPost(tp, req->dwEventType, false, g_hStopTheadEvent, wtd)) { LogDebug("Posted work task to worker"); } else { LogDebugFmt("Failed to post task to worker"); free(wtd); } } _freea(req); ThreadPoolFree(tp); CloseHandle(hReadFileEvent); // Driver closing is done here since this thread could terminate due to an error situation // and if closing were done elsewhere (such as service exit) the driver device would be kept open, consequently // blocking process creation events until service shutdown CloseHandle(g_hDriver); g_hDriver = INVALID_HANDLE_VALUE; return 0; }
// // Perform the scanning as specified in the various input parameters // void Scan(DWORD dwEventType, int dScanContext, PROCFILTER_EVENT *e, YARASCAN_CONTEXT *ctx, HANDLE hDriver, HANDLE hWriteCompletionEvent, DWORD dwProcessId, DWORD dwParentProcessId, WCHAR *lpszFileName, void *lpImageBase, void *lpvScanDataArray) { if (!lpszFileName) return; LONG64 llStart = GetPerformanceCount(); CONFIG_DATA *cd = GetConfigData(); bool bScanFile = false; bool bScanMemory = false; bool bBlock = false; bool bLog = false; bool bQuarantine = false; // Pull the scan parameters out of config if (dScanContext == PROCFILTER_SCAN_CONTEXT_PROCESS_CREATE) { bScanFile = cd->bScanFileOnProcessCreate; bScanMemory = cd->bScanMemoryOnProcessCreate; } else if (dScanContext == PROCFILTER_SCAN_CONTEXT_PROCESS_TERMINATE) { bScanFile = cd->bScanFileOnProcessTerminate; bScanMemory = cd->bScanMemoryOnProcessTerminate; } else if (dScanContext == PROCFILTER_SCAN_CONTEXT_PERIODIC_SCAN) { bScanFile = cd->bScanFileOnPeriodic; bScanMemory = cd->bScanMemoryOnPeriodic; } else if (dScanContext == PROCFILTER_SCAN_CONTEXT_IMAGE_LOAD) { bScanFile = cd->bScanFileOnImageLoad; bScanMemory = cd->bScanMemoryOnImageLoad; } else { Die("Invalid context passed to Scan(): %d", dScanContext); } // Initialize the API event with the passed-in parameters ApiEventReinit(e, PROCFILTER_EVENT_YARA_SCAN_INIT); e->dwProcessId = dwProcessId; e->dwParentProcessId = dwParentProcessId; e->lpszFileName = lpszFileName; e->dScanContext = dScanContext; e->bScanFile = bScanFile; e->bScanMemory = bScanMemory; e->lpvScanData = lpvScanDataArray; // Export the event to the API and handle the result flags DWORD dwPluginResultFlags = ApiEventExport(e); if (dwPluginResultFlags & PROCFILTER_RESULT_BLOCK_PROCESS) bBlock = true; if (dwPluginResultFlags & PROCFILTER_RESULT_DONT_SCAN_MEMORY) bScanMemory = false; if (dwPluginResultFlags & PROCFILTER_RESULT_FORCE_SCAN_MEMORY) bScanMemory = true; if (dwPluginResultFlags & PROCFILTER_RESULT_DONT_SCAN_FILE) bScanFile = false; if (dwPluginResultFlags & PROCFILTER_RESULT_FORCE_SCAN_FILE) bScanFile = true; if (dwPluginResultFlags & PROCFILTER_RESULT_QUARANTINE) bQuarantine = true; // Scan the file if requested SCAN_RESULT srFileResult; ZeroMemory(&srFileResult, sizeof(SCAN_RESULT)); if (bScanFile) { CALLBACK_USER_DATA cud = { e, dwProcessId, lpszFileName, lpvScanDataArray, dScanContext, PROCFILTER_MATCH_FILE }; YarascanScanFile(ctx, lpszFileName, cd->dwScanFileSizeLimit, OnMatchCallback, OnMetaCallback, &cud, &srFileResult); if (srFileResult.bScanSuccessful) { bBlock |= srFileResult.bBlock; bLog |= srFileResult.bLog; bQuarantine |= srFileResult.bQuarantine; } else { EventWriteSCAN_FILE_FAILED(dwProcessId, lpszFileName, srFileResult.szError); } } // Scan the memory if requested SCAN_RESULT srMemoryResult; ZeroMemory(&srMemoryResult, sizeof(SCAN_RESULT)); if (bScanMemory) { CALLBACK_USER_DATA cud = { e, dwProcessId, lpszFileName, lpvScanDataArray, dScanContext, PROCFILTER_MATCH_MEMORY }; YarascanScanMemory(ctx, dwProcessId, OnMatchCallback, OnMetaCallback, &cud, &srMemoryResult); if (srMemoryResult.bScanSuccessful) { bBlock |= srMemoryResult.bBlock; bLog |= srMemoryResult.bLog; bQuarantine |= srMemoryResult.bQuarantine; } else { EventWriteSCAN_PROCESS_FAILED(dwProcessId, lpszFileName, srMemoryResult.szError); } } // Export the scan results to plugins ApiEventReinit(e, PROCFILTER_EVENT_YARA_SCAN_COMPLETE); e->dwProcessId = dwProcessId; e->dwParentProcessId = dwParentProcessId; e->lpszFileName = lpszFileName; e->dScanContext = dScanContext; e->srFileResult = bScanFile ? &srFileResult : NULL; e->srMemoryResult = bScanMemory ? &srMemoryResult : NULL; e->bBlockProcess = bBlock; e->lpvScanData = lpvScanDataArray; dwPluginResultFlags = ApiEventExport(e); if (dwPluginResultFlags & PROCFILTER_RESULT_BLOCK_PROCESS) bBlock = true; if (dwPluginResultFlags & PROCFILTER_RESULT_QUARANTINE) bQuarantine = true; WCHAR *szFileQuarantineRuleNames = bScanFile && srFileResult.bScanSuccessful ? srFileResult.szQuarantineRuleNames : NULL; WCHAR *szMemoryQuarantineRuleNames = bScanMemory && srMemoryResult.bScanSuccessful ? srMemoryResult.szQuarantineRuleNames : NULL; // Quarantine here if (bQuarantine) { char hexdigest[SHA1_HEXDIGEST_LENGTH+1] = { '\0' }; if (QuarantineFile(lpszFileName, cd->szQuarantineDirectory, cd->dwQuarantineFileSizeLimit, szFileQuarantineRuleNames, szMemoryQuarantineRuleNames, hexdigest)) { EventWriteFILE_QUARANTINED(dwProcessId, lpszFileName, hexdigest, (bScanFile && srFileResult.bScanSuccessful) ? srFileResult.szQuarantineRuleNames : NULL, (bScanMemory && srMemoryResult.bScanSuccessful) ? srMemoryResult.szQuarantineRuleNames : NULL); } } // Write the result back to the kernel driver, which releases the process bool bProcessBlocked = false; if (dScanContext == PROCFILTER_SCAN_CONTEXT_PROCESS_CREATE || dScanContext == PROCFILTER_SCAN_CONTEXT_PROCESS_TERMINATE) { PROCFILTER_RESPONSE response; ZeroMemory(&response, sizeof(PROCFILTER_RESPONSE)); response.dwEventType = dwEventType; response.dwProcessId = dwProcessId; // Block the process according to configuration if (dScanContext == PROCFILTER_SCAN_CONTEXT_PROCESS_CREATE) { if (cd->bDenyProcessCreationOnFailedScan) { if (bScanFile && !srFileResult.bScanSuccessful) bBlock = true; if (bScanMemory && !srMemoryResult.bScanSuccessful) bBlock = true; } if (bBlock) { response.bBlock = true; } } if (DriverSendResponse(hDriver, hWriteCompletionEvent, &response)) { if (dScanContext == PROCFILTER_SCAN_CONTEXT_PROCESS_CREATE) bProcessBlocked = true; } } else if (dScanContext == PROCFILTER_SCAN_CONTEXT_IMAGE_LOAD) { PROCFILTER_RESPONSE response; ZeroMemory(&response, sizeof(PROCFILTER_RESPONSE)); response.dwEventType = dwEventType; response.dwProcessId = dwProcessId; response.lpImageBase = lpImageBase; DriverSendResponse(hDriver, hWriteCompletionEvent, &response); } // Log to event log based on what was sent to the kernel (excluding the quarantining) WCHAR *szFileLogRuleNames = bScanFile && srFileResult.bScanSuccessful ? srFileResult.szLogRuleNames : NULL; WCHAR *szFileBlockRuleNames = bScanFile && srFileResult.bScanSuccessful ? srFileResult.szBlockRuleNames : NULL; WCHAR *szFileMatchRuleNames = bScanFile && srFileResult.bScanSuccessful ? srFileResult.szMatchedRuleNames : NULL; WCHAR *szMemoryLogRuleNames = bScanMemory && srMemoryResult.bScanSuccessful ? srMemoryResult.szLogRuleNames : NULL; WCHAR *szMemoryBlockRuleNames = bScanMemory && srMemoryResult.bScanSuccessful ? srMemoryResult.szBlockRuleNames : NULL; WCHAR *szMemoryMatchRuleNames = bScanMemory && srMemoryResult.bScanSuccessful ? srMemoryResult.szMatchedRuleNames : NULL; // Log the actions taken according to which events happened if (dScanContext == PROCFILTER_SCAN_CONTEXT_PROCESS_CREATE) { if (bLog) EventWriteEXECUTION_LOGGED(dwProcessId, lpszFileName, szFileLogRuleNames, szMemoryLogRuleNames); if (bBlock) EventWriteEXECUTION_BLOCKED(dwProcessId, lpszFileName, szFileBlockRuleNames, szMemoryBlockRuleNames); } else if (dScanContext == PROCFILTER_SCAN_CONTEXT_PROCESS_TERMINATE) { if (bLog) EventWriteEXITING_PROCESS_SCAN_MATCHED_LOGGED_RULE(dwProcessId, lpszFileName, szFileLogRuleNames, szMemoryLogRuleNames); if (bBlock) EventWriteEXITING_PROCESS_SCAN_MATCHED_BLOCKED_RULE(dwProcessId, lpszFileName, szFileBlockRuleNames, szMemoryBlockRuleNames); } else if (dScanContext == PROCFILTER_SCAN_CONTEXT_PERIODIC_SCAN) { if (bLog) EventWriteRUNNING_PROCESS_MATCHED_LOGGED_RULE(dwProcessId, lpszFileName, szFileLogRuleNames, szMemoryLogRuleNames); if (bBlock) { EventWriteRUNNING_PROCESS_MATCHED_BLOCKED_RULE(dwProcessId, lpszFileName, szFileBlockRuleNames, szMemoryBlockRuleNames); if (TerminateProcessByPid(dwProcessId, true, lpszFileName, szFileBlockRuleNames, szMemoryBlockRuleNames)) { bProcessBlocked = true; } } } else if (dScanContext == PROCFILTER_SCAN_CONTEXT_IMAGE_LOAD) { if (bLog || bBlock) { WCHAR *lpszImageLoaderProcessName = NULL; DWORD dwImageLoaderProcessNameSize = sizeof(WCHAR) * (MAX_PATH+1); HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwProcessId); if (hProcess) { lpszImageLoaderProcessName = (WCHAR*)_malloca(dwImageLoaderProcessNameSize); if (!QueryFullProcessImageNameW(hProcess, PROCESS_NAME_NATIVE, lpszImageLoaderProcessName, &dwImageLoaderProcessNameSize)) { _freea(lpszImageLoaderProcessName); lpszImageLoaderProcessName = NULL; } CloseHandle(hProcess); } if (bLog) EventWriteLOADED_IMAGE_LOGGED(dwProcessId, lpszImageLoaderProcessName, lpszFileName, szFileLogRuleNames, szMemoryLogRuleNames); if (bBlock) { EventWriteLOADED_IMAGE_BLOCKED(dwProcessId, lpszImageLoaderProcessName, lpszFileName, szFileBlockRuleNames, szMemoryBlockRuleNames); if (TerminateProcessByPid(dwProcessId, true, lpszFileName, szFileBlockRuleNames, szMemoryBlockRuleNames)) { bProcessBlocked = true; } } if (lpszImageLoaderProcessName) _freea(lpszImageLoaderProcessName); } } // Export post-scan notice to plugins ApiEventReinit(e, PROCFILTER_EVENT_YARA_SCAN_CLEANUP); e->dwProcessId = dwProcessId; e->dwParentProcessId = dwParentProcessId; e->lpszFileName = lpszFileName; e->dScanContext = dScanContext; e->srFileResult = bScanFile ? &srFileResult : NULL; e->srMemoryResult = bScanMemory ? &srMemoryResult : NULL; e->bBlockProcess = bBlock; e->bProcessBlocked = bProcessBlocked; e->lpvScanData = lpvScanDataArray; ApiEventExport(e); // Performance data update LONG64 llDuration = GetPerformanceCount() - llStart; MmaUpdate(&g_Stats[dScanContext].mma, llDuration); MmaUpdate(&g_Stats[PROCFILTER_NUM_CONTEXTS].mma, llDuration); }