这是直接后续 在 CSS 中获取 32 位 API 响应数据 的内容,无需 JavaScript
在 CSS 中,可以将响应数据(16 位)同时用于内在宽度和高度,这相比于没有 JavaScript 时完全无法获取 API 响应数据而言,是一个巨大的进步。
然而,在我弄明白之后的那些日子里,我更倾向于:要是它是16位
32次,而不是只有两次,会更有趣。
睡前冥想时突然有了一个灵感
"如果图像文档能够 自己 调整 它自身 的大小会怎么样?"
有了灵感后,通常会经历一系列的想法,每个想法都闪现出其实现的方法……我只需要确认一下是否真的有这种图像类型。
我拿起手机,在我所了解的所有动画图像格式中搜索,看看它们是否可以做到。svg ,webp ,apng ,gif ,或者是一些奇怪的视频格式?没有找到任何东西。
一大早,我心里有个声音说继续研究SVG动画。
我尝试了内嵌的CSS,媒体查询(media queries),使用了<defs>,更多的使用了<defs>,深入研究了众多的SVG动画文档,尝试欺骗它们,并查阅了其他的想法和与动画相关的属性,但都没有办法让SVG设置高度或宽度。
不过,那最后一个链接让我想到了……嗯
...关于
viewBox
呢?我将会面临一些其他的挑战,但…… 这个 可以动画化吗?
vvv
确实是这样!!
^^^
整理解决方案空间
现在的问题是,如果你没有为根 svg
元素设置 width
和 height
属性,然后尝试将 svg 用作伪元素内容,它会被渲染为 0px
x 0px
,因为这是一个矢量文档,所以不再具有固有尺寸。
所以我添加了preserveAspectRatio属性……结果仍然是 0x0
……然后在我的CSS中,我将宽度固定为 10px
,并通过viewBox
的保持纵横比属性来自适应高度(我可以在SVG中嵌入动画来调整高度),这时包含它的HTML元素的高度就自动调整到了正确的高度。
:3(表示可爱或开心的脸)
如果只有一个帧,这就把我原来的32位数据减少了一半;因为只能传输一个维度,另一个维度是静态的。
但是!现在,我第二个维度是时间,而第一个维度随时间而变化,所以可以找到足够多的数据。
真激动人心!
我首先学了一切我能学到的关于如何控制SVG动画的知识(https://oak.is/thinking/animated-svgs/),然后编写了一个服务器端脚本,生成了我的第一个动画SVG。
<?php
header('Content-type: image/svg+xml');
$data = array(
400,
450,
150,
20,
175
);
$datalen = count($data);
$viewBoxXYWidth = '0 0 10 ';
$frames = array_map(function ($val, $index) use ($viewBoxXYWidth) {
return $viewBoxXYWidth . ((string) ($val));
}, $data, range(1, $datalen));
$dur = $datalen * 0.33; // 总时长
$keytimeStep = 1 / ($datalen); // 每帧的均匀时间间隔
$keytimes = implode("; ", array_map(function ($index) use ($keytimeStep) {
return ($index * $keytimeStep);
}, range(0, $datalen - 1)));
$values = implode("; ", $frames);
echo '<svg viewBox="0 0 10 100" preserveAspectRatio="xMinYMin meet" xmlns="http://www.w3.org/2000/svg">
<animate
attributeName="viewBox"
dur="' . $dur . 's"
fill="freeze"
begin="0.1s;"
values="' . $values . '"
keytimes="' . $keytimes . '"
repeatCount="indefinite"
calcMode="discrete"
/>
</svg>';
?>
点击全屏模式;点击退出全屏
(为什么是 PHP 呀?!——因为我已经好几年一直在为一个已经设置好运行 PHP 的服务器付费了……即使我靠非常擅长 JavaScript 和 node 挣了很多钱,有时候觉得,每查一个函数、操作符和语法来完成你本可以不用具体细节就能搞定的事还挺有意思的。笑一笑)
现在,首先让我们fork我的第一个CodePen来自我之前的那篇文章,看看CSS如何响应并调整 --vars 大小,随着SVG动画的进行。
确认了!我们能够读取大小变化。就像之前文章里讲的,最后还是会用 view-timeline
测量方法,而不是那个 tan(atan2()) 的方法。
在数据渗出(exfiltration)完成后,我们需要从 content
中移除它,因为它会让我的CPU过热。
从概念上来说,如何程序化地提取1D + 时间的
上面的演示单独使用时并不是非常有用。它会报告高度的副本每次高度存在时,但我们需要保存它,……如果不知道这些16位值的顺序且无法信任这些值,那么一堆16位值又有什么用呢?
我知道我可以使用CPU Hack在CSS中累积值并通过数学方式确定哪个--var会接收到更新的值,,因此,我不会担心CSS的具体问题。那么,我们一般如何随时间渗出1D信息呢?
哨兵值(https://en.wikipedia.org/wiki/Sentinel_value )来救驾!
我们使用的测量区域的大小并不一定非要限制在16位,即使我只想限制数据包本身为16位。因此,我们也可以在这个区域内加入一些哨兵数据。css-api-fetch 自带处理值高达 99999
的能力,这远远超过了 65535
(即16位的最大值)。
那我们到底需要知道什么呢?
可能会碰上什么难题?
如果在我们的数据中连续出现两个相同的值,我们需要一个中断来表示这是两个不同的数据帧。我已经决定我们将目标定为512位,所以SVG动画中最多能包含32个16位的数据帧,并其间插入哨兵帧...
如果 CPU 负荷过重,SVG 动画可能会显得跳过某些步骤。这意味着我们需要一种始终知道当前步骤的方法。所以我们不用单一的“数据帧之间”的标志,而是使用类似 CSS nth-* 选择器的 1 基数数据索引作为标志值,使其成为它自己的一个步骤,然后再显示该索引的数据。
哨兵指标 -> 数据...
这让我们知道它何时会循环一遍,可能是当我们遇到哨兵 1
的时候。
但是我们怎么知道它会不会跳到另一个数据帧,导致我们不小心把记录错放了位置?
我们需要让它一直运行直到正确,而确认数据是否正确的最佳方法是校验和(例如:校验和)! 因此,我们需要另一个数据帧,并为此值设置一个哨兵值。
让我们来创建一个校验码算法
我可以使用css-bin-bits
工具来进行数据的异或操作,但这样做比较耗资源,而且在其他地方也用不到,我们不妨找一个用CSS就能简单搞定的替代方案。
从数学的角度来看,如果取一个 16 位的值,除以 256 并向下取整,再取该 16 位值模 256,这样就可以得到高字节和低字节。将这两个 8 位数相加,这样就得到了 9 位。这听起来像是一个合理的校验和方案,回头再看看这个方法怎么样。
我们并不一定要限制在16位范围内来计算校验和,只要最后的校验和是16位就可以了,这样的话我们就直接把最多32个值加起来好了。
我们得小心点,因为跳帧会导致错误的存储写入。所以我们将偶数索引的值多写一次,好有点像有秩序的样子。
这个总和,16 位值
,32 次
,再加上额外的 16 次
,大约是 22 位
。两边进行 11 位
的除和取模运算,回到最初的考虑,再加上,得到一个 12 位
的校验和。
这似乎合理……虽然不能完全排除错误,但SVG要想通过跳过几个步骤来生成相同的校验和,难度很大……无论如何,我们也要将数据长度
一同返回,并将其加入校验和计算之中,只需将其作为计算校验和的最后一步。最大数据长度(即我们想要处理的16位值的数量)仅为32
,所以将长度值加入12位中,不会使总位数超过16位的限制。真好!
剧透:这就是我干的事情,但是CSS大约在21位时开始变得有损,所以我将其拆分,然后按小块执行了同样的算法。服务器端也是这样使用该算法。
从技术上讲,按照我们描述的设置,在动画中的顺序可以是任意的,只要每个标记都告诉你,下一个帧数据应该在哪个索引位置即可,这样的话。
我们将数据长度值
放在响应的最前面,并在其前添加一个哨兵(就像其他数据一样处理,在SVG动画中的值之前添加一个哨兵)。
有 34 个哨兵。SVG viewBox
的高度不能设为 0
,而CSS内部用 0
表示没有数据会更方便,所以我们可以假设我们有 35 个哨兵,其中 0
是特意留空未使用的。
现在所有的数据帧都嵌入到了SVG中,并且它们的值都加上了35。Length
和checksum
数据值也会将35加到viewBox的值上。在表示哨兵的SVG动画中,viewBox
的高度值为1到34(跳过0),每个值都明确表示了SVG动画中的下一帧代表什么。
CSS 一侧,我们只需检查原始测量值的数值是否大于 34,如果是 data
,就从其中减去 35
,如果小于 35
的数值,那么它就是一个 sentinel
。
完成生成 SVG 动画的步骤后,我考虑了如何开始用 CSS 实现这个数据隐藏传输过程。
这里有PHP代码哦!
<?php
header('Content-type: image/svg+xml');
$data = array(
400,
450,
150,
20,
175
);
$datalen = count($data);
$viewBoxXYWidth = '0 0 10 ';
// 为所有值加上35,这样我们可以用0到34作为哨兵。0表示CSS侧的哨兵标志,1到32表示数据帧,33表示数据长度,34表示校验和
$frames = array_map(function ($val, $index) use ($viewBoxXYWidth) {
return ($viewBoxXYWidth . ((string) $index) . '; ' . $viewBoxXYWidth . ((string) ($val + 35)));
}, $data, range(1, $datalen)); // 1到32表示下个帧是该索引(1-based)的值(加上35)
// 无论数组中有多少个元素,'33'表示下一个帧是数据长度,这也会用于校验和
array_unshift($frames, $viewBoxXYWidth . '33; ' . $viewBoxXYWidth . ((string) ($datalen + 35))); // + 35 因为是数据
// unshift确保长度是第一个读取的值,从而可以及时报告进度
$fullsum = 0;
for ($x = 0; $x <= ($datalen - 1); $x++) {
// 加倍奇数项,这样有一定的规律
// 奇数索引(基于0)在CSS侧被视为偶数
$fullsum += ($data[$x] + (($x & 1) * $data[$x]));
}
$checksum = floor($fullsum / 2048) + ($fullsum % 2048) + $datalen + 35; // + 35 因为是数据
// 无论数组中有多少个元素,'34'表示下一个帧是校验和
array_push($frames, $viewBoxXYWidth . '34; ' . $viewBoxXYWidth . $checksum);
$actualNumItems = count($frames) * 2;
$dur = $actualNumItems * 0.33; // 总时间(秒)
$keytimeStep = 1 / ($actualNumItems); // 每帧的时间间隔
$keytimes = implode("; ", array_map(function ($index) use ($keytimeStep) {
return ($index * $keytimeStep);
}, range(0, $actualNumItems - 1)));
$values = implode("; ", $frames);
echo '<svg viewBox="0 0 10 100" preserveAspectRatio="xMinYMin meet" xmlns="http://www.w3.org/2000/svg">
<animate
attributeName="viewBox"
dur="' . $dur . 's"
fill="freeze"
begin="0.1s;"
values="' . $values . '"
keytimes="' . $keytimes . '"
repeatCount="indefinite"
calcMode="discrete"
/>
</svg>';
?>
全屏模式;退出全屏
用CSS实现这一点有几种方法,而且随着[最近的规范更新],未来可能会有更多新方法。
我的第一个方法在概念上最容易实现——为每一条数据都使用一个视图时间轴,并重复同样的步骤。虽然它能工作,但我每向前一步,都感到不满,觉得这样做太糟糕了。如果我继续这样做,:root
上可能会有近40个动画。
所以我睡了
当我醒来时,我躺在床上,凝视着窗外,脸上带着刚醒或冥想后的那种迷糊而清醒的感觉,笑了好一会儿。然后,脑海里突然涌入了很多想法。我翻身拿起笔记本和最近的笔,坐起来,开始写下如何仅用6个CSS动画来实现这个算法的具体步骤。
真的就是在纸上解决的;就是这样实现的。
我起床后,打开电脑,没有继续之前的项目,创建了一个新的CodePen。
我在那里的乱涂鸦中标记了4个html元素,然后在CSS面板中为这4个空类选择器添加了大量注释。它不再放在:root
上了,但我们可以在里面放置任何依赖于它的元素。
直到把纸上的笔记转录并详细化到CodePen里,才添加了任何功能。
完成之后,我看了那些笔记,并开始按照笔记里说的做,一直做到最后实现了最终效果。
我写的是“20”而不是“35”,因为我准备用256位来做测试。
我会深入讲解它是如何工作的。由于view-timeline和timeline-scope,你会看到数据可以像克莱因瓶一样流动:表面在动画中被吸入“洞”里,回到顶部再次流动过表面,通过DOM层不断增大小和复杂度,然后通过“黑洞”回到更高层次的意识(:root)。
它主要表现为垂直的循环(与主要为水平的循环或静态的循环相比)
使用 CSS 提取 512 比特我们稍微调整了笔记,使其更清晰。
256测试题→512最终测试
而且我在里面添加了一个演示节点(presentation节点),这很好,因为在算法运行时,我可以展示内部细节。
但是这里是最终的总结,去除了所有实现和展示的干扰。这正是它如何运作。这里是最简单的总结,它如何运作。
一篇文章可能不适合包含这么多外部细节,但我将逐一拆解每一部分来展示具体实现方式。
主控
在这个结构的最上面有四个时间线值及其动画。我们就把这些放上去吧。
这个功能的关键数据流在于,它使我们能够将嵌套在DOM深处的数据提升到主机(时间线范围)。但这样做效率不高,因此我们需要限制这种操作的频率。每个注册的属性及其动画可以承载一个数据。该数据的值由结构深处某个元素的inline
或block
视图位置决定——这部分我们稍后再详细讨论。
(可以参考之前嵌入的循环示例,以更好地理解数据流动情况)
我们这里要提取的四项数据是,
--xfl-cpu-phase
- 这是一个0到4之间的数字,表示当前正在执行的CPU Hack的阶段。CPU Hack的一帧由4到5个CSS渲染帧构成,每个阶段循环一次,即‘ticks’一次CPU Hack。我将在本文稍后更具体地演示。
--xfl-raw-data
- 这里存放的是SVG在其动画周期中的高度。我们的原始数据。如前所述,如果这个值小于35,那么该离散步骤是一个哨兵值。如果大于34,该离散步骤是我们16位值加上35,这与之前的哨兵值所指示的内容相对应。
--xfl-data-type
- 这表示最新的哨兵值。此值保持不变直到遇到下一个哨兵值。从设置 --xfl-raw-data
到此值之间有一个 CSS 帧的延迟。
--xfl-data-value
- 这是当前数据值,在原始值中减去 35
后的值,或者如果还没到这一步,则为 0
。从设置 --xfl-data-type
到设置此值有 1 个 CSS 帧的延迟。
我也提前将 svg-animation-current-state-reporter
包裹在条件中,只有在进程未完成时才启用并加载动画SVG。这样,在完成进程后,所有内部元素会从内存中移除,同时,沉重的动画SVG也会停止渲染。
关键帧的值从max
值递减到0。我稍后会解释为什么这些设置是反向的——请查找Uno反向卡的图片。
CPU 数据窃取器
然后我们搭建一个[CPU Hack(CPU 漏洞利用技巧)]的基本框架。
CPU Hack 的模板代码只是按照某个变量命名模式来定义 capture
和 hoist
动画,以便创建这两个动画。
如果我们有一个整数 --xfl\\1
,想要让它随时间水平循环,我们会注册它,并设置捕获和提升的动画如下所示:
@keyframes 抓取 {
0%, 100% {
--xfl\\1-捕获: var(--xfl\\1);
}
}
@keyframes 吊起 {
0%, 100% {
--xfl\\1-提升: var(--xfl\\1-捕获, 0);
}
}
全屏 退出全屏
然后完成在 .cpu-exfiltrator
元素中的循环设置,该元素托管了两个 CPU 动画。我先只完成其中一个值的设置。
--xfl\\1: calc(
var(--xfl\\1-hoist, 0) + 1
);
全屏 退出全屏
这是一个棒极了的副作用,可能是因为优化了暂停时设置数值属性的过程,使得这两个动画必须同时处于 running
状态才能静态重置。
最后,因为我们使用了新版本的自动CPU Hack(你不必像在原来的hack中那样通过:hover来循环阶段),我们将之前使用的--xfl-cpu-phase
变量接进来使用(该变量托管在父元素上,我们可以通过样式查询来响应它),并控制动画的播放状态。
我们也输出 --cpu-next-phase
,随后它会被提升回顶部,并利用其视图位置和时间线范围来设置 --xfl-cpu-phase
的下一个阶段的值。
我已经添加了一个额外的步骤,以暂停CPU Hack操作,直到SVG动画测量成功确定下一个的--xfl-data-type
。
@container style(--xfl-cpu-phase: 4) { <!-- 容器使用 --xfl-cpu-phase: 4 样式 -->
animation-play-state: paused, paused; <!-- 动画播放状态设置为暂停 -->
--cpu-next-phase: calc( <!-- --cpu-next-phase 的值由计算决定 -->
min(1, var(--xfl-data-type)) * 4
); <!-- 计算公式为:最小值(1 或 --xfl-data-type)乘以 4 -->
}
切换到全屏 退出全屏
(目前,data-type 始终为 0,因此一旦下一阶段接好,这将已经开始循环 CPU 欺诈攻击。一旦我们有了 data-type 哨兵,它就不会再循环,直到我们故意用 0
哨兵清除它)
之后,我们还会添加一个条件,以防止CPU第1阶段在所有数据到位之前开始。这将确保在数据类型(哨兵)锁定和数据值(原始-35)锁定之间的时间段内,我们希望在此期间保持CPU Hack处于捕获阶段。可以说它处于“准备好准备就绪的状态”,就像Abraham Hicks可能说的那样。
我将先注册所有32个值,包括校验和和长度,这些是我们期望SVG动画上报的。
由于注册 --xfl\\1
到 --xfl\\32
是一大块注册内容,而 CPU 动画也只是些标准动画,我会把这些都挪到破解程序的最下面,今后就无视它们。
自动CPU破解程序
这将下一个 CPU 阶段参数与 --xfl-cpu-phase
值关联起来。
.cpu-phase-cycle-request0r {
display: block;
position: absolute;
overflow: hidden;
background: hotpink;
width: 100px;
height: 10px;
bottom: 100vh;
&::before {
content: "";
position: absolute;
left: 0px;
top: 0px;
height: 100%;
width: calc(25px * var(--cpu-next-phase));
background: lime;
view-timeline: --xfl-cpu-phase inline;
}
}
进入全屏 退出全屏
这里有一些 CSS 框架代码,让元素变成一个可滚动的容器并将其移出屏幕外。重要的是:
view-timeline: --xfl-cpu-phase inline;
这指出了这个伪元素的右边缘在其100px宽的父元素中的位置。将它从左开始作为我们的动画“进度”,动画从0移动到4。25px表示完成了25%,即当25%处于0到4的范围内时,映射到1。
图片来源于一次谷歌搜索,指向 推特 的链接
从技术上讲,动画的变化范围是 4 到 0,测量是从伪元素的右侧边缘开始,向右滚动时进行。这里的伪元素指的是一个宽度为 25px 的元素。当这个宽度为 25px 的伪元素在宽度为 100px 的滚动父元素的右侧 75% 位置时,它的值会映射到 1,而 75% 处于 4 和 0 之间。
这样理解起来会容易一些,不用去想那些复杂的反转数学运算,直接接受从0到4的简单变化,因为动画的最大值是4,(还是不考虑动画是从4开始的这一点)。
让我们也将 CPU 保持在阶段 0 直到数据准备好为止的就绪态。注释在我们示例代码的第 64 行。
数据准备就绪 = 数据类型值 > 0 && 原始帧数据值 - 35 === 数据值;
--xfl-data-is-ready: calc(
min(1, var(--xfl-data-type, 0)) *
(1 - min(1, max(
(var(--xfl-raw-data, 0) - 35) - var(--xfl-data-value, 0),
var(--xfl-data-value, 0) - (var(--xfl-raw-data, 0) - 35)
)))
);
@container style(--xfl-cpu-phase: 0) {
animation-play-state: running, paused;
--cpu-next-phase: var(--xfl-data-is-ready);
}
切换到全屏模式,退出全屏
等等,CSS 里面是什么?
CSS 中有这个吗?
这些现在已经很过时了,如果我现在来做,方法会有所不同,这些代码是在clamp()
还未流行之前写的。但每次需要复制粘贴一些数字比较器时,我仍会打开这个旧的CodePen。可以更新这些内容,并加以解释,不过先给你这个链接:https://codepen.io/propjockey/pen/YzZMNaz
一起来学习 SVG 动画吧
这与CPU Exfiltrator
部分极其相似,因为采用的是相同的技术,即将数据从这里往上移动并通过DOM测量(范围)。
我们将测量并报告最初设定的基础元素的最后三个数值。
在 ::before
伪元素中,我们将渲染 SVG,并使用 block
视图位置设置 --xfl-raw-data
,这表示动画 SVG 的高度测量值(即动画 SVG 的高度)。(记得,我们会将宽度固定为 10px
)
在 ::after
上,我们将 --xfl-data-type
参数的哨兵值从 0 到 34 行内设置,并将 --xfl-data-value
参数的 16 位值块内设置。
父元素需要足够宽以至少渲染SVG 10px,并准确提供0到34的哨点值测量。
父母也需要能够测量16位数值(即最大为+35)。因为我们在第一步设定了一个最大值为10万(100k),所以我们就会使用这个值,尽管它比我们需要的大约多出30%。
把它移到屏幕左上角,避免出现滚动条。
所以,
.svg-animation-current-state-reporter
拿到了
position: absolute;
background: rgba(255, 0, 0, 0.5);
width: 34px;
/* --xfl-data-type 关键帧是从 34 到 0,因为最大数据类型是 34 */
height: calc(var(--xfl-max) * 1px);
bottom: calc(var(--xfl-max) * 1px + 100vh);
left: calc(-100vw - 100px);
overflow: hidden;
font-size: 0px!important;
line-height: 0px!important;
margin: 0px;
padding: 0px;
进入全屏,退出全屏
之前就
&::before {
content: url('http://css-api.propjockey.io/api.svg.php?');
position: absolute;
background: lime;
left: 0px;
top: 0px;
width: 10px!important;
--height: 2135px;
font-size: 0px!important;
line-height: 0px!important;
view-timeline: --xfl-raw-data block;
}
点击全屏来进入,然后点击退出来退出全屏
并且 ::after
position: absolute;
width: 1px;
height: 1px;
left: calc(
var(--TODO_SENTINEL_VALUE, 0) * 1px - 1px
);
top: calc(
var(--TODO_DATA_VALUE, 0) * 1px - 1px
);
background: black;
view-timeline: --xfl-data-type inline, --xfl-data-value block;
进入全屏 退出全屏
这里这些after值的存储位置是其父级滚动容器内1px正方形伪元素的位置。由于这个伪元素本身是1x1大小,我们在左边和上边的计算中各减去1px,这样当对应值为0时,它会报告为0。
这和之前差不多。
正如注释中提到的,我们在确定这些值时会遇到几个复杂情况。
/* 这里有4个阶段
// 1) CPU 告诉我们重置为0
// 2) CPU 处于第0阶段(捕获运行),直到所有阶段完成
// a. 如果 SVG 动画帧是 type 类型,则设置 type,否则使用上一个值
// b. 如果 SVG 动画帧是 data 类型,则设置 data,否则使用上一个值
// 4) 当 CPU 执行时,我们需要保持上一个值并忽略 SVG 动画
*/
全屏,退出全屏
理解这一点的关键是,任何比较值都设为0或1。如果是真就设为1,假就设为0。然后乘以某个值。如果是假,结果还是0,否则结果就是那个值。
Ana Tudor 可以在这里看看她如何详细解释这个想法是如何运作的
然后,如果我们进行两次比较,对于第二个值采用不同的或相反的比较方式,并将结果相加(确保最多只有一个比较器设置为1),那么这样的两个操作相当于逻辑中的“否则如果”。
如果还没有准备好,就用旧值;如果已经准备好,用新值。
我们如何在SVG动画的每个独立步骤中保持这个特定值,即使类型已经报告过了。
这里的 CSS 代码从第 191 行起,在我们下面添加的一大块 --xfl\\...
属性注册块的上方:
@property --xfl\\1 { syntax: "<integer>"; initial-value: 0; inherits: true; }
等等,其中有一些额外的注释:
设置 CSS --var 的特定值
我们刚才提到的逻辑正好与我们用来处理所有类似--xfl\\1
、--xfl\\2
、--xfl\\32
值的概念相同。
--xfl-set\\1: calc(
/* 计算 (1 - min(1, max(1 - var(--xfl-data-type, 0), var(--xfl-data-type, 0) - 1))) * var(--xfl-data-is-ready) */
(1 - min(1, max(
1 - var(--xfl-data-type, 0),
var(--xfl-data-type, 0) - 1
))) * var(--xfl-data-is-ready)
);
--xfl\\1: calc(
/* 计算 var(--xfl-set\\1) * var(--xfl-data-value, 0) + (1 - var(--xfl-set\\1)) * var(--xfl\\1-hoist, 0) */
var(--xfl-set\\1) * var(--xfl-data-value, 0) +
(1 - var(--xfl-set\\1)) * var(--xfl\\1-hoist, 0)
);
进入全屏模式 退出全屏
这可以读作 --xfl-set\\1
,表示如果 --xfl-data-type
大于或等于 1 使用 --xfl-data-is-ready
,这意味着 否则为0。
--xfl-data-is-ready
之前被设为一个标志,使我们在 phase 0 阶段保持,直到切换到 phase 1 的时候。
也就是说,我们的条件是 &&
逻辑。两个标志位都必须为 1 才能通过检查。
然后你继续读取 --xfl\\1
,如果 --xfl-set\\1
,则使用 --xfl-data-value
(当前的 SVG 动画值),若不 --xfl-set\\1
,则使用 --xfl\\1-hoist
(CPU 操作之前存储的 --xfl\1-hoist 值)。
这是非常重复的,几乎描述了这个过程的大部分。
最后的步骤是执行基本的 calc()
和 mod()
运算来构建校验和(checksum),正如前面提到的那样,然后将计算出的校验和与 SVG 动画中嵌入的校验和进行比较,如果两者相等,就添加到 CPU 漏洞利用程序中,这样我们就能知道何时完成。这一切都是一样的步骤。
现在是时候了。 嘿嘿 :)
介绍:利用 CSS 动画的 SVG 数据渗出攻击因为我想要展示这次破解过程中的每一个步骤或细节,每个元素一个值,因此,这种展示方式显得过于繁琐。HTML代码超过2000行,CSS代码超过400行。并且我还使用了css-bin-bits将每个寄存器转换为二进制等。
(点击代码框右下角的“重新运行”按钮以实时查看。)
不支持JavaScript。
打开通讯录 👽
如果你有兴趣,随时都可以联系我,觉得这个很酷并且想了解更多!我总是很乐意回答你的问题。
PropJockey.io | CodePen | DEV | GitHub | Mastodon |
---|---|---|---|---|
共同學習,寫下你的評論
評論加載中...
作者其他優質文章