|14 min read|By BypassCore Team

SetWindowDisplayAffinity Bypass — Complete Screen Capture Bypass Guide 2026

SetWindowDisplayAffinity is the primary Windows API used to protect window content from screen capture. Exam proctoring software, DRM players, banking applications, and secure messaging clients all rely on it to black out their windows during screenshots and screen recordings. This guide covers every known bypass technique — from kernel object manipulation to direct GPU framebuffer reads — with working code references from BypassCore's open-source tooling.

What Is SetWindowDisplayAffinity?

SetWindowDisplayAffinity is a Win32 API introduced in Windows 7 that controls whether a window's content is included in screen capture operations. When an application calls this function with the WDA_EXCLUDEFROMCAPTURE flag (value 0x00000011, available since Windows 10 2004), the Desktop Window Manager (DWM) excludes that window from all capture surfaces. The window becomes completely invisible to screenshot tools, screen recording software, and remote desktop streams — it renders as a black rectangle or disappears entirely.

The older flag WDA_MONITOR (value 0x00000001) achieves a similar effect but renders the protected window as a black rectangle in captures rather than hiding it completely. Both flags are widely deployed:

// Applications using SetWindowDisplayAffinity:

  • $ Exam proctoring — Proctorio, ExamSoft, Respondus LockDown Browser
  • $ DRM video players — Netflix desktop app, streaming platforms
  • $ Banking apps — secure transaction windows, OTP displays
  • $ Secure messaging — Signal desktop, encrypted chat clients
  • $ Enterprise DLP — data loss prevention overlays and secure viewers

The API call itself is trivial — a single function call protects the entire window. This simplicity is what makes it the most commonly deployed screen capture protection on Windows, and why understanding how to bypass SetWindowDisplayAffinity is essential for security research and red team operations.

How SetWindowDisplayAffinity Works Internally

When you call SetWindowDisplayAffinity(hWnd, WDA_EXCLUDEFROMCAPTURE), the call travels through user32.dll into the kernel-mode window manager (win32kfull.sys). Inside the kernel, the window's tagWND structure is updated — specifically, the dwDisplayAffinity field is set to the requested value. The DWM compositor reads this field when building capture surfaces and skips any window marked with the exclude flag.

// Simplified tagWND structure (win32kfull.sys)

typedef struct tagWND {
    THRDESKHEAD    head;
    DWORD          state;
    DWORD          state2;
    DWORD          ExStyle;
    DWORD          style;
    // ... many fields ...
    DWORD          dwDisplayAffinity;  // <-- the target field
    // ... more fields ...
} WND, *PWND;

The DWM compositor maintains two separate composition targets: the display surface (what goes to the physical monitor) and the capture surface (what APIs like DXGI Desktop Duplication and Windows Graphics Capture read from). When a window has WDA_EXCLUDEFROMCAPTURE set, DWM simply does not composite that window into the capture surface. The critical insight is that this filtering happens entirely in software — the GPU still renders and scans out all windows to the physical display regardless of affinity flags.

Affected Capture APIs

Blocked by WDA

BitBlt, PrintWindow, DXGI Desktop Duplication, Windows.Graphics.Capture, Magnification API

Not Blocked

Direct GPU framebuffer access, kernel-mode screen reads, hardware capture cards, physical camera recording

Bypass Methods — Easiest to Most Advanced

There are four primary approaches to bypassing SetWindowDisplayAffinity, ranging from simple kernel writes to hardware-level framebuffer access. Each has different tradeoffs in terms of stealth, reliability, and complexity.

Method 1: DKOM — Direct Kernel Object Manipulation

The most straightforward bypass is to modify the dwDisplayAffinity field in the tagWND structure directly in kernel memory. Since SetWindowDisplayAffinity just writes a DWORD to a kernel structure, you can write it back to zero. This requires a kernel-mode driver or a read/write primitive in the kernel address space.

// DKOM bypass — reset display affinity in tagWND

// 1. Get the kernel-mode PWND from the HWND
//    ValidateHwnd() or desktop heap walk
PWND pWnd = GetKernelWndPtr(hTargetWnd);

// 2. Calculate offset to dwDisplayAffinity
//    Offset varies by Windows build — use symbol resolution
DWORD offset = ResolveAffinityOffset();

