也是Java代码的图片



图像通常存储为二进制文件,而Javascript文件本质上是纯文本。两种类型的文件都必须遵循自己的规则:图像具有特定的文件格式,该格式以特定方式对数据进行编码。为了使Javascript文件可执行,它们必须遵循特定的语法。我想知道:是否有可能创建一个同样有效的Javascript语法的图像文件以便执行?



在继续阅读之前,我强烈建议 您将实验结果与以下代码沙箱一起使用:



https : //codesandbox.io/s/executable-gif-8yq0j?file=/index.html



如果您想查看图像并自己进行探索,则你可以在这里下载:



https://executable-gif.glitch.me/image.gif



选择正确的图片类型



不幸的是,图像包含大量二进制数据,当将它们解释为Javascript时,将引发错误。所以我首先想到的是:如果我只是将所有图像数据放在一个大注释中,该怎么办?



/*ALL OF THE BINARY IMAGE DATA*/


这将是有效的Javascript文件。但是,图像文件必须以特定的字节序列开头,即特定于图像格式的文件头。例如,PNG文件必须始终以字节序列89 50 4E 47 0D 0A 1A 0A开头。如果图像以开头/*,则该文件不再是图像文件。



这个文件头使我想到了以下想法:如果我们使用以下字节序列作为变量名,并为其分配长字符串值,该怎么办:



PNG=`ALL OF THE BINARY IMAGE DATA`;


我们使用模板字符串而不是常规字符串,"或者'因为二进制数据可能包含换行符,并且模板字符串对此效果更好。



不幸的是,图像文件头中的大多数字节序列都包含不可打印的字符,这些变量无法在变量名中使用。但是,我们可以使用一种格式:GIF。GIF标头块看起来像47 49 46 38 39 61,可以方便地转换为ASCII字符串GIF89a-绝对有效的变量名!



选择合适的图像尺寸



现在,我们找到了以有效变量名开头的图像格式,我们需要添加等号和反引号。因此,文件的下四个字节将是:3D 09 60 04





图像的第一字节采用



GIF格式,标头之后的四个字节定义了图像的尺寸。我们需要在其中放入3D(等号)和60(反引号,打开一条线)。 GIF使用很少的字节序排序,因此第二个和第四个字符对图像大小有很大的影响。它们应尽可能小,以使图像的宽度和高度不会成千上万。因此,我们需要存储大3D字节60个最低有效字节。



图片宽度的第二个字节必须是有效的空格,因为它将是等号和行首之间的空格GIF89a= `...... 还应记住,十六进制字符代码应尽可能小,否则图像将很大。



最小的空白字符是09(水平制表符)。它为我们提供了3D 09图像的宽度,即小端格式为2365;比我想要的宽一点,但仍然完全可以接受。



对于第二个高度字节,可以选择一个具有良好长宽比的值。我选择04,它使我们的高度为60 04或1120像素。



将脚本放入文件中



到目前为止,我们的可执行GIF几乎不执行任何操作。它只是将一个GIF89a长字符串分配给全局变量。我们希望发生一些有趣的事情! GIF中的大多数数据都用于对图像进行编码,因此,如果我们尝试在其中插入Javascript,则图像可能会严重失真。但是由于某种原因,GIF格式包含称为Comment Extension的内容。这是一个存储GIF解码器无法解释的元数据的地方-这是我们Javascript逻辑的理想之地。



该注释扩展名可在GIF颜色图表之后找到。由于我们可以在其中放置任何内容,因此我们可以轻松关闭GIF89a,添加所有Javascript,然后启动多行注释块,以使其余图像不会影响Javascript解析器。



最终,我们的文件可能如下所示:



GIF89a= ` BINARY COLOR TABLE DATA ... COMMENT BLOCK:

`;alert("Javascript!");/*

REST OF THE IMAGE */


