Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does this magic JavaScript code work?

This is a small piece of JavaScript code that alerts "Hello world":

゚ω゚ノ=/`m´)ノ~┻━┻//*´∇`*/['_'];o=(゚ー゚)=_=3;c=(゚Θ゚)=(゚ー゚)-(゚ー゚);(゚Д゚)=(゚Θ゚)=(o^_^o)/(o^_^o);(゚Д゚)={゚Θ゚:'_',゚ω゚ノ:((゚ω゚ノ==3)+'_')[゚Θ゚],゚ー゚ノ:(゚ω゚ノ+'_')[o^_^o-(゚Θ゚)],゚Д゚ノ:((゚ー゚==3)+'_')[゚ー゚]};(゚Д゚)[゚Θ゚]=((゚ω゚ノ==3)+'_')[c^_^o];(゚Д゚)['c']=((゚Д゚)+'_')[(゚ー゚)+(゚ー゚)-(゚Θ゚)];(゚Д゚)['o']=((゚Д゚)+'_')[゚Θ゚];(゚o゚)=(゚Д゚)['c']+(゚Д゚)['o']+(゚ω゚ノ+'_')[゚Θ゚]+((゚ω゚ノ==3)+'_')[゚ー゚]+((゚Д゚)+'_')[(゚ー゚)+(゚ー゚)]+((゚ー゚==3)+'_')[゚Θ゚]+((゚ー゚==3)+'_')[(゚ー゚)-(゚Θ゚)]+(゚Д゚)['c']+((゚Д゚)+'_')[(゚ー゚)+(゚ー゚)]+(゚Д゚)['o']+((゚ー゚==3)+'_')[゚Θ゚];(゚Д゚)['_']=(o^_^o)[゚o゚][゚o゚];(゚ε゚)=((゚ー゚==3)+'_')[゚Θ゚]+(゚Д゚).゚Д゚ノ+((゚Д゚)+'_')[(゚ー゚)+(゚ー゚)]+((゚ー゚==3)+'_')[o^_^o-゚Θ゚]+((゚ー゚==3)+'_')[゚Θ゚]+(゚ω゚ノ+'_')[゚Θ゚];(゚ー゚)+=(゚Θ゚);(゚Д゚)[゚ε゚]='\\';(゚Д゚).゚Θ゚ノ=(゚Д゚+゚ー゚)[o^_^o-(゚Θ゚)];(o゚ー゚o)=(゚ω゚ノ+'_')[c^_^o];(゚Д゚)[゚o゚]='\"';(゚Д゚)['_']((゚Д゚)['_'](゚ε゚+(゚Д゚)[゚o゚]+(゚Д゚)[゚ε゚]+(゚Θ゚)+(゚ー゚)+(゚Θ゚)+(゚Д゚)[゚ε゚]+(゚Θ゚)+((゚ー゚)+(゚Θ゚))+(゚ー゚)+(゚Д゚)[゚ε゚]+(゚Θ゚)+(゚ー゚)+((゚ー゚)+(゚Θ゚))+(゚Д゚)[゚ε゚]+(゚Θ゚)+((o^_^o)+(o^_^o))+((o^_^o)-(゚Θ゚))+(゚Д゚)[゚ε゚]+(゚Θ゚)+((o^_^o)+(o^_^o))+(゚ー゚)+(゚Д゚)[゚ε゚]+((゚ー゚)+(゚Θ゚))+(c^_^o)+(゚Д゚)[゚ε゚]+(゚ー゚)+((o^_^o)-(゚Θ゚))+(゚Д゚)[゚ε゚]+(゚Θ゚)+(゚Θ゚)+(c^_^o)+(゚Д゚)[゚ε゚]+(゚Θ゚)+(゚ー゚)+((゚ー゚)+(゚Θ゚))+(゚Д゚)[゚ε゚]+(゚Θ゚)+((゚ー゚)+(゚Θ゚))+(゚ー゚)+(゚Д゚)[゚ε゚]+(゚Θ゚)+((゚ー゚)+(゚Θ゚))+(゚ー゚)+(゚Д゚)[゚ε゚]+(゚Θ゚)+((゚ー゚)+(゚Θ゚))+((゚ー゚)+(o^_^o))+(゚Д゚)[゚ε゚]+(゚ー゚)+(c^_^o)+(゚Д゚)[゚ε゚]+(゚Θ゚)+((o^_^o)-(゚Θ゚))+((゚ー゚)+(o^_^o))+(゚Д゚)[゚ε゚]+(゚Θ゚)+((゚ー゚)+(゚Θ゚))+((゚ー゚)+(o^_^o))+(゚Д゚)[゚ε゚]+(゚Θ゚)+((o^_^o)+(o^_^o))+((o^_^o)-(゚Θ゚))+(゚Д゚)[゚ε゚]+(゚Θ゚)+((゚ー゚)+(゚Θ゚))+(゚ー゚)+(゚Д゚)[゚ε゚]+(゚Θ゚)+(゚ー゚)+(゚ー゚)+(゚Д゚)[゚ε゚]+(゚ー゚)+((o^_^o)-(゚Θ゚))+(゚Д゚)[゚ε゚]+((゚ー゚)+(゚Θ゚))+(゚Θ゚)+(゚Д゚)[゚o゚])(゚Θ゚))('_'); 

