阅读本文前,强烈建议先行阅读:《红字的研究》。
🤔什么管线❓
要劫持谁❗️😱
对大多数非计算机相关专业的同学而言,这是一个很难理解的名词。简要的说,“管线”指的是 GPU 中的渲染管线;“劫持”的意思是在渲染管线中插入我们希望渲染的内容,或改变渲染的方式。
从使用体验的角度上讲,通过“管线劫持”可以让计算机的 GPU 向屏幕输出任何自定义的内容,比如考试答案。
听起来好耳熟!这不就是“字幕”/“水印”吗???
当然……不是!
Well… 如果只是从“表现形式”这个单一的方面看,的确,好像和字幕并没什么区别:都是将答案显示在屏幕上。
但是它却具备一些非常之奇妙的、“字幕”/“水印”并不具备的特质:
- 第二机位监考的手机无法拍到它,所以考生不需要“卡机位”
- 不会出现文字与题目互相遮挡,导致考生看不清的现象
- 免疫一切屏幕捕获,哪怕是驱动级的屏幕捕获
- 专业的描述是:“水印”/“字幕”是把答案“显示”在屏幕上;而管线劫持是把答案“投射”在屏幕上
听起来像是天方夜谭,对吧?一段可以被投射在屏幕上的文字,却几乎无法被摄像头拍到?完全没有任何道理!但请先别急,在我们麻瓜的世界里,没有魔法,只有科学。
如果你是相关专业,并具备相当的理工背景,可以直接参考这五篇论文:
Davis, J., Hsieh, Y.-H., & Lee, H.-C. (2015). Humans perceive flicker artifacts at 500 Hz. Scientific Reports, 5, Article 7861. https://doi.org/10.1038/srep07861
Hasinoff, S. W., Sharlet, D., Geiss, R., Adams, A., Barron, J. T., Kainz, F., Chen, J., & Levoy, M. (2016). Burst photography for high dynamic range and low-light imaging on mobile cameras. ACM Transactions on Graphics, 35(6), Article 192, 1–12. https://doi.org/10.1145/2980179.2980254
Köhler, S., Lovisotto, G., Birnbach, S., Baker, R., & Martinovic, I. (2021). They see me rollin’: Inherent vulnerability of the rolling shutter in CMOS image sensors. In Proceedings of the 37th Annual Computer Security Applications Conference (pp. 399–413). Association for Computing Machinery. https://doi.org/10.1145/3485832.3488016
Schaber, P., Dong, S., Guthier, B., Kopf, S., & Effelsberg, W. (2015). Modeling temporal effects in re-captured video. In Proceedings of the 23rd ACM International Conference on Multimedia (pp. 1279–1282). Association for Computing Machinery. https://doi.org/10.1145/2733373.2806405
Wronski, B., Garcia-Dorado, I., Ernst, M., Kelly, D., Krainin, M., Liang, C.-K., Levoy, M., & Milanfar, P. (2019). Handheld multi-frame super-resolution. ACM Transactions on Graphics, 38(4), Article 28, 1–18. https://doi.org/10.1145/3306346.3323024
如此最为科学严谨。
如果论文对你来说并不友好, ELPIS 尽量用“低技术、多比喻”的方式说明白。但即便如此,以下内容也稍有些硬核。Bear with us!
📸镜头的工作原理⚙️
首先,想要弄明白为什么摄像头“拍不到”,先要弄明白摄像头是“怎么拍到的”。对于任何现代手机摄像头,其工作原理大致如下:
物体所发出(或反射出)的光线,先通过镜头组进入相机内部,然后经由(电子)快门控制曝光时长,最后 CMOS 组件(相当于老式相机的胶卷)负责感光成像。这样,一张照片就拍摄完成了。
人们常说照片是一瞬间的定格,但从物理学的角度这句话并不严谨:如果真的是定格了“瞬间”,照片就不会出现残影模糊的现象了,因为对于每一个“瞬间”,宏观物体的状态都是确定的,是精准的。
所以实际上,照片记录的是“一段极短时间内,被摄物运动量的总和”。比如某手机前置摄像头的快门时间是 1/30 秒,也就意味着从按下快门开始算的 1/30 秒内,如果被摄物基本保持不动,则被叠加在一起的运动量几乎没有,也就没有残影。但是如果在这 1/30 秒内,被摄物运动幅度较大,则被叠加在一起的运动量就会较多,也就出现了残影。
拓展阅读
芝诺佯谬(Zeno’s paradoxes/飞矢不动悖论)给出如下表述:一支飞行的箭是静止的。由于每一时刻这支箭都有其确定的位置因而是静止的,因此箭就不能处于运动状态。
我们当然知道,飞行中的箭矢一定是在运动的。结合前文中的“照片记录的是一段极短时间内,被摄物运动量的总和”这句话,你是否能推翻芝诺佯谬?
从拍照📷到录像📹
接下来,我们从“拍照”延申到“录像”。录像的本质无非是很多张照片拼在一起,产生“动起来”的感觉。比如 30 帧的录像(每秒拍摄 30 张照片),每张照片的曝光时间就是 1/30 秒;60 帧的录像,每张照片曝光的时间就是 1/60 秒。为了更加好的理解我们接下来讲的内容,我们先看一下当物体的运动速度与摄像头的帧率一致的时候,会发生什么?
这不是 PS 出来的录像,而是一种真实的物理现象。直升机的确在天上飞,但是螺旋桨好像看起来没有动。这是因为螺旋桨的转速和摄像头的帧率碰巧一致了。
我们假设摄像头帧率为 30,也就是说每一帧是 1/30 秒。如果螺旋桨转动整整一圈的时间也刚好是 1/30 秒,那么在这 1/30 秒的时间内,螺旋桨转了一圈又刚好回到了原位!对于每一帧,皆是如此!所以螺旋桨好像看起来“没动”。
不是螺旋桨真的没动,而是相机被“欺骗”了。
可这些,和“看不见”又有什么关系呢?
既然我们知道相机可以被“欺骗”,我们就可以人为的构造“欺骗”相机的条件!
我们假设有一个奇妙的小色块,它可以在瞬间在黑白两种颜色之间切换。我们令纯白为 0,纯黑为 100,并且令色块每切换一次颜色所需的时间刚好为 1/120 秒。
已知:色块初始色为纯白;
如果:有一台快门速度为 1/30 秒(30 帧率)的相机对色块拍照一次;
请问:拍出来的颜色会是什么?
- 纯白?
- 纯黑?
- 还是…灰色?
感觉有点抽象?我们来画个图。
t = 0 时,色块为纯白,相机开始拍照
t = 1/120 时,色块为纯黑,相机持续拍照
t = 2/120 时,色块为纯白,相机持续拍照
t = 3/120 时,色块为纯黑,相机持续拍照
t = 4/120 = 1/30 时,色块为纯白,相机停止拍照
那么相机拍出来会是什么颜色呢?
算法是:
C_avg = Σ(C_i × T_i) / Σ(T_i)
C_i 表示第 i 个颜色对应的数字(纯白 = 0,纯黑 = 100)
T_i 表示第 i 个颜色持续的时间
- C_avg 表示拍出来的颜色
换成人话说就是:SUM(颜色数字 * 持续时间)/ 总体持续时间
也就是:
(0 * 1/120 + 100 * 1/120 + 0 * 120 + 100 * 1/120) / (1 / 30) = 50
50 是一个介于 0(纯白)和 100(纯黑)之间的数字,所以,答案是介于黑白正中间的灰色!
别忘了,色块的颜色不是纯黑就是纯白,从来没有过灰色!请再回顾一下前文的一句话:照片是一段极短时间内,被摄物运动量的总和。这句话的重点是“运动量”三个字,物体本身的物理运动(平移、旋转等位移)当然是一种“运动量”,但是物体的颜色的变化,也是一种“运动量”!
你看!我们完全可以在色彩上“欺骗”相机!在真实的色彩世界中,颜色被用 RGB 表示:
所以只要可以精确控制在极短时间内文字颜色的变换,我们甚至可以控制文字在摄像头中显示出各种不同的色彩!
诚然,截至目前,距离实现“拍不到”还是有一定差距。不过基本的方法论就是这样啦!余下的事情只是在基本方法论之上的演绎。
我们知道,这部分的讲述有点…戛然而止的感觉:略微爽,但不够爽。ELPIS 在这里致歉各位看官老爷!毕竟,网站是公开的平台,恕我们无法把所有的技术路线、实现细节都一一道出(尽管我们内心特别希望可以与大家分享,因为真的真的很有趣)。所以,我们现在不得不只把基础知识说出来,然后给爱思考的、甚至想自己动手实现的各位留一个很难的课后作业。
原理我懂了
“劫持”体现在那里?
说了这么多,其实我们还没真正解释清楚,为什么需要“劫持” GPU 的渲染管线!前面提到过,如果想做到“肉眼可见但相机难以捕捉”,我们必须让文字内容以极高的频率快速变化,甚至每次变化的间隔要短至 1/200 秒。
如果完全依靠 CPU 来完成这一过程,几乎不可能。因为常规流程是:先把需要显示的文字生成到系统内存(RAM)中,再由 CPU 进行处理,然后把结果拷贝到 GPU 的显存中,接着 GPU 才会渲染并输出到屏幕。这个过程涉及多次内存传输和 CPU 计算,延迟太高,根本跟不上所需的刷新速度。
那能不能直接把文字送进 GPU 的显存里,让 GPU 自己完成渲染并直接显示呢?理论上当然可以,而且效率极高。但在实践中,这并不简单 —— 因为这意味着要绕过常规的渲染 API 调用流程,直接介入 GPU 的渲染管线。
我们需要先看看 GPU 的渲染管线是怎样工作的。
如图所示,通过 HLSL(D3D11/12)即可精细化的操作 GPU 的 Pixel Shader(片元着色器),从而完成极高频的染色。
由于我们没有利用任何现有的 API,而是自己用代码“强行介入”了 GPU 的工作流程,也就相当于“劫持”了管线。
所以,“管线劫持”的目的是使 GPU 可以以极高频对一个区域进行渲染,从而达到对第二机位隐藏文字的目的。
更美妙的是,这种方法不会在软件层面留下任何痕迹。着色器会在考前载入完毕,载入后退出,不影响计算机的正常使用,更不影响考试。因为严格意义上说,着色器只是决定了屏幕画面的显示方式,着色完成后并不存在任何进程。而考试软件自然不关心考生显示器色温、色准、刷新率等等与考试完全不相关的、并且每台计算机、每块屏幕都可能不一致的东西。
另外,由于我们“劫持”了渲染管线,在面对屏幕录制时,我们可以轻易的“摘除”不希望被录制进去的内容。当然,有一个前提:我们必须完全控制一台计算机。唯有如此才可以 100% 使得驱动级别的录制无效。这并不是简单的安装某个软件、执行某个命令可以做到的。而是需要利用 0day(零日漏洞)才能实现对计算机内核的完全控制。在业界中,如何彻底制止驱动级别的屏幕捕获是一个“老大难”问题。虽然截至目前(和可预见的将来),任何考试软件都不可能接入驱动级别的屏幕录制(因为要么需要 GPU 厂商专门为了某款考试软件定制驱动,要么需要额外的特殊硬件),但我们依旧做了充分的 future proof 方案,确保哪怕在最极端的条件下,屏幕上投射出的文字都没有可能被录制。
“投射” vs “显示”
我们与“字幕/水印”的区别
市面上所有的“字幕/水印”,都是将文字“显示”在屏幕上。
想要在电脑屏幕上把一段文字“显示”出来,有各种各样的办法,十数种编程语言都可以轻易做到。
但是无论用哪种语言、哪种方法,都绕不过一件事:你需要向操作系统申请一个窗口用来显示文字。
用过“水印/字幕”的同学可能有疑惑:文字明明是直接出现在屏幕上的,并不是显示在什么“窗口”上的呀!这是因为,窗口不一定都是可见的,窗口的很多特质是可以由编程者指定的。比如,如果我想实现“字幕/水印”,我可以请求操作系统给我一个背景透明的窗口。文字的确是显示在窗口上,只不过窗口本身是透明的。
下面的 C++ 代码就是所有“字幕/水印”软件用来向操作系统申请窗口的基础代码。
// 注册窗口类
const wchar_t CLASS_NAME[] = L"SampleWindowClass";
// 关联窗口过程函数
WNDCLASS wc = { };
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
c.lpszClassName = CLASS_NAME;
RegisterClass(&wc);
// 创建窗口对象
HWND hwnd = CreateWindowEx(
0, // 扩展窗口样式
CLASS_NAME, // 窗口类名
L"C++ 示例窗口", // 窗口标题
WS_OVERLAPPEDWINDOW, // 窗口基础样式
CW_USEDEFAULT, CW_USEDEFAULT, // 初始坐标 (X, Y)
800, 600, // 窗口宽高 (Width, Height)
NULL, NULL, hInstance, NULL
);
// 显示并刷新窗口
ShowWindow(hwnd, nCmdShow);
以上代码的作用是:向操作系统申请创建一个窗口,用于显示自定义内容。
但这就造成了一个问题:只要试图向操作系统申请资源,就必定留痕。
如果不想留痕,那就不能向操作系统申请窗口,如果没有窗口,就不能显示文字。如果要显示文字,就必须有窗口,如果要有窗口,就需要向操作系统申请,如果申请……
好了,这个鸡生蛋蛋生鸡的问题到此为止。一句话,只要考试软件检查“有谁向操作系统递交过窗口申请”这件事,所有的“字幕/水印”都瞬间鸡飞蛋打。
有些考试软件的确检查,所以对付这些考试软件“字幕/水印”必然失败。不过有一款考试软件很有趣,就是 ETS 旗下的 Secure Browser。它是唯一一个虽然做了检查,但拦不住“字幕/水印”的!原因是它的检查方式太草率,导致漏掉了很多很多本不该“高抬贵手”的窗口。如果监考方想要修复这个漏洞,其实只需要改 2~3 行代码。改动之后,世界上就再也不存在“水印/字幕”这种东西了。
而 ELPIS 的“合成管线劫持”,是将目标内容“投射”到屏幕。
在这个语境里,“投射”意味着“无需申请窗口”。Why?Again,因为我们“劫持了渲染管线”,我们可以绕过软件、绕过操作系统,直接控制显示屏上的每一个像素,物理意义上的。
这让我们完美的躲避了鸡生蛋蛋生鸡的问题。所以,无论哪个考试软件、用什么方式检查窗口,都无法找到我们。毕竟,本质上,我们从未申请过任何窗口。
好不好
看疗效
最后,关于让考生“看得清”这一点…由于方案的本质,我们很难在网页上展示出来到底对人眼有多清晰!因为我们:
无法截屏:驱动级别的过滤使得我们的文字无法出现在任何截屏里;
无法拍照:方案设计的初衷就是避免文字被拍下来!哪怕我们特地距离很近的拍下,文字也几乎不可见,无法说明“对人眼清晰可见”,反而会让人看完后觉得“人眼也看不清”。
那就请各位看官看在我们码了这么多字的份上,暂且相信我们:你一定可以看得清!完全不会影响阅读!
方案局限性
“合成管线劫持”方案的好处讲完了,我们也来聊点坏的,说说这方案的局限性。
最重要的先说,虽然极高频的变换对人眼几乎是不可见的,对于大部分人来说,人眼的识别上限大约是 60 帧,超过 60 帧对人眼来说就是连续显示的图像,但是对于极少部分对光极度敏感的人来说,这个方案有一定概率触发癫痫!
所以有癫痫史的同学们,这方案不要用!考试的确重要,但是健康更可贵!在 ELPIS 的内部测试中,曾有极少数情况下测试者汇报有不适感受。比如在持续阅读一小时的文字后,有轻微的头晕、恶心等现象。但由于 ELPIS 团队内暂无癫痫患者,所以更多副作用暂且未知。(就算有我们也不会让她/他去测试!)
其次,这个方案对考试笔记本的要求相当高。笔记本需要一个十分强劲独立显卡,和一块 240Hz 的高刷屏,屏幕响应时间理想情况下应为 1ms。这导致大部分考生的笔记本根本无法达到要求。
没办法,我们不能“既要又要也要”。一个又好用、又稳定、又好读、又隐形的方案的代价就是一台顶配的笔记本。
结束语
从 25 年 4 月开始,我们就一直试图构想出一种完美解决双机位的方案。我们尝试了很多很多种方法,比如“利用定制的短波通滤光片使得某种特定颜色的屏幕内容无法被摄像头拍到”。又比如“在计算机屏幕上粘附某种复合的、多层的薄膜,使屏幕在摄像头拍摄下出现光栅效应(阶梯状锯齿的摩尔纹),从而让摄像头失真。
虽然我们尝试了不下 7、8 种各式各样奇思妙想的方案,但后来都因为效果问题、隐蔽性问题、成本问题、跨设备普适性等问题,被我们一一否决了。直到有一个已经在 Nvidia 工作的前同事,出于自身职业的角度,提出了如上的构想,我们终于恍然大明白!原来,还可以这样玩!原来不需要借助任何特殊道具,只需要一台高端游戏本,就可以完美解决两难困境!
这再次提醒我们,科学技术才是第一生产力。谁能想到解决 ETS 重金部署的双机位的功臣,本质上竟然一块小小的 GPU 芯片?这让人不禁联想到中国高端芯片的发展进程,还真是感到任重而道远。至少目前在高端芯片制造领域,还得有一段“师夷长技以制夷”的过程。
在这个过程中,ELPIS 更要好好的将“在专业上有能力”但是“被没啥用的标准化考试卡住”的各位稳稳送出国。ELPIS 团队绝大数成员具备强理工背景,我们深知就像 GRE、托福这种东西,在2025年的今天,已经纯粹变成了为了卡住学生而特地设计的、与所学专业严重脱节的、给考试中心赚大钱的工具。托福如此,GRE 更甚。所以我们偏要有理有据的反潮流,反标准化。况且,哪个理工人可以拒绝“破解”的诱惑?可以拒绝在智商的高地上演精彩刺激的攻防战呢?
最后,祝各位看官老爷事半功倍。无论是否选择我们 ELPIS,都可以一帆风顺,前途似锦。如果你选择我们,若干年后可能我们会在世界的某处相遇。你不认识我,我也不认识你,但我们都有一个共同的,名为 ELPIS 的小秘密。
很有趣,甚至还有点浪漫~
结束语的结束语
笔者按
“这篇文章,我没看懂怎么办?是否能给我再讲解一下 xxx 部分?”
我们十分理解对于非理工科的同学来说,本文也许显得有点晦涩难懂,让人看完云里雾里。Trust me,笔者本人也并非理工科出身,当我那负责带领技术团队的好同事把关于“合成管线劫持”的材料发给我,让我写成一篇科普风文章的时候,我的内心是崩溃的。
这篇文章是我用尽力气将各种奇怪的数学、物理、统计学、计算机概念“降级”成我认为普通人还算可以勉强理解的程度。但臣妾也仅仅只能做到如此了🙇。况且要是没有我在中间转圜,可能您现在读到的就是各种公式和代码了。
所以,很遗憾我不能(也没有能力)提供进一步的解析了。因为我们只是个平平无奇的代考机构,不是可以帮人补足大学 4 年(甚至要额外加上研究生 2 年)的理工科背景知识的神奇学院。
结束语的结束语的结束语
这次真没了
如果您看到了这里,能否请您点击下方的 Like 按钮?
点击按钮不会留下您的任何信息,也不会产生可以追溯到个人或设备的任何标识符。Likes 按钮仅仅是一个十分简单的计数器,但它对我意义重大。由于按钮本身不搜集任何标识符,所以理论上您可以重复点赞,系统没办法去重。不过最好还是只点一个,谢谢~
原本我设计了两个按钮,一个 Like 一个 Dislike。后来想想,只保留了 Like 🤷。而且这篇文章是全站唯一一个有点赞功能的文章哦!
谢谢您看到这里!完结撒花!🎉🎉🎉