// 3. Write zero to clear the protection
DWORD newAffinity = WDA_NONE;  // 0x00000000
KernelWrite(pWnd + offset, &newAffinity, sizeof(DWORD));

// Window is now capturable by all standard APIs

The main challenge is finding the correct offset for dwDisplayAffinity within tagWND, which changes between Windows builds. You can resolve this dynamically by scanning the structure after calling SetWindowDisplayAffinity on a test window and looking for the known value. This bypass is simple and effective, but it requires kernel access and can be detected by PatchGuard if you modify kernel code to get there. Using a vulnerable driver for the read/write primitive is the standard approach.

Method 2: DWM Composition Bypass

Instead of modifying the window's affinity flag, you can hook the DWM compositor itself to force protected windows into the capture surface. The DWM process (dwm.exe) checks each window's display affinity during composition. By hooking the internal DWM functions that perform this check, you can force all windows to be included in the capture output regardless of their affinity setting.

// DWM composition hook approach

// Target: CVisual::GetDisplayAffinity() inside dwm.exe
// or: CWindowData::GetDisplayAffinity()

// Hook returns WDA_NONE (0) for all windows,
// forcing DWM to include them in capture surfaces.

// Injection into dwm.exe requires:
// 1. SeDebugPrivilege or PPL bypass
// 2. DLL injection or code cave in dwm.exe
// 3. Hook the affinity check function

// Alternative: patch the conditional jump that
// skips protected windows during composition

DWM hooking is more complex than DKOM because dwm.exe runs as a Protected Process Light (PPL) on modern Windows. You need to bypass PPL protection first — either through a kernel driver, or by exploiting the DWM process before PPL is fully initialized during boot. The advantage is that this approach captures all protected windows at once without needing to enumerate and patch each one individually.

Method 3: Mirror Driver / Virtual Display

A virtual display approach creates an Indirect Display Driver (IDD) that receives the full composited desktop output. The key insight is that DWM's affinity filtering applies per-output — it determines what to include in each display's capture surface. A carefully configured virtual display can receive content that the primary display's capture surface excludes, because the virtual display can be set up to receive the pre-filtering composition.

In practice, this technique works by creating a mirror display that clones the primary output at the driver level, below DWM's affinity filtering layer. The IDD driver receives raw frame data from the GPU, which includes all windows regardless of their SetWindowDisplayAffinity flags. BypassCore's phantom-screen project implements this as a stealthy IDD driver that exposes captured frames through shared memory for consumption by any userland process.

// Virtual display capture pipeline:

  • 1. Load IDD driver — registers as indirect display adapter
  • 2. Create virtual monitor — clones primary output resolution
  • 3. Receive frame data — GPU scanout includes all windows
  • 4. Expose via shared memory — userland reads clean frames
  • 5. Hide from enumeration — virtual display is invisible to apps

Method 4: GPU Framebuffer Direct Read (Most Powerful)

The most powerful and fundamentally undetectable bypass is to read the display scanout surface directly from the GPU's framebuffer via PCI BAR (Base Address Register) mapping. This technique completely bypasses all software-level protections because SetWindowDisplayAffinity only affects the DWM compositor's software capture path — it has zero effect on what the GPU physically sends to the monitor. The GPU's display engine reads from the final composited framebuffer, which always contains every visible window.

BypassCore's capture-bypass tool implements this technique with full support for Intel, AMD, and NVIDIA GPUs. Here is how the pipeline works:

// GPU framebuffer direct read pipeline

// Step 1: PCI bus scan — locate the GPU device
PCIScanForGPU(&bus, &device, &function);

// Step 2: Map GPU MMIO registers via PCI BAR0
PVOID mmioBase = MapPCIBar(bus, dev, func, BAR0);

// Step 3: Read display pipe registers
//   Intel: DSPCNTR, DSPADDR, DSPSTRIDE
//   AMD:   GRPH_PRIMARY_SURFACE_ADDRESS
//   NVIDIA: NV_PDISP_FE_SCANOUT
PHYSICAL_ADDRESS fbPhysAddr = ReadScanoutAddress(mmioBase);
DWORD stride = ReadScanoutStride(mmioBase);

// Step 4: Translate through GGTT (Global Graphics
//         Translation Table) to physical address
PHYSICAL_ADDRESS physAddr = GGTTTranslate(
    mmioBase, fbPhysAddr
);

