REMOVE/AVOID the io, irp, IOCTL, irp mjor functions, system threads, permanent hooks, driver objects, section objects or device objects .


#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
#define BASE64_CHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
// 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
// ==========================================================
#pragma pack(push, 1)

typedef struct _INSTRUCTIONS {
BOOLEAN close;
BOOLEAN read;
BOOLEAN write;
BOOLEAN reqBase;
UINT_PTR processId;
UINT_PTR address;
ULONGLONG size;
PVOID bufferAddress;
PVOID output;
ULONG64 baseAddress;
char moduleName[256];
char data[1024]; // Added to match user-mode
} INSTRUCTIONS, PINSTRUCTIONS;
#pragma pack(pop)

// ==========================================================
// 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;
}
}
UCHAR Base64DecodeChar(char c) {
if (c >= 'A' && c <= 'Z') return c - 'A';
if (c >= 'a' && c <= 'z') return c - 'a' + 26;
if (c >= '0' && c <= '9') return c - '0' + 52;
if (c == '+') return 62;
if (c == '/') return 63;
return 0xFF; // Invalid character
}

NTSTATUS DecodeBase64(const char* base64Input, UCHAR* outputBuffer, SIZE_T bufferSize, SIZE_T* decodedSize) {
if (!base64Input || !outputBuffer || !decodedSize)
return STATUS_INVALID_PARAMETER;

SIZE_T inputLen = strlen(base64Input);
if (inputLen % 4 != 0)
return STATUS_INVALID_PARAMETER;

SIZE_T outputLen = (inputLen / 4) * 3;
if (outputLen > bufferSize)
return STATUS_BUFFER_TOO_SMALL;

decodedSize = 0;

for (SIZE_T i = 0; i < inputLen; i += 4) {
UCHAR sextet_a = Base64DecodeChar(base64Input[i]);
UCHAR sextet_b = Base64DecodeChar(base64Input[i + 1]);
UCHAR sextet_c = Base64DecodeChar(base64Input[i + 2]);
UCHAR sextet_d = Base64DecodeChar(base64Input[i + 3]);

if (sextet_a == 0xFF || sextet_b == 0xFF)
return STATUS_INVALID_PARAMETER;

UCHAR triple[3] = {0};

triple[0] = (sextet_a << 2) | (sextet_b >> 4);
if (base64Input[i + 2] != '=') {
if (sextet_c == 0xFF)
return STATUS_INVALID_PARAMETER;
triple[1] = ((sextet_b & 0xF) << 4) | (sextet_c >> 2);
}
if (base64Input[i + 3] != '=') {
if (sextet_d == 0xFF)
return STATUS_INVALID_PARAMETER;
triple[2] = ((sextet_c & 0x3) << 6) | sextet_d;
}

// Copy the decoded bytes to the output buffer
outputBuffer[decodedSize] = triple[0];
(decodedSize)++;

if (base64Input[i + 2] != '=') {
outputBuffer[decodedSize] = triple[1];
(decodedSize)++;
}

if (base64Input[i + 3] != '=') {
outputBuffer[decodedSize] = triple[2];
(decodedSize)++;
}
}

return STATUS_SUCCESS;
}

NTSTATUS EncodeBase64(const UCHAR input, SIZE_T inputSize, char outputBuffer, SIZE_T bufferSize, SIZE_T encodedSize) {
if (!input || !outputBuffer || !encodedSize)
return STATUS_INVALID_PARAMETER;

const char base64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
SIZE_T outputNeeded = ((inputSize + 2) / 3) * 4;
if (outputNeeded + 1 > bufferSize) // +1 for null terminator if needed
return STATUS_BUFFER_TOO_SMALL;

SIZE_T i = 0, j = 0;
for (; i + 3 <= inputSize; i += 3) {
UCHAR a = input[i];
UCHAR b = input[i + 1];
UCHAR c = input[i + 2];

outputBuffer[j++] = base64_table[(a >> 2) & 0x3F];
outputBuffer[j++] = base64_table[((a & 0x3) << 4) | ((b & 0xF0) >> 4)];
outputBuffer[j++] = base64_table[((b & 0xF) << 2) | ((c & 0xC0) >> 6)];
outputBuffer[j++] = base64_table[c & 0x3F];
}

// Handle padding
if (i < inputSize) {
UCHAR a = input[i];
UCHAR b = (i + 1 < inputSize) ? input[i + 1] : 0;

outputBuffer[j++] = base64_table[(a >> 2) & 0x3F];
outputBuffer[j++] = base64_table[((a & 0x3) << 4) | ((b & 0xF0) >> 4)];
outputBuffer[j++] = (i + 1 < inputSize) ? base64_table[((b & 0xF) << 2)] : '=';
outputBuffer[j++] = '=';
}

encodedSize = j;
return STATUS_SUCCESS;
}


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


