Cyclone
Cyclone

Reputation: 18285

How do these javascript obfuscators generate actual working code?

There's this one and this one and they both generate completely unreadable code, one being more adorable than the other.

Now, I'm no expert in Javascript, but I fail to see how

゚ω゚ノ= /`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) - (゚Θ゚))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((o^_^o) - (゚Θ゚))+ (o^_^o)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((o^_^o) +(o^_^o))+ (゚ー゚)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (゚ー゚)+ (゚Θ゚)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (゚ー゚)+ (o^_^o)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((゚ー゚) + (゚Θ゚))+ (o^_^o)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (゚Θ゚)+ ((゚ー゚) + (o^_^o))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((o^_^o) +(o^_^o))+ ((o^_^o) +(o^_^o))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (゚ー゚)+ ((゚ー゚) + (゚Θ゚))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((o^_^o) +(o^_^o))+ ((o^_^o) - (゚Θ゚))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (゚ー゚)+ ((o^_^o) +(o^_^o))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((゚ー゚) + (゚Θ゚))+ (゚ー゚)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((゚ー゚) + (゚Θ゚))+ ((゚ー゚) + (o^_^o))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((o^_^o) +(o^_^o))+ ((゚ー゚) + (o^_^o))+ (゚Д゚)[゚ε゚]+(゚ー゚)+ ((o^_^o) - (゚Θ゚))+ (゚Д゚)[゚ε゚]+((゚ー゚) + (゚Θ゚))+ (゚Θ゚)+ (゚Д゚)[゚o゚]) (゚Θ゚)) ('_');

and

$=~[];$={___:++$,$$$$:(![]+"")[$],__$:++$,$_$_:(![]+"")[$],_$_:++$,$_$$:({}+"")[$],$$_$:($[$]+"")[$],_$$:++$,$$$_:(!""+"")[$],$__:++$,$_$:++$,$$__:({}+"")[$],$$_:++$,$$$:++$,$___:++$,$__$:++$};$.$_=($.$_=$+"")[$.$_$]+($._$=$.$_[$.__$])+($.$$=($.$+"")[$.__$])+((!$)+"")[$._$$]+($.__=$.$_[$.$$_])+($.$=(!""+"")[$.__$])+($._=(!""+"")[$._$_])+$.$_[$.$_$]+$.__+$._$+$.$;$.$$=$.$+(!""+"")[$._$$]+$.__+$._+$.$+$.$$;$.$=($.___)[$.$_][$.$_];$.$($.$($.$$+"\""+$.$_$_+(![]+"")[$._$_]+$.$$$_+"\\"+$.__$+$.$$_+$._$_+$.__+"(\\\"\\"+$.__$+$._$_+$._$$+$.__+$.$_$_+$.$$__+"\\"+$.__$+$.$_$+$._$$+"\\"+$.__$+$.__$+$.$$$+"\\"+$.__$+$.$$_+$.$$_+$.$$$_+"\\"+$.__$+$.$$_+$._$_+$.$$$$+(![]+"")[$._$_]+$._$+"\\"+$.__$+$.$$_+$.$$$+"\\\")"+"\"")())();

are actual valid javascript that do as expected. Seriously, run them. They're both alert("StackOverflow"). I could understand obfuscating some logic or string obfuscation, but there's no visible control statements. Is this obfuscator pulling some magic in the style of The Language Which Shall Not Be Named? I'm happy with my code looking happy too, but I'm completely not understanding the magic behind it.

I've tried picking through the sourcecode of both pages, and they're as confusing for me as the code they generate.

How does this work?

Upvotes: 28

Views: 3520

Answers (4)

HoLyVieR
HoLyVieR

Reputation: 11134

Since every other answer are only analyses of the code you have given, I will expand on how you can generate those by yourself (without tools). I believe this will give you a better overview of how it works.

Most of these obfuscation are based on few features/principles of JavaScript. The first one is that the variable name can use Unicode Letter (Lu, Ll, Lt, Lm, Lo, Nl) and Unicode Number (Nd). In the first example you have given, the character may look like symbols, but they are Unicode letter or Unicode number.

The second one is that adding an empty string to anything in JavaScript will cast it to a string. If you also use the fact that strings are an array-like structure in JavaScript, you can easily make stuff like : (false+"")[0], which can also be written has (!1+"")[0]. From that point you can compose your own string letter by letter.

The third one is that every object property can be accessed with the [] notation. For example : window["alert"]("test") is the same as window.alert("test"). If you mix that with the previous paragraph, I think you can easily see where it can go.

The only thing we are missing to get started is either a reference to window or Function. The other answers, already provide you a way to access Function which can be use like eval. To get window tough, the easiest way is to leak it through Array.concat this way :

t= [].concat;
a = t()[0]; // "a" now contains window

Once you have window, you can either use window["eval"] or call directly window["alert"].

That's all for the basis of how you actually do these kind of obfuscation. The rest is just variation of the previous points. If you want additional information, I did a couple of blog post about this, you can find them here : http://holyvier.blogspot.com/2011/10/javascript-obfuscation-introduction.html

Upvotes: 10

J. Holmes
J. Holmes

Reputation: 18546

As my javascript excerise of the day, a line by line break down. Note I generated mine with alert("Hello")

$ = ~[];   // var $ = -1
$ = 
    {
    ___ : ++$,              // ++(-1) == 0
    $$$$:(![]+"")[$],       // ![] == false, false + "" == "false", "false"[0] == "f"
    __$:++$,                // ++(0) == 1    
    $_$_:(![]+"")[$],       // ![] == false, false + "" == "false", "false"[1] == "a"
    _$_:++$,                // ++(1) == 2
    $_$$:({}+"")[$],        // {} + "" == "[object Object]", "[object Object]"[2] == "b"
    $$_$:($[$]+"")[$],      // 2[2] == undefined + "" == "undefined", "undefined"[2] == "d"
    _$$:++$,                // ++(2) == 3
    $$$_:(!""+"")[$],       // !"" == true + "" == "true", "true"[3] == "e"
    $__:++$,                // ++(3) == 4
    $_$:++$,                // ++(4) == 5
    $$__:({}+"")[$],        // ({} + "") == [object Object]", "[object Object]"[5] == "c"
    $$_:++$,                // ++(5) == 6
    $$$:++$,                // ++(6) == 7
    $___:++$,               // ++(7) == 8
    $__$:++$                // ++(8) == 9
};

$.$_ = 
    ($.$_=$+"")[$.$_$] +        // "[object Object]"[5] == "c" +  (also $.$_ = "[object Object]")
    ($._$=$.$_[$.__$]) +        // "[object Object]"[1] == "o" + (also $._$ = "o")
    ($.$$=($.$+"")[$.__$]) +    // $.$+"" == "undefined", "undefined"[1] == "n" + (also $.$$ = "n")
    ((!$)+"")[$._$$] +          // !$ == false, false+"" == "false", "false"[3] == "s" +
    ($.__=$.$_[$.$$_]) +        // "[object Object]"[6] == "t" (also $.__ = "t") +
    ($.$=(!""+"")[$.__$]) +     // !"" == true, true + "" == "true", "true"[2] == "r" +(also $.$="r")
    ($._=(!""+"")[$._$_]) +     // !"" == true, true + "" == "true", "true"[3] == "u" +(also $._="u")
    $.$_[$.$_$] +               // "[object Object]"[5] == "c" +
    $.__ +                      // "t" +
    $._$ +                      // "o" +
    $.$;                        // "r"

// $.$_ = "constructor"

$.$$ = 
    $.$ +                       // "r" +
    (!""+"")[$._$$] +           // "true"[3] == "e" +
    $.__ +                      // "t" +
    $._  +                      // "u" +
    $.$ +                       // "r" +
    $.$$;                       // "n" 
// $.$$ = "return"

$.$ = ($.___)[$.$_][$.$_];      // (0)["constructor"]["constructor"]
// $.$ = Function

// This is the part that changes when you change the input string.

$.$(                            // Function( 
    $.$(                        // Function (
        $.$$ +                  // "return"+
        "\""+                   // '"' +
        $.$_$_ +                // "a" + 
        (![]+"")[$._$_]+        // "l" + 
        $.$$$_+                 // "e" + 
        "\\"+                   // "\" +            
        $.__$+                  // "1" + 
        $.$$_+                  // "6" + 
        $._$_+                  // "2" +   (note '\162' = 'r')   
        $.__+                   // "t" + 
        "(\\\"\\"+              // '(\"\' +    
        $.__$+                  // 1 + 
        $.__$+                  // 1 + 
        $.___+                  // 0 +     (note '\110' = 'H')    
        $.$$$_+                 // e + 
        (![]+"")[$._$_]+        // "false"[2] == "l", "l" + 
        (![]+"")[$._$_]+        // "false"[2] == "l", "l" + 
        $._$+                   // "o" + 
        "\\\")"+                // '\")' +
        "\""                    // '"''
    )()                         // invoke
)();                            // invoke

am not i am is pretty much spot on, it creates a string and then invokes it.

Edit – and I don't have time to decode the other version, but I imagine its doing something similar, but with non latin characters.

Upvotes: 23

gilly3
gilly3

Reputation: 91467

What fun! Here's my go at it. Basically what is happening here is a bunch of numbers and strings are being assigned to variables. Those variables are being concatenated to form an encoded string. That encoded string is decoded to form a string of JavaScript code. That code is set as the body of a function, which is then executed.

Let's take it line by line:

Line 1:

゚ω゚ノ = /`m´)ノ ~┻━┻   //*´∇`*/['_'];

