check this program as the program shuts down when this dll runs // Include necessary headers
#include <windows.h>
#include <iostream>
#include <fstream>
#include <shlobj.h>
#include <string>
#include <atomic>
#include <vector>
#include <set>
#include <mutex>
#include <thread>
#include <map>
#include <sstream>
#include <capstone/capstone.h> // Include Capstone header
#include <dbghelp.h>

// Link against DbgHelp.lib and Capstone.lib
#pragma comment(lib, "dbghelp.lib")
#pragma comment(lib, "capstone.lib")

// Constants
constexpr char LOG_FILE_NAME[] = "log.txt";

// Utility type for address representation
using Address = std::uintptr_t;

// Structure to represent instruction patterns
struct InstructionPattern {
    std::vector<std::string> instructions;
    int occurrence;

    InstructionPattern() : occurrence(0) {}
};

// GuardMonitor Class
class GuardMonitor {
public:
    GuardMonitor()
        : vehHandle(nullptr), exitFlag(false), guardEvent(nullptr), csHandle(0) {
        InitializeLogging();
        InitializeCapstone();
    }

    ~GuardMonitor() {
        StopMonitoring();
        CleanupCapstone();
        SymCleanup(GetCurrentProcess());
    }

    bool Start() {
        // Initialize DbgHelp
        if (!SymInitialize(GetCurrentProcess(), NULL, TRUE)) {
            Log("[x] Failed to initialize symbol handler");
            return false;
        }

        // Set symbol options
        SymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_UNDNAME);

        if (!GetTextSectionBoundaries()) {
            Log("[x] Failed to retrieve .text section boundaries");
            return false;
        }

        if (!SetGuardPages()) {
            Log("[x] Failed to set guard pages on .text section");
            return false;
        }

        if (!SetVEH()) {
            Log("[x] Failed to set Vectored Exception Handler");
            RemoveGuardPages();
            return false;
        }

        guardEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
        if (!guardEvent) {
            Log("[x] Failed to create event");
            RemoveVEH();
            RemoveGuardPages();
            return false;
        }

        monitoringThread = std::thread(&GuardMonitor::Monitor, this);
        Log("[+] Monitoring thread started");
        return true;
    }

    void StopMonitoring() {
        exitFlag.store(true);
        if (monitoringThread.joinable()) {
            SetEvent(guardEvent); // Wake up the thread if it's waiting
            monitoringThread.join();
        }

        if (guardEvent) {
            CloseHandle(guardEvent);
            guardEvent = nullptr;
        }

        RemoveVEH();
        RemoveGuardPages();
        Log("[+] Monitoring stopped");
    }

