Introducing SecureScreenOverlay v2.1: An Open-Source Solution for Enhanced Screen Capture Protection on Windows

Joined
Jun 12, 2020
Messages
60
Reaction score
3
This open-source C++ program, named SecureScreenOverlay v2.1, provides a comprehensive solution for screen capture protection on Windows and is compilable with Embarcadero Dev-C++. The application deploys an opaque full-screen overlay that automatically activates when detecting PrintScreen, Alt+PrintScreen keys, or known capture processes such as Snipping Tool, OBS Studio, Greenshot, or ShareX. It leverages a low-level global keyboard hook and continuous process monitoring via CreateToolhelp32Snapshot.

The protection mechanism utilizes SetWindowDisplayAffinity with WDA_EXCLUDEFROMCAPTURE to exclude sensitive windows from captures, while simultaneously purging the clipboard using OpenClipboard and EmptyClipboard. It also displays an informative black overlay with clear instructions. An emergency exit is gracefully accessible via the combination Ctrl+Alt+Q, which instantly restores access to the protected blue window without requiring the Task Manager, thanks to an emergencyExit flag that blocks any reactivation.

The code includes professional logging to DebugView and the console, automated startup tests, robust error handling with GetLastError, and comprehensive resource cleanup upon exit. This makes it an ideal solution for securing sensitive content in demonstration or professional environments while maintaining a smooth and controlled user experience.
C++:
/*


MIT License


Copyright (c) 2025 CoTon_TiGe_MoUaRf



Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:



The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.



This project is divided into two parts for sharing purposes due to its length. Each part can be used independently while maintaining the same terms outlined in this license.



THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


*/
#include <windows.h>

#include <tlhelp32.h>

#include <psapi.h>

#include <iostream>

#include <vector>

#include <string>

#include <sstream>

#include <commctrl.h>


#pragma comment(lib, "user32.lib")

#pragma comment(lib, "ole32.lib")

#pragma comment(lib, "comctl32.lib")

#pragma comment(lib, "psapi.lib")

#pragma comment(lib, "kernel32.lib")


const char CLASS_NAME[] = "SecureScreenOverlay";

HHOOK keyboardHook = NULL;

HWND overlayWindow = NULL;

HWND protectedWindow = NULL;

bool protectionActive = false;

bool emergencyExit = false; // NOUVEAU: Flag sortie d'urgence


// Define constants

#ifndef WDA_EXCLUDEFROMCAPTURE

#define WDA_EXCLUDEFROMCAPTURE 1

#endif

#ifndef WDA_NONE

#define WDA_NONE 0

#endif


// Function pointer

typedef BOOL(WINAPI *SetWindowDisplayAffinity_t)(HWND, DWORD);

SetWindowDisplayAffinity_t SetWindowDisplayAffinity = NULL;


// Liste des processus de capture

const char* captureProcesses[] = {

    "SnippingTool.exe", "Microsoft.Photos.exe", "ScreenSketch.exe",

    "Greenshot.exe", "ShareX.exe", "obs64.exe", "obs32.exe",

    "XboxGameBar.exe", "GameBar.exe", "Snipaste.exe",

    "Lightshot.exe", "PicPick.exe", "CleanShot.exe"

};

const int numCaptureProcesses = sizeof(captureProcesses) / sizeof(captureProcesses[0]);


// Forward declarations

LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam);

LRESULT CALLBACK OverlayProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

LRESULT CALLBACK MainWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

bool LogError(const char* msg);

bool LogInfo(const char* msg);

void Cleanup();

bool IsCaptureProcessRunning();

bool PurgeClipboard();

bool ActivateProtection(bool activate);

bool ApplyDisplayAffinity(HWND hwnd, bool excludeFromCapture);

void TestProtection();

void EmergencyExit(); // NOUVEAU: Sortie d'urgence


// Logging

