Mini FIlter to Block IO upload operations from Browser URL and some clarifications

Hi all!

1)Actually I want to develop a minifilter driver to block the upload access from browser site ( For eg: I want to upload a profile picture on Facebook, I click on the upload button so that it will open an "open dialog " local directory where I can search the picture. I want to block this upload dialog or restrict access to the file system directory). I looked upon UI windows automation where I can block this open dialog but the real problem is drag and drop. Do u guys know any idea about how to approach or is there any change in the IRP callback data to identify whether this IRP is from the particular browser or site.

I wrote a code that gives the process image path and fileName (TEXTFILE.txt) when I open the TEXTFILE.txt

#include<fltKernel.h>
#include<dontuse.h>
#include “ntddk.h”
typedef NTSTATUS(*QUERY_INFO_PROCESS) (
__in HANDLE ProcessHandle,
__in PROCESSINFOCLASS ProcessInformationClass,
__out_bcount(ProcessInformationLength) PVOID ProcessInformation,
__in ULONG ProcessInformationLength,
__out_opt PULONG ReturnLength
);
QUERY_INFO_PROCESS ZwQueryInformationProcess;

#pragma prefast(disable:__WARNING_ENCODE_MEMBER_FUNCTION_POINTER, “Not valid for kernel mode drivers”)

PFLT_FILTER FilterHandle;
FLT_PREOP_CALLBACK_STATUS MiniPreCreate(PFLT_CALLBACK_DATA Data, PCFLT_RELATED_OBJECTS FltObjects, PVOID* CompletionContext);
FLT_POSTOP_CALLBACK_STATUS MiniPostCreate(Inout PFLT_CALLBACK_DATA Data,
In PCFLT_RELATED_OBJECTS FltObjects,
In_opt PVOID CompletionContext,
In FLT_POST_OPERATION_FLAGS Flags);
NTSTATUS NullQueryTeardown(In PCFLT_RELATED_OBJECTS FltObjects,In FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags);

const FLT_OPERATION_REGISTRATION Callbacks =
{
{IRP_MJ_CREATE, 0 , MiniPreCreate, MiniPostCreate},
{IRP_MJ_OPERATION_END}
};
NTSTATUS MiniUnload(FLT_FILTER_UNLOAD_FLAGS Flags)
{
UNREFERENCED_PARAMETER(Flags);
PAGED_CODE();
KdPrint((“Driver UNloaded\r\n”));
FltUnregisterFilter(FilterHandle);
return STATUS_SUCCESS;
}

const FLT_REGISTRATION FilterRegistration = {
sizeof(FLT_REGISTRATION),
FLT_REGISTRATION_VERSION,0,
NULL,
Callbacks,
MiniUnload,
NULL, NullQueryTeardown, NULL, NULL, NULL, NULL, NULL, NULL
};