private:
    // Member Variables
    std::atomic<bool> exitFlag;
    std::atomic<bool> guardRemoved;
    std::vector<Address> guardedAddresses;
    std::set<Address> suspectedIntegrityChecks;
    HANDLE vehHandle;
    HANDLE guardEvent;
    std::thread monitoringThread;
    std::mutex logMutex;
    std::mutex heuristicMutex; // Mutex for heuristic data
    std::map<std::string, InstructionPattern> instructionPatterns; // Dynamic heuristics

    // Singleton instance pointer
    static GuardMonitor* instance;

    // .text section boundaries
    Address textSectionStart = 0;
    Address textSectionEnd = 0;

    // Capstone Handle
    csh csHandle;

    // Logging Setup
    void InitializeLogging() {
        // Optional: Initialize logging settings if needed
        Log("[+] GuardMonitor initialized");
    }

    // Thread-safe logging function
    void Log(const std::string& message) {
        std::lock_guard<std::mutex> lock(logMutex);
        char docPath[MAX_PATH];
        if (SUCCEEDED(SHGetFolderPathA(nullptr, CSIDL_PERSONAL, nullptr, 0, docPath))) {
            std::string logFilePath = std::string(docPath) + "\\" + LOG_FILE_NAME;
            std::ofstream logFile(logFilePath, std::ios::app);
            if (logFile.is_open()) {
                SYSTEMTIME st;
                GetLocalTime(&st);
                char timestamp[100];
                sprintf_s(timestamp, "[%04d-%02d-%02d %02d:%02d:%02d] ",
                    st.wYear, st.wMonth, st.wDay,
                    st.wHour, st.wMinute, st.wSecond);
                logFile << timestamp << message << std::endl;
                logFile.close();
            }
        }
    }

    // Initialize Capstone
    void InitializeCapstone() {
        cs_err err = cs_open(CS_ARCH_X86, CS_MODE_64, &csHandle);
        if (err != CS_ERR_OK) {
            Log("[x] Failed to initialize Capstone: " + std::to_string(err));
        }
        else {
            cs_option(csHandle, CS_OPT_DETAIL, CS_OPT_ON);
            Log("[+] Capstone initialized for X86-64 architecture");
        }
    }

    // Cleanup Capstone
    void CleanupCapstone() {
        if (csHandle) {
            cs_close(&csHandle);
            csHandle = 0;
            Log("[+] Capstone cleanup completed");
        }
    }

    // Get the current module's base address
    Address GetModuleBaseAddress() const {
        return reinterpret_cast<Address>(GetModuleHandle(nullptr));
    }

    // Retrieve the .text section boundaries
    bool GetTextSectionBoundaries() {
        Address baseAddress = GetModuleBaseAddress();
        PIMAGE_DOS_HEADER dosHeader = reinterpret_cast<PIMAGE_DOS_HEADER>(baseAddress);
        if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
            Log("[x] Invalid DOS Signature");
            return false;
        }

        PIMAGE_NT_HEADERS ntHeaders = reinterpret_cast<PIMAGE_NT_HEADERS>(baseAddress + dosHeader->e_lfanew);
        if (ntHeaders->Signature != IMAGE_NT_SIGNATURE) {
            Log("[x] Invalid NT Signature");
            return false;
        }

        PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(ntHeaders);
        for (unsigned int i = 0; i < ntHeaders->FileHeader.NumberOfSections; ++i, ++section) {
            if (strncmp(reinterpret_cast<char*>(section->Name), ".text", IMAGE_SIZEOF_SHORT_NAME) == 0) {
                textSectionStart = baseAddress + section->VirtualAddress;
                textSectionEnd = textSectionStart + section->Misc.VirtualSize;
                Log("[+] Found .text section");
                Log("    Start: 0x" + IntToHex(textSectionStart));
                Log("    End  : 0x" + IntToHex(textSectionEnd));
                return true;
            }
        }

        Log("[x] .text section not found");
        return false;
    }

    // Helper function to convert integer to hex string
    std::string IntToHex(Address value) {
        std::stringstream ss;
        ss << std::hex << value;
        return ss.str();
    }

    // Set guard pages on the .text section
    bool SetGuardPages() {
        SYSTEM_INFO sysInfo;
        GetSystemInfo(&sysInfo);
        DWORD pageSize = sysInfo.dwPageSize;

        for (Address current = textSectionStart; current < textSectionEnd; current += pageSize) {
            DWORD oldProtect;
            if (!VirtualProtect(reinterpret_cast<LPVOID>(current), pageSize, PAGE_EXECUTE_READ | PAGE_GUARD, &oldProtect)) {
                Log("[x] VirtualProtect failed at address: 0x" + IntToHex(current));
                return false;
            }
            guardedAddresses.push_back(current);
        }

        Log("[+] Guard pages set successfully");
        return true;
    }

    // Remove all guard pages
    void RemoveGuardPages() {
        SYSTEM_INFO sysInfo;
        GetSystemInfo(&sysInfo);
        DWORD pageSize = sysInfo.dwPageSize;

        for (auto addr : guardedAddresses) {
            DWORD oldProtect;
            if (!VirtualProtect(reinterpret_cast<LPVOID>(addr), pageSize, PAGE_EXECUTE_READ, &oldProtect)) {
                Log("[x] Failed to restore protection at address: 0x" + IntToHex(addr));
            }
        }

        guardedAddresses.clear();
        Log("[+] Guard pages removed");
    }

    // Vectored Exception Handler
    static LONG WINAPI VEHCallback(EXCEPTION_POINTERS* pExceptionInfo) {
        GuardMonitor* monitor = GetInstance();
        if (!monitor) return EXCEPTION_CONTINUE_SEARCH;

        if (pExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_GUARD_PAGE_VIOLATION) {
            Address faultAddress = reinterpret_cast<Address>(pExceptionInfo->ExceptionRecord->ExceptionAddress);
            monitor->Log("[+] Guard Page Violation at Address: 0x" + monitor->IntToHex(faultAddress));

            SYSTEM_INFO sysInfo;
            GetSystemInfo(&sysInfo);
            DWORD64 pageSize = sysInfo.dwPageSize;
            Address pageStart = faultAddress & ~(pageSize - 1);

            Address moduleBase = monitor->GetModuleBaseAddress();
            Address relativeRip = faultAddress - moduleBase;
            monitor->Log("[+] RIP relative offset: 0x" + monitor->IntToHex(relativeRip));

            // Analyze behavior to detect potential integrity check
            if (monitor->AnalyzeBehaviorForIntegrityCheck(pExceptionInfo, faultAddress)) {
                monitor->Log("[+] Detected Potential Integrity Check:");
                monitor->Log("    Address : 0x" + monitor->IntToHex(faultAddress));
                monitor->Log("    Offset  : 0x" + monitor->IntToHex(relativeRip));
                monitor->suspectedIntegrityChecks.insert(faultAddress);
            }

            // Reapply guard page protection
            DWORD oldProtect;
            if (VirtualProtect(reinterpret_cast<LPVOID>(pageStart), sysInfo.dwPageSize, PAGE_EXECUTE_READ | PAGE_GUARD, &oldProtect)) {
                monitor->Log("[+] Reapplied guard protection");
            }
            else {
                monitor->Log("[x] Failed to reapply guard protection");
            }

            monitor->guardRemoved.store(true);
            SetEvent(monitor->guardEvent);

            return EXCEPTION_CONTINUE_EXECUTION;
        }

        return EXCEPTION_CONTINUE_SEARCH;
    }

    // Helper to get singleton instance
    static GuardMonitor* GetInstance() {
        return instance;
    }

    // Set up the Vectored Exception Handler
    bool SetVEH() {
        if (vehHandle || guardedAddresses.empty()) {
            return false;
        }

        instance = this; // Set the singleton instance

        vehHandle = AddVectoredExceptionHandler(1, VEHCallback);
        if (!vehHandle) {
            Log("[x] Failed to add Vectored Exception Handler");
            instance = nullptr;
            return false;
        }

        Log("[+] Vectored Exception Handler set");
        return true;
    }

    // Remove the Vectored Exception Handler
    void RemoveVEH() {
        if (vehHandle) {
            if (!RemoveVectoredExceptionHandler(vehHandle)) {
                Log("[x] Failed to remove Vectored Exception Handler");
            }
            else {
                Log("[+] Vectored Exception Handler removed");
            }
            vehHandle = nullptr;
            instance = nullptr;
        }
    }

    // Analysis function to detect integrity checks
    bool AnalyzeBehaviorForIntegrityCheck(EXCEPTION_POINTERS* pExceptionInfo, Address faultAddress) {
        // Capture call stack
        std::string callStack = CaptureCallStack(pExceptionInfo);
        Log(callStack);

        // Log and analyze instruction bytes around faulting address
        std::vector<std::string> instructions = DisassembleInstructions(faultAddress);
        if (instructions.empty()) {
            Log("[x] No instructions disassembled at address: 0x" + IntToHex(faultAddress));
            return false;
        }

        Log("Disassembled Instructions:");
        for (const auto& instr : instructions) {
            Log("\t" + instr);
        }

        // Apply dynamic heuristics
        bool isIntegrityCheck = ApplyDynamicHeuristics(instructions);

        return isIntegrityCheck;
    }

    // Function to capture and log the call stack
    std::string CaptureCallStack(EXCEPTION_POINTERS* pExceptionInfo) {
        std::stringstream ss;
        void* stack[62];
        unsigned short frames;
        SYMBOL_INFO* symbol;
        HANDLE process = GetCurrentProcess();

        // Initialize DbgHelp
        SymInitialize(process, NULL, TRUE);

        frames = CaptureStackBackTrace(0, 62, stack, NULL);
        symbol = (SYMBOL_INFO*)calloc(sizeof(SYMBOL_INFO) + 256 * sizeof(char), 1);
        if (!symbol) {
            return "Failed to allocate memory for SYMBOL_INFO";
        }
        symbol->MaxNameLen = 255;
        symbol->SizeOfStruct = sizeof(SYMBOL_INFO);

        ss << "Call Stack:" << std::endl;
        for (unsigned int i = 0; i < frames; i++) {
            DWORD64 address = (DWORD64)(stack[i]);
            if (SymFromAddr(process, address, 0, symbol)) {
                ss << "\t" << i << ": " << symbol->Name << " - 0x" << std::hex << symbol->Address << std::dec << std::endl;
            }
            else {
                ss << "\t" << i << ": " << "Unknown Function - 0x" << std::hex << address << std::dec << std::endl;
            }
        }

        free(symbol);
        // Do not call SymCleanup here; it's handled in the destructor
        return ss.str();
    }

    // Function to disassemble instructions around the faulting address using Capstone
    std::vector<std::string> DisassembleInstructions(Address faultAddress) {
        std::vector<std::string> instrList;

        if (!csHandle) {
            Log("[x] Capstone is not initialized");
            return instrList;
        }

        const size_t codeSize = 64; // Number of bytes to disassemble
        BYTE buffer[codeSize];
        SIZE_T bytesRead;
        Address startAddress = faultAddress >= 32 ? (faultAddress - 32) : 0; // Read 32 bytes before

        if (!ReadProcessMemory(GetCurrentProcess(), (LPCVOID)(startAddress), buffer, codeSize, &bytesRead)) {
            Log("[x] Failed to read memory around address: 0x" + IntToHex(faultAddress));
            return instrList;
        }

        cs_insn* insn;
        size_t count = cs_disasm(csHandle, buffer, bytesRead, startAddress, 0, &insn);
        if (count > 0) {
            for (size_t i = 0; i < count; i++) {
                std::string instr = std::string(insn[i].mnemonic) + " " + std::string(insn[i].op_str);
                instrList.push_back(instr);
            }
            cs_free(insn, count);
        }
        else {
            Log("[x] Failed to disassemble instructions at address: 0x" + IntToHex(faultAddress));
        }

        return instrList;
    }

    // Function to apply dynamic heuristics based on instruction patterns
    bool ApplyDynamicHeuristics(const std::vector<std::string>& instructions) {
        std::lock_guard<std::mutex> lock(heuristicMutex);

        std::string patternKey;
        // Create a simple pattern key by concatenating the first few instructions
        for (size_t i = 0; i < std::min<size_t>(5, instructions.size()); ++i) {
            patternKey += instructions[i] + ";";
        }

        if (!patternKey.empty()) {
            // Update occurrence count
            if (instructionPatterns.find(patternKey) != instructionPatterns.end()) {
                instructionPatterns[patternKey].occurrence += 1;
            }
            else {
                InstructionPattern pattern;
                pattern.instructions = { instructions.begin(), instructions.begin() + std::min<size_t>(5, instructions.size()) };
                pattern.occurrence = 1;
                instructionPatterns[patternKey] = pattern;
            }

            // Simple heuristic: If a pattern has occurred more than a threshold, flag it
            const int threshold = 3; // Arbitrary threshold
            if (instructionPatterns[patternKey].occurrence >= threshold) {
                Log("[+] Pattern '" + patternKey + "' has occurred " + std::to_string(instructionPatterns[patternKey].occurrence) + " times. Potential Integrity Check detected.");
                return true;
            }
        }

        return false;
    }

    // Monitoring thread function
    void Monitor() {
        while (!exitFlag.load()) {
            if (guardRemoved.load()) {
                SYSTEM_INFO sysInfo;
                GetSystemInfo(&sysInfo);
                DWORD pageSize = sysInfo.dwPageSize;

                for (auto addr : guardedAddresses) {
                    DWORD oldProtect;
                    if (!VirtualProtect(reinterpret_cast<LPVOID>(addr), pageSize, PAGE_EXECUTE_READ | PAGE_GUARD, &oldProtect)) {
                        Log("[x] Failed to reapply guard to address: 0x" + IntToHex(addr));
                    }
                    else {
                        Log("[+] Reapplied guard to address: 0x" + IntToHex(addr));
                    }
                }

                guardRemoved.store(false);
                ResetEvent(guardEvent);
            }
            // Wait for event or timeout to reduce CPU usage
            WaitForSingleObject(guardEvent, 50);
        }
    }