bool LogError(const char* msg) {

    char buffer[2048];

    DWORD error = GetLastError();

    sprintf_s(buffer, sizeof(buffer), "[SecureScreen] %s (Error: %lu)", msg, error);

    OutputDebugStringA(buffer);

    OutputDebugStringA("\r\n");

    std::cerr << buffer << std::endl;

    MessageBoxA(NULL, buffer, "SecureScreen Error", MB_OK | MB_ICONERROR | MB_TOPMOST);

    return false;

}


bool LogInfo(const char* msg) {

    char buffer[1024];

    sprintf_s(buffer, sizeof(buffer), "[SecureScreen] %s", msg);

    OutputDebugStringA(buffer);

    OutputDebugStringA("\r\n");

    std::cout << buffer << std::endl;

    return true;

}


// Nettoyage

void Cleanup() {

    if (keyboardHook) {

        UnhookWindowsHookEx(keyboardHook);

        keyboardHook = NULL;

    }

    if (overlayWindow) {

        DestroyWindow(overlayWindow);

        overlayWindow = NULL;

    }

    if (protectedWindow) {

        DestroyWindow(protectedWindow);

        protectedWindow = NULL;

    }

    protectionActive = false;

}


// Détection processus

bool IsCaptureProcessRunning() {

    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

    if (hSnapshot == INVALID_HANDLE_VALUE) return false;


    PROCESSENTRY32 pe32;

    pe32.dwSize = sizeof(PROCESSENTRY32);


    if (Process32First(hSnapshot, &pe32)) {

        do {

            std::string processName = pe32.szExeFile;

            for (int i = 0; i < numCaptureProcesses; i++) {

                if (_stricmp(processName.c_str(), captureProcesses[i]) == 0) {

                    CloseHandle(hSnapshot);

                    char msg[256];

                    sprintf_s(msg, sizeof(msg), "Capture process detected: %s", captureProcesses[i]);

                    LogInfo(msg);

                    return true;

                }

            }

        } while (Process32Next(hSnapshot, &pe32));

    }

    CloseHandle(hSnapshot);

    return false;

}


// Purge presse-papiers

bool PurgeClipboard() {

    if (OpenClipboard(NULL)) {

        EmptyClipboard();

        CloseClipboard();

        LogInfo("Clipboard purged successfully");

        return true;

    }

    return false;

}


// Display affinity

bool ApplyDisplayAffinity(HWND hwnd, bool excludeFromCapture) {

    if (!SetWindowDisplayAffinity || !hwnd) return false;

    DWORD affinity = excludeFromCapture ? WDA_EXCLUDEFROMCAPTURE : WDA_NONE;

    BOOL result = SetWindowDisplayAffinity(hwnd, affinity);

    if (!result) {

        DWORD error = GetLastError();

        char msg[256];

        sprintf_s(msg, sizeof(msg), "SetWindowDisplayAffinity failed (Error: %lu)", error);

        OutputDebugStringA(msg);

        return false;

    }

    return true;

}


// NOUVEAU: Sortie d'urgence gracieuse

void EmergencyExit() {

    LogInfo("Emergency exit requested - gracefully shutting down");

    protectionActive = false;

    if (overlayWindow) {

        ShowWindow(overlayWindow, SW_HIDE);

        ApplyDisplayAffinity(overlayWindow, false);

    }

    if (protectedWindow) {

        ApplyDisplayAffinity(protectedWindow, false);

        SetForegroundWindow(protectedWindow);

    }

    emergencyExit = true;

}


// Activation protection

bool ActivateProtection(bool activate) {

    if (emergencyExit) return false; // Bloqué si sortie d'urgence demandée

    

    if (!overlayWindow || !protectedWindow) return false;

    

    protectionActive = activate;

    

    if (activate) {

        ApplyDisplayAffinity(protectedWindow, true);

        ApplyDisplayAffinity(overlayWindow, true);

        SetForegroundWindow(overlayWindow);

        ShowWindow(overlayWindow, SW_SHOWNA);

        UpdateWindow(overlayWindow);

        PurgeClipboard();

        LogInfo("Protection ACTIVATED");

    } else {

        ApplyDisplayAffinity(protectedWindow, false);

        ApplyDisplayAffinity(overlayWindow, false);

        ShowWindow(overlayWindow, SW_HIDE);

        LogInfo("Protection DEACTIVATED");

    }

    return true;

}


