1.i want u to make it so that usermode sends the instructions to driver instead of the driver to the user mode.
2.usermode will send a notification saying hi to km once kernel mode recieves this message it will send a message back saying hi that will show on my usermode console
3. after comfimation user mode will have the decision to   send and recieve intruction  typedef struct _INSTRUCTIONS {
BOOLEAN close;
BOOLEAN read;
BOOLEAN reqBase;
PVOID bufferAddress;
UINT_PTR address;
ULONGLONG size;
PVOID output;
ULONG64 baseAddress;
char moduleName[256]; // Changed from 'const char' to a character array for string storage
} INSTRUCTIONS, PINSTRUCTIONS;
kernel mode will perform the usermodes instrcution and send back the results which user mode will recieve read and display the results on my screen

do not modyfy communication method

kernel mode
#include <ntifs.h>
#include <ntddk.h>

// ==========================================================
// Definitions and Macros
// ==========================================================

#define TARGET_PROCESS_NAME L"notepad.exe" // Replace with your target process name
#define MY_WNF_STATE_NAME 0x2821B2CA3BC4075ULL // WNF_AUDC_CAPTURE

// Windows Build Numbers
#define WINDOWS_1803 17134
#define WINDOWS_1809 17763
#define WINDOWS_1903 18362
#define WINDOWS_1909 18363
#define WINDOWS_2004 19041
#define WINDOWS_20H2 19569
#define WINDOWS_21H1 20180

// Page size definitions
#define PAGE_OFFSET_SIZE 12
#define PMASK 0x000FFFFFFFFFF000ull // Corrected PMASK for x64

// ==========================================================
// Function Pointer Types for WNF (Undocumented APIs)
// ==========================================================

typedef ULONG64 WNF_STATE_NAME;
typedef ULONG64 WNF_CHANGE_STAMP;

typedef enum _WNF_SUBSCRIPTION_FLAG {
WnfSubscriptionNone = 0x0,
WnfSubscriptionPublishCurrentState = 0x1,
// Add other flags as needed
} WNF_SUBSCRIPTION_FLAG;

typedef struct _WNF_SUBSCRIPTION {
// Define necessary fields based on WNF structures
} WNF_SUBSCRIPTION, PWNF_SUBSCRIPTION;

typedef struct _WNF_TYPE_ID {
// Define Type ID structure based on WNF specifications
} WNF_TYPE_ID, PCWNF_TYPE_ID;

// Function pointer typedefs
typedef NTSTATUS (PExSubscribeWnfStateChange)(
PWNF_SUBSCRIPTION Subscription,
WNF_STATE_NAME StateName,
WNF_SUBSCRIPTION_FLAG SubscriptionFlag,
PVOID Callback,
PVOID CallbackContext,
PCWNF_TYPE_ID TypeId,
PVOID DeliveryDescriptor,
ULONG DeliveryDescriptorSize
);

typedef NTSTATUS (PExPublishWnfStateData)(
PCWNF_STATE_NAME StateName,
PVOID Buffer,
ULONG Length,
PCWNF_TYPE_ID TypeId,
PVOID ExplicitScope,
ULONG MatchingChangeStamp
);

typedef NTSTATUS (PExUnsubscribeWnfStateChange)(
PWNF_SUBSCRIPTION Subscription
);

// Global function pointers
PExPublishWnfStateData ExPublishWnfStateDataFunc = NULL;
PExUnsubscribeWnfStateChange ExUnsubscribeWnfStateChangeFunc = NULL;

// ==========================================================
// Data Structures
// ==========================================================

typedef struct _INSTRUCTIONS {
BOOLEAN close;
BOOLEAN read;
BOOLEAN reqBase;
PVOID bufferAddress;
UINT_PTR address;
ULONGLONG size;
PVOID output;
ULONG64 baseAddress;
char moduleName[256]; // Changed from 'const char' to a character array for string storage
} INSTRUCTIONS, PINSTRUCTIONS;

// ==========================================================
// Function Declarations
// ==========================================================

NTKERNELAPI
PVOID
PsGetProcessSectionBaseAddress(
__in PEPROCESS Process
);

