Get 一种可以用来装逼的 JavaScript 编码风格

摘要:JavaScript 是弱类型的编程语言,我们在写代码的时候充斥着大量的类型转换,在我之前的文章 【JS进阶】你真的掌握变量和类型了吗 中有过相关的介绍,其实上面代码的核心就是用到了下面三个类型转换:

大家好,我是ConardLi。

上周有个朋友在群里发了一段代码,复制到浏览器发现居然是可以运行的:

[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]][([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[+!+[]+[!+[]+!+[]+!+[]]]+([]+[])[(![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(!![]+[])[+[]]+([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]()[+!+[]+[!+[]+!+[]]]+([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+!+[]]+([][[]]+[])[!+[]+!+[]]+(![]+[])[!+[]+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+([]+[])[(![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(!![]+[])[+[]]+([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]()[+!+[]+[!+[]+!+[]]]+([+[]]+![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[!+[]+!+[]+[+[]]])()

研究了一下,挺有意思的,只用 []()!+ 这六个字符就可以实现一段可执行的   JavaScipt 代码,这是咋实现的呢?

类型转换

JavaScript 是弱类型的编程语言,我们在写代码的时候充斥着大量的类型转换,在我之前的文章 【JS进阶】你真的掌握变量和类型了吗 中有过相关的介绍:


其实上面代码的核心就是用到了下面三个类型转换:

  • ! 后面跟的字符会被转换成布尔值
  • + 后面跟的字符会被转换成数值
  • +[] 前面的字符会被转换成字符串

通过上面的方法,我们可以尝试做一些简单的转换:

false       =>  ![]

true => !![]

undefined => [][[]]

NaN => +[![]]

数字

怎么用这几个符号来表示数字呢?最简单的 0 :

+[] === 0

这个很好理解,根据上面表格中的总结我们知道,空数组转换成数字是 0,我们只需要在 [] 前面加上 + 让它转换成数字就可以得到 0 。

那么 1 可以怎么得到呢?

+!+[] === 1

因为 +[] 转换成了 0 , 0 是一个假值,那么 !+[] 就是一个真值,把一个真值转换成数字就会得到 1 ,所以我们只需要在   !+[] 前面加上 + 就可以得到 1。

那么 2 就简单了,让两个 1 相加就可以了:

!+[]+!+[] === 2

以此类推, 3456789 都可以这样表示。

如果是一个非常大的数呢?要一直相加代码就太复杂了,我们可以用另一种方法,先转换成字符串再转换成数字:

[+!+[]] === [1]

[+[]]] === [0]

[+!+[]] + [+[]]] === [1]+[0] === '10'

+[[+!+[]]+[+[]]] === 10

这样,任意一个大数都可以表示了 ...

字母

字母怎么得到呢?

首先我们尝试得到一个 undefined :

[][0] ===  undefined   //获取一个空数组的第0个元素
[][ +[] ] === undefined //用 +[] 表示0

下面我们利用一下第三条法则: +[]前面的字符会被转换成字符串

[][+[]] +[] === 'undefined' 

这样我们就得到了 'undefined' 这样一个字符串,也就是可以拿到 u n d e f i 这其中任意一个字符,比如我们要拿到字符 u :

  "undefined"          [  0]  === "u"
[ "undefined" ][ 0][ 0] === "u"
[ undefined +[] ][+[]][+[]] === "u"
[ [][[]] +[] ][+[]][+[]] === "u"

怎么拿到字符 a 呢,同理,我们可以从 false 里面获取:

"false"[1] === 'a'
"false"[+!![]] === 'a'
(false +[]) [+!![]] === 'a'
(![] +[]) [+!![]] === 'a'

方法

首先,我们把字符拼接起来可以得到一个方法名:

// 拿到想要的字母
"undefined"[4] // "f"
"undefined"[5] // "i"
"undefined"[6] // "n"
"undefined"[3] // "d"

// 拼接字母
"f"+"i"+"n"+"d" // "find"

然后我们通过 [] 调用方法:

[]["f"+"i"+"n"+"d"] 
[]["find"]
[] .find

调用一个空数组的 find 方法有啥用呢?

没啥用 ... 我们尝试把这个方法再转换成字符串:

[]["find"] +[]  === "function find() { [native code] }"

太妙了,我们又有很多新的字符( a c d e f i n o t u v )可以用了 ...

根据已有的字符,我们可以拼接成一个 constructor 字符串,也就是构造方法,当我们尝试对一些原始值读取它的 constructor 时,就可以拿到它的构造器了:

0       ["constructor"] // Number
"" ["constructor"] // String
[] ["constructor"] // Array
false ["constructor"] // Boolean

然后我们把构造器再转换成字符串:

0["constructor"]+[] // "function Number() { ... }"

我们又有了更多的新字符: m b S g B A F ...

用这样的方法,我们可以先把一些关键字或表达式转换成字符串,再去获取其中的字母,就可以表示所有的字母了...

特殊字符

字符串的 fontcolor() 方法可以用于按照指定的颜色来显示字符串,实际上它就是包了一个 HTML Font 标签:


我们通过一个空字符串去访问 fontcolor 方法,就得到了下面的字符串:

""["fontcolor"]()   // "<font color="undefined"></font>"

这样,这些特殊字符 < > = " / 就可以用了 ...

怎么执行任意代码?

通过前面的方法,我们基本可以表示任意字符串了,怎么怎么可以把任意字符串表示成任意可执行的代码呢?

答案是 Function 构造函数,我们可以通过 Function 构造函数来创建一个新的 Function 对象,也就是一个新的函数:


然后我们在后面加上 () 就可以执行这个函数:

Function("alert(1)")()

那么怎么获取到 Function 构造函数呢?

在前面的章节我们提到,通过 []["find"] 可以拿到数组的 find 方法,那么 find 方法的构造函数其实就是   Function 了,所以:

[]["find"]["constructor"] === Function

我们可以像这样执行一个字符串代码:

const str = "alert(1)";
[]["find"]["constructor"](str)()

尝试一下

下面我们来尝试把上面的代码全部通过 []()!+ 表示:

表示 f:

(![]+[])[+[]]

表示 find:

(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+([][[]]+[])[!+[]+!+[]]

表示 constructor:

([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]

表示 alert:

(![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]

表示 []["find"]["constructor"]("alert(1)")() :

[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]][([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[+!+[]+[!+[]+!+[]+!+[]]]+[+!+[]]+([+[]]+![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[!+[]+!+[]+[+[]]])()

通过这个网站可以在线转换任意代码: http://www.jsfuck.com/

好了,去装逼吧 ...

来源:code秘密花园

本文内容仅供个人学习、研究或参考使用,不构成任何形式的决策建议、专业指导或法律依据。未经授权,禁止任何单位或个人以商业售卖、虚假宣传、侵权传播等非学习研究目的使用本文内容。如需分享或转载,请保留原文来源信息,不得篡改、删减内容或侵犯相关权益。感谢您的理解与支持!

链接: https://shenqiku.cn/article/FLY_11910