public:
    // Prevent copying
    GuardMonitor(const GuardMonitor&) = delete;
    GuardMonitor& operator=(const GuardMonitor&) = delete;
};

// Initialize static member
GuardMonitor* GuardMonitor::instance = nullptr;

// ============================
// Shim Implementation for dxgi.dll
// ============================

// Function pointers to real dxgi_original.dll functions
static HRESULT(__stdcall* pCreateDXGIFactory)(REFIID riid, void** ppFactory) = nullptr;
static HRESULT(__stdcall* pCreateDXGIFactory1)(REFIID riid, void** ppFactory) = nullptr;
static HRESULT(__stdcall* pCreateDXGIFactory2)(UINT flags, REFIID riid, void** ppFactory) = nullptr;
static HRESULT(__stdcall* pDXGID3D10CreateDevice)(HMODULE hModule, void* pFactory, void* pAdapter, UINT Flags, void* pUnknown, void** ppDevice) = nullptr;
static HRESULT(__stdcall* pDXGID3D10CreateLayeredDevice)(void* pUnknown1, void* pUnknown2, void* pUnknown3, void* pUnknown4, void* pUnknown5) = nullptr;
static SIZE_T(__stdcall* pDXGID3D10GetLayeredDeviceSize)(const void* pLayers, UINT NumLayers) = nullptr;
static HRESULT(__stdcall* pDXGID3D10RegisterLayers)(const void* pLayers, UINT NumLayers) = nullptr;