// Test protection

void TestProtection() {

    LogInfo("Running protection tests...");

    if (IsCaptureProcessRunning()) {

        LogInfo("CRITICAL: Capture process detected");

        ActivateProtection(true);

    }

    PurgeClipboard();

    if (protectedWindow) ApplyDisplayAffinity(protectedWindow, true);

}


// 🔑 HOOK CLAVIER AMÉLIORÉ avec Ctrl+Alt+Q

LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) {

    if (nCode == HC_ACTION && !emergencyExit) {

        KBDLLHOOKSTRUCT* pKeyBoard = reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam);

        

        // ✅ NOUVEAU: Ctrl+Alt+Q = Sortie d'urgence

        if (wParam == WM_KEYDOWN && pKeyBoard->vkCode == 0x51) { // 'Q'

            if ((GetAsyncKeyState(VK_CONTROL) & 0x8000) && (GetAsyncKeyState(VK_MENU) & 0x8000)) {

                LogInfo("Ctrl+Alt+Q detected - Emergency exit");

                EmergencyExit();

                return 1; // Bloquer la touche Q

            }

        }

        

        // PrintScreen

        if (wParam == WM_KEYDOWN && pKeyBoard->vkCode == VK_SNAPSHOT) {

            LogInfo("PrintScreen blocked");

            ActivateProtection(true);

            return 1;

        }

        

        // Alt+PrintScreen

        if (wParam == WM_KEYDOWN && pKeyBoard->vkCode == VK_SNAPSHOT &&

            (GetAsyncKeyState(VK_MENU) & 0x8000)) {

            LogInfo("Alt+PrintScreen blocked");

            ActivateProtection(true);

            return 1;

        }

        

        if (IsCaptureProcessRunning()) {

            ActivateProtection(true);

        }

    }

    return CallNextHookEx(keyboardHook, nCode, wParam, lParam);

}


// Overlay avec instructions de sortie

LRESULT CALLBACK OverlayProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {

    switch (uMsg) {

        case WM_DESTROY:

            PostQuitMessage(0);

            return 0;

        case WM_PAINT: {

            PAINTSTRUCT ps;

            HDC hdc = BeginPaint(hwnd, &ps);

            RECT rect;

            GetClientRect(hwnd, &rect);

            

            // Fond noir

            HBRUSH blackBrush = CreateSolidBrush(RGB(0, 0, 0));

            FillRect(hdc, &rect, blackBrush);

            DeleteObject(blackBrush);

            

            // Texte principal

            SetTextColor(hdc, RGB(255, 255, 0));

            SetBkMode(hdc, TRANSPARENT);

            

            // ✅ AJOUTÉ: Instructions de sortie

            char exitMsg[] = "SCREEN CAPTURE BLOCKED\r\n\r\n"

                           "EMERGENCY EXIT: Ctrl + Alt + Q\r\n"

                           "Protection active - captures impossible";

            

            DrawTextA(hdc, exitMsg, -1, &rect, DT_CENTER | DT_VCENTER);

            EndPaint(hwnd, &ps);

            return 0;

        }

    }

    return DefWindowProc(hwnd, uMsg, wParam, lParam);

}


// Fenêtre principale

LRESULT CALLBACK MainWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {

    switch (uMsg) {

        case WM_DESTROY:

            PostQuitMessage(0);

            return 0;

        case WM_PAINT: {

            PAINTSTRUCT ps;

            HDC hdc = BeginPaint(hwnd, &ps);

            RECT rect;

            GetClientRect(hwnd, &rect);

            

            HBRUSH blueBrush = CreateSolidBrush(RGB(0, 50, 150));

            FillRect(hdc, &rect, blueBrush);

            DeleteObject(blueBrush);

            

            SetTextColor(hdc, RGB(255, 255, 255));

            SetBkMode(hdc, TRANSPARENT);

            DrawTextA(hdc, "SECURE CONTENT WINDOW\r\nCtrl+Alt+Q to exit protection",

                     -1, &rect, DT_CENTER | DT_VCENTER);

            EndPaint(hwnd, &ps);

            return 0;

        }

    }

    return DefWindowProc(hwnd, uMsg, wParam, lParam);

}


