Ejemplo n.º 1
0
int CTimer::RandomSeed()
{
#ifdef _WIN32
    return GetPerformanceCount() / GetFrequency();
#else
    return 0;
#endif
}
Ejemplo n.º 2
0
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;
}
Ejemplo n.º 3
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);
}