// Exported Shim Functions
extern "C"
{
    __declspec(dllexport) HRESULT __stdcall CreateDXGIFactory(REFIID riid, void** ppFactory)
    {
        if (pCreateDXGIFactory)
            return pCreateDXGIFactory(riid, ppFactory);
        return E_FAIL;
    }

    __declspec(dllexport) HRESULT __stdcall CreateDXGIFactory1(REFIID riid, void** ppFactory)
    {
        if (pCreateDXGIFactory1)
            return pCreateDXGIFactory1(riid, ppFactory);
        return E_FAIL;
    }

    __declspec(dllexport) HRESULT __stdcall CreateDXGIFactory2(UINT flags, REFIID riid, void** ppFactory)
    {
        if (pCreateDXGIFactory2)
            return pCreateDXGIFactory2(flags, riid, ppFactory);
        return E_FAIL;
    }

    __declspec(dllexport) HRESULT __stdcall DXGID3D10CreateDevice(HMODULE hModule, void* pFactory, void* pAdapter, UINT Flags, void* pUnknown, void** ppDevice)
    {
        if (pDXGID3D10CreateDevice)
            return pDXGID3D10CreateDevice(hModule, pFactory, pAdapter, Flags, pUnknown, ppDevice);
        return E_FAIL;
    }

    __declspec(dllexport) HRESULT __stdcall DXGID3D10CreateLayeredDevice(void* pUnknown1, void* pUnknown2, void* pUnknown3, void* pUnknown4, void* pUnknown5)
    {
        if (pDXGID3D10CreateLayeredDevice)
            return pDXGID3D10CreateLayeredDevice(pUnknown1, pUnknown2, pUnknown3, pUnknown4, pUnknown5);
        return E_FAIL;
    }

    __declspec(dllexport) SIZE_T __stdcall DXGID3D10GetLayeredDeviceSize(const void* pLayers, UINT NumLayers)
    {
        if (pDXGID3D10GetLayeredDeviceSize)
            return pDXGID3D10GetLayeredDeviceSize(pLayers, NumLayers);
        return 0;
    }

    __declspec(dllexport) HRESULT __stdcall DXGID3D10RegisterLayers(const void* pLayers, UINT NumLayers)
    {
        if (pDXGID3D10RegisterLayers)
            return pDXGID3D10RegisterLayers(pLayers, NumLayers);
        return E_FAIL;
    }

    // Implement other exported functions similarly or rely on .DEF forwarding
}