A good looking version:

゚ω゚ノ = /`m´)ノ~┻━┻//*´∇`*/['_']; o = (゚ー゚) = _ = 3; c = (゚Θ゚) = (゚ー゚) - (゚ー゚); (゚Д゚) = (゚Θ゚) = (o^_^o)/(o^_^o); (゚Д゚) = {   ゚Θ゚:  '_',   ゚ω゚ノ: ((゚ω゚ノ==3)+'_')[゚Θ゚],   ゚ー゚ノ: (゚ω゚ノ+'_')[o^_^o-(゚Θ゚)],   ゚Д゚ノ: ((゚ー゚==3)+'_')[゚ー゚] }; (゚Д゚)[゚Θ゚] = ((゚ω゚ノ==3)+'_')[c^_^o]; (゚Д゚)['c'] = ((゚Д゚)+'_')[(゚ー゚)+(゚ー゚)-(゚Θ゚)]; (゚Д゚)['o'] = ((゚Д゚)+'_')[゚Θ゚]; (゚o゚)=(゚Д゚)['c'] + (゚Д゚)['o'] + (゚ω゚ノ + '_')[゚Θ゚] + ((゚ω゚ノ==3) + '_')[゚ー゚] + ((゚Д゚) + '_')[(゚ー゚) + (゚ー゚)] + ((゚ー゚==3) + '_')[゚Θ゚] + ((゚ー゚==3) + '_')[(゚ー゚) - (゚Θ゚)] + (゚Д゚)['c'] + ((゚Д゚) + '_')[(゚ー゚) + (゚ー゚)] + (゚Д゚)['o'] + ((゚ー゚==3) + '_')[゚Θ゚]; (゚Д゚)['_'] = (o^_^o)[゚o゚][゚o゚]; (゚ε゚) = ((゚ー゚==3) + '_')[゚Θ゚] + (゚Д゚).゚Д゚ノ + ((゚Д゚) + '_')[(゚ー゚) + (゚ー゚)] + ((゚ー゚==3) + '_')[o^_^o-゚Θ゚] + ((゚ー゚==3) + '_')[゚Θ゚] + (゚ω゚ノ+'_')[゚Θ゚]; (゚ー゚) += (゚Θ゚); (゚Д゚)[゚ε゚] = '\\'; (゚Д゚).゚Θ゚ノ = (゚Д゚+゚ー゚)[o^_^o-(゚Θ゚)]; (o゚ー゚o) = (゚ω゚ノ+'_')[c^_^o]; (゚Д゚)[゚o゚] = '\"'; (゚Д゚)['_']((゚Д゚)['_'](゚ε゚+(゚Д゚)[゚o゚]+(゚Д゚)[゚ε゚]+(゚Θ゚)+(゚ー゚)+(゚Θ゚)+(゚Д゚)[゚ε゚]+(゚Θ゚)+((゚ー゚)+(゚Θ゚))+(゚ー゚)+(゚Д゚)[゚ε゚]+(゚Θ゚)+(゚ー゚)+((゚ー゚)+(゚Θ゚))+(゚Д゚)[゚ε゚]+(゚Θ゚)+((o^_^o)+(o^_^o))+((o^_^o)-(゚Θ゚))+(゚Д゚)[゚ε゚]+(゚Θ゚)+((o^_^o)+(o^_^o))+(゚ー゚)+(゚Д゚)[゚ε゚]+((゚ー゚)+(゚Θ゚))+(c^_^o)+(゚Д゚)[゚ε゚]+(゚ー゚)+((o^_^o)-(゚Θ゚))+(゚Д゚)[゚ε゚]+(゚Θ゚)+(゚Θ゚)+(c^_^o)+(゚Д゚)[゚ε゚]+(゚Θ゚)+(゚ー゚)+((゚ー゚)+(゚Θ゚))+(゚Д゚)[゚ε゚]+(゚Θ゚)+((゚ー゚)+(゚Θ゚))+(゚ー゚)+(゚Д゚)[゚ε゚]+(゚Θ゚)+((゚ー゚)+(゚Θ゚))+(゚ー゚)+(゚Д゚)[゚ε゚]+(゚Θ゚)+((゚ー゚)+(゚Θ゚))+((゚ー゚)+(o^_^o))+(゚Д゚)[゚ε゚]+(゚ー゚)+(c^_^o)+(゚Д゚)[゚ε゚]+(゚Θ゚)+((o^_^o)-(゚Θ゚))+((゚ー゚)+(o^_^o))+(゚Д゚)[゚ε゚]+(゚Θ゚)+((゚ー゚)+(゚Θ゚))+((゚ー゚)+(o^_^o))+(゚Д゚)[゚ε゚]+(゚Θ゚)+((o^_^o)+(o^_^o))+((o^_^o)-(゚Θ゚))+(゚Д゚)[゚ε゚]+(゚Θ゚)+((゚ー゚)+(゚Θ゚))+(゚ー゚)+(゚Д゚)[゚ε゚]+(゚Θ゚)+(゚ー゚)+(゚ー゚)+(゚Д゚)[゚ε゚]+(゚ー゚)+((o^_^o)-(゚Θ゚))+(゚Д゚)[゚ε゚]+((゚ー゚)+(゚Θ゚))+(゚Θ゚)+(゚Д゚)[゚o゚])(゚Θ゚))('_'); 

