I am working on a simple process filtering minifilter driver. Managed to make it work in test mode, also managed to get it signed by Microsoft. Problem is: built it in release mode with the linker's /INTEGRITYCHECK option, signed it, works perfect on my machine, and on the virtual machines that i have hosted on my local machine for testing (hyper-V).
As soon as I asked my colleague to run it, he gets a BSOD with "UNEXPECTED KERNEL MODE TRAP" after just opening some processes.
I am attaching myself to PsSetCreateProcessNotifyRoutineEx, code below. Not sure where to look at this point, I fail to understand why can't I reproduce the issue.
Registering with this:
KdPrint((DRIVER_PREFIX "Registering process callback\n"));
//PROCESS CALLBACKS
status = PsSetCreateProcessNotifyRoutineEx(OnProcessNotify, FALSE);
if (!NT_SUCCESS(status)) {
KdPrint((DRIVER_PREFIX "failed to register process callback (0x%08X)\n", status));
KdPrint((DRIVER_PREFIX "Unregistering OnProcessNotify... \r\n"));
PsSetCreateProcessNotifyRoutineEx(OnProcessNotify, TRUE);
KdPrint((DRIVER_PREFIX "Unregistered OnProcessNotify \r\n"));
return status;
}
The structure that I'm sending to the clients:
typedef struct _ACCESS_DATA
{
UINT32 ProcessID;
UINT32 EventType;
WCHAR Path[MAX_PATH]; // [260 bytes] Max size of a full path in windows.
WCHAR CommandLine[MAX_CMDLINE]; // [8191 bytes] Max size of a commandline
} ACCESS_DATA, * PACCESS_DATA;
The reply structure that I'm waiting from the clients:
typedef struct _REPLY_DATA
{
BOOLEAN Allow; // TRUE if request is permitted, FALSE if not permitted.
UINT32 Reserved; // Alignment. Must be NULL.
} REPLY_DATA, * PREPLY_DATA;
The main method that I'm using. Basically upon any process interception, I am asking the client apps whether I should allow it or not. I have two separate communication channel to ask two separate applications. Again, this works perfectly on my computer and on any virtual machine I create on my computer. Not on two of my colleagues machines, nor on some other virtual machines hosted on a different on-prem server. Can't figure out why. All of them are Windows 10 x64, the driver was built for Windows 10 x64.
void OnProcessNotify(_Inout_ PEPROCESS Process, _In_ HANDLE ProcessId, _Inout_opt_ PPS_CREATE_NOTIFY_INFO CreateInfo) {
UNREFERENCED_PARAMETER(Process);
KdPrint((DRIVER_PREFIX "Started something \r\n"));
if (CreateInfo) {
if (CreateInfo->FileOpenNameAvailable && CreateInfo->ImageFileName)
{
//KdPrint(("Pid: %p\n", ProcessId));
KdPrint((DRIVER_PREFIX "ImageFilePath: %wZ\r\n", CreateInfo->ImageFileName));
KdPrint((DRIVER_PREFIX "CmdLine: %wZ\r\n", CreateInfo->CommandLine));
PREPLY_DATA pReplyData = NULL;
PREPLY_DATA ac_pReplyData = NULL;
PAGED_CODE();
pReplyData = ExAllocatePoolWithTag(NonPagedPool, sizeof(REPLY_DATA), REPLY_DATA_TAG);
ac_pReplyData = ExAllocatePoolWithTag(NonPagedPool, sizeof(REPLY_DATA), REPLY_DATA_TAG);
if (pReplyData != NULL && ac_pReplyData != NULL) {
PPROCESS_ACCESS_DATA pAccessData;
pAccessData = ExAllocatePoolWithTag(NonPagedPool, sizeof(PROCESS_ACCESS_DATA), ACCESS_DATA_TAG);
if (pAccessData != NULL) {
//do work
pAccessData->ProcessID = (UINT32)HandleToPid(ProcessId);
//(UINT32)(((ULONG_PTR)ProcessId) & 0xFFFFFFFF);
pAccessData->EventType = 8;
pAccessData->ParentProcessID = (UINT32)HandleToPid(CreateInfo->ParentProcessId);
WCHAR ProcessPath[MAX_PATH] = { 0 };
RtlCopyMemory(ProcessPath, CreateInfo->ImageFileName->Buffer, CreateInfo->ImageFileName->MaximumLength);
RtlZeroMemory(pAccessData->Path, MAX_PATH * sizeof(wchar_t));
//RtlCopyMemory(pAccessData->Path, FileNameInfo->Name.Buffer, FileNameInfo->Name.Length);
RtlCopyMemory(pAccessData->Path, ProcessPath, MAX_PATH * sizeof(wchar_t));
WCHAR CommandLine[MAX_CMDLINE] = { 0 };
RtlCopyMemory(CommandLine, CreateInfo->CommandLine->Buffer, CreateInfo->CommandLine->MaximumLength);
RtlZeroMemory(pAccessData->CommandLine, MAX_CMDLINE * sizeof(wchar_t));
//RtlCopyMemory(pAccessData->CommandLine, FileNameInfo->Name.Buffer, FileNameInfo->Name.Length);
RtlCopyMemory(pAccessData->CommandLine, CommandLine, MAX_CMDLINE * sizeof(wchar_t));
KdPrint((DRIVER_PREFIX "File trying to Execute: %ws\r\n", CreateInfo->ImageFileName->Buffer));
//begin send the request to the first client app, if connected
LARGE_INTEGER Timeout;
Timeout.QuadPart = -((LONGLONG)1 * 1 * 1000 * 1000); // 1000 milliseconds
NTSTATUS status;
ULONG ReplyDataSize = sizeof(REPLY_DATA);
status = FltSendMessage(FilterHandle, &IN_ProcessPort, pAccessData, sizeof(PROCESS_ACCESS_DATA), pReplyData, &ReplyDataSize, &Timeout);
if (Timeout.QuadPart != 0 && NT_SUCCESS(status))
{
//block or not block
if (pReplyData->Allow == TRUE)
{
KdPrint((DRIVER_PREFIX "File Allowed to Execute: %ws\r\n", CreateInfo->ImageFileName->Buffer));
}
else
{
CreateInfo->CreationStatus = STATUS_ACCESS_DENIED;
KdPrint((DRIVER_PREFIX "Process DENIED to Execute: %ws\r\n", CreateInfo->ImageFileName->Buffer));
}
}
//end send the request to the first client app, if connected
//begin send the request to the second client app, if connected
LARGE_INTEGER AC_Timeout;
AC_Timeout.QuadPart = -((LONGLONG)10 * 1000 * (1000 * 10) /*nanoseconds*/); // 10 seconds
NTSTATUS ac_status;
ULONG AC_ReplyDataSize = sizeof(REPLY_DATA);
ac_status = FltSendMessage(FilterHandle, &AC_ProcessPort, pAccessData, sizeof(PROCESS_ACCESS_DATA), ac_pReplyData, &AC_ReplyDataSize, &AC_Timeout);
if (AC_Timeout.QuadPart != 0 && NT_SUCCESS(ac_status))
{
//block or not block
if (ac_pReplyData->Allow == FALSE)
{
CreateInfo->CreationStatus = STATUS_ACCESS_DENIED;
KdPrint((DRIVER_PREFIX "Process DENIED to Execute: %ws\r\n", CreateInfo->ImageFileName->Buffer));
}
else
{
KdPrint((DRIVER_PREFIX "File Allowed to Execute: %ws\r\n", CreateInfo->ImageFileName->Buffer));
}
}
//end send the request to the first client app, if connected
ExFreePoolWithTag(pAccessData, ACCESS_DATA_TAG);
}
ExFreePoolWithTag(pReplyData, REPLY_DATA_TAG);
ExFreePoolWithTag(ac_pReplyData, REPLY_DATA_TAG);
}
}
}