bool SetupKeyboardHook() {

    keyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardProc, GetModuleHandle(NULL), 0);

    if (!keyboardHook) return LogError("Failed to install keyboard hook");

    return true;

}


bool CreateProtectedWindow(HINSTANCE hInstance) {

    WNDCLASS wc = {};

    wc.lpfnWndProc = MainWindowProc;

    wc.hInstance = hInstance;

    wc.lpszClassName = "ProtectedContent";

    wc.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);

    wc.hCursor = LoadCursor(NULL, IDC_ARROW);

    RegisterClass(&wc);


    protectedWindow = CreateWindowEx(WS_EX_APPWINDOW,

        "ProtectedContent", "Secure Content Window",

        WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 800, 600,

        NULL, NULL, hInstance, NULL);


    if (!protectedWindow) return LogError("Failed to create protected window");

    ShowWindow(protectedWindow, SW_SHOW);

    UpdateWindow(protectedWindow);

    return true;

}


bool CreateOverlay(HINSTANCE hInstance) {

    WNDCLASS wc = {};

    wc.lpfnWndProc = OverlayProc;

    wc.hInstance = hInstance;

    wc.lpszClassName = CLASS_NAME;

    wc.hCursor = LoadCursor(NULL, IDC_ARROW);

    wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);

    if (!RegisterClass(&wc)) return LogError("Failed to register overlay class");


    int screenWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN);

    int screenHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN);

    int screenX = GetSystemMetrics(SM_XVIRTUALSCREEN);

    int screenY = GetSystemMetrics(SM_YVIRTUALSCREEN);


    overlayWindow = CreateWindowEx(WS_EX_LAYERED | WS_EX_TOPMOST | WS_EX_TOOLWINDOW | WS_EX_NOACTIVATE,

        CLASS_NAME, "Secure Overlay", WS_POPUP,

        screenX, screenY, screenWidth, screenHeight, NULL, NULL, hInstance, NULL);


    if (!overlayWindow) return LogError("Failed to create overlay window");


    HMODULE user32 = LoadLibraryA("user32.dll");

    if (user32) {

        SetWindowDisplayAffinity = (SetWindowDisplayAffinity_t)GetProcAddress(user32, "SetWindowDisplayAffinity");

        FreeLibrary(user32);

    }


    SetLayeredWindowAttributes(overlayWindow, RGB(0, 0, 0), 255, LWA_ALPHA);

    ShowWindow(overlayWindow, SW_HIDE);

    return true;

}


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow) {

    HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);

    if (FAILED(hr)) return 1;


    InitCommonControls();


    if (!CreateProtectedWindow(hInstance) || !CreateOverlay(hInstance) || !SetupKeyboardHook()) {

        Cleanup();

        CoUninitialize();

        return 1;

    }


    TestProtection();

    LogInfo("=== SecureScreenOverlay v2.1 EMERGENCY EXIT ===");

    LogInfo("Use Ctrl+Alt+Q to exit protection mode");


    MSG msg;

    while (GetMessage(&msg, NULL, 0, 0) && !emergencyExit) {

        TranslateMessage(&msg);

        DispatchMessage(&msg);

        

        static DWORD lastCheck = 0;

        if (GetTickCount() - lastCheck > 5000 && !emergencyExit) {

            if (IsCaptureProcessRunning()) ActivateProtection(true);

            lastCheck = GetTickCount();

        }

    }


    Cleanup();

    CoUninitialize();

    return 0;

}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,438
Messages
2,571,699
Members
48,796
Latest member
Greg L.
Top