NTSTATUS GetProcessImageName(HANDLE processId, PUNICODE_STRING ProcessImageName)
{
NTSTATUS status;
ULONG returnedLength;
ULONG bufferLength;
HANDLE hProcess= NULL;
PVOID buffer;
PEPROCESS eProcess;
PUNICODE_STRING imageName;

PAGED_CODE(); // this eliminates the possibility of the IDLE Thread/Process

status = PsLookupProcessByProcessId(processId, &eProcess);

if (NT_SUCCESS(status))
{
	status = ObOpenObjectByPointer(eProcess, 0, NULL, 0, 0, KernelMode, &hProcess);
	if (NT_SUCCESS(status))
	{
	}
	else {
		DbgPrint("ObOpenObjectByPointer Failed: %08x\n", status);
	}
	ObDereferenceObject(eProcess);
}
else {
	DbgPrint("PsLookupProcessByProcessId Failed: %08x\n", status);
}

if (NULL == ZwQueryInformationProcess) {

	UNICODE_STRING routineName;

	RtlInitUnicodeString(&routineName, L"ZwQueryInformationProcess");

	ZwQueryInformationProcess =
		(QUERY_INFO_PROCESS)MmGetSystemRoutineAddress(&routineName);

	if (NULL == ZwQueryInformationProcess) {
		DbgPrint("Cannot resolve ZwQueryInformationProcess\n");
	}
}

/* Query the actual size of the process path */
status = ZwQueryInformationProcess(hProcess,
	ProcessImageFileName,
	NULL, // buffer
	0, // buffer size
	&returnedLength);

if (STATUS_INFO_LENGTH_MISMATCH != status) {
	return status;
}

/* Check there is enough space to store the actual process
   path when it is found. If not return an error with the
   required size */
bufferLength = returnedLength - sizeof(UNICODE_STRING);
if (ProcessImageName->MaximumLength < bufferLength)
{
	ProcessImageName->MaximumLength = (USHORT)bufferLength;
	return STATUS_BUFFER_OVERFLOW;
}

/* Allocate a temporary buffer to store the path name */
buffer = ExAllocatePoolWithTag(NonPagedPool, returnedLength, 'uLT1');

if (NULL == buffer)
{
	return STATUS_INSUFFICIENT_RESOURCES;
}

/* Retrieve the process path from the handle to the process */
status = ZwQueryInformationProcess(hProcess,
	ProcessImageFileName,
	buffer,
	returnedLength,
	&returnedLength);

if (NT_SUCCESS(status))
{
	/* Copy the path name */
	imageName = (PUNICODE_STRING)buffer;
	RtlCopyUnicodeString(ProcessImageName, imageName);
}

/* Free the temp buffer which stored the path */
ExFreePoolWithTag(buffer, 'uLT1');

return status;

}
FLT_PREOP_CALLBACK_STATUS MiniPreCreate(PFLT_CALLBACK_DATA Data, PCFLT_RELATED_OBJECTS FltObjects, PVOID* CompletionContext)
{
UNREFERENCED_PARAMETER(FltObjects);
UNREFERENCED_PARAMETER(CompletionContext = NULL);

PAGED_CODE();

return  FLT_PREOP_SUCCESS_WITH_CALLBACK;

}
FLT_POSTOP_CALLBACK_STATUS MiniPostCreate(Inout PFLT_CALLBACK_DATA Data,In PCFLT_RELATED_OBJECTS FltObjects,In_opt PVOID CompletionContext,In FLT_POST_OPERATION_FLAGS Flags)
{

UNREFERENCED_PARAMETER(CompletionContext);
UNREFERENCED_PARAMETER(Flags);
PAGED_CODE();

if (Data->RequestorMode == KernelMode)
{
	return FLT_POSTOP_FINISHED_PROCESSING;
}
if (Data->Iopb->MajorFunction == IRP_MJ_WRITE || Data->Iopb->MajorFunction == IRP_MJ_SET_INFORMATION || Data->Iopb->MajorFunction == IRP_MJ_CREATE)
{
	PFLT_FILE_NAME_INFORMATION	FileNameInfo;
	NTSTATUS status;
	WCHAR Name[200];
	PEPROCESS objCurProcess = NULL;
	HANDLE hProcess ;
	status = FltGetFileNameInformation(Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &FileNameInfo);

	if (NT_SUCCESS(status))
	{
		status = FltParseFileNameInformation(FileNameInfo);

		if (NT_SUCCESS(status))
		{
			if (FileNameInfo->Name.MaximumLength < 260)
			{
				RtlCopyMemory(Name, FileNameInfo->Name.Buffer, FileNameInfo->Name.MaximumLength);
				_wcsupr(Name);

				if (wcsstr(Name, L"TEXTFILE.TXT") != NULL)
				{
					KdPrint(("post create and file name matched"));
					UNICODE_STRING fullPath;
					objCurProcess = IoThreadToProcess(Data->Thread);
					hProcess = PsGetProcessId(objCurProcess);
					fullPath.Length = 0;
					fullPath.MaximumLength = 520;
					fullPath.Buffer = (PWSTR)ExAllocatePoolWithTag(NonPagedPool, 520, 'uUT1');
					GetProcessImageName(hProcess, &fullPath);
					PFILE_OBJECT file = FltObjects->FileObject;
					KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "%wZ is writing to [ %ws ]\n\n", fullPath, file->FileName.Buffer));

//To block the IO OPERATIONS
//auto params = &Data->Iopb->Parameters.Create.SecurityContext->DesiredAccess;

						/*if (params == GENERIC_WRITE || params == GENERIC_READ || params == GENERIC_ALL)
						{
							KdPrint(("File creation ACCESS DENIED: %wZ \n", &Data->Iopb->TargetFileObject->FileName));
							FltCancelFileOpen(FltObjects->Instance, FltObjects->FileObject);
							FltReleaseFileNameInformation(FileNameInfo);
							Data->IoStatus.Status = STATUS_ACCESS_DENIED;
							Data->IoStatus.Information = 0;
							return  FLT_POSTOP_FINISHED_PROCESSING;
						}*/
				}
			}
		}
	}