JSFiddle

It is taken from here: https://codegolf.stackexchange.com/questions/23975/obfuscation-challenge/24041#24041

How does it work? I don't even see the alert in that code.

like image 587
Tony Dinh Avatar asked Mar 23 '14 07:03

Tony Dinh


2 Answers

Before looking closer at the code, you have to know that since JavaScript 1.5 identifiers are allowed to contain not just ASCII characters but also Unicode characters.

In this case many of these funny sequences are just identifiers. After exchanging these identifiers by simpler identifiers and removing unnecessary comments and parenthesis, the code looks as follows:

a = /`m´)ノ~┻━┻/['_']; o = b = _ = 3; c = d = b-b; e = d = o^_^o/o^_^o; e = {   d: '_',   a: ((a==3)+'_')[d],   h: (a+'_')[o^_^o-d],   i: ((b==3)+'_')[b] }; e[d]   = ((a==3)+'_')[c^_^o]; e['c'] = (e+'_')[b+b-d]; e['o'] = (e+'_')[d]; f      = e['c']+e['o']+(a+'_')[d]+((a==3)+'_')[b]+(e+'_')[b+b]+((b==3)+'_')[d]+((b==3)+'_')[b-d]+e['c']+(e+'_')[b+b]+e['o']+((b==3)+'_')[d]; e['_'] = (o^_^o)[f][f]; g      = ((b==3)+'_')[d]+e.i+(e+'_')[b+b]+((b==3)+'_')[o^_^o-d]+((b==3)+'_')[d]+(a+'_')[d]; b      += d; e[g]   = '\\'; e.j    = (e+b)[o^_^o-d]; obo    = (a+'_')[c^_^o]; e[f]   = '\"'; e['_'](e['_'](g+e[f]+e[g]+d+b+d+e[g]+d+(b+d)+b+e[g]+d+b+(b+d)+e[g]+d+((o^_^o)+(o^_^o))+((o^_^o)-d)+e[g]+d+((o^_^o)+(o^_^o))+b+e[g]+(b+d)+(c^_^o)+e[g]+b+((o^_^o)-d)+e[g]+d+d+(c^_^o)+e[g]+d+b+(b+d)+e[g]+d+(b+d)+b+e[g]+d+(b+d)+b+e[g]+d+(b+d)+(b+(o^_^o))+e[g]+b+(c^_^o)+e[g]+d+((o^_^o)-d)+(b+(o^_^o))+e[g]+d+(b+d)+(b+(o^_^o))+e[g]+d+((o^_^o)+(o^_^o))+((o^_^o)-d)+e[g]+d+(b+d)+b+e[g]+d+b+b+e[g]+b+((o^_^o)-d)+e[g]+(b+d)+d+e[f])(d))('_'); 

Now we’re able to evaluate each statement at a time:

  • a = /`m´)ノ~┻━┻/['_'] evaluates to a = undefined
  • o = b = _ = 3 assigns o, b, and _ the integer 3
  • c = d = b-b assigns c and d the integer 0
  • e = d = o^_^o/o^_^o assigns e and d the integer 1 (o^_^o evaluates to 3 XOR 3 XOR 3, which yields 3)
  • e = { d: '_', a: ((a==3)+'_')[d], h: (a+'_')[o^_^o-d], i: ((b==3)+'_')[b] } assigns e the object { d: '_', a: 'a', h: 'd', i: 'e' }
  • e[d] = ((a==3)+'_')[c^_^o] assigns e[1] the string 'f'
  • e['c'] = (e+'_')[b+b-d] assigns e['c'] the string 'c'
  • e['o'] = (e+'_')[d] assigns e['o'] the string 'o'