PVOID GetProcessBaseAddress(HANDLE pid);
DWORD GetUserDirectoryTableBaseOffset();
ULONG_PTR GetProcessCr3(PEPROCESS pProcess);
ULONG_PTR GetKernelDirBase();
NTSTATUS ReadVirtual(uint64_t dirbase, uint64_t address, uint8_t buffer, SIZE_T size, SIZE_T read);
NTSTATUS WriteVirtual(uint64_t dirbase, uint64_t address, uint8_t buffer, SIZE_T size, SIZE_T written);
NTSTATUS ReadPhysicalAddress(PVOID TargetAddress, PVOID lpBuffer, SIZE_T Size, SIZE_T BytesRead);
NTSTATUS WritePhysicalAddress(PVOID TargetAddress, PVOID lpBuffer, SIZE_T Size, SIZE_T BytesWritten);
uint64_t TranslateLinearAddress(uint64_t directoryTableBase, uint64_t virtualAddress);
NTSTATUS ReadProcessMemory(int pid, PVOID Address, PVOID AllocatedBuffer, SIZE_T size, SIZE_T read);
NTSTATUS WriteProcessMemory(int pid, PVOID Address, PVOID AllocatedBuffer, SIZE_T size, SIZE_T* written);
VOID ProcessNotifyCallback(
__in HANDLE ParentId,
__in HANDLE ProcessId,
__in BOOLEAN Create
);
VOID DriverUnload(PDRIVER_OBJECT DriverObject);

// ==========================================================
// Global Variables
// ==========================================================

PWNF_SUBSCRIPTION g_WnfSubscription = NULL;

// ==========================================================
// Function Definitions
// ==========================================================

// Retrieve the base address of a process given its PID
PVOID GetProcessBaseAddress(HANDLE pid)
{
PEPROCESS pProcess = NULL;
if (pid == NULL) return NULL;

NTSTATUS NtRet = PsLookupProcessByProcessId(pid, &pProcess);
if (NtRet != STATUS_SUCCESS) return NULL;

PVOID Base = PsGetProcessSectionBaseAddress(pProcess);
ObDereferenceObject(pProcess);
return Base;
}

// Get the offset for the UserDirectoryTableBase based on Windows version
DWORD GetUserDirectoryTableBaseOffset()
{
RTL_OSVERSIONINFOW ver = { 0 };
RtlGetVersion(&ver);

switch (ver.dwBuildNumber)
{
case WINDOWS_1803:
case WINDOWS_1809:
return 0x0278;
case WINDOWS_1903:
case WINDOWS_1909:
case WINDOWS_2004:
case WINDOWS_20H2:
case WINDOWS_21H1:
default:
return 0x0388;
}
}

// Retrieve the CR3 (Page Directory Base) of a process
ULONG_PTR GetProcessCr3(PEPROCESS pProcess)
{
PUCHAR process = (PUCHAR)pProcess;
#ifdef _WIN64
ULONG_PTR* process_dirbase_ptr = (ULONG_PTR)(process + 0x28); // dirbase for x64
#else
ULONG_PTR process_dirbase_ptr = (ULONG_PTR*)(process + 0x18); // dirbase for x86
#endif
ULONG_PTR process_dirbase = process_dirbase_ptr;

if (process_dirbase == 0)
{
DWORD UserDirOffset = GetUserDirectoryTableBaseOffset();
ULONG_PTR process_userdirbase_ptr = (ULONG_PTR*)(process + UserDirOffset);
return process_userdirbase_ptr;
}
return process_dirbase;
}

// Example function to get the kernel's CR3 (for demonstration; typically not used)
ULONG_PTR GetKernelDirBase()
{
// Note: Accessing the kernel's CR3 is generally unsafe and not recommended
// This is just for illustrative purposes
return __readcr3();
}

// Translate a virtual address to a physical address using the provided directory table base
uint64_t TranslateLinearAddress(uint64_t directoryTableBase, uint64_t virtualAddress) {
directoryTableBase &= 0xFFFFFFFFFF000ull; // Align directoryTableBase

uint64_t pageOffset = virtualAddress & 0xFFF;
uint64_t pte = (virtualAddress >> 12) & 0x1FF;
uint64_t pt = (virtualAddress >> 21) & 0x1FF;
uint64_t pd = (virtualAddress >> 30) & 0x1FF;
uint64_t pdp = (virtualAddress >> 39) & 0x1FF;

SIZE_T readsize = 0;
uint64_t pdpe = 0;
if (!NT_SUCCESS(ReadPhysicalAddress((PVOID)(directoryTableBase + 8 * pdp), &pdpe, sizeof(pdpe), &readsize)) || (pdpe & 1))
return 0;

uint64_t pde = 0;
if (!NT_SUCCESS(ReadPhysicalAddress((PVOID)((pdpe & PMASK) + 8 * pd), &pde, sizeof(pde), &readsize)) || (pde & 1))
return 0;

// 1GB large page
if (pde & (1 << 7)) // Check the PS (Page Size) bit
return (pde & 0x000FFFFFFFFFF000ull) + (virtualAddress & 0x3FFFFFFFull);

uint64_t pteAddr = 0;
if (!NT_SUCCESS(ReadPhysicalAddress((PVOID)((pde & PMASK) + 8 * pt), &pteAddr, sizeof(pteAddr), &readsize)) || (pteAddr & 1))
return 0;

// 2MB large page
if (pteAddr & (1 << 7)) // Check the PS bit
return (pteAddr & PMASK) + (virtualAddress & 0x1FFFFFull);

uint64_t physPage = 0;
if (!NT_SUCCESS(ReadPhysicalAddress((PVOID)( (pteAddr & PMASK) + 8 * pte), &physPage, sizeof(physPage), &readsize)) || !(physPage & 1))
return 0;

physPage &= PMASK;
return physPage + pageOffset;
}

