草庐IT

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

coder 2024-05-31 原文

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

我认为检测没有那么容易,因为它们有很多方法可以捕获屏幕 Desktop Duplication API、BitBlt、Direct3D、DirectX、DirectShow 等等。

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

  1. 由于我们的应用程序将在 Windows 7 及更高版本上运行,因此我通过检查我设置的桌面组成来利用 DWM(Destop 窗口管理器)SetWindowDisplayAffinityWDA_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 完成吗?

更新 29-05-2019

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

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

最佳答案

我想将此添加为答案,因为在 moved to chat 的评论中进行了大量讨论,所以我想对其进行总结,以便即将到来的观众了解讨论和我最终得到的解决方案。

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

但作为 RomanR。在聊天中提到“使用用于视频的叠加层无助于隐藏应用程序的用户界面”。

我也确认了这一点,正如我在更新中提到的,我已经创建了一个 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;
}

关于c# - 阻止特定 c# winforms 的桌面共享或检测桌面共享,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56302217/

有关c# - 阻止特定 c# winforms 的桌面共享或检测桌面共享的更多相关文章

  1. ruby - 在 Ruby 程序执行时阻止 Windows 7 PC 进入休眠状态 - 2

    我需要在客户计算机上运行Ruby应用程序。通常需要几天才能完成(复制大备份文件)。问题是如果启用sleep,它会中断应用程序。否则,计算机将持续运行数周,直到我下次访问为止。有什么方法可以防止执行期间休眠并让Windows在执行后休眠吗?欢迎任何疯狂的想法;-) 最佳答案 Here建议使用SetThreadExecutionStateWinAPI函数,使应用程序能够通知系统它正在使用中,从而防止系统在应用程序运行时进入休眠状态或关闭显示。像这样的东西:require'Win32API'ES_AWAYMODE_REQUIRED=0x0

  2. ruby - 通过 ruby​​ 进程共享变量 - 2

    我正在编写一个gem,我必须在其中fork两个启动两个webrick服务器的进程。我想通过基类的类方法启动这个服务器,因为应该只有这两个服务器在运行,而不是多个。在运行时,我想调用这两个服务器上的一些方法来更改变量。我的问题是,我无法通过基类的类方法访问fork的实例变量。此外,我不能在我的基类中使用线程,因为在幕后我正在使用另一个不是线程安全的库。所以我必须将每个服务器派生到它自己的进程。我用类变量试过了,比如@@server。但是当我试图通过基类访问这个变量时,它是nil。我读到在Ruby中不可能在分支之间共享类变量,对吗?那么,还有其他解决办法吗?我考虑过使用单例,但我不确定这是

  3. ruby - RuntimeError(自动加载常量 Apps 多线程时检测到循环依赖 - 2

    我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("

  4. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  5. C# 到 Ruby sha1 base64 编码 - 2

    我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha

  6. 基于C#实现简易绘图工具【100010177】 - 2

    C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

  7. Ruby - 如何在读取文件时跳过/忽略特定行? - 2

    在读取/解析文件(使用Ruby)时忽略某些行的最佳方法是什么?我正在尝试仅解析Cucumber.feature文件中的场景,并希望跳过不以Scenario/Given/When/Then/And/But开头的行。下面的代码有效,但它很荒谬,所以我正在寻找一个聪明的解决方案:)File.open(file).each_linedo|line|line.chomp!nextifline.empty?nextifline.include?"#"nextifline.include?"Feature"nextifline.include?"Inorder"nextifline.include?

  8. ruby-on-rails - 如何处理 Grape 中特定操作的过滤器之前? - 2

    我正在我的Rails项目中安装Grape以构建RESTfulAPI。现在一些端点的操作需要身份验证,而另一些则不需要身份验证。例如,我有users端点,看起来像这样:moduleBackendmoduleV1classUsers现在如您所见,除了password/forget之外的所有操作都需要用户登录/验证。创建一个新的端点也没有意义,比如passwords并且只是删除password/forget从逻辑上讲,这个端点应该与用户资源。问题是Grapebefore过滤器没有像except,only这样的选项,我可以在其中说对某些操作应用过滤器。您通常如何干净利落地处理这种情况?

  9. ruby - 在模块/类之间共享全局记录器 - 2

    在许多ruby​​类之间共享记录器实例的最佳(正确)方法是什么?现在我只是将记录器创建为全局$logger=Logger.new变量,但我觉得有更好的方法可以在不使用全局变量的情况下执行此操作。如果我有以下内容:moduleFooclassAclassBclassC...classZend在所有类之间共享记录器实例的最佳方式是什么?我是以某种方式在Foo模块中声明/创建记录器还是只是使用全局$logger没问题? 最佳答案 在模块中添加常量:moduleFooLogger=Logger.newclassAclassBclassC..

  10. ruby - 检测由 RSpec、Ruby 运行的代码 - 2

    我想知道我的代码是否在rspec下运行。这可能吗?原因是我正在加载一些错误记录器,这些记录器在测试期间会被故意错误(expect{x}.toraise_error)弄得乱七八糟。我查看了我的ENV变量,没有(明显的)测试环境变量的迹象。 最佳答案 在spec_helper.rb的开头添加:ENV['RACK_ENV']='test'现在您可以在代码中检查RACK_ENV是否经过测试。 关于ruby-检测由RSpec、Ruby运行的代码,我们在StackOverflow上找到一个类似的问题

随机推荐