Why PsSetCreateProcessNotifyRoutineEx give me incorrect result

I wrote simple Driver for scan new created process. Firstly I create 2 event object one for usermodeapp and one for kernelmode. In DriverEntryRoutine i call IoCreateNotificationEvent to creating event(A) object for usermode app, and in the user side i create event(B) and send it driver via ioctl.Then driver uses ObReferenceObjectByHandle(B) to access user mode handle. After this usermodeapp send next ioctl to start PsSetCreateProcessNotifyRoutineEx routine. It works well. So when new process is created , inside CallBack function I firstly send signal(KeSetEvent(A)) to wake up usermode app and call WaitForSingleObject(B). And when usermode app wake up it sleeping for 5 seconds and then send signal to kernel via SetEvent(B).Its also works fine. But if I want to print count of created process I didnt get all of newly created process. Why? I put source code and attach visual studio project files: I will be happy if someone help me. Tahnk you very much for reading.

Source Code:

UserModeAPP:

#include <Windows.h>
#include <stdio.h>

#define IOCTL_RECV_EVENT CTL_CODE(FILE_DEVICE_UNKNOWN,0x801,METHOD_BUFFERED,FILE_ALL_ACCESS)
#define IOCTL_START_MONITOR CTL_CODE(FILE_DEVICE_UNKNOWN,0x802,METHOD_BUFFERED,FILE_ALL_ACCESS)