// Read a physical address into a buffer
NTSTATUS ReadPhysicalAddress(PVOID TargetAddress, PVOID lpBuffer, SIZE_T Size, SIZE_T BytesRead)
{
if (TargetAddress == NULL || lpBuffer == NULL || BytesRead == NULL)
return STATUS_INVALID_PARAMETER;

MM_COPY_ADDRESS AddrToRead = { 0 };
AddrToRead.PhysicalAddress.QuadPart = (ULONG_PTR)TargetAddress;

NTSTATUS status = MmCopyMemory(lpBuffer, AddrToRead, Size, MM_COPY_MEMORY_PHYSICAL, BytesRead);
return status;
}

// Write a buffer to a physical address
NTSTATUS WritePhysicalAddress(PVOID TargetAddress, PVOID lpBuffer, SIZE_T Size, SIZE_T* BytesWritten)
{
if (!TargetAddress || !lpBuffer || !BytesWritten)
return STATUS_INVALID_PARAMETER;

PHYSICAL_ADDRESS AddrToWrite = { 0 };
AddrToWrite.QuadPart = (ULONG_PTR)TargetAddress;

// Limit MmMapIoSpaceEx to PAGE_SIZE (4096 bytes)
if (Size > PAGE_SIZE)
return STATUS_INVALID_PARAMETER;

PVOID pmapped_mem = MmMapIoSpaceEx(AddrToWrite, Size, PAGE_READWRITE);
if (!pmapped_mem)
return STATUS_UNSUCCESSFUL;

RtlCopyMemory(pmapped_mem, lpBuffer, Size);
BytesWritten = Size;
MmUnmapIoSpace(pmapped_mem, Size);
return STATUS_SUCCESS;
}

// Read virtual memory from a process
NTSTATUS ReadVirtual(uint64_t dirbase, uint64_t address, uint8_t buffer, SIZE_T size, SIZE_T* read)
{
if (!buffer || !read)
return STATUS_INVALID_PARAMETER;

uint64_t paddress;
NTSTATUS status = STATUS_SUCCESS;
SIZE_T CurOffset = 0;
SIZE_T TotalSize = size;

while (TotalSize > 0)
{
paddress = TranslateLinearAddress(dirbase, address + CurOffset);
if (!paddress)
return STATUS_UNSUCCESSFUL;

ULONG64 ReadSize = min(PAGE_SIZE - (paddress & 0xFFF), TotalSize);
SIZE_T BytesReadLocal = 0;

status = ReadPhysicalAddress((PVOID)paddress, buffer + CurOffset, ReadSize, &BytesReadLocal);
if (!NT_SUCCESS(status) || BytesReadLocal == 0)
break;

TotalSize -= BytesReadLocal;
CurOffset += BytesReadLocal;
}

read = CurOffset;
return status;
}

// Write virtual memory to a process
NTSTATUS WriteVirtual(uint64_t dirbase, uint64_t address, uint8_t buffer, SIZE_T size, SIZE_T* written)
{
if (!buffer || !written)
return STATUS_INVALID_PARAMETER;

uint64_t paddress;
NTSTATUS status = STATUS_SUCCESS;
SIZE_T CurOffset = 0;
SIZE_T TotalSize = size;

while (TotalSize > 0)
{
paddress = TranslateLinearAddress(dirbase, address + CurOffset);
if (!paddress)
return STATUS_UNSUCCESSFUL;

ULONG64 WriteSize = min(PAGE_SIZE - (paddress & 0xFFF), TotalSize);
SIZE_T BytesWrittenLocal = 0;

status = WritePhysicalAddress((PVOID)paddress, buffer + CurOffset, WriteSize, &BytesWrittenLocal);
if (!NT_SUCCESS(status) || BytesWrittenLocal == 0)
break;

TotalSize -= BytesWrittenLocal;
CurOffset += BytesWrittenLocal;
}

written = CurOffset;
return status;
}

