文档章节

JavaScript学习:JSFuck代码阅读笔记

北风其凉
 北风其凉
发布于 2016/02/06 21:42
字数 1181
阅读 792
收藏 11

JSFuck源码地址(GitHub):https://github.com/aemkei/jsfuck

JSFuck在OSC上的介绍页面:http://www.oschina.net/p/jsfuck

JSFuck可以将JavaScript代码进行转换,转换后的代码只使用6个字符([,],(,),!,+),实现的功能和转换前代码是一样的。出于好奇和学习的目的,我研究了一下JSFuck的源码。

在网站 http://www.jsfuck.com/ 中有一个例子,将JavaScript语句 alert(1) 转换为只由六种字符的版本:

将这段代码放到HTML文件的script标签下,就可以运行了:

<html>
    <head>
        <title>happy new year</title>
    </head>
    <body>
    <script>
 [][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+(![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]]+[+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]])()
    </script>
    </body>
</html>

不过,我想了解的是,为什么这段代码会起作用。研究后才发现,这段代码等价于另一段代码:

[]["filter"]["constructor"]("return eval")()("alert(1)")

在这段代码中,alert(1)是我们要转换的JavaScript源码,这段代码的意思是执行JavaScript代码alert(1)。这段代码是由四个字符串和字符[、]、(、)构成的。也就是说,我们只要能把字符串中的每一个字符,都用[,],(,),!,+这六个字符表示出来,那么我们就完全可以将任何一段JavaScript代码,找到仅用这六个字符表示的等价形式。

那么,我们来看一下各个字符的等价形式:(如果用console.log输出右边的部分,则会返回左边的字符,0-9这10个字符外面又套了一层[],这样做是为了保证在之后用+运算符进行拼接时不被系统识别为加法运算)

