首页
社区
课程
招聘
[原创]如何避免窗口被游戏反作弊误杀以及替代方案
发表于: 4天前 1550

[原创]如何避免窗口被游戏反作弊误杀以及替代方案

4天前
1550

任务栏可能:

ABN_FULLSCREENAPP 是最可靠的全屏检测,Windows Shell 自己就是用这个判断是否隐藏任务栏。

反作弊引擎(EAC、BattlEye、Vanguard)会:

利用 WS_EX_NOREDIRECTIONBITMAP

这个标志让窗口没有重定向表面(Redirection Surface)

缺点: 不是所有截图方式都能规避,Windows.Graphics.Capture 仍可能抓到。

注入 explorer.exe,在内部创建 DirectComposition visual:

优点: 没有独立窗口,反作弊无从检测
缺点: 注入 explorer 本身风险高

不是隐藏,而是真正销毁,截图结束后重建:

缺点: 无法覆盖所有截图方式,有延迟

如果 overlay 只是少量文字/图标,让它截图时无害可见

现实建议: 如果 overlay 只是显示信息(时钟、监控等),让它截图中可见反而最安全。反作弊针对的是刻意隐藏的覆盖层,一个正常可见的窗口不会触发检测。

事件 检测方式 响应
全屏游戏进入 ABN_FULLSCREENAPP / HSHELL_RUDEAPPACTIVATED 隐藏 overlay
全屏游戏退出 ABN_FULLSCREENAPP(lp=0) / HSHELL_WINDOWACTIVATED 显示 + 同步位置
任务栏移动/调整大小 ABN_POSCHANGED / Timer 兜底 重新定位
任务栏自动隐藏 Timer 检查 GetWindowRect 跟随隐藏
场景 建议
不跑游戏/无反作弊 WDA_EXCLUDEFROMCAPTURE
有反作弊运行 不隐藏,让 overlay 与任务栏融为一体
需要绝对隐藏 WS_EX_NOREDIRECTIONBITMAP + DComp 渲染
最安全 注入 explorer,不创建独立窗口
class TaskbarOverlay {
    HWND m_hOverlay = NULL;
    HWND m_hTray = NULL;

    // 检测任务栏是否可见
    bool IsTaskbarVisible() {
        if (!m_hTray || !IsWindowVisible(m_hTray))
            return false;

        // 检查是否被全屏窗口遮挡
        APPBARDATA abd = { sizeof(abd) };
        UINT state = (UINT)SHAppBarMessage(ABM_GETSTATE, &abd);
      
        // ABS_AUTOHIDE 时可能隐藏了
        if (state & ABS_AUTOHIDE) {
            RECT rc;
            GetWindowRect(m_hTray, &rc);
            // 任务栏缩到1像素说明已隐藏
            if ((rc.bottom - rc.top) <= 2 || (rc.right - rc.left) <= 2)
                return false;
        }

        // 检查是否有全屏窗口遮挡
        return !IsFullscreenAppRunning();
    }

    bool IsFullscreenAppRunning() {
        // 方法1: 用 Shell API
        APPBARDATA abd = { sizeof(abd) };
        // ABM_GETSTATE 不能直接检测全屏
        // 用前台窗口判断
        HWND hFg = GetForegroundWindow();
        if (!hFg || hFg == m_hTray) return false;

        RECT rcWnd, rcMonitor;
        GetWindowRect(hFg, &rcWnd);
      
        HMONITOR hMon = MonitorFromWindow(hFg, MONITOR_DEFAULTTONEAREST);
        MONITORINFO mi = { sizeof(mi) };
        GetMonitorInfoW(hMon, &mi);
        rcMonitor = mi.rcMonitor;

        // 窗口覆盖整个屏幕 = 全屏
        return (rcWnd.left <= rcMonitor.left &&
                rcWnd.top <= rcMonitor.top &&
                rcWnd.right >= rcMonitor.right &&
                rcWnd.bottom >= rcMonitor.bottom);
    }

    void SyncOverlay() {
        if (IsTaskbarVisible()) {
            RECT rc;
            GetWindowRect(m_hTray, &rc);
            SetWindowPos(m_hOverlay, HWND_TOPMOST,
                rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
                SWP_SHOWWINDOW | SWP_NOACTIVATE);
        } else {
            ShowWindow(m_hOverlay, SW_HIDE);
        }
    }
};
// 注册 Shell Hook —— 收到前台窗口变化等通知
UINT WM_SHELLHOOK = RegisterWindowMessageW(L"SHELLHOOK");
RegisterShellHookWindow(m_hOverlay);

// WndProc 中处理
case WM_SHELLHOOK: // 即上面注册的消息
    switch (wParam) {
    case HSHELL_RUDEAPPACTIVATED:  // 全屏应用激活
        ShowWindow(m_hOverlay, SW_HIDE);
        break;
    case HSHELL_WINDOWACTIVATED:   // 普通窗口激活
        SyncOverlay();
        break;
    case HSHELL_REDRAW:
        SyncOverlay();
        break;
    }
    break;
