使用DirectX防止屏幕截图

8
我希望使用DirectX渲染单个图像。它应该类似于VLC播放器的“directx视频输出”,无法使用简单的屏幕捕获软件或printscreen键来捕获帧。不应该(或非常困难)截屏!有人知道这在VLC播放器中是如何工作的吗?还有其他可能的解决方案吗?也许可以使用“Output Protection Manager”(请参见http://msdn.microsoft.com/en-us/library/dd388980(VS.85).aspx)。我在学校学习了约3年的C#编程经验。我也做过一些C++编程,但我更喜欢使用WPF或Managed DirectX的C#解决方案。对我的英语表示抱歉,谢谢您提前的帮助!!!
2个回答

15
首先,VLC的内容无法通过打印屏幕或其他屏幕捕捉技术进行捕获的原因是因为(至少在旧版Windows上),它们使用了“覆盖层”来呈现视频。这是一种特殊的GPU结构,允许渲染到普通屏幕表面上方的虚拟“平面”上。由于这绕过了其他所有内容并直接传输到GPU,因此没有任何简单的方法可以捕获它。注意:在最近的几个Windows版本中,关于覆盖层的规则发生了很大变化。应用程序不能假定D3D9 / DDraw覆盖层得到支持,现在应用程序不应该使用它们,因为系统有更好的方法以相同的高性能呈现内容。
Direct3D 9覆盖层
如果您正在使用Direct3D 9显示视频内容,则也可以使用覆盖层。请参见MSDN上的此页面以获取有关如何执行此操作的信息。对于D3D9覆盖层的使用存在许多限制,并且不受许多硬件的支持,因此我将描述其他方法。

这种技术不能防止其他应用程序将它们注入到您的地址空间并捕获您的礼物。此外,由于在某些硬件上不受支持,有些捕获API实际上会禁用覆盖层,因此它并不提供非常强的保护保证。

基于GPU的内容保护

如果您有足够的时间了解GPU内容保护,并且知道您将显示非标准DRM受保护的视频格式,则可以使用GPU内容保护来创建自己的受保护媒体路径。我不是这个领域的专家,很少有人是。我不建议这样做,但我想指出一下。此MSDN页面介绍了它如何在Direct3D 9中实现,另一页介绍了它如何在Direct3D 11中实现。

这种技术提供了强大的保证,即内容未被捕获,因为密钥交换几乎完全通过硬件进行(例如HDCP)。

Media Foundation Protected Media Path (PMP)

如果您使用受支持的基于DRM的媒体格式显示视频,则可以使用Media Foundation的Protected Media Path,该路径利用了先前描述的基于GPU的内容保护。它还将大部分功能封装在一个单独的受保护进程中,其他应用程序无法拦截或以其他方式与其交互。如果有人尝试安装测试签名驱动程序或以其他方式注入未经受信任根授权机构代码签名的二进制文件,则Windows将不允许解密内容,从而使您的内容保持安全。这种技术提供了强有力的保证,确保内容未被捕获。Netflix在Windows、蓝光播放器和其他设备上都使用了这个技术。

DXGI Swap-chain Flags

假设您正在使用Direct3D 10.x/11.x(希望现在是2014年,而不是D3D 9)呈现内容,则可以在交换链上使用多个标志来锁定您的内容。

您可以在交换链标志中传递DXGI_SWAP_CHAIN_FLAG_RESTRICTED_CONTENT,以便如果系统没有HDCP或类似的输出保护,则失败交换链创建。这对于您的目的可能不是必要的,但如果您担心有人捕获HDMI或模拟输出,则很好。
您绝对需要的标志称为DXGI_SWAP_CHAIN_FLAG_DISPLAY_ONLY。这将防止所有屏幕捕获API从看到您的交换链。它们只会将其显示为黑色矩形。
请参见此页面以获取所有DXGI交换链标志。
这种技术不提供GPU基础内容保护所提供的强大保证,但是如果您相当自信其他应用程序不会像注入自己到您的地址空间并钩住您的现有调用等疯狂的事情,那么您可以确信这可以防止任何人看到您的内容(当然除了监视器)。
全窗口保护
有时您可能想要保护的不仅仅是DXGI呈现的内容。在这种情况下,您实际上可以利用类似的机制,仅仅保护整个窗口不被各种屏幕捕获技术捕获。这是一个名为SetWindowDisplayAffinity的API。它在强度和功能上相当于为交换链传递DXGI_SWAP_CHAIN_FLAG_DISPLAY_ONLY标志,但它还保护使用GDI、旧版DirectX技术等呈现的内容。传递WDA_MONITOR标志以启用给定HWND的保护,或传递WDA_NONE以禁用保护。
完全公开地说,我在微软工作,负责处理显示逻辑,包括某些形式的屏幕捕获和内容保护。

你可以帮助处理这个问题吗?https://dev59.com/tFMI5IYBdhLWcg3waqo4 - Amogh

3

也许从声音上来看,您需要通过钩入全局Windows过程截取WM_PRINTCLIENT,如果使用了WM_PRINTCLIENT消息,则只需从挂钩的窗口过程返回。有关WM_PRINTCLIENT的详细信息,请参见Feng Yuan在此处的详细信息。另一种方法是拦截剪贴板函数,其中数据来自特定应用程序,剪贴板包含位图。请参见Larry Osterman关于this的博客。这是一个关于CodeProject实现全局Windows钩子的文章,我还可以提供两个链接herehere。(所有内容均在CodeProject上)

我尝试使用WM_PRINTCLIENT来解决问题,但我从未收到WM_PRINTCLIENT消息。在我的应用程序中,我使用了主窗口的 protected override void WndProc(ref Message m)。拦截剪贴板功能无效,因为屏幕捕获软件不会将捕获的位图保存到剪贴板中(例如Windows 7的截图工具选项)。 - raisyn
如果你看一下CodeProject的最后一个链接,那里有一个钩子可以用于剪贴板...由于我没有Windows 7,所以无法说它是如何工作的... :) - t0mm13b
有的,但是屏幕截图软件(例如 Snipping Tool)不使用剪贴板。因此,钩子将永远不会被执行! 但还是谢谢你的帮助!!! - raisyn
1
我认为唯一可能的解决方案是使用DirectX输出,这是无法被捕获的(就像在VLC中如果你将输出模式设置为directx-video-output)。 - raisyn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接