4 ms·
I put in alert('hello') and it worked. That's awesome. But how? I searched the code it made and didn't see 'hello.' I understand the stuff below, how it uses JS
by zekenie 13y ago
I put in alert('hello') and it worked. That's awesome. But how? I searched the code it made and didn't see 'hello.' I understand the stuff below, how it uses JS's weird properties to the basic types... but how does it encode characters?
- CWIZO 13y agoIt converts certain things into strings. Like [][[]] => undefined, and then gets the characters by index from that string and puts your original string together.
- antocv 13y agoIm not sure but once you have 0, 1, 2 and 10 as numbers you could add and subtract those to get any number you want, then express those numbers as strings (casting).
- barrkel 13y agoLook at the source. It uses various techniques to get at e.g. type names, and then uses string indexing to access characters in the type name. It has enough characters like this to be able to call fromCharCode.
- jayrox 13y agoi imagine it is using bit shifts similar to brainfuck http://en.wikipedia.org/wiki/Brainfuck http://en.wikipedia.org/wiki/Brainfuck
- mjhoy 13y agoTry it letter by letter. For instance, to get the string "a": (![]+[])[+[[+!+[]]]] Take the first part, `(![]+[])`. `![]` evaluates to `false`. Then `+[]` coerces false into a string, so the expression is `"false"`. The rest of the expression (more complicated) evaluates to `[[1]]`, which will grab the `"a"` from `"false"`. Now why there is the extra surrounding brackets, I'm not sure, because `[1]` would have worked as well.
- bargl 13y agoIt looks like the generator is suboptimal, but still really cool. (![]+[])[+!+[]] evaluates to "a" as well. It looks like it turns it into an array twice. It goes +!+[] === 1 then [+!+[]] === [1] then +[[+!+[]]] === 1 then [+[[+!+[]]]] === [1]
- Pitarou 13y agoIt takes advantage of JS's complicated type coercion semantics and the overloading of the [] and + operators. We start with [] and [[]]. convert [] to a boolean with !: ![] --> false !![] --> true convert [] to undefined by subscripting it: [][[]] --> undefined convert [] [[]] and true to numbers by prefixing them with + and adding them with +: +[] --> 0 +[[]] --> NaN +!![] --> +true --> 1 +!![]+(+!![]) --> +true+(+true) --> 1+(1) --> 2 etc. convert any of these to strings by prefixing them with []+ []+[] --> "" []+![] --> []+false --> "false" []+[][[]] --> []+undefined --> "undefined" []+(+[]) --> []+0 --> "0" get individual characters with the array subscript operator: ([]+![])[+[]] --> ([]+false)[0] --> "false"[0] --> "f" ([]+!![])[+!![]+(+!![])+(+!![])] --> ([]+true)[1+(1)+(1)] --> "true"[3] --> "e" etc... So now we can obtain a limited number of characters: "a" "d" "e" "f" "i" "l" "n" "r" "s" "t" "u" "N" "0" "1" "2" "3" "4" "5" "6" "7" "8" "9" which we can combine into strings with the + operator: "f"+"i"+"l"+"t"+"e"+"r" --> "filter" "1"+"e"+"1"+"0"+"0"+"0" --> "1e1000" It's not much, but it's enough to obtain large numbers: +("1"+"2"+"3"+"4") --> +("1234") --> 1234 +("1"+"e"+"1"+"0"+"0"+"0") --> +("1e1000") --> Infinity and, most importantly, to access a property of the array object: []["filter"] --> function filter() { [native code] } and by converting these back to a string: []+[]["filter"] --> "function filter() { [native code] }" []+Infinity --> "Infinity" we can expand our alphabet still further, and access some even more exciting properties: []["constructor"] --> function Array() { [native code] } ([]+[])["constructor"] --> function String() { [native code] } (![])["constructor"] --> function Boolean() { [native code] } (+[])["constructor"] --> function Number() { [native code] } []["filter"]["constructor"] --> function Function() { [native code] } Almost there now. By converting these back to strings we can access even more characters, and by passing the strings to the Function() constructor we can can construct functions and evaluate them! In other words, we have "eval". Let's use it to access the window object: []["filter"]["constructor"]("return this") --> function anonymous() {return this} []["filter"]["constructor"]("return this")() --> window So now we have access to the global context and eval. We don't quite have access to the full range of letters, but we have enough letters to call toString, and use it's base conversion ability to get the full lowercase alphabet: 10["toString"](36) --> "a" 11["toString"](36) --> "b" ... 25["toString"](36) --> "p" ... 35["toString"](36) --> "z" And now we have "p", we can use escape and unescape to get most of the rest: unescape(escape(" ")[0]+4+0) --> "@" So there you have it! The source code essentially runs this process backwards: it repeatedly uses regular expressions to convert the code back into "()[]!+" one step at a time.