// Read the memory of a process by PID
NTSTATUS ReadProcessMemory(int pid, PVOID Address, PVOID AllocatedBuffer, SIZE_T size, SIZE_T read)
{
if (pid == 0 || Address == NULL || AllocatedBuffer == NULL || read == NULL)
return STATUS_INVALID_PARAMETER;

PEPROCESS pProcess = NULL;
NTSTATUS NtRet = PsLookupProcessByProcessId((HANDLE)(ULONG_PTR)pid, &pProcess);
if (NtRet != STATUS_SUCCESS)
return NtRet;

ULONG_PTR process_dirbase = GetProcessCr3(pProcess);
ObDereferenceObject(pProcess);

NtRet = ReadVirtual(process_dirbase, (ULONG_PTR)Address, (uint8_t*)AllocatedBuffer, size, read);
return NtRet;
}

// Write the memory of a process by PID
NTSTATUS WriteProcessMemory(int pid, PVOID Address, PVOID AllocatedBuffer, SIZE_T size, SIZE_T* written)
{
if (pid == 0 || Address == NULL || AllocatedBuffer == NULL || written == NULL)
return STATUS_INVALID_PARAMETER;

PEPROCESS pProcess = NULL;
NTSTATUS NtRet = PsLookupProcessByProcessId((HANDLE)(ULONG_PTR)pid, &pProcess);
if (NtRet != STATUS_SUCCESS)
return NtRet;

ULONG_PTR process_dirbase = GetProcessCr3(pProcess);
ObDereferenceObject(pProcess);

NtRet = WriteVirtual(process_dirbase, (ULONG_PTR)Address, (uint8_t*)AllocatedBuffer, size, written);
return NtRet;
}

// Callback function for WNF state changes
NTSTATUS notifCallback(
PWNF_SUBSCRIPTION Subscription,
WNF_STATE_NAME StateName,
ULONG SubscribedEventSet,
WNF_CHANGE_STAMP ChangeStamp,
PCWNF_TYPE_ID TypeId,
PVOID CallbackContext
)
{
UNREFERENCED_PARAMETER(TypeId);
UNREFERENCED_PARAMETER(CallbackContext);
UNREFERENCED_PARAMETER(SubscribedEventSet);

NTSTATUS status = STATUS_SUCCESS;
ULONG bufferSize = 0x0;
PVOID pStateData = NULL;
WNF_CHANGE_STAMP changeStampLocal = 0;

// Query required buffer size
status = ExQueryWnfStateDataFunc(Subscription, &changeStampLocal, NULL, &bufferSize);
if (status != STATUS_BUFFER_TOO_SMALL)
goto Exit;

// Allocate buffer
pStateData = ExAllocatePoolWithTag(PagedPool, bufferSize, 'LULZ');
if (pStateData == NULL) {
status = STATUS_UNSUCCESSFUL;
goto Exit;
}

// Query the state data
status = ExQueryWnfStateDataFunc(Subscription, &changeStampLocal, pStateData, &bufferSize);
if (NT_SUCCESS(status)) {
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "## Data processed: %S\n", (PWSTR)pStateData);
// Implement further processing of pStateData as needed
}

Exit:
if (pStateData != NULL)
ExFreePoolWithTag(pStateData, 'LULZ');
return status;
}

// Function to subscribe to WNF state changes
NTSTATUS CallExSubscribeWnfStateChange()
{
PWNF_SUBSCRIPTION wnfSubscription = NULL;
WNF_STATE_NAME stateName = MY_WNF_STATE_NAME; // Use the corrected WNF state name
NTSTATUS status;

status = ExSubscribeWnfStateChange(&wnfSubscription, stateName, WnfSubscriptionPublishCurrentState,
NULL, ¬ifCallback, NULL, NULL, 0);
if (NT_SUCCESS(status)) {
g_WnfSubscription = wnfSubscription;
DbgPrint("Subscription address: %p\n", (PVOID)wnfSubscription);
}

return status;
}

// ==========================================================
// Process Notification Callback
// ==========================================================