FltReleaseFileNameInformation(FileNameInfo);
}
return FLT_POSTOP_FINISHED_PROCESSING;

}
NTSTATUS NullQueryTeardown(
In PCFLT_RELATED_OBJECTS FltObjects,
In FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags
)
{
UNREFERENCED_PARAMETER(FltObjects);
UNREFERENCED_PARAMETER(Flags);

PAGED_CODE();

return STATUS_SUCCESS;

}
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
NTSTATUS status = STATUS_SUCCESS;

UNICODE_STRING PsGetProcessImageFileNameStr = { 0 };
RtlInitUnicodeString(&PsGetProcessImageFileNameStr, L"PsGetProcessImageFileName");
KdPrint(("driver loaded successfully"));
if (NT_SUCCESS(status))
{
	status = FltStartFiltering(FilterHandle);
	if (!NT_SUCCESS(status))
	{
		FltUnregisterFilter(FilterHandle);
	}
}
return status;

}
Sometimes This code gives Blue Screen of Death.

The output of my code when I upload my TEXTFILE from a site from Microsoft edge browser its process name is browserbroker.exe and runtimebroker.exe

  1. This ZwQueryInformationProcess I referred in
    https://stackoverflow.com/questions/3707133/how-to-use-zwqueryinformationprocess-to-get-processimagefilename-in-a-kernel-dri
    Why can’t I use header files like Windows.h? How can I include these types of header files? I can’t close the handle by using CloseHandle() as I cant use this header file.

Thankyou For reading this! It will be helpful if u have some ideas about how to approach my project or any suggestions. :slight_smile:

is there any change in the IRP callback data to identify whether this IRP is from the particular browser or site

Nope…At the file system level all you get are discreet file system operations (open/close/read/write/etc.).Trying to batch those together into some higher level operation (i.e. “this is likely a browser upload”) will require heuristics. And you’ll never know which site it’s going to as that has nothing to do with the file system.

You can’t include Windows.h because that’s a user mode header. In drivers we close handles with ZwClose (or FltClose, depending on where the handle came from).

I’d suggest you take a seminar because there’s a lot to learn here…In the meantime you probably want to start with something simpler than a file system filter while you get your bearings.

1 Like

@“Scott_Noone_(OSR)” said:

is there any change in the IRP callback data to identify whether this IRP is from the particular browser or site

Nope…At the file system level all you get are discreet file system operations (open/close/read/write/etc.).Trying to batch those together into some higher level operation (i.e. “this is likely a browser upload”) will require heuristics. And you’ll never know which site it’s going to as that has nothing to do with the file system.

You can’t include Windows.h because that’s a user mode header. In drivers we close handles with ZwClose (or FltClose, depending on where the handle came from).

I’d suggest you take a seminar because there’s a lot to learn here…In the meantime you probably want to start with something simpler than a file system filter while you get your bearings.

Thank you for u suggestions!