ULONG_PTR GetKernelDirBase() {
PUCHAR process = (PUCHAR)PsGetCurrentProcess();
ULONG_PTR cr3 = (PULONG_PTR)(process + 0x28); //dirbase x64, 32bit is 0x18
return cr3;

}

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

// Verify that CallbackDataSize is sufficient for INSTRUCTIONS struct
if (CallbackData && CallbackDataSize >= sizeof(INSTRUCTIONS)) {
PINSTRUCTIONS instructions = (PINSTRUCTIONS)CallbackData;

if (instructions->read) {
// Handle read operation

// Validate parameters
if (instructions->processId == 0 || instructions->address == 0 || instructions->size == 0) {
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[Driver] Invalid parameters for read operation.\n");
status = ExPublishWnfStateDataFunc(
&MY_WNF_STATE_NAME,
"Read operation failed: Invalid parameters.",
(ULONG)strlen("Read operation failed: Invalid parameters.") + 1, // Include null terminator
NULL,
NULL,
0
);
return status;
}

// Allocate memory to store read data
UCHAR* readBuffer = (UCHAR*)ExAllocatePoolWithTag(NonPagedPool, instructions->size, 'rdmK');
if (!readBuffer) {
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[Driver] Read operation failed: Unable to allocate memory.\n");
status = ExPublishWnfStateDataFunc(
&MY_WNF_STATE_NAME,
"Read operation failed: Unable to allocate memory.",
(ULONG)strlen("Read operation failed: Unable to allocate memory.") + 1,
NULL,
NULL,
0
);
return status;
}

// Zero-initialize the buffer
RtlZeroMemory(readBuffer, instructions->size);

// Read memory from target process
SIZE_T bytesRead = 0;
status = ReadProcessMemory(
(int)(ULONG_PTR)instructions->processId,
(PVOID)(ULONG_PTR)instructions->address,
readBuffer,
instructions->size,
&bytesRead
);

if (!NT_SUCCESS(status) || bytesRead == 0) {
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[Driver] ReadProcessMemory failed: 0x%X (BytesRead: %zu)\n", status, bytesRead);
ExFreePoolWithTag(readBuffer, 'rdmK');
status = ExPublishWnfStateDataFunc(
&MY_WNF_STATE_NAME,
"Read operation failed.",
(ULONG)strlen("Read operation failed.") + 1,
NULL,
NULL,
0
);
return status;
}

// Encode the read data to Base64
SIZE_T base64Size = ((bytesRead + 2) / 3) * 4;
// Check if encoded data size exceeds maximum allowed (e.g., 4096 bytes)
if (base64Size + 1 > 4096) { // +1 for null terminator
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[Driver] Read operation failed: Encoded data exceeds buffer size.\n");
ExFreePoolWithTag(readBuffer, 'rdmK');
status = ExPublishWnfStateDataFunc(
&MY_WNF_STATE_NAME,
"Read operation failed: Encoded data exceeds buffer size.",
(ULONG)strlen("Read operation failed: Encoded data exceeds buffer size.") + 1,
NULL,
NULL,
0
);
return status;
}

// Allocate buffer for Base64 encoded data
char* encodedData = (char*)ExAllocatePoolWithTag(NonPagedPool, base64Size + 1, 'encK'); // +1 for null terminator
if (!encodedData) {
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[Driver] Read operation failed: Unable to allocate Base64 buffer.\n");
ExFreePoolWithTag(readBuffer, 'rdmK');
status = ExPublishWnfStateDataFunc(
&MY_WNF_STATE_NAME,
"Read operation failed: Unable to allocate Base64 buffer.",
(ULONG)strlen("Read operation failed: Unable to allocate Base64 buffer.") + 1,
NULL,
NULL,
0
);
return status;
}

// Encode to Base64
SIZE_T encodedLength = 0;
status = EncodeBase64(readBuffer, bytesRead, encodedData, base64Size + 1, &encodedLength);
ExFreePoolWithTag(readBuffer, 'rdmK'); // Free read buffer

if (!NT_SUCCESS(status)) {
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[Driver] EncodeBase64 failed: 0x%X\n", status);
ExFreePoolWithTag(encodedData, 'encK');
status = ExPublishWnfStateDataFunc(
&MY_WNF_STATE_NAME,
"Read operation failed: Base64 encode failed.",
(ULONG)strlen("Read operation failed: Base64 encode failed.") + 1,
NULL,
NULL,
0
);
return status;
}

// Ensure null termination
if (encodedLength < base64Size + 1) {
encodedData[encodedLength] = '\0';
} else {
// Force null termination to prevent buffer overruns
encodedData[base64Size] = '\0';
}

// Publish the encoded data back via WNF
status = ExPublishWnfStateDataFunc(
&MY_WNF_STATE_NAME,
encodedData,
(ULONG)(encodedLength + 1), // Include null terminator
NULL,
NULL,
0
);

if (NT_SUCCESS(status)) {
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[Driver] Read operation completed successfully. %zu bytes read, %zu bytes encoded.\n", bytesRead, encodedLength);
}
else {
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[Driver] ExPublishWnfStateDataFunc failed: 0x%X\n", status);
}

ExFreePoolWithTag(encodedData, 'encK'); // Free encoded data buffer
}
else if (instructions->write) {
// Handle write operation

// Validate parameters
if (instructions->processId == 0 || instructions->address == 0 || instructions->size == 0 || instructions->data[0] == '\0') {
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[Driver] Invalid parameters for write operation.\n");
status = ExPublishWnfStateDataFunc(
&MY_WNF_STATE_NAME,
"Write operation failed: Invalid parameters.",
(ULONG)strlen("Write operation failed: Invalid parameters.") + 1,
NULL,
NULL,
0
);
return status;
}

// Decode the Base64 data
UCHAR decodedData[512];
SIZE_T decodedSize = 0;
status = DecodeBase64(instructions->data, decodedData, sizeof(decodedData), &decodedSize);
if (!NT_SUCCESS(status)) {
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[Driver] DecodeBase64 failed: 0x%X\n", status);
// Inform user-mode about the failure
status = ExPublishWnfStateDataFunc(
&MY_WNF_STATE_NAME,
"Write operation failed: Base64 decode failed.",
(ULONG)strlen("Write operation failed: Base64 decode failed.") + 1,
NULL,
NULL,
0
);
return status;
}

// Proceed with writing memory using decodedData and decodedSize
SIZE_T bytesWritten = 0;
status = WriteProcessMemory(
(int)(ULONG_PTR)instructions->processId,
(PVOID)(ULONG_PTR)instructions->address,
decodedData,
decodedSize,
&bytesWritten
);

if (NT_SUCCESS(status) && bytesWritten == decodedSize) {
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[Driver] Write operation completed successfully. %zu bytes written to process %lu at address 0x%llX\n", bytesWritten, instructions->processId, instructions->address);
status = ExPublishWnfStateDataFunc(
&MY_WNF_STATE_NAME,
"Write operation completed successfully.",
(ULONG)strlen("Write operation completed successfully.") + 1,
NULL,
NULL,
0
);
}
else {
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[Driver] WriteProcessMemory failed: 0x%X (BytesWritten: %zu)\n", status, bytesWritten);
// Inform user-mode about the failure
status = ExPublishWnfStateDataFunc(
&MY_WNF_STATE_NAME,
"Write operation failed.",
(ULONG)strlen("Write operation failed.") + 1,
NULL,
NULL,
0
);
}
}
// Handle other instructions...
}
else if (CallbackData && CallbackDataSize > 0) {
// Handle messages that don't match INSTRUCTIONS struct
// For example: simple messages like "Hi"

// Allocate memory for the received message, ensuring no buffer overflows
CHAR* receivedMessage = (CHAR*)ExAllocatePoolWithTag(NonPagedPoolNx, CallbackDataSize + 1, 'msgK');
if (!receivedMessage) {
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[Driver] Failed to allocate memory for received message.\n");
return STATUS_INSUFFICIENT_RESOURCES;
}

// Zero-initialize the allocated memory
RtlZeroMemory(receivedMessage, CallbackDataSize + 1);

// Copy the received data, ensuring not to exceed the allocated buffer
RtlCopyMemory(receivedMessage, CallbackData, min(CallbackDataSize, (ULONG)strlen("Hi")));

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 = ExPublishWnfStateDataFunc(
&MY_WNF_STATE_NAME,
replyMessage,
(ULONG)strlen(replyMessage) + 1, // Include null terminator
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, "[Driver] Failed to send reply, status: 0x%08X\n", status);
}
}

// Free the allocated memory for the received message
ExFreePoolWithTag(receivedMessage, 'msgK');
}
else {
// Handle unexpected or insufficient CallbackDataSize
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_WARNING_LEVEL, "[Driver] Received invalid or unsupported data.\n");
}

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, notifCallback, 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
NTSTATUS 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;
}