'0':'[+[]]'
'1':'[+!+[]]'
'2':'[!+[]+!+[]]'
'3':'[!+[]+!+[]+!+[]]'
'4':'[!+[]+!+[]+!+[]+!+[]]'
'5':'[!+[]+!+[]+!+[]+!+[]+!+[]]'
'6':'[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]'
'7':'[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]'
'8':'[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]'
'9':'[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]'
'a':'(false+"")[1]'
'b':'(Function("return{}")()+"")[2]'
'c':'([]["filter"]+"")[3]'
'd':'(undefined+"")[2]'
'e':'(true+"")[3]'
'f':'(false+"")[0]'
'g':'(false+[0]+String)[20]'
'h':'(+(101))["toString"](21)[1]'
'i':'([false]+undefined)[10]'
'j':'(Function("return{}")()+"")[10]'
'k':'(+(20))["toString"](21)'
'l':'(false+"")[2]'
'm':'(Number+"")[11]'
'n':'(undefined+"")[1]'
'o':'(true+[]["filter"])[10]'
'p':'(+(211))["toString"](31)[1]'
'q':'(+(212))["toString"](31)[1]'
'r':'(true+"")[1]'
's':'(false+"")[3]'
't':'(true+"")[0]'
'u':'(undefined+"")[0]'
'v':'(+(31))["toString"](32)'
'w':'(+(32))["toString"](33)'
'x':'(+(101))["toString"](34)[1]'
'y':'(NaN+[Infinity])[10]'
'z':'(+(35))["toString"](36)'
'A':'(+[]+Array)[10]'
'B':'(+[]+Boolean)[10]'
'C':'Function("return escape")()(("")["italics"]())[2]'
'D':'Function("return escape")()([]["filter"])["slice"]("-1")'
'E':'(RegExp+"")[12]'
'F':'(+[]+Function)[10]'
'G':'(false+Function("return Date")()())[30]'
'H':'Function("return unescape")()("%"+(48)+"")'
'I':'(Infinity+"")[0]'
'J':'Function("return unescape")()("%"+(4)+"a")'
'K':'Function("return unescape")()("%"+(4)+"b")'
'L':'Function("return unescape")()("%"+(4)+"c")'
'M':'(true+Function("return Date")()())[30]'
'N':'(NaN+"")[0]'
'O':'(NaN+Function("return{}")())[11]'
'P':'Function("return unescape")()("%"+(50)+"")'
'Q':'Function("return unescape")()("%"+(51)+"")'
'R':'(+[]+RegExp)[10]'
'S':'(+[]+String)[10]'
'T':'(NaN+Function("return Date")()())[30]'
'U':'(NaN+Function("return{}")()["toString"]["call"]())[11]'
'V':'Function("return unescape")()("%"+(56)+"")'
'W':'Function("return unescape")()("%"+(57)+"")'
'X':'Function("return unescape")()("%"+(58)+"")'
'Y':'Function("return unescape")()("%"+(59)+"")'
'Z':'Function("return unescape")()("%"+(5)+"a")'
' ':'(NaN+[]["filter"])[11]'
'!':'Function("return unescape")()("%"+(21)+"")'
'"':'("")["fontcolor"]()[12]'
'#':'Function("return unescape")()("%"+(23)+"")'
'$':'Function("return unescape")()("%"+(24)+"")'
'%':'Function("return escape")()([]["filter"])[20]'
'&':'("")["link"](0+")[10]'
''':'Function("return unescape")()("%"+(27)+"")'
'(':'(false+[]["filter"])[20]'
')':'(true+[]["filter"])[20]'
'*':'Function("return unescape")()("%"+(2)+"a")'
'+':'(+(+!+[]+(!+[]+[])[!+[]+!+[]+!+[]]+[+!+[]]+[+[]]+[+[]])+[])[2]'
',':'([]["slice"]["call"](false+"")+"")[1]'
'-':'(+(.+[0000000001])+"")[2]'
'.':'(+(+!+[]+[+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+[!+[]+!+[]]+[+[]])+[])[+!+[]]'
'/':'(false+[0])["italics"]()[10]'
':':'(RegExp()+"")[3]'
';':'("")["link"](")[14]'
'<':'("")["italics"]()[0]'
'=':'("")["fontcolor"]()[11]'
'>':'("")["italics"]()[2]'
'?':'(RegExp()+"")[2]'
'@':'Function("return unescape")()("%"+(40)+"")'
'[':'(Function("return{}")()+"")[0]'
'\':'Function("return unescape")()("%"+(5)+"c")'
']':'(Function("return{}")()+"")["slice"]("-1")'
'^':'Function("return unescape")()("%"+(5)+"e")'
'_':'Function("return unescape")()("%"+(5)+"f")'
'`':'Function("return unescape")()("%"+(60)+"")'
'{':'(NaN+[]["filter"])[21]'
'|':'Function("return unescape")()("%"+(7)+"c")'
'}':'([]["filter"]+"")["slice"]("-1")'
'~':'Function("return unescape")()("%"+(7)+"e")'

要将上面的字符转换成六种字符的等价形式,还需要用到下面的几个等价形式带入解决:

var SIMPLE = {
  'false':      '![]',
  'true':       '!![]',
  'undefined':  '[][[]]',
  'NaN':        '+[![]]',
  'Infinity':   '+(+!+[]+(!+[]+[])[!+[]+!+[]+!+[]]+[+!+[]]+[+[]]+[+[]]+[+[]])' // +"1e1000"
};

var CONSTRUCTORS = {
  'Array':    '[]',
  'Number':   '(+[])',
  'String':   '([]+[])',
  'Boolean':  '(![])',
  'Function': '[]["filter"]',
  'RegExp':   'Function("return/"+false+"/")()'
};

使用SIMPLE和CONSTRUCTORS内的等价形式,即可推算出上面那些字符的内容。比如a的等价形式是(false+"")[1],将false替换为![],将""替换为[],将1替换为+!+[],就可以推算出a使用六个字符表示的等价形式为(![]+[])[+!+[]]。(PS:从中不难发现作者aemkei真是用心良苦)

这样看来,以alert(1)为例,每个字符的等价形式如下:

'a':'(![]+[])[+!+[]]'
'l':'(![]+[])[!+[]+!+[]]'
'e':'(!![]+[])[!+[]+!+[]+!+[]]'
'r':'(!![]+[])[+!+[]]'
't':'(!![]+[])[+[]]'
'(':'(![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]]'
'1':'[+!+[]]'
')':'(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]]'

将它们用符号“+”连接起来,就可以获取"alert(1)"的等价形式了!同理我们获得了"filter"、"constuctor"、"return eval"的等价形式,再回头看看这段代码:

[]["filter"]["constructor"]("return eval")()("alert(1)")

将字符串替换后,放入HTML中的script标签里面,或是放到一个js文件里面,就可以用浏览器打开HTML文件查看效果啦!

(图中浏览器版本为:Google Chrome 46.0.2490.80 m)

-- 2016年2月8日 再补充一点:

如果JSFuck找不到一个字符的等价形式(比如输入中含有汉字),那么JSFuck会通过下面的方式找到该字符,以字符“呵”为例:

([]+[])["constructor"]["fromCharCode"]("呵".charCodeAt(0))

其中表达式

"呵".charCodeAt(0)

可以通过计算得出,它的值是21621,那么上面的表达式就可以替换为

([]+[])["constructor"]["fromCharCode"](21621)

将这个表达式中的字符串和数字运用之前介绍的规则进行等价替换,就可以完美地将非ASCII码字符转换为六种JSFuck符号的问题了!

END

© 著作权归作者所有

共有 人打赏支持
北风其凉

北风其凉

粉丝 116
博文 498
码字总数 463468
作品 4
朝阳
程序员
私信 提问
JSFuck —— 直接让你崩溃的 JavaScript 脚本

JSFuck 可以让你只用 6 个字符 []()!+ 来编写 JavaScript 程序。

oschina
2015/05/04
48
0
JSFuck —— 只用 6 个字符 []()!+ 编写 JS 程序

JSFuck 可以让你只用 6 个字符 []()!+ 来编写 JavaScript 程序。

oschina
2013/09/14
33
0
OSChina 开源周刊第三十三期 —— Node.js 和 io.js 准备合作!

每周技术抢先看,总有你想要的! 开源资讯 Node.js 和 io.js 准备合作!合久必分,分久必合? Nervana 开源深度学习软件,性能超 Facebook、Nvidia产品 B 站建开源工作组 多 APP 使用其开源项...

OSC编辑部
2015/05/09
0
0
OSChina 开源周刊第 33 期 —— Java 7 生命周期终结

每周技术抢先看,总有你想要的! 开源资讯 Node.js 和 io.js 准备合作!合久必分,分久必合? Nervana 开源深度学习软件,性能超 Facebook、Nvidia产品 B 站建开源工作组 多 APP 使用其开源项...

OSC编辑部
2015/05/09
4.4K
1
【译】六个字符构建 Javascript 世界

李俊冬,租赁大前端,17 年 2 月加入链家,先后负责新房 B 端、租赁 C 端的前端开发。 前言 无用但有趣的冷知识,通过 构建 Javascript 世界,hope you enjoy it! Javascript 是一门非常奇怪...

a独家记忆
2018/06/22
0
0

没有更多内容

加载失败,请刷新页面

加载更多

远程获得的有趣的linux命令

使用这些工具从远程了解天气、阅读资料等。 我们即将结束为期 24 天的 Linux 命令行玩具日历。希望你有一直在看,如果没有,请回到开始,从头看过来。你会发现 Linux 终端有很多游戏、消遣和...

Linux就该这么学
28分钟前
4
0
Apollo配置详细步骤(Windows环境)

一. 准备工作 1.下载 apollo 安装包 下载链接:http://activemq.apache.org/apollo/download.html 2.下载 java JDK 安装包 ( apollo 依赖 java 环境) 下载链接:http://www.oracle.com/techn......

morpheusWB
49分钟前
5
0
聊聊flink的AsyncWaitOperator

序 本文主要研究一下flink的AsyncWaitOperator AsyncWaitOperator flink-streaming-java_2.11-1.7.0-sources.jar!/org/apache/flink/streaming/api/operators/async/AsyncWaitOperator.java ......

go4it
今天
5
0
Java并发编程基础(四)

ThreadGroup 在主线程创建得线程,如果没有给他指定线程组,那么创建的线程,默认和主线程同一个线程组。线程组可以底下可以是线程,也可以实线程组。 构建线程组的方法: private ThreadGr...

chendom
今天
7
0
Scala学习(一)

学习Spark之前需要学习Scala。 参考学习的书籍:快学Scala

柠檬果过
今天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部