文档章节

JavaScript学习:JSFuck代码阅读笔记

北风其凉
 北风其凉
发布于 2016/02/06 21:42
字数 1181
阅读 768
收藏 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

© 著作权归作者所有

共有 人打赏支持
北风其凉

北风其凉

粉丝 115
博文 498
码字总数 463468
作品 4
朝阳
程序员
私信 提问
OSChina 开源周刊第三十三期 —— Node.js 和 io.js 准备合作!

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

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

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

a独家记忆
06/22
0
0
我是这样黑进你Node.js生产服务器的

本文首发于我的知乎专栏HackingSexy:zhuanlan.zhihu.com/p/43514079 TL,DR: 这篇文章讲述了从一个黑客的角度,以渗透前端项目为目标,从生成 payload,混淆,隐藏 payload,发布 npm,社会...

彭家进_
09/03
0
0
投稿007期 | 代码中的酸甜苦辣

对于码农来说,代码就是生活的一部分。有首歌这样唱:生活就是油盐酱醋再加一点糖(根据歌词大家应该知道我是哪里人)。所以写代码的时候,甚至代码本身,都是五味杂陈的。下面有一些我经历过...

__innocence
08/08
0
0
js的array实现栈数据结构

申明:本文是js系列笔记之一,有不正确的地方请尽管指出,大家相互学习,共同进步; 首先在阅读本文之前,默认你已经知道了javascript的数组类型,并且了解array的pop()和push方法;这里对这...

XBGG
07/03
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Linux学习-1031(rsync同步工具 上)

10.28 rsync工具介绍 10.29/10.30 rsync常用选项 10.31 rsync通过ssh同步 一、 rsync工具介绍 rsync是一个同步工具,在日常的运维中常会用到。它可以本地同步,也实现可以远程两台机器同步。...

wxy丶
18分钟前
1
0
python实战一期:第一天

1. 为什么学习python 1.1 为什么要学Python? Python第一是个非常牛B的脚本语言,能满足绝大部分自动化运维的需求,又能做后端C/S架构,又能用WEB框架快速开发出高大上的Web界面,只有当你自...

laoba
20分钟前
2
0
Java并发编程学习三:线程同步的关键字以及理解

上篇文章中介绍了Java线程的带来的问题与内存模型中介绍了线程可能会引发的问题以及对应Java的内存模型,顺带介绍了Volatile和Sychronized关键字。今天对Java中涉及到的常见的关键类和关键字...

JerryLin123
26分钟前
0
0
我用代码来给你们分析一个赚钱的技巧

赚钱是个俗气的话题,但又是人人都绕不开的事情。我今天来“科学”地触碰下这个话题。 谈赚钱,就会谈到理财、投资,谈到炒股。有这样一个笑话: 问:如何成为百万富翁? 答:带一千万进入股...

crossin
27分钟前
1
0
spring MatchingBean应用

1、编写接口FactoryList import java.util.List;public interface FactoryList<E extends MatchingBean<K>, K> extends List<E> { E getBean(K factor); List<E> getBeanLi......

重城重楼
40分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部