VOID ProcessNotifyCallback(
__in HANDLE ParentId,
__in HANDLE ProcessId,
__in BOOLEAN Create
)
{
UNREFERENCED_PARAMETER(ParentId);

if (Create)
{
PEPROCESS pProcess = NULL;
NTSTATUS status = PsLookupProcessByProcessId(ProcessId, &pProcess);
if (NT_SUCCESS(status))
{
// Get process image file name
WCHAR imageName[300] = { 0 };
UNICODE_STRING uProcessImageName = { 0 };

// Use SeLocateProcessImageName
status = SeLocateProcessImageName(pProcess, &uProcessImageName);
if (NT_SUCCESS(status))
{
// Extract file name from full path
PWSTR processName = wcsrchr(uProcessImageName.Buffer, L''); // Corrected to search for backslash
if (processName)
{
processName++; // Move past the backslash

// Check if this is the target process
if (_wcsicmp(processName, TARGET_PROCESS_NAME) == 0)
{
// Perform memory operations here

// Get base address
PVOID baseAddress = GetProcessBaseAddress(ProcessId);
if (baseAddress)
{
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[Driver] Base address of %ws: %p\n", processName, baseAddress);

// Example: Read some memory from the process
UCHAR buffer[256] = { 0 };
SIZE_T bytesRead = 0;
NTSTATUS ntStatus = ReadProcessMemory((int)(ULONG_PTR)ProcessId, baseAddress, buffer, sizeof(buffer), &bytesRead);

if (NT_SUCCESS(ntStatus))
{
// Do something with the read data
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[Driver] Successfully read %zu bytes from %ws\n", bytesRead, processName);
}
else
{
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[Driver] Failed to read process memory: 0x%X\n", ntStatus);
}

// Example: Write to process memory (be cautious with actual addresses)
/
UCHAR writeData[256] = { / ... */ };
SIZE_T bytesWritten = 0;
ntStatus = WriteProcessMemory((int)(ULONG_PTR)ProcessId, baseAddress, writeData, sizeof(writeData), &bytesWritten);

if (NT_SUCCESS(ntStatus))
{
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[Driver] Successfully wrote %zu bytes to %ws\n", bytesWritten, processName);
}
else
{
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[Driver] Failed to write process memory: 0x%X\n", ntStatus);
}
/
}
else
{
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[Driver] Failed to get base address of %ws\n", processName);
}
}
}
else
{
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[Driver] Failed to parse process name\n");
}

// Free the UNICODE_STRING allocated by SeLocateProcessImageName
ExFreePoolWithTag(uProcessImageName.Buffer, 'imgN');
}
else
{
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[Driver] SeLocateProcessImageName failed with status: 0x%X\n", status);
}

ObDereferenceObject(pProcess);
}
else
{
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[Driver] PsLookupProcessByProcessId failed with status: 0x%X\n", status);
}
}
}

// ==========================================================
// Driver Unload Routine
// ==========================================================

VOID DriverUnload(PDRIVER_OBJECT DriverObject)
{
UNICODE_STRING symbolicLinkName;
RtlInitUnicodeString(&symbolicLinkName, L"??\MyKernelDriverLink");

// Remove the process notify routine
NTSTATUS status = PsSetCreateProcessNotifyRoutine(ProcessNotifyCallback, TRUE);
if (!NT_SUCCESS(status))
{
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[Driver] Failed to remove process notify routine: 0x%X\n", status);
}
else
{
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[Driver] Process notify routine removed successfully\n");
}

// Unsubscribe WNF state change if subscribed
if (g_WnfSubscription != NULL && ExUnsubscribeWnfStateChangeFunc != NULL)
{
ExUnsubscribeWnfStateChangeFunc(g_WnfSubscription);
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[Driver] WNF subscription unsubscribed successfully\n");
}

// Delete the symbolic link and device object (if created)
// Assuming device creation was implemented as per user requirements. If not, this section can be omitted.

DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[Driver] Driver unloaded\n");
}

// ==========================================================
// WNF Functions and DriverEntry Implementation
// ==========================================================

