A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© xiaofeifei112 中级黑马   /  2018-7-26 10:28  /  1720 人查看  /  3 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 xiaofeifei112 于 2018-7-26 10:36 编辑

什么是jsfuck?

  想象一下自己第一次见到代码的样子,满屏的奇怪字符?WTF?而当我看到jsfuck的时候,再次体会到了这种感觉。请看下面的代码:
[JavaScript] 纯文本查看 复制代码
[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+(![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]]+[+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]])()

WTF???(黑人问号脸)

  没错!这确实是一串js代码,你可以直接放到控制台去执行,最后执行的结果是alert(1)。JS就是这么一门神奇的语言。本着对知识的渴求与对未知事物的探索精神(雾),下面我们就一起来研究下jsfuck的原理。

   在讲jsfuck之前,先要说起一个js的经典面试题:[]==![]

  这道题是考验js基础的,利用的是js的一些基本原理——类型转换。类型转换大家都了解,比如简单的 ‘a’+1结果就是’a1’,在这个计算过程中1被隐式转换成string类型,这道面试题也是这个原理。Js语法中’==’两边如果不是同一类型则会进行类型转换。

  但是相信很多接触过前端的同事见到这个题目时候的第一反应,是这个表达式的结果是false,然而拿到控制台执行之后却发现是true,这让很多人十分不解。特别是当我们在控制台打印代码的时候,会出现一些令人费解的事情。如:
[JavaScript] 纯文本查看 复制代码
Boolean([])   //true
 
Boolean(![])  //false
  其实上述代码,我们进行了强制转换,在js中在把对象做布尔值转换的时候,会把所有对象都转换为true(包括创建的new Boolean(false)对象转换之后也是true,具体可参考犀牛书3.8.3)。而相等运算符却不是这么计算的,在相等运算符中,如果运算符两边的值有一个是布尔类型,则会把true转换成1,false则转换为0。而在这道题目中![]的结果肯定是布尔值false,则会转换为0。

[]==0
  这时候解释起来就简单了很多,相等运算符如果有一边是数字,而另一边是对象,则会把对象转换成数字。而空的数组对象转换成数字是0(犀牛书3.8)那么结果便是:

0==0  //true
  讲了这么多,终于可以进入正题了。之所以开篇讲这么一个题目,是为了更好理解jsfuck的原理。在官网上(直接百度jsfuck就行),我们能看到官方给出的jsfuck的Basics,下面我们来逐条分析。(水平有限,如果有发现错误可以指出,大家一起研究)



false => ![]  

//非运算符会把[]的布尔值取反




true => !![]  

//再取反则是true



undefined => [][[]]
//这一个就比较复杂,在js中数组的索引可以为负数和非整数,而在这种情况下会将索引转换成字符串,作为对象的属性访问,我们知道[]转换为字符串为空字符串,则上面等价于:[][‘’]。然而数组对象并没有名为’’的属性,在js中访问一个对象并不存在的属性时,会给出undefined



NaN => +[![]]  

//这里利用了+运算符的特性,这里+不是加号运算符(姑且这么叫)而是一元运算符的一种,一元加法,用于把操作数转换为数字或者NaN并返回这个数字。上式等价于+[false],而根据类型转换的规则我们知道,这样得到的结果为NaN



0 => +[]  

//根据类型转换规则,[]转换为数字为0



1 => +!+[]  

//本式为上面的变式,根据运算符的优先级,先执行+[]为0,再转换成布尔取反为true,true转换为数字为1



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

//中间一个+为加法运算符优先级比较低,等价于true+true,值为2



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

//可拆分成[+!+[]]加[+[]],左边为[1],右边为[0],+作为连接字符串运算符,而根据数组转换成字符串我们可以知道上面等价于‘1’+‘0’,得到的是字符串‘10’



Array => []  

//[]就是数组对象的事例,用于获取字符串’Array’(暂时没有弄清楚作者的意思,这个Array对象的获取相当复杂,利用了js对象的原型链,其代码非常之繁琐,我会在最后一篇人肉翻译jsfuck代码中详细讲述。如果有大神了解原作者在此只放一个‘[]’的原因,请告诉我,我会对博客进行更改,并附上大神的名字提名感谢)



Number => +[]  

//与上式相同



String => []+[]  

//与上式相同



Boolean => ![]

//与上式相同



Function => []["filter"]

//与上式相同



eval => []["filter"]["constructor"]( CODE )()  

//这里比较复杂,我们先来看前半部分[]["filter"]["constructor"],这一部分可以看到拿的是一个数组对象的‘filter’属性下面的‘constructor’属性,‘filter’属性是数组的一个方法,但在这里并没有用到该方法,你把它替换成别的方法也可以照常运行(例如‘map’),关键是下面这一步,filter的constructor属性,我们知道在js中任何方法都可以看做是Function对象的一个实例,而Function就作为所有函数的构造函数。这里拿到的就是函数的Function()构造函数。而Function()构造函数的最后一个参数会作为函数体执行。因此这段语句会执行‘CODE里的内容’。



window => []["filter"]["constructor"]("return this")()

//与上式相同,拿到的是函数的构造函数,第一个括号内便是函数体。并且Fuction()构造函数所创建的函数并不使用词法作用域(划重点!),他是直接执行在顶层函数中的,也就是全局作用域,因此this返回window。

参考:
https://blog.csdn.net/qq_36539075/article/details/79946099

3 个回复

正序浏览
回复 使用道具 举报
回复 使用道具 举报
奈斯,很赞
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马