// Step 5: Map and copy the physical framebuffer
PVOID fbMapping = MmMapIoSpace(physAddr, fbSize);
RtlCopyMemory(outputBuffer, fbMapping, fbSize);

// Result: raw pixel data of everything on screen,
// including all WDA_EXCLUDEFROMCAPTURE windows

This technique is fundamentally unbypassable from the application side because it reads what the GPU has already composited for display output. No amount of software protection can prevent the GPU from physically sending the correct pixels to the monitor, and those same pixels exist in the framebuffer that we read. The approach is also PatchGuard-safe — it does not patch any kernel code, does not hook any functions, and does not modify any protected structures. It simply maps physical memory and reads it.

Why It Works

SetWindowDisplayAffinity filters the software capture path only. The GPU display engine always composites all visible windows into the scanout buffer, which is a hardware requirement for physical display output.

Why It Is Undetectable

No hooks, no patches, no API calls. The driver maps physical memory through legitimate PCI BAR access. No function is detoured, no kernel structure is modified, and no userland API is called.

Detection & Countermeasures

Security software can attempt to detect some of these bypass methods, though the more advanced techniques are extremely difficult to counter. Here is what defenders can realistically detect:

// Detection capabilities by method:

  • DKOM: Detectable via periodic affinity field monitoring — if the app re-checks its own affinity and finds it cleared, the bypass is discovered
  • DWM Hook: Detectable via DWM integrity checks, PPL validation, and hook scanning within the dwm.exe process
  • Virtual Display: Detectable via display adapter enumeration, driver signature checks, and known IDD driver fingerprinting
  • GPU Framebuffer: Extremely difficult to detect — no hooks, no patches, no observable side effects from userland or kernel

The DKOM approach is the easiest to detect because applications can periodically call GetWindowDisplayAffinity to verify their protection is still active. If it returns WDA_NONE when the app set it to WDA_EXCLUDEFROMCAPTURE, the bypass is immediately obvious. To counter this, a complete DKOM bypass also hooks the GetWindowDisplayAffinity path to return the expected value — BypassCore's implementation handles this automatically.

Which Method Should You Use?

Quick Testing / PoC

Use DKOM. Fastest to implement, works on any window, only needs a kernel read/write primitive. Good enough for testing and demonstrations.

Targeted Bypass

Use DWM hooking. Captures all protected windows at once, persistent across window creation/destruction. Requires PPL bypass.

Continuous Capture

Use the virtual display method. Provides a real-time capture stream with minimal performance impact. Ideal for screen recording scenarios.

Maximum Stealth

Use GPU framebuffer direct read. Zero detectability from software. The capture-bypass tool provides a ready-to-use implementation.

For most real-world scenarios, the GPU framebuffer method is the recommended approach. It requires a signed kernel driver for the PCI BAR mapping, but once loaded, it provides completely undetectable capture of the full display output with no software hooks or modifications. BypassCore's capture-bypass repository includes working implementations for all four methods, with the GPU framebuffer approach supporting Intel Gen9+, AMD GCN+, and NVIDIA Maxwell+ architectures.

Demo & Source Code

BypassCore maintains two open-source repositories that implement these techniques. The capture-bypass repo contains the full GPU framebuffer capture implementation along with the DKOM and DWM hooking methods. The phantom-screen repo provides the virtual display driver approach with a user-friendly capture interface.

// Quick start with capture-bypass:

  • $ git clone https://github.com/bypasscore/capture-bypass
  • $ cd capture-bypass && build.bat
  • $ sc create CaptureBypass type=kernel binPath=CaptureBypass.sys
  • $ sc start CaptureBypass
  • $ CaptureClient.exe --method gpu --output frame.bmp

The demo video in the capture-bypass repo shows the tool capturing a window protected with WDA_EXCLUDEFROMCAPTURE in real time while standard Windows screenshot tools show only a black rectangle. This demonstrates the fundamental difference between the software capture path (which respects display affinity) and the hardware framebuffer path (which does not).

Need a SetWindowDisplayAffinity Bypass?

Whether you need to capture protected windows for security research, red team operations, or QA testing — BypassCore builds undetectable capture solutions that defeat all software-level screen protections.

> Get in Touch

Related Articles