fix this so it writes a log that contains the adress violations info and the base adressss in the user doc folder #include <windows.h>
#include <iostream>
#include <vector>
#include <thread>
#include <atomic>
#include <mutex>
#include <iomanip>

// ------------------ Configuration and Globals ------------------ //

// Define the base address (`Exe`) and the offset (`Offset`).
// For demonstration purposes, we'll use the address of a dummy variable.
DWORD64 Exe = (DWORD64)&Exe;        // Base address (using the address of Exe itself)
DWORD Offset = sizeof(Exe);         // Offset (size of Exe)

// Address to guard
DWORD64 AddressToGuard = 0;

// Handle for the Vectored Exception Handler
HANDLE TestVEHHandle = NULL;

// Original memory protection of the guarded address
DWORD TestVEHOldProtect = 0;

// Flag to signal exit
std::atomic<bool> ExitQueued(false);

// Flag to indicate guard removal
volatile bool GuardRemoved = false;

// Mutex for thread-safe logging
std::mutex logMutex;

// ------------------ Utility Functions ------------------ //

// Simple thread-safe logging function
void LOG(const char* format, ...)
{
    std::lock_guard<std::mutex> lock(logMutex);

    va_list args;
    va_start(args, format);
    vprintf(format, args);
    va_end(args);
}

// Dummy function to simulate adding to an address list
bool AddToAddressList(DWORD64 address)
{
    // For demonstration, we'll simply return true
    // In a real scenario, you might store the address or perform additional checks
    return true;
}

// ------------------ Vectored Exception Handler ------------------ //

LONG WINAPI TestVEH(EXCEPTION_POINTERS* ExceptionInfo)
{
    if (ExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_GUARD_PAGE_VIOLATION)
    {
        // Extract the instruction pointer (RIP) from the context
#ifdef _WIN64
        DWORD64 rip = ExceptionInfo->ContextRecord->Rip;
#else
        DWORD64 rip = ExceptionInfo->ContextRecord->Eip;
#endif

        if (AddToAddressList(rip))
        {
            LOG("[+] Guard Page Violation at RIP: 0x%016llX\n", rip);
        }

        GuardRemoved = true; // Signal that the guard page has been removed

        // Pause execution until the guard is re-applied
        while (GuardRemoved)
        {
            Sleep(10); // Sleep briefly to prevent tight looping
        }

        // Continue execution
        return EXCEPTION_CONTINUE_EXECUTION;
    }

    // For other exceptions, continue searching
    return EXCEPTION_CONTINUE_SEARCH;
}

// ------------------ VEH Management Functions ------------------ //

// Function to remove the Vectored Exception Handler and restore memory protection
void RemoveTestVEH()
{
    if (!TestVEHHandle)
    {
        LOG("[x] (!TestVEHHandle)\n");
        return;
    }

    // Restore the original memory protection
    DWORD buffer;
    if (!VirtualProtect((LPVOID)(AddressToGuard), 1, TestVEHOldProtect, &buffer))
    {
        LOG("[x] Failed to restore memory protection. Error: %lu\n", GetLastError());
        return;
    }

    // Remove the VEH handler
    if (!RemoveVectoredExceptionHandler(TestVEHHandle))
    {
        LOG("[x] Failed to remove Vectored Exception Handler. Error: %lu\n", GetLastError());
        return;
    }

    LOG("[+] Vectored Exception Handler removed and memory protection restored.\n");

    TestVEHHandle = NULL;
    TestVEHOldProtect = 0;
}

// Function to set up the VEH and apply the initial guard page
bool SetTestVEH()
{
    if (TestVEHHandle)
    {
        LOG("[x] VEH already set.\n");
        return false;
    }

    // Add the Vectored Exception Handler
    TestVEHHandle = AddVectoredExceptionHandler(1, TestVEH);
    if (!TestVEHHandle)
    {
        LOG("[x] Failed to add Vectored Exception Handler. Error: %lu\n", GetLastError());
        return false;
    }

    // Apply the guard page to the specified address
    DWORD oldProtect;
    if (!VirtualProtect((LPVOID)(AddressToGuard), 1, PAGE_EXECUTE_READ | PAGE_GUARD, &oldProtect))
    {
        LOG("[x] Failed to set guard page. Error: %lu\n", GetLastError());
        RemoveVectoredExceptionHandler(TestVEHHandle);
        TestVEHHandle = NULL;
        return false;
    }

    TestVEHOldProtect = oldProtect;

    LOG("[+] Vectored Exception Handler added and guard page set at address: 0x%016llX\n", AddressToGuard);

    return true;
}

// ------------------ Monitoring Thread ------------------ //

void VEHThread()
{
    // Set the address to guard (base + offset)
    AddressToGuard = Exe + Offset;

    LOG("[*] VEHThread started. Monitoring address: 0x%016llX\n", AddressToGuard);

    if (!SetTestVEH())
    {
        LOG("[x] Failed to set up VEH. Exiting VEHThread.\n");
        return;
    }

    while (!ExitQueued)
    {
        if (GuardRemoved)
        {
            // Re-apply the guard page
            DWORD oldProtect;
            if (!VirtualProtect((LPVOID)(AddressToGuard), 1, PAGE_EXECUTE_READ | PAGE_GUARD, &oldProtect))
            {
                LOG("[x] Failed to re-apply guard page. Error: %lu\n", GetLastError());
                // Decide whether to continue or exit
            }
            else
            {
                LOG("[+] Guard page re-applied at address: 0x%016llX\n", AddressToGuard);
                GuardRemoved = false; // Reset the flag
            }
        }

        Sleep(100); // Sleep to reduce CPU usage
    }

    RemoveTestVEH();

    LOG("[*] VEHThread exiting.\n");
}

// ------------------ Test Function to Trigger Guard Page Violation ------------------ //

// Function to access the guarded address, causing a guard page violation
void AccessGuardedAddress()
{
    volatile char* ptr = (volatile char*)AddressToGuard;

    for (int i = 0; i < 5; ++i)
    {
        LOG("[*] Accessing guarded address: 0x%016llX\n", (DWORD64)ptr);
        char value = *ptr; // Accessing the address
        LOG("[*] Read value: 0x%02X\n", value);
        Sleep(500); // Wait before next access
    }
}

// ------------------ Main Function ------------------ //

int main()
{
    // Start the VEH monitoring thread
    std::thread monitorThread(VEHThread);

    // Give some time for the VEH to be set up
    Sleep(1000);

    // Start the test function in the main thread
    AccessGuardedAddress();

    // Signal the monitoring thread to exit
    ExitQueued = true;

    // Wait for the monitoring thread to finish
    if (monitorThread.joinable())
        monitorThread.join();

    LOG("[*] Application exiting.\n");

    return 0;
}