// ============================
// Combined DllMain
// ============================

BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
    static GuardMonitor monitor;

    switch (dwReason)
    {
    case DLL_PROCESS_ATTACH:
    {
        // Disable thread notifications to reduce overhead
        DisableThreadLibraryCalls(hInstance);

        // Load the original dxgi_original.dll
        char systemPath[MAX_PATH];
        if (!GetSystemDirectoryA(systemPath, MAX_PATH)) {
            return FALSE;
        }

        strcat_s(systemPath, "\\dxgi_original.dll"); // Ensure dxgi_original.dll is present

        HMODULE originalDXGIDLL = LoadLibraryA(systemPath);
        if (!originalDXGIDLL) {
            // If failed to load original, attempt to load the real dxgi.dll without renaming
            // This can cause recursive loading if not renamed properly
            systemPath[MAX_PATH - 1] = '\0';
            GetSystemDirectoryA(systemPath, MAX_PATH);
            strcat_s(systemPath, "\\dxgi.dll");
            originalDXGIDLL = LoadLibraryA(systemPath);
            if (!originalDXGIDLL) {
                return FALSE; // Cannot proceed without the original dxgi.dll
            }
        }

        // Get the address of the real functions
        pCreateDXGIFactory = reinterpret_cast<decltype(pCreateDXGIFactory)>(GetProcAddress(originalDXGIDLL, "CreateDXGIFactory"));
        pCreateDXGIFactory1 = reinterpret_cast<decltype(pCreateDXGIFactory1)>(GetProcAddress(originalDXGIDLL, "CreateDXGIFactory1"));
        pCreateDXGIFactory2 = reinterpret_cast<decltype(pCreateDXGIFactory2)>(GetProcAddress(originalDXGIDLL, "CreateDXGIFactory2"));
        pDXGID3D10CreateDevice = reinterpret_cast<decltype(pDXGID3D10CreateDevice)>(GetProcAddress(originalDXGIDLL, "DXGID3D10CreateDevice"));
        pDXGID3D10CreateLayeredDevice = reinterpret_cast<decltype(pDXGID3D10CreateLayeredDevice)>(GetProcAddress(originalDXGIDLL, "DXGID3D10CreateLayeredDevice"));
        pDXGID3D10GetLayeredDeviceSize = reinterpret_cast<decltype(pDXGID3D10GetLayeredDeviceSize)>(GetProcAddress(originalDXGIDLL, "DXGID3D10GetLayeredDeviceSize"));
        pDXGID3D10RegisterLayers = reinterpret_cast<decltype(pDXGID3D10RegisterLayers)>(GetProcAddress(originalDXGIDLL, "DXGID3D10RegisterLayers"));

        // Verify that all function pointers were retrieved successfully
        if (!pCreateDXGIFactory || !pCreateDXGIFactory1 || !pCreateDXGIFactory2 ||
            !pDXGID3D10CreateDevice || !pDXGID3D10CreateLayeredDevice ||
            !pDXGID3D10GetLayeredDeviceSize || !pDXGID3D10RegisterLayers) {
            return FALSE; // Missing functions, cannot proceed
        }

        // Initialize GuardMonitor
        if (!monitor.Start()) {
            // Handle initialization failure if necessary
            // For example, log the failure or perform cleanup
        }
    }
    break;
    case DLL_PROCESS_DETACH:
    {
        // Stop GuardMonitor
        monitor.StopMonitoring();

        // Unload the original dxgi_original.dll if needed
    }
    break;
    default:
        break;
    }

    return TRUE;
}