// 注册 AppBar 接收全屏通知
APPBARDATA abd = { sizeof(abd) };
abd.hWnd = m_hOverlay;
abd.uCallbackMessage = WM_USER + 100;
SHAppBarMessage(ABM_NEW, &abd);

// WndProc
case WM_USER + 100:
    if (wParam == ABN_FULLSCREENAPP) {
        if (lParam) {
            // 全屏应用进入 —— 隐藏
            ShowWindow(m_hOverlay, SW_HIDE);
        } else {
            // 全屏应用退出 —— 恢复
            SyncOverlay();
        }
    }
    break;
static HWND g_hOverlay;
static HWND g_hTray;

LRESULT CALLBACK OverlayProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) {
    static UINT WM_SHELLHOOK;
  
    switch (msg) {
    case WM_CREATE:
        WM_SHELLHOOK = RegisterWindowMessageW(L"SHELLHOOK");
        RegisterShellHookWindow(hwnd);
      
        // 同时注册 AppBar 以获取全屏通知
        {
            APPBARDATA abd = { sizeof(abd), hwnd, WM_USER + 1 };
            SHAppBarMessage(ABM_NEW, &abd);
        }
        // 定时器兜底(处理边界情况)
        SetTimer(hwnd, 1, 1000, NULL);
        break;

    case WM_TIMER:
        SyncPosition();
        break;

    case WM_USER + 1: // AppBar callback
        if (wp == ABN_FULLSCREENAPP) {
            ShowWindow(hwnd, lp ? SW_HIDE : SW_SHOWNOACTIVATE);
            if (!lp) SyncPosition();
        } else if (wp == ABN_POSCHANGED) {
            SyncPosition(); // 任务栏位置变了
        }
        break;

    case WM_DESTROY:
        DeregisterShellHookWindow(hwnd);
        {
            APPBARDATA abd = { sizeof(abd), hwnd };
            SHAppBarMessage(ABM_REMOVE, &abd);
        }
        break;
    }

    // Shell Hook 消息
    if (msg == WM_SHELLHOOK) {
        switch (wp) {
        case HSHELL_RUDEAPPACTIVATED:
            ShowWindow(hwnd, SW_HIDE);
            break;
        case HSHELL_WINDOWACTIVATED:
            SyncPosition();
            ShowWindow(hwnd, SW_SHOWNOACTIVATE);
            break;
        }
        return 0;
    }

    return DefWindowProcW(hwnd, msg, wp, lp);
}

void SyncPosition() {
    RECT rc;
    GetWindowRect(g_hTray, &rc);
    SetWindowPos(g_hOverlay, HWND_TOPMOST,
        rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
        SWP_NOACTIVATE | SWP_SHOWWINDOW);
}
HWND hOverlay = CreateWindowExW(
    WS_EX_NOREDIRECTIONBITMAP | WS_EX_TOPMOST | 
    WS_EX_TRANSPARENT | WS_EX_TOOLWINDOW,
    L"Overlay", NULL,
    WS_POPUP | WS_VISIBLE,
    x, y, w, h, NULL, NULL, hInst, NULL);

[内核课程]《Windows内核攻防实战》!从零到实战,融合AI与Windows内核攻防全技术栈,打造具备自动化能力的内核开发高手。

收藏
免费 48
打赏
分享
最新回复 (28)
雪    币: 236
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
2
你的分享对大家帮助很大,非常感谢!
4天前
0
雪    币: 11
活跃值: (523)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
4天前
0
雪    币: 6280
活跃值: (8061)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
将窗口在副机进行绘制好点,然后融合器进行融合。
4天前
0
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
5
666
4天前
0
雪    币: 2790
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
6
很有用的资料,感谢分享                        
4天前
0
雪    币: 216
活跃值: (3246)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
666
4天前
0
雪    币: 364
活跃值: (2922)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
8
666
4天前
0
雪    币: 1638
活跃值: (6147)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
9
看看
4天前
0
雪    币: 0
活跃值: (1378)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
感谢你的积极参与,期待更多精彩内容
3天前
0
雪    币: 53
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
11
学习学习
3天前
0
雪    币: 50
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
12
666
3天前
0
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
13
666
3天前
0
雪    币: 8725
活跃值: (5686)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
感谢大佬的分享,下载下来,慢慢学习
3天前
0
雪    币: 4
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
15
感谢大佬的分享
3天前
0
雪    币: 426
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
16
学习学习
3天前
0
雪    币: 206
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
17
good
3天前
0
雪    币: 11489
活跃值: (7375)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
学习了
3天前
0
雪    币: 106
活跃值: (1809)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
学习了
3天前
0
雪    币: 219
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
20
学习了
3天前
0
雪    币: 10
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
21
感谢大佬的分享,下载下来,慢慢学习
2天前
0
雪    币: 2790
活跃值: (6517)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
22
感谢分享!
2天前
0
雪    币: 206
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
23
6666666666
2天前
0
雪    币: 427
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
24
mark
2天前
0
雪    币: 4765
活跃值: (5710)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25
6
1天前
0
游客
登录 | 注册 方可回帖
返回