为什么在JavaScript中这个表达式被评估为“a”?

时间:2017-05-28 15:32:35

标签: javascript types obfuscation deobfuscation

我抓住了一些混淆的JavaScript代码。我试图理解它,并且这样做,我在控制台中输入了它的一部分。我无法理解为什么

> ((!!+[]+"")[+!![]])
< "a"

为什么JavaScript中((!!+[]+"")[+!![]])等于"a"?是否还有其他一些代码片段可以获取其他字母?

我想这与自动投射有关。

5 个答案:

答案 0 :(得分:7)

( ( !!+[] + "" ) [ +!![] ] )
( (  !!0  + "" ) [ +true ] )
( ( false + "" ) [ +true ] )
( (   "false"  ) [   1   ] )
(         "false"[1]       )
(            "a"           ) 
  

是否还有其他一些代码片段可以获取其他字母?

您可以使用相同的概念来获取“true”,“false”,“undefined”,“NaN”等所有字母......

答案 1 :(得分:4)

您应该在JavaScript中使用运算符优先级和类型转换:

lambda function

至少,

!!+[] // Is falsey. this is same for !!+0 or !!+""
false + "" // Is "false". as 5+"" is "5".

![] // Is falsey.
!false // Is true
+true //  Is equal to 1. +[] = 0, +false = 0

答案 2 :(得分:4)

让我们使用控制台来得到我们的答案,假设我们不知道这意味着什么,输入

控制台中的

[] + ""输出""

只需添加(!!+[])即可返回布尔false。如果您将布尔false追加到"",则会因类型强制而获得字符串false

正如所料,输入(!!+[]+"")输出"false"到控制台。

继续,在JavaScript中,您可以将字符串视为字符数组,并且可以使用数组表示法访问它们的字符。

因此,在((!!+[]+"")[+!![]])中,您可以移除最外面的括号以使其看起来更简单。现在我们有(!!+[]+"")[+!![]]()中的第一部分返回字符串"false"[]中的下一部分访问字符串"false"的字符。您现在可以打赌+!![]"false"[1]等于"a"后以某种方式返回1.

现在让我们了解+!![]如何等于1

[]是一个空数组,您可以将其视为0在JavaScript中为true(因为JavaScript中的“任何'真实'都是true }“),所以![]是false!![]true

现在我们留下+true,这只是将true转换为1的数字的简写。现在,您可以看到+!![]如何评估1并且您理解(希望)该混淆的代码如何工作!

答案 3 :(得分:3)

理解这一点的关键是要知道JavaScript对它看到的evalute表达式进行了隐式类型转换。换句话说,虽然您可能不知道向字符串添加数字意味着什么,但JavaScript会猜测而不是发出错误。它与您在C ++中获得的内容相反,在这种情况下会给出明确的错误。

例如,无论+x实际是什么,x始终会计算为数字。 !x也是如此。因此,对于你的表达:

// A: !!+[]+"" which is evaluated like !(!(+[]))+""
+[]       === 0
!0        === true
!true     === false
false+''  === 'false'

// B: +!![] which is evaluated like +(!(![]))
![]       === false
!false    === true
+true     === 1

我们得到的A[B]只是'false'[1] === 'a'

您可以在MDN了解有关implicit type conversionsoperator precedence的详情。

隐式类型转换是经验丰富的JavaScript程序员在比较值时更喜欢使用===而不是==的原因。

答案 4 :(得分:2)

以下详细介绍了正在发生的事情:

( !! +[] + "" ) [ +!![] ]
//   ^^^ 

+[]数组文字上的一元加号运算,相当于Number([]),结果为0See this为什么评估为0

( !! 0 + "" ) [ +!![] ]
//^^^^

!!0相当于!!Boolean(0)),其评估为false,因为0是假值。

( false + "" ) [ +!![] ]
//^^^^^^^^^^^

false+""是简单的字符串连接,因此评估为"false"

"false" [ +!![] ]
//         ^^^^ 

!![]等同于!!Boolean([]),因为对象的布尔转换返回true。评估结果为true

"false" [ +true ]
//        ^^^^^

+true相当于Number(true),其评估为1

"false" [ 1 ]

最后是a

这里的关键点是Javascript在计算表达式时进行隐式类型转换或类型强制。要了解有关类型强制的更多信息,我建议使用Axel Rauschmayer博士撰写的这篇优秀资源

Type Coercion