This was all just the setup and the following variables are set:

a = undefined b = 3 c = 0 d = 1 e = {     1: "f",     a: "a",     c: "c",     d: "_",     h: "d",     i: "e",     o: "o" } 

The next statement is the first that constructs something:

f = e['c'] +             // => "c"     e['o'] +             // => "o"     (a+'_')[d] +         // => "undefined_"[1] = "n"     ((a==3)+'_')[b] +    // => "false_"[3]     = "s"     (e+'_')[b+b] +       // => "object_"[6]    = "t"     ((b==3)+'_')[d] +    // => "true_"[1]      = "r"     ((b==3)+'_')[b-d] +  // => "true_"[2]      = "s"     e['c'] +             // => "c"     (e+'_')[b+b] +       // => "object_"[6]    = "t"     e['o'] +             // => "o"     ((b==3)+'_')[d];     // => "true"[1]       = "r" 

So f = "constructor". In the next statement this "constructor" is used to retrieve a function:

e['_'] = (o^_^o)[f][f] 

This is equivalent to (3).constructor.constructor, which yields the function Function, so:

e['_'] = Function 

This Function function is special as one can construct functions dynamically by passing it the function body code via parameter:

f = Function("alert(1)") // equivalent to f = function() { alert(1) } 

I’ll skip the next few statements and just write the resulting variables and values:

a = undefined b = 4 c = 0 d = 1 e = {     1: "f",     _: Function,     a: "a",     c: "c",     constructor: "\"",     d: "_",     h: "d",     i: "e",     j: "b",     o: "o",     return: "\\" } f = "constructor" obo = "u" 

The last statement does the final work:

e['_'](e['_'](g+e[f]+e[g]+d+b+d+e[g]+d+(b+d)+b+e[g]+d+b+(b+d)+e[g]+d+((o^_^o)+(o^_^o))+((o^_^o)-d)+e[g]+d+((o^_^o)+(o^_^o))+b+e[g]+(b+d)+(c^_^o)+e[g]+b+((o^_^o)-d)+e[g]+d+d+(c^_^o)+e[g]+d+b+(b+d)+e[g]+d+(b+d)+b+e[g]+d+(b+d)+b+e[g]+d+(b+d)+(b+(o^_^o))+e[g]+b+(c^_^o)+e[g]+d+((o^_^o)-d)+(b+(o^_^o))+e[g]+d+(b+d)+(b+(o^_^o))+e[g]+d+((o^_^o)+(o^_^o))+((o^_^o)-d)+e[g]+d+(b+d)+b+e[g]+d+b+b+e[g]+b+((o^_^o)-d)+e[g]+(b+d)+d+e[f])(d))('_'); 

This is equivalent to:

Function(Function( … )(1))('_') 

The long expression builds the following string:

return"\141\154\145\162\164\50\42\110\145\154\154\157\40\127\157\162\154\144\42\51" 

The escaped string evaluates:

alert("Hello World") 

This return code is passed to Function, which creates an anonymous function like:

function anonymous() {     return"\141\154\145\162\164\50\42\110\145\154\154\157\40\127\157\162\154\144\42\51"; } 

Which, we know, is equivalent to:

function anonymous() {     return"alert(\"Hello World\")"; } 

This function is then executed with 1 as parameter, which returns the resulting string:

alert("Hello World") 

This is then passed to Function again, which creates a new anonymous function:

function anonymous() {     alert("Hello World"); } 

Finally, this function is also invoked with '_' as parameter.

like image 153
Gumbo Avatar answered Sep 20 '22 01:09

Gumbo


There is a lot of stuff in here. Parentheses around variables are non-functional.

Basically he constructs this string:

return"\141\154\145\162\164\50\42\110\145\154\154\157\40\127\157\162\154\144\42\51" 

Which is an escaped version of

return "alert(\"Hello World\")" 

And finally does this:

Function(Function('return "alert(\\"Hello World\\")"')())() 