int main(void)
{
	HANDLE hEvent = NULL;
	HANDLE hEvent2 = NULL;
	HANDLE hDriver = INVALID_HANDLE_VALUE;
	DWORD dwRet = 0;
	int i = 0;

	hDriver = CreateFileW(L"\\\\.\\XXEvent", GENERIC_READ |GENERIC_WRITE,
		FILE_SHARE_READ |FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (hDriver == INVALID_HANDLE_VALUE)
	{
		printf("Error open driver\n");
		return -1;
	}

	hEvent = CreateEventW(NULL, TRUE, FALSE, L"XXTESTEVENT");
	if (hEvent == NULL)
	{
		printf("Error CreateEvent\n");
		return -1;
	}

	hEvent2 = OpenEventW(SYNCHRONIZE, FALSE, L"Global\\XXTESTEVENT2");
	if (hEvent2 == NULL)
	{
		printf("Error open event2");
		return -1;
	}

	DeviceIoControl(hDriver, IOCTL_RECV_EVENT, (PVOID)&hEvent, sizeof(HANDLE), NULL, 0, &dwRet, NULL);

	DeviceIoControl(hDriver, IOCTL_START_MONITOR, NULL, 0, NULL, 0, &dwRet, NULL);

	while (1)
	{
		WaitForSingleObject(hEvent2, INFINITE);
		i++;
		Sleep(5000);
		printf("Process Created:%d\n",i);
		SetEvent(hEvent);
		ResetEvent(hEvent);
	}
}

SourceCode KernelMode:


#include <ntddk.h>

#define IOCTL_RECV_EVENT CTL_CODE(FILE_DEVICE_UNKNOWN,0x801,METHOD_BUFFERED,FILE_ALL_ACCESS)
#define IOCTL_START_MONITOR CTL_CODE(FILE_DEVICE_UNKNOWN,0x802,METHOD_BUFFERED,FILE_ALL_ACCESS)

UNICODE_STRING gDeviceName = RTL_CONSTANT_STRING(L"\\Device\\XXTEST");
UNICODE_STRING gSymbolicLink = RTL_CONSTANT_STRING(L"\\??\\XXEvent");
UNICODE_STRING EventName = RTL_CONSTANT_STRING(L"\\BaseNamedObjects\\XXTESTEVENT2");

PDEVICE_OBJECT gDeviceObject = NULL;
PKEVENT gEvent = { 0 };
PKEVENT localEvent = { 0 };
HANDLE hEvent = NULL;
KGUARDED_MUTEX gMutex = { 0 };

VOID XXoutine(PEPROCESS Process, HANDLE hProcessID, PPS_CREATE_NOTIFY_INFO Create)
{
	UNREFERENCED_PARAMETER(Process);
	UNREFERENCED_PARAMETER(hProcessID);
	UNREFERENCED_PARAMETER(Create);

	if (Create != NULL)
	{
		KeAcquireGuardedMutex(&gMutex);
		

		KeSetEvent(localEvent, 0, FALSE);
		KeClearEvent(localEvent);

		KeWaitForSingleObject(gEvent, Executive, UserMode, FALSE, NULL);
		/*KeClearEvent(gEvent);*/
		/*KeReleaseGuardedMutex(&gMutex);*/
		DbgPrint("%wZ", Create->ImageFileName);
		KeReleaseGuardedMutex(&gMutex);
	}

}

VOID Unload(PDRIVER_OBJECT DriverObject)
{
	UNREFERENCED_PARAMETER(DriverObject);

	IoDeleteSymbolicLink(&gSymbolicLink);
	IoDeleteDevice(gDeviceObject);
	PsSetCreateProcessNotifyRoutineEx(XXoutine, TRUE);
	ZwClose(hEvent);

	DbgPrint("Unloaded");
}

NTSTATUS IrpCreateClose(PDEVICE_OBJECT pDeviceObject, PIRP irp)
{
	UNREFERENCED_PARAMETER(pDeviceObject);
	

	irp->IoStatus.Information = 0;
	irp->IoStatus.Status = STATUS_SUCCESS;

	IoCompleteRequest(irp, IO_NO_INCREMENT);
	

	return STATUS_SUCCESS;
}

VOID RegisterNotify(VOID)
{
	NTSTATUS status = STATUS_SUCCESS;
	status = PsSetCreateProcessNotifyRoutineEx(XXoutine, FALSE);
	if (!NT_SUCCESS(status))
	{
		DbgPrint("Error create notify routine\n");
	}
}

NTSTATUS IoCtrl(PDEVICE_OBJECT pDeviceObject, PIRP Irp)
{
	UNREFERENCED_PARAMETER(pDeviceObject);
	PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation(Irp);
	PVOID OutBuffer = Irp->AssociatedIrp.SystemBuffer;
	HANDLE hUserHandle = NULL;
	NTSTATUS status = STATUS_SUCCESS;

	if (irpsp->Parameters.DeviceIoControl.IoControlCode == IOCTL_RECV_EVENT)
	{
		
		hUserHandle = *(HANDLE*)OutBuffer;
		status = ObReferenceObjectByHandle(hUserHandle, SYNCHRONIZE, *ExEventObjectType, UserMode, &gEvent, NULL);
		if (!NT_SUCCESS(status))
		{
			DbgPrint("Error get usermode handle\n");
		}
		else {
			DbgPrint("Yeah i get usermode handle");
		}
	}

	if (irpsp->Parameters.DeviceIoControl.IoControlCode == IOCTL_START_MONITOR)
	{
		
		RegisterNotify();
		status = STATUS_SUCCESS;
	}

	Irp->IoStatus.Information = 0;
	Irp->IoStatus.Status = status;
	IoCompleteRequest(Irp, IO_NO_INCREMENT);
	return status;
}

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

	DriverObject->DriverUnload = Unload;

	status = IoCreateDevice(DriverObject,
		0,
		&gDeviceName,
		FILE_DEVICE_UNKNOWN,
		FILE_DEVICE_SECURE_OPEN,
		FALSE,
		&gDeviceObject);

	if (!NT_SUCCESS(status))
	{
		DbgPrint("Error create DeviceDirectoryData object");
		return status;
	}

	status = IoCreateSymbolicLink(&gSymbolicLink, &gDeviceName);
	if (!NT_SUCCESS(status))
	{
		DbgPrint("Error IoCreateSymbolicLink");
		IoDeleteDevice(gDeviceObject);
		return status;
	}

	DriverObject->MajorFunction[IRP_MJ_CREATE] = IrpCreateClose;
	DriverObject->MajorFunction[IRP_MJ_CLOSE] =  IrpCreateClose;
	DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IoCtrl;

	KeInitializeGuardedMutex(&gMutex);
	

	localEvent = IoCreateNotificationEvent(&EventName, &hEvent);
	KeClearEvent(localEvent);

	

	return status;
}

Well an obvious one is that your code expects no processes could be created in the time you driver is waiting for the IOCTL. When you signal the event it may already be set by a previous process create that the application has not responded to, at which point you lose on process on the count.

See my reply to your other thread. And do the community a favor, please… it’s helpful if you could get the formatting of your post correct. It makes it much easier for us to read.

It’s just markdown, like you’d use on GitHub or whatever. If it doesn’t show-up like you expect, edit your post until it looks like you want it to look. Please.

Peter