JavaScript學習:JSFuck代碼閱讀筆記

cbgd 8年前發布 | 14K 次閱讀 JavaScript開發

來自: http://my.oschina.net/Tsybius2014/blog/614234


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)

END

 本文由用戶 cbgd 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!