do not remove methods just fix mistakes do not remove function but u are allowed to move or add different functions
#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 0x41C64E6DA3BC1074ULL // 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 &= 0xFFFFFFFFFF000 ull; // 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 & 0x000FFFFFFFFFF000 ull) + (virtualAddress & 0x3FFFFFFF ull);

  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 & 0x1FFFFF ull);

  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 ChangeStamp,
       PVOID TypeId,
       PVOID CallbackContext,
       PVOID CallbackData,
       ULONG CallbackDataSize
   ) 
{
   UNREFERENCED_PARAMETER(Subscription);
   UNREFERENCED_PARAMETER(StateName);
   UNREFERENCED_PARAMETER(TypeId);
   UNREFERENCED_PARAMETER(CallbackContext);

    NTSTATUS status = STATUS_SUCCESS;
    if (CallbackData && CallbackDataSize >= sizeof(INSTRUCTIONS)) {
       // Assume CallbackData is an INSTRUCTIONS structure
       PINSTRUCTIONS instructions = (PINSTRUCTIONS)CallbackData;
    
       // Process instructions
       if (instructions->read) {
           // Perform read operation
           // Example: Read memory at instructions->address
           // ...
    
           // Prepare result
           char resultMessage[] = "Read operation completed";
           status = ExPublishWnfStateData(&MY_WNF_STATE_NAME, resultMessage, sizeof(resultMessage), NULL, NULL, 0);
           if (NT_SUCCESS(status)) {
               DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "Kernel sent result: %s\n", resultMessage);
            } 
            else {
               DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "Failed to send result, status: 0x%08X\n", status);
            }
       }
       // Handle other instructions
       // ...
    }
    else if (CallbackData && CallbackDataSize > 0) {
       // Process the received data
       char* receivedMessage = ExAllocatePoolWithTag(NonPagedPoolNx, CallbackDataSize + 1, 'msgK');
       if (receivedMessage) {
           RtlZeroMemory(receivedMessage, CallbackDataSize + 1);
           RtlCopyMemory(receivedMessage, CallbackData, CallbackDataSize);

           DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "Kernel received message: %s\n", receivedMessage);

           // Check if the message is 'Hi' and respond accordingly
           if (strcmp(receivedMessage, "Hi") == 0) {
               // Send 'Hi' back to user-mode
               char replyMessage[] = "Hi";
               status = ExPublishWnfStateData(&MY_WNF_STATE_NAME, replyMessage, sizeof(replyMessage), NULL, NULL, 0);
               if (NT_SUCCESS(status)) {
                   DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "Kernel sent reply: %s\n", replyMessage);
               } else {
                   DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "Failed to send reply, status: 0x%08X\n", status);
               }
           }
           

           ExFreePoolWithTag(receivedMessage, 'msgK');
        } 
        else {
           status = STATUS_INSUFFICIENT_RESOURCES;
        }
    }

   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;
}
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. Sending 'Hi' to kernel-mode.");

       // Send 'Hi' to kernel-mode
       SendMessageToKernel("Hi");

       // Keep the application running
       while (true)
       {
           Thread.Sleep(1000);
       }
   }
   static void SendMessageToKernel(string message)
   {
       // Convert the message to bytes
       byte[] dataToSend = Encoding.ASCII.GetBytes(message);

       // Publish the state
       NtWnf.PublishStateData(new WnfStateName(MY_WNF_STATE_NAME), dataToSend);
       Console.WriteLine("Sent message to kernel-mode: " + message);
    }       


    // Callback when WNF state changes
    static void OnWnfStateChange(WnfStateChange change)
    {
        Console.WriteLine("WNF State Changed!");
    
        // Convert the received data to a string
        string receivedMessage = Encoding.ASCII.GetString(change.Data.ToArray());
        Console.WriteLine("Received message from kernel-mode: " + receivedMessage);
    
        if (receivedMessage == "Hi")
        {
            Console.WriteLine("Received 'Hi' from kernel-mode. Sending instructions...");
    
            // Prepare instructions
            INSTRUCTIONS instructions = new INSTRUCTIONS
            {
                close = 0,
                read = 1,
                reqBase = 0,
                bufferAddress = IntPtr.Zero,
                address = UIntPtr.Zero,
                size = 0,
                output = IntPtr.Zero,
                baseAddress = 0,
                moduleName = "ExampleModule"
            };
    
            // Send instructions
            SendInstructionsToKernel(instructions);
        }
        else if (receivedMessage == "Read operation completed")
        {
            Console.WriteLine("Kernel-mode has completed the read operation.");
            // Process the results if any
            // ...
        }
        else
        {
            // Handle other messages or results
            Console.WriteLine("Received data: " + receivedMessage);
        }
    }

   
    static void SendInstructionsToKernel(INSTRUCTIONS instructions)
   {
       int size = Marshal.SizeOf(instructions);
       IntPtr ptr = Marshal.AllocHGlobal(size);
       Marshal.StructureToPtr(instructions, ptr, false);

       byte[] dataToSend = new byte[size];
       Marshal.Copy(ptr, dataToSend, 0, size);
       Marshal.FreeHGlobal(ptr);

       NtWnf.PublishStateData(new WnfStateName(MY_WNF_STATE_NAME), dataToSend);
       Console.WriteLine("Sent instructions to kernel-mode.");
   }

    // 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;
    }
  }
}