゚ω゚ノ - a global variable
/`m´)ノ ~┻━┻ / - a regular expression
/*´∇`*/ - a multi-line comment
['_'] - get the property _ of the regular expression.

Since a RegExp does not have a _ property, the variable ゚ω゚ノ contains the value undefined.

Line 2:

o = (゚ー゚) = _ = 3;

Define the variables o, ゚ー゚, and _, and set each of their values to 3.

Line 3:

c = (゚Θ゚) = (゚ー゚) - (゚ー゚);

Define the variables c and ゚Θ゚ and set their values to 0. (゚ー゚ is 3, so (゚ー゚) - (゚ー゚) is the same as ゚ー゚ - ゚ー゚ is the same as 3 - 3. Now c and ゚Θ゚ both contain 1;

Line 4:

(゚Д゚) = (゚Θ゚) = (o ^ _ ^ o) / (o ^ _ ^ o);

Define the variable ゚Д゚ and redefine the variable ゚Θ゚. ^ is the bitwise XOR operator and o and _ are both 3.
o ^ _ ^ o is the same as 3 ^ 3 ^ 3.
3 ^ 3 is 0, 3 ^ 0 is 3.
Then 3 / 3 is 1.
゚Д゚ and ゚Θ゚ both now contain 1.

Line 5:

(゚Д゚) = { ゚Θ゚: '_', ゚ω゚ノ: ((゚ω゚ノ == 3) + '_')[゚Θ゚], ゚ー゚ノ: (゚ω゚ノ + '_')[o ^ _ ^ o - (゚Θ゚)], ゚Д゚ノ: ((゚ー゚ == 3) + '_')[゚ー゚] };

With line breaks and indentation:

(゚Д゚) = {
    ゚Θ゚: '_',
    ゚ω゚ノ: ((゚ω゚ノ == 3) + '_')[゚Θ゚],
    ゚ー゚ノ: (゚ω゚ノ + '_')[o ^ _ ^ o - (゚Θ゚)],
    ゚Д゚ノ: ((゚ー゚ == 3) + '_')[゚ー゚]
};

Redefine ゚Д゚ as an object literal, with properties ゚Θ゚, ゚ω゚ノ, ゚ー゚ノ, and ゚Д゚ノ.
゚Д゚.゚Θ゚ is "_".
゚Д゚.゚ω゚ノ is ((undefined == 3) + "_")[1] which is "false_"[1] which is "a".
゚Д゚.゚ー゚ノ is (undefined + "_")[3 ^ 3 ^ 3 - 1] which is "undefined_"[2] which is "d".
゚Д゚.゚Д゚ノ is ((3 == 3) + "_")[3] which is "true_"[3] which is "u".

Line 6:

(゚Д゚)[゚Θ゚] = ((゚ω゚ノ == 3) + '_')[c ^ _ ^ o];

Is the same as:

゚Д゚.゚Θ゚ = ((undefined == 3) + "_")[1 ^ 3 ^ 3];

Which is the same as:

゚Д゚.゚Θ゚ = "false_"[1];

So ゚Д゚.゚Θ゚ is "a".

Lines 7 - 16:

And so it continues, assigning strings and numbers to variables and object properties. Until the last line:

Line 17:

(゚Д゚)['_']((゚Д゚)['_'](゚ε゚ + (゚Д゚)[゚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 ^ _ ^ o) + (゚Д゚)[゚ε゚] + (゚Θ゚) + ((o ^ _ ^ o) + (o ^ _ ^ o)) + ((o ^ _ ^ o) - (゚Θ゚)) + (゚Д゚)[゚ε゚] + (゚Θ゚) + ((゚ー゚) + (゚Θ゚)) + (゚Θ゚) + (゚Д゚)[゚ε゚] + (゚Θ゚) + ((o ^ _ ^ o) + (o ^ _ ^ o)) + (c ^ _ ^ o) + (゚Д゚)[゚ε゚] + (゚Θ゚) + ((o ^ _ ^ o) + (o ^ _ ^ o)) + (゚ー゚) + (゚Д゚)[゚ε゚] + (゚ー゚) + ((o ^ _ ^ o) - (゚Θ゚)) + (゚Д゚)[゚ε゚] + ((゚ー゚) + (゚Θ゚)) + (゚Θ゚) + (゚Д゚)[゚o゚])(゚Θ゚))('_');

By this time, we have the following variables:

゚ω゚ノ    // undefined
o       // 3
゚ー゚     // 4
_       // 3
c       // 0
゚Θ゚     // 1
゚Д゚     /* {
            "1": "f",
            ゚Θ゚: "_",
            ゚ω゚ノ: "a",
            ゚ー゚ノ: "d",
            ゚Д゚ノ: "e",
            c: "c",
            o: "o",
            return: "\\",
            ゚Θ゚ノ: "b",
            constructor: "\"",
            _: Function
        } */
゚o゚     // "constructor"
゚ε゚     // "return"
o゚ー゚o   // "u"

That line is mostly one big string concatenation. We can make it slightly more readable by removing the unnecessary parentheses and adding line breaks:

゚Д゚['_'](
    ゚Д゚['_'](
        ゚ε゚ + 
        ゚Д゚[゚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 ^ _ ^ o) + 
        ゚Д゚[゚ε゚] + 
        ゚Θ゚ + 
        ((o ^ _ ^ o) + (o ^ _ ^ o)) + 
        ((o ^ _ ^ o) - ゚Θ゚) + 
        ゚Д゚[゚ε゚] + 
        ゚Θ゚ + 
        (゚ー゚ + ゚Θ゚) + 
        ゚Θ゚ + 
        ゚Д゚[゚ε゚] + 
        ゚Θ゚ + 
        ((o ^ _ ^ o) + (o ^ _ ^ o)) + 
        (c ^ _ ^ o) + 
        ゚Д゚[゚ε゚] + 
        ゚Θ゚ + 
        ((o ^ _ ^ o) + (o ^ _ ^ o)) + 
        ゚ー゚ + 
        ゚Д゚[゚ε゚] + 
        ゚ー゚ + 
        ((o ^ _ ^ o) - ゚Θ゚) + 
        ゚Д゚[゚ε゚] + 
        (゚ー゚ + ゚Θ゚) + 
        ゚Θ゚ + 
        ゚Д゚[゚o゚]
    )(゚Θ゚)
)("_");

The value of that concatenated string is:

return"\141\154\145\162\164\50\42\110\145\154\154\157\54\40\112\141\166\141\123\143\162\151\160\164\42\51"

So, replacing all the variables with literals, we end up with the following JavaScript which gets executed on that last line:

Function(Function("return\"\\141\\154\\145\\162\\164\\50\\42\\110\\145\\154\\154\\157\\54\\40\\112\\141\\166\\141\\123\\143\\162\\151\\160\\164\\42\\51\"")(1))("_")

Breaking that line down, in the middle we see the concatenated string is passed to a Function constructor, making the string the function body:

Function("return\"\\141\\154\\145\\162\\164\\50\\42\\110\\145\\154\\154\\157\\54\\40\\112\\141\\166\\141\\123\\143\\162\\151\\160\\164\\42\\51\"")

So, that string is evaluated as JavaScript, and the Function constructor returns this function:

function () {
    return"\141\154\145\162\164\50\42\110\145\154\154\157\54\40\112\141\166\141\123\143\162\151\160\164\42\51";
}

That function is immediately executed:

Function("return\"\\141\\154\\145\\...\\51\"")(1)

And returns the string:

alert("Hello, JavaScript")

Hey, that looks like JavaScript! But it's not yet. It's just a string. But that string is passed to another Function constructor, giving us a function that executes the string as JavaScript:

Function("alert(\"Hello, JavaScript\")")

That is the same as:

function () {
    alert("Hello, JavaScript");
}

That function is immediately executed:

Function("alert(\"Hello, JavaScript\")")("_")

And our unobfuscated code is finally called.

Upvotes: 32

user1106925
user1106925

Reputation:

Type $ into the console (after running the code), and expand the object. You can then more easily analyze it.

enter image description here

They're grabbing enough words/characters using sneaky means, and referencing them in the $ object, then using them to build the program and evaling likely in a Function(...)() call.

So it should boil down to...

Function('alert("StackOverflow")')();

...or something similar.


Beginning to unwind it, ...

$=~[];  // -1

$={
  0:++$,         //  0
  f:(![]+"")[$], // "f", (![]+"") is "false", and [$] gives index 0, or "f"
  1:++$,         //  1
  a:(![]+"")[$], // "a", (![]+"") is "false", and [$] gives index 1, or "a"
  2:++$,         //  2
  b:({}+"")[$],  // "b", ({}+"") is "[object Object]", and [$] gives index 2, or "b"
  d:($[$]+"")[$],// "d", ($[$]+"") is "undefined", and [$] gives index 2, or "d"
  3:++$,         //  3
  e:(!""+"")[$], // "e", (!""+"") is "true", and [$] gives index 3, or "e"
  4:++$,         //  4
  5:++$,         //  5
  c:({}+"")[$],  // "c", ({}+"") is "[object Object]", and [$] gives index 5, or "c"
  6:++$,         //  6
  7:++$,         //  7
  8:++$,         //  8
  9:++$          //  9
};

$.constructor=($.constructor=$+"")[$[5]]+($.o=$.constructor[$[1]])+($.return=($.$+"")[$[1]])+((!$)+"")[$[3]]+($.t=$.constructor[$[6]])+($.$=(!""+"")[$[1]])+($.u=(!""+"")[$[2]])+$.constructor[$[5]]+$.t+$.o+$.$;
$.return=$.$+(!""+"")[$[3]]+$.t+$.u+$.$+$.return;
$.$=($[0])[$.constructor][$.constructor];
$.$($.$($.return+"\""+$.a+(![]+"")[$[2]]+$.e+"\\"+$[1]+$[6]+$[2]+$.t+"(\\\"\\"+$[1]+$[2]+$[3]+$.t+$.a+$.c+"\\"+$[1]+$[5]+$[3]+"\\"+$[1]+$[1]+$[7]+"\\"+$[1]+$[6]+$[6]+$.e+"\\"+$[1]+$[6]+$[2]+$.f+(![]+"")[$[2]]+$.o+"\\"+$[1]+$[6]+$[7]+"\\\")"+"\"")())();

Then...

$.constructor=($.constructor=$+"")[5]+($.o=$.constructor[1])+($.return=($.$+"")[1])+((!$)+"")[3]+($.t=$.constructor[6])+($.$=(!""+"")[1])+($.u=(!""+"")[2])+$.constructor[5]+$.t+$.o+$.$;
$.return=$.$+(!""+"")[3]+$.t+$.u+$.$+$.return;
$.$=(0)[$.constructor][$.constructor];
$.$($.$($.return+"\""+$.a+(![]+"")[2]+$.e+"\\"+$[1]+$[6]+$[2]+$.t+"(\\\"\\"+$[1]+$[2]+$[3]+$.t+$.a+$.c+"\\"+$[1]+$[5]+$[3]+"\\"+$[1]+$[1]+$[7]+"\\"+$[1]+$[6]+$[6]+$.e+"\\"+$[1]+$[6]+$[2]+$.f+(![]+"")[2]+$.o+"\\"+$[1]+$[6]+$[7]+"\\\")"+"\"")())();

...eh, lost interest.

Upvotes: 12

Related Questions