文档章节

JavaScript学习:JSFuck代码阅读笔记

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

© 著作权归作者所有

共有 人打赏支持
北风其凉

北风其凉

粉丝 114
博文 497
码字总数 462457
作品 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
投稿007期 | 代码中的酸甜苦辣

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

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

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

XBGG
07/03
0
0
JavaScript语言精粹学习笔记(一)

《JavaScript语言精粹》相比《JavaScript权威指南》而言,是一本太薄的书了。然而也许正因为小而精,所以难有权威指南那样阅读起来浅显易懂却又醍醐灌顶般的感觉,语言精粹还是略微感觉有些艰...

小微
2012/12/27
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

1、Vue解决安卓4.4不兼容的问题

1.npm安装 npm install babel-polyfill--save-devnpm install es6-promise--save-dev package.json中会出现 "babel-polyfill": "^6.26.0","es6-promise": "^4.1.1", 2.main.js引入 impo......

阿K1225
14分钟前
1
0
mybatis generator 属性详解

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN""http://mybatis.org/dtd/mybatis......

太黑_thj
18分钟前
1
0
windows nvm 安装 node

nvm 是 node 的版本控制管理 下面是下载 nvm 的地址,选择 nvm-setup.zip 下载 https://github.com/coreybutler/nvm-windows/releases 就是下一步下一步,一键安装 基本命令有: nvm arch [32...

U_I_A_N
20分钟前
0
0
js判断字符串中是否包含某个字符串

indexOf() indexof()方法可以返回某个指定的字符串值在字符串中首次出现的位置。如果要检索的字符串值没有出现,则该方法返回-1。 var str = "123";console.log(str.indexOf("3") != -1);...

小星星_cjx
33分钟前
0
0
函数式组件完整例子

之前创建的组件是比较简单,没有管理或者监听任何传递给他的状态,也没有生命周期方法。它只是一个接收参数的函数。 在下面这个例子中,我们标记组件为 functional,这意味它是无状态 (没有响...

tianyawhl
35分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部