阻止特定 c# winforms 的桌面共享或检测桌面共享

Posted

技术标签:

【中文标题】阻止特定 c# winforms 的桌面共享或检测桌面共享【英文标题】:Prevent desktop sharing of a particular c# winforms or detect desktop sharing 【发布时间】:2019-10-11 14:55:15 【问题描述】:

在开发考试软件时,我需要防止通过 TeamViewer、AnyDesk、Ammyy Admin 等应用程序共享桌面,或者至少检测到它。我们的考试软件是用C#开发的,是一个winform一个一个的渲染问题。

我认为检测并不容易,因为它们有很多方法可以捕获屏幕桌面复制 API、BitBlt、Direct3D、DirectX、DirectShow 等等。

所以我开始探索如何防止我的 c# winform 在桌面共享开始时显示。为此,到目前为止,我已经尝试过以下事情:

    由于我们的应用程序将在 Windows 7 及更高版本上运行,因此我通过检查桌面组合来利用 DWM(Destop Window Manager),我将 SetWindowDisplayAffinity 设置为 WDA_MONITOR 以启用对我的 winform 的保护。通过在我开始桌面共享时执行此操作,远程的计算机可以在表单上看到黑色层。但并非所有桌面共享应用程序都具有相同的行为。就像 TeamViewer 的行为符合预期但 Ammyy Admin 一样,AnyDesk 却没有。 如何有的应用程序显示黑色层而有的不显示?还有什么我可以做的吗?
if (winForm != null)

    if (Protect)
        result = SetWindowDisplayAffinity(winForm.Handle, WDA_MONITOR);
    else
        result = SetWindowDisplayAffinity(winForm.Handle, WDA_NONE);

我编写的这种方法并不能完全证明所有桌面共享应用程序,所以有没有 100% 的解决方案来防止/检测桌面共享?

如果你尝试过 VLC 播放器的“DirectX (DirectDraw) 视频输出”,那么这个输出方法也会像 SetWindowDisplayAffinity 一样做同样的事情,它会在任何桌面共享应用程序启动时在视频上放置黑色层,我对此进行了测试适用于近 9 个桌面共享应用程序,知道它是如何完成的吗?可以用c#winform完成吗?

2019 年 5 月 29 日更新

检查 VLC 代码后,我知道他们使用 DirectDraw 使用硬件覆盖。所以我创建了 vc++ 项目并使用了 d3d9 并创建了带有红色表面的叠加层,现在如果我远离机器,那么红色的表格会显示为黑色。答对了!!问题解决了一半。

现在,我正在尝试为该窗口设置透明度,以便叠加层将显示在我的 C# 应用程序之上,并且考生可以参加考试,如果使用遥控器,则叠加层将显示为黑色。为了使窗口透明,我使用了DwmExtendFrameIntoClientArea winapi,但现在在远程上它也可以透明地看到。有什么办法吗?

【问题讨论】:

评论不用于扩展讨论;这个对话是moved to chat。 【参考方案1】:

我想添加这个作为答案,因为很多讨论都是在 moved to chat 的 cmets 中进行的,所以我想总结一下,以便即将到来的观众了解我结束的讨论和解决方案跟上。

首先我想弄清楚 VLC 的“DirectX (DirectDraw) 视频输出”是如何工作的? VLC 的这种特殊输出模式使用 DirectDraw 来创建硬件覆盖并在其上播放视频。虽然屏幕捕获(不是来自移动或外部摄像头)大多数捕获机制通过请求 GDI 来捕获屏幕,但硬件覆盖直接在 GPU 上渲染,GDI 无法访问 GPU。就像 GDI->CPU+RAM,DirectX->GPU+VRAM 这就是为什么在截屏时 VLC 的视频播放部分显示为黑色。欲了解更多信息https://***.com/a/21535254/1629242

但作为 RomanR。在聊天中提到“使用用于视频的叠加层不会帮助隐藏应用程序的 UI”。

我也确认了这一点,正如我在更新中提到的,我创建了一个 vc++ 项目,如果我在其上播放视频,则使用 D3D9 创建硬件覆盖,然后在屏幕录制中显示黑色区域,但我没有找到任何方法该叠加层透明,以便它可以放在我的应用程序上或将应用程序内容放在叠加层上,以便在录制屏幕时应用程序内容将不可见。

Riddel 提出了“反病毒工作方式和迭代所有进程和哈希检查常用屏幕共享工具的方式”的新想法,但我个人认为这不会是通用解决方案,因为我必须维护此类应用程序的列表它是散列,如果发现任何新应用程序,则更新该列表。此外,任何人都可以编辑字节来破坏散列值以使其为假。

我接受的解决方案:

Windows API 提供了一个功能,可以帮助仅在监视器上显示窗口的内容。即SetWindowDisplayAffinity,这就像魅力!

最低支持操作系统的问题:

虽然 MSDN 文档提到“最小支持的客户端::Windows 7”,但在 Windows 7 上它不适用于所有屏幕捕获应用程序。罗曼R。在评论中说:“这将从 Windows 8 开始正常工作(可能还有 Windows 7 的平台更新)。在纯 Windows 7 上,您将面临免费桌面共享并且无法保护您的内容。”

所以目前,我已经完成了SetWindowDisplayAffinity 我将其实现为:

private const uint WDA_NONE = 0x0;
private const uint WDA_MONITOR = 0x1;

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool SetWindowDisplayAffinity(IntPtr hWnd, uint dwAffinity);

public static bool SetDRM(Form winForm, bool Protect)

    bool result = false;
    if (winForm != null)
    
        if (Protect)
            result = SetWindowDisplayAffinity(winForm.Handle, WDA_MONITOR);
        else
            result = SetWindowDisplayAffinity(winForm.Handle, WDA_NONE);
    
    return result;

【讨论】:

嗨,Amogh,我们可以检测我们的应用程序窗口是否共享,而不是阻止吗? 我只想检测并向管理员发送通知电子邮件,而不是阻止它。这可能吗? @ChandrasekarKesavan 我不这么认为,Windows 不会为此类活动触发任何挂钩或事件。我已经为此进行了很多搜索和调查。问题是有很多方法可以捕获屏幕。最著名的是 BitBlt,但微软没有记录任何 API 会在任何应用程序执行 Bit Blitting 时触发。这就是我为什么选择保护应用程序窗口不被捕获并且效果很好的原因。 @ChandrasekarKesavan 即使如果你找到了一种方法,请告诉我:) 当然。感谢您分享信息。

以上是关于阻止特定 c# winforms 的桌面共享或检测桌面共享的主要内容,如果未能解决你的问题,请参考以下文章

WinForm多线程实现HTTP网络检测工具

C# Winforms 按钮到 Windows 中的特定屏幕

从 WinForm C# 在 WhatsApp 桌面聊天中添加文件

C#如何让WinForm嵌入桌面窗口最底层

从 WinForms C# 项目创建 .exe 或 MSI

阻止对特定应用程序的任何内存或 DLL 文件注入