但是,有一个小的限制:尽管注释块本身可以是任意大小,但它由几个子块组成,并且每个子块的最大大小为255。子块之间有一个字节,用于确定下一个子块的长度。因此,要在此处适应大型脚本,需要将其分成小片段,如下所示:



alert('Javascript');/*0x4A*/console.log('another subblock');/*0x1F*/...


注释中的十六进制代码是确定下一个子块大小的字节。它们不特定于Javascript,但对于GIF文件格式是必需的。为了避免干扰其余的代码,需要将它们放在注释中。我编写了一个处理脚本片段并将其添加到图像文件的小脚本:https :



//gist.github.com/SebastianStamm/c2433819cb9e2e5af84df0904aa43cb8



清理二进制数据



现在我们有了基本的结构,我们需要确保二进制图像数据不会弄乱代码的语法。如上一节所述,该文件分为三部分:第一部分是对GIF89a变量的赋值,第二部分是Javascript代码,第三部分是多行注释。



让我们看一下有关为变量分配值的第一部分:



GIF89a= ` BINARY DATA `;


如果二进制数据包含一个字符`多个字符的组合${,那么我们就会遇到问题,因为它们将终止模式字符串或创建无效的表达式。修复非常简单:只需更改二进制数据即可!例如,可以使用字符(十六进制代码61来代替字符`(十六进制代码60)。由于文件的此部分包含调色板,因此这将导致某些颜色的细微变化,例如,使用颜色代替不太可能有人会注意到差异。a#286148#286048



处理失真



在Javascript代码的末尾,我们打开了多行注释,以使二进制图像数据不会影响Javascript解析:



alert("Script done");/*BINARY IMAGE DATA ...


如果图像数据包含一系列字符*/,则注释将过早结束,从而使Javascript文件无效。再次在这里,我们可以手动更改两个字符之一,以使它们不结束注释。但是,由于我们现在处于编码图像的区域中,因此结果将是损坏的图像,例如:





图像损坏



在最坏的情况下,图像可能根本无法显示。通过仔细选择要反转的位,我可以使失真最小化。幸运的是,仅有少数几种破坏性组合的情况*/例如,在“有效的Javascript文件”行的底部,完成的图像中仍然存在轻微的失真,但是总体而言,我对结果感到满意。



完成文件



我们剩下的最后一项操作-文件完成。该文件必须以00 3B字节结尾,因此我们需要尽早结束注释。由于这是文件的末尾,任何潜在的损害都是微妙的,所以我刚刚结束了块注释,并添加了一行注释,这样文件末尾就不会引起解析问题:



/* BINARY DATA*/// 00 3B


说服浏览器执行图像



现在,毕竟,我们终于有了一个既是图像又是有效的Javascript文件的文件。但是,我们需要克服最后一个障碍:如果将图像上传到服务器并尝试在标记中使用它script,那么很可能会遇到类似的错误:



拒绝从' http:// localhost:8080 / image.gif '执行脚本,因为其MIME类型('image / gif')是不可执行的。[因为其MIME类型不可执行,所以拒绝从' http://本地主机:8080 / image.gif '执行脚本。]


也就是说,浏览器正确地说:“这是一张图片,我不会执行它!” 在大多数情况下,这是非常合适的。但是我们仍然想要实现它。解决方案是根本不告诉浏览器这是图像。为此,我编写了一个小型服务器,该服务器提供没有标题信息的图像。



如果没有标头中的MIME类型信息,浏览器将不知道它是一个图像,并且恰好在上下文中做得最好:将其呈现为标记中的图像,<img>或将其作为Javascript标记中执行<script>



但是...这是为什么呢?



我自己还没弄清楚。这样的任务对大脑来说是一个很好的热身,但是如果您能想到一个确实有用的情况,请告诉我!






广告



开发人员服务器与我们公司的虚拟服务器有关。

长期以来,我们一直在使用英特尔独家提供的快速服务器驱动器,并没有节省硬件-仅提供品牌设备和市场上提供服务的最现代解决方案。






All Articles