// Function to initialize WNF communication
NTSTATUS InitializeWNF()
{
// Dynamically resolve the ExPublishWnfStateData function
UNICODE_STRING publishFunctionName;
RtlInitUnicodeString(&publishFunctionName, L"ExPublishWnfStateData");
ExPublishWnfStateDataFunc = (PExPublishWnfStateData)MmGetSystemRoutineAddress(&publishFunctionName);

// Dynamically resolve the ExUnsubscribeWnfStateChange function
UNICODE_STRING unsubscribeFunctionName;
RtlInitUnicodeString(&unsubscribeFunctionName, L"ExUnsubscribeWnfStateChange");
ExUnsubscribeWnfStateChangeFunc = (PExUnsubscribeWnfStateChange)MmGetSystemRoutineAddress(&unsubscribeFunctionName);

if (ExPublishWnfStateDataFunc == NULL || ExUnsubscribeWnfStateChangeFunc == NULL)
{
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[Driver] Failed to resolve WNF functions\n");
return STATUS_UNSUCCESSFUL;
}

// Prepare your data (if needed)
/
INSTRUCTIONS instructions = { 0 };
instructions.reqBase = TRUE;
instructions.baseAddress = 0x12345678; // Example base address
instructions.output = (PVOID)instructions.baseAddress;

// Publish the data to the WNF state
NTSTATUS status = ExPublishWnfStateDataFunc(
&MY_WNF_STATE_NAME,
&instructions,
sizeof(INSTRUCTIONS),
NULL,
NULL,
0
);

if (!NT_SUCCESS(status))
{
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[Driver] ExPublishWnfStateData failed: 0x%08X\n", status);
return status;
}

DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[Driver] Published WNF state data successfully\n");
/

// Subscribe to the WNF state change
status = CallExSubscribeWnfStateChange();
if (!NT_SUCCESS(status))
{
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[Driver] ExSubscribeWnfStateChange failed: 0x%08X\n", status);
return status;
}

DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[Driver] Subscribed to WNF state changes successfully\n");
return STATUS_SUCCESS;
}

// Main DriverEntry function
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
UNREFERENCED_PARAMETER(RegistryPath);

NTSTATUS status;

// Register the process creation notify routine
status = PsSetCreateProcessNotifyRoutine(ProcessNotifyCallback, FALSE);
if (!NT_SUCCESS(status))
{
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[Driver] PsSetCreateProcessNotifyRoutine failed: 0x%X\n", status);
return status;
}
else
{
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[Driver] Process notify routine set successfully\n");
}

// Initialize WNF communication
status = InitializeWNF();
if (!NT_SUCCESS(status))
{
// If WNF initialization fails, unload the driver
PsSetCreateProcessNotifyRoutine(ProcessNotifyCallback, TRUE);
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[Driver] WNF initialization failed. Driver will unload.\n");
return status;
}

// Set the unload routine
DriverObject->DriverUnload = DriverUnload;

DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[Driver] Driver loaded successfully\n");
return STATUS_SUCCESS;
}


usermode

using System;
using NtApiDotNet;
using System.Threading;

namespace WnfSubscriber
{
class Program
{
// Define the WNF state name
private const ulong MY_WNF_STATE_NAME = 0x41C64E6DA3BC1074;

static void Main(string[] args)
{
WnfClient client = new WnfClient();

// Subscribe to the WNF state
client.SubscribeState(MY_WNF_STATE_NAME, OnWnfStateChange);

Console.WriteLine("Subscribed to WNF state. Waiting for changes...");

// Keep the application running
while (true)
{
Thread.Sleep(1000);
}
}

// Callback when WNF state changes
static void OnWnfStateChange(WnfStateChange change)
{
Console.WriteLine("WNF State Changed!");

// Assuming the state data is the INSTRUCTIONS structure
// Deserialize the data accordingly
if (change.Data.Length >= Marshal.SizeOf(typeof(INSTRUCTIONS)))
{
INSTRUCTIONS instructions = change.Data.ToStructure<INSTRUCTIONS>();

Console.WriteLine("Received Instructions:");
Console.WriteLine($"Close: {instructions.close}");
Console.WriteLine($"Read: {instructions.read}");
Console.WriteLine($"Request Base: {instructions.reqBase}");
Console.WriteLine($"Buffer Address: {instructions.bufferAddress}");
Console.WriteLine($"Address: 0x{instructions.address:X}");
Console.WriteLine($"Size: {instructions.size}");
Console.WriteLine($"Output: {instructions.output}");
Console.WriteLine($"Base Address: 0x{instructions.baseAddress:X}");
Console.WriteLine($"Module Name: {instructions.moduleName}");
}
else
{
Console.WriteLine("Received data is smaller than expected.");
}
}

// Define the INSTRUCTIONS structure
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
struct INSTRUCTIONS
{
public byte close;
public byte read;
public byte reqBase;
public IntPtr bufferAddress;
public UIntPtr address;
public ulong size;
public IntPtr output;
public ulong baseAddress;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string moduleName;
}
}
}