The double Function seems like an arbitrary thing to do, but it's not. Function() interprets backslashes in the string as escape characters. So the first call decodes, and the second executes.

Function("return '\\110\\145\\154\\154\\157'")() // => "Hello" 

This is the same code, better formatted, and with "normal" variable names;

var1=/`m´)ノ~┻━┻//*´∇`*/['_']; three=(threeThenFour)=_=3; c=(one)=(threeThenFour)-(threeThenFour); (anObject)=(one)=(three)/(three); (anObject)={   one:'_',   var1:((var1==3)+'_')[one],   var2ノ:(var1+'_')[three-(one)],   var4ノ:((threeThenFour==3)+'_')[threeThenFour] }; (anObject)[one]=((var1==3)+'_')[c ^ _ ^ three]; (anObject)['c']=((anObject)+'_')[(threeThenFour)+(threeThenFour)-(one)]; (anObject)['three']=((anObject)+'_')[one]; (theConstructor)=(anObject)['c']+   (anObject)['three']+   (var1+'_')[one]+   ((var1==3)+'_')[threeThenFour]+   ((anObject)+'_')[(threeThenFour)+(threeThenFour)]+   ((threeThenFour==3)+'_')[one]+   ((threeThenFour==3)+'_')[(threeThenFour)-(one)]+   (anObject)['c']+   ((anObject)+'_')[(threeThenFour)+(threeThenFour)]+   (anObject)['three']+   ((threeThenFour==3)+'_')[one];  // theConstructor => "constructor"   (anObject)['_']=(three)[theConstructor][theConstructor]; (theReturn)=((threeThenFour==3)+'_')[one]+   (anObject).var4ノ+   ((anObject)+'_')[(threeThenFour)+(threeThenFour)]+   ((threeThenFour==3)+'_')[three-one]+   ((threeThenFour==3)+'_')[one]+   (var1+'_')[one];  // theReturn => "return"  (threeThenFour)+=(one); (anObject)[theReturn]='\\'; (anObject).var3ノ=(anObject+threeThenFour)[three-(one)]; (ovar2o)=(var1+'_')[c ^ _ ^ three]; (anObject)[theConstructor]='\"';  // (anObject)['_'] => Function  (anObject)['_'](   (anObject)['_'](theReturn+                  (anObject)[theConstructor]+                  (anObject)[theReturn]+                  (one)+                  (threeThenFour)+                  (one)+                  (anObject)[theReturn]+                  (one)+                  ((threeThenFour)+(one))+                  (threeThenFour)+                  (anObject)[theReturn]+                  (one)+(                    threeThenFour)+                  ((threeThenFour)+(one))+                  (anObject)[theReturn]+                  (one)+                  ((three)+(three))+                  ((three)-(one))+                  (anObject)[theReturn]+                  (one)+                  ((three)+(three))+                  (threeThenFour)+                  (anObject)[theReturn]+                  ((threeThenFour)+(one))+                  (c ^ _ ^ three)+                  (anObject)[theReturn]+                  (threeThenFour)+((three)-(one))+                  (anObject)[theReturn]+                  (one)+(one)+                  (c ^ _ ^ three)+                  (anObject)[theReturn]+                  (one)+                  (threeThenFour)+                  ((threeThenFour)+(one))+                  (anObject)[theReturn]+                  (one)+                  ((threeThenFour)+(one))+                  (threeThenFour)+                  (anObject)[theReturn]+                  (one)+                  ((threeThenFour)+(one))+                  (threeThenFour)+                  (anObject)[theReturn]+                  (one)+                  ((threeThenFour)+(one))+                  ((threeThenFour)+(three))+                  (anObject)[theReturn]+                  (threeThenFour)+                  (c ^ _ ^ three)+                  (anObject)[theReturn]+                  (one)+                  ((three)-(one))+                  ((threeThenFour)+(three))+                  (anObject)[theReturn]+                  (one)+                  ((threeThenFour)+(one))+                  ((threeThenFour)+(three))+                  (anObject)[theReturn]+                  (one)+                  ((three)+(three))+                  ((three)-(one))+                  (anObject)[theReturn]+                  (one)+                  ((threeThenFour)+(one))+                  (threeThenFour)+                  (anObject)[theReturn]+                  (one)+                  (threeThenFour)+                  (threeThenFour)+                  (anObject)[theReturn]+                  (threeThenFour)+                  ((three)-(one))+                  (anObject)[theReturn]+                  ((threeThenFour)+(one))+                  (one)+                  (anObject)[theConstructor]                 )   (one) )('_'); 
like image 23
sabof Avatar answered Sep 23 '22 01:09

sabof