I have used minispy as an example to block access to some processes for some files. I am sending the file path and process path to the user-mode application and in user-mode processing is done. Finally, the user-mode application returns TRUE/FALSE, and in kernel mode, if the response is TRUE from the user-mode application then Blocking is done.
This runs successfully for approx 45min and sometimes 1hr. And finally the blue screen system crash with an error as PAGE FAULT IN NONPAGED AREA.
I am unable to figure out why this is happening after some periods of time?
I am lost now. Please help me to identify the cause of this problem.
I will be very thankful to you.
Note: User Mode application takes 1-8 milli sec to respond after processing.
I have also attached a screenshot of BlueScreenView: https://ibb.co/Nmsv3Nc
Minifilter Code:
FLT_PREOP_CALLBACK_STATUS MiniPreRead(PFLT_CALLBACK_DATA Data, PCFLT_RELATED_OBJECTS FltObjects, PVOID* CompletionContext) {
UNREFERENCED_PARAMETER(Data);
UNREFERENCED_PARAMETER(FltObjects);
UNREFERENCED_PARAMETER(CompletionContext);
//DbgPrint("MiniPreRead");
PFLT_FILE_NAME_INFORMATION FileNameInfo = NULL;
PMINISPY_NOTIFICATION notification = NULL;
PUNICODE_STRING pni = NULL;
BOOLEAN isBlock, shouldSkipThisFileName;
ULONG seconds_to_wait;
PVOID replyBuffer = NULL;
ULONG replyLength;
LARGE_INTEGER timeOut;
NTSTATUS status;
WCHAR Name[260] = { 0 };
WCHAR ProcessPath[260] = { 0 };
//update from usermode reply
isBlock = FALSE;
shouldSkipThisFileName = FALSE;
//TODO: How much Waiting Time?
seconds_to_wait = 5;
timeOut.QuadPart = -((LONGLONG)seconds_to_wait * 10 * 1000 * 1000);
status = FltGetFileNameInformation(Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &FileNameInfo);
if (!NT_SUCCESS(status)) {
goto cleanup;
}
status = FltParseFileNameInformation(FileNameInfo);
if (!NT_SUCCESS(status)) {
goto cleanup;
}
if (FileNameInfo->Name.MaximumLength >= 260) {
goto cleanup;
}
RtlCopyMemory(Name, FileNameInfo->Name.Buffer, FileNameInfo->Name.MaximumLength);
DbgPrint("\n\nMiniPreRead: FileName = %ws\n", Name);
//skip systm process as fileName: ntoskrnl svchost, & fileType: .sys, .dll
shouldSkipThisFileName = (wcsstr(Name, L"ntoskrnl") != NULL || wcsstr(Name, L"svchost") != NULL || wcsstr(Name, L".SYS") != NULL || wcsstr(Name, L".sys") != NULL || wcsstr(Name, L".DLL") != NULL || wcsstr(Name, L".dll") != NULL) ? TRUE : FALSE;
//skip if path is not the drivePath
if (wcsstr(Name, L"Device\\HarddiskVolume") == NULL) {
goto cleanup;
}
if (shouldSkipThisFileName) {
goto cleanup;
}
status = STATUS_UNSUCCESSFUL;
status = GetProcessImageName(IoThreadToProcess(Data->Thread), &pni); //TODO: Improve by https://docs.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-getprocessimagefilenamea
try {
if (!NT_SUCCESS(status)) {
leave;
}
if (NULL == pni->Buffer) {
status = STATUS_INSUFFICIENT_RESOURCES;
leave;
}
RtlCopyMemory(ProcessPath, pni->Buffer, pni->MaximumLength);
//TODO: skip for system32 process for now
if (wcsstr(ProcessPath, L"Windows\\System32") != NULL) {
DbgPrint("\n\nMiniPreRead: kernelToUserMode: Skipping SystemProcess: %ws\n", ProcessPath);
leave;
}
//TODO: skip Just for Testing purpose
if (wcsstr(ProcessPath, L"explorer.exe") != NULL) {
DbgPrint("\n\nMiniPreRead: kernelToUserMode: Skipping explorer: %ws\n", ProcessPath);
leave;
}
DbgPrint("\n\nMiniPreRead: kernelToUserMode:| |\n");
DbgPrint("\n\nMiniPreRead: kernelToUserMode: Final psName: %ws\n", ProcessPath);
DbgPrint("\n\nMiniPreRead: kernelToUserMode: Final FileName: %ws\n", Name);
#ifndef KERNEL_TO_USER
notification = ExAllocatePoolWithTag(NonPagedPool, sizeof(MINISPY_NOTIFICATION), SPY_TAG);
if (NULL == notification) {
status = STATUS_INSUFFICIENT_RESOURCES;
leave;
}
RtlCopyMemory(¬ification->ProcessPath, ProcessPath, 260);
RtlCopyMemory(¬ification->filePath, Name, 260);
notification->msgCountNumId = ++globalCount % 10000000;
//replyLength = sizeof(MINISPY_REPLY);
//TODO For both userMode and kernel mode as recommend on doc: replyLength = sizeof(FILTER_REPLY_HEADER) + sizeof(MINISPY_REPLY);
replyLength = sizeof(FILTER_REPLY_HEADER) + sizeof(MINISPY_REPLY);
DbgPrint("\n\nMiniPreRead: kernelToUserMode: Waiting for usermode reply for MsgSendId: %d,ps: %ws...\n", notification->msgCountNumId, pni->Buffer);
status = FltSendMessage(MiniSpyData.Filter, &MiniSpyData.ClientPort,
notification,
sizeof(MINISPY_NOTIFICATION),
notification,
&replyLength,
NULL);
if (STATUS_TIMEOUT == status) {
DbgPrint("\n\nMiniPreRead: kernelToUserMode: timeout occured!\n");
}
else if (STATUS_SUCCESS == status) {
try {
isBlock = ((PMINISPY_REPLY)notification)->res;
}
finally {}
DbgPrint("\n\nMiniPreRead: kernelToUserMode: Reply isBlock: %d,MsgSendId: %d,ps: %ws\n", isBlock, ((PMINISPY_REPLY)notification)->msgCountId ,ProcessPath);
}
else {
DbgPrint("\n\nMiniPreRead: kernelToUserMode: --- couldn't send processPath %ws to the user-mode, status 0x%X\n", ProcessPath, status);
// STATUS_INSUFFICIENT_RESOURCES STATUS_PORT_DISCONNECTED STATUS_THREAD_IS_TERMINATING
}
#endif
}
finally {
if (notification != NULL) {
ExFreePoolWithTag(notification, SPY_TAG);
}
if (pni != NULL) {
ExFreePool(pni);
}
}
Blocking:
if (isBlock) {
KdPrint(("read file: %ws blocked \r\n", Name)); // only in DEBUG
DbgPrint(("read file: %ws blocked \r\n", Name));
Data->IoStatus.Status = STATUS_ACCESS_DENIED;
Data->IoStatus.Information = 0;
if (FileNameInfo) {
FltReleaseFileNameInformation(FileNameInfo);
}
return FLT_PREOP_COMPLETE;
}
cleanup:
if (FileNameInfo) {
FltReleaseFileNameInformation(FileNameInfo);
}
return FLT_PREOP_SUCCESS_NO_CALLBACK;
}