Переглянути джерело

Move wiki over to Readme.

Martin Kleppe 9 роки тому
батько
коміт
66ea655409
1 змінених файлів з 429 додано та 4 видалено
  1. 429 4
      README.md

+ 429 - 4
README.md

@@ -6,6 +6,8 @@ It does not depend on a browser, so you can even run it on Node.js.
 
 Demo: [jsfuck.com](http://www.jsfuck.com)
 
+By [@aemkei](https://twitter.com/aemkei) and [friends](https://github.com/aemkei/jsfuck/graphs/contributors).
+
 ### Example
 
 The following source will do an `alert(1)`:
@@ -48,12 +50,435 @@ The following source will do an `alert(1)`:
     eval        =>  []["filter"]["constructor"]("return eval")()( CODE )
     window      =>  []["filter"]["constructor"]("return this")()
     
-See the full list [here](https://github.com/aemkei/jsfuck/blob/master/jsfuck.js) and read the [Wiki](https://github.com/aemkei/jsfuck/wiki) for a detailed explanation.  
+See the full list [here](https://github.com/aemkei/jsfuck/blob/master/jsfuck.js).  
 
 ### Links
 
-* Follow [@aemkei](http://twitter.com/aemkei) (Martin Kleppe) <br>
-* Original discussion at [Sla.ckers.org](http://sla.ckers.org/forum/read.php?24,32930)
+# JSFuck - How it Works
+
+This wiki should document the different approaches to run any JavaScript with the smallest subset of characters.
+
+**Note:** Feel free to join the discussion here: https://gitter.im/aemkei/jsfuck
+
+## `[]` – Brackets
+
+Let's start with the opening and closing brackets and see what is possible here. They are super useful for this project and it are considered as a core element because they provide a way to 1. deal with arrays and 2. access properties and methods.
+
+
+### `[]` – Array Literals
+
+Create new arrays:
+
+```js
+[] // an empty array
+[[]] // an array with one element (another array) 
+```
+
+### `[X][i]` – Array / Object Access
+
+```js
+[][[]]   // undefined, same as [][""]
+```
+
+Later we will be able to do this:
+
+```js
+"abc"[0]     // get single letter
+[]["length"] // get property
+[]["fill"]   // get methods
+```
+
+### `[X][0]` - Array wrapping trick
+
+By wrapping an expression in an array then getting the element at index zero, you can apply several operators on one expression. This means brackets `[]` can replace parenthesis `()` to isolate expressions:
+
+```js
+[X][0] === X
+++[ ++[ ++[X][0] ][0] ][0] === X + 3
+```
+
+## `+` – Plus Sign
+
+This symbol is useful two, because it allows us to create number, add two values, concatenating strings and (combined with '[]') create strings.
+
+The current version of JSFuck uses it a lot but we not sure if they are fundamental.
+
+### Cast to Number
+
+```js
++[] // 0 - the number 0
+```
+
+### Increment Numbers
+using the Array wrapping trick
+
+```
+++[ 0  ][  0  ] // 1
+++[ [] ][ +[] ] // 1
+```
+
+### Getting `undefined`
+
+Getting an element by index in an empty array will return undefined:
+```js
+undefined === [][0]
+undefined === [][ +[] ]
+undefined === [][ [] ] // will look for property _empty string_ in the array
+```
+
+### Getting `NaN`
+
+Casting `undefined` to Number will result in not-a-number:
+
+```
++[][[]]    // +undefined = NaN
+```
+
+### Add Numbers
+
+```js
+          1 +           1 // 2
+++[[]][+[]] + ++[[]][+[]] // 2
+```
+
+A shorter way using ++:
+
+```js
+++[          1][  0] // 2
+++[++[[]][+[]]][+[]] // 2
+```
+
+Using this technique, we are able to access all digits:
+
+`0`, `1`, `2`, `3`, `4`, `5`, `6`, `7`, `8`, `9`
+
+### `+[]` – Casting to String
+
+Combining the brackets and the plus sign, allows us to turn other values into strings.
+
+Casts to String:
+
+```js
+[]          +[] // "" - empty string
++[]         +[] // "0"
+[][[]]      +[] // "undefined"
+++[][[]]    +[] // "NaN
+++[[]][+[]] +[] // "1"
+```
+
+### `"word"[i]` – Get Single Characters
+
+As we have strings, we can get single characters:
+
+```js
+ "undefined"      [  0] // "u"
+["undefined"][  0][  0] // "u"
+[[][+[]]+[] ][+[]][+[]] // "u"
+```
+
+```js
+[[][+[]]+[]][+[]][           1 ] // n
+[[][+[]]+[]][+[]][ ++[[]][+[]] ] // n
+```
+
+Since we have "NaN" and "undefined", we got the following characters: 
+
+`N`,`a`,`d`,`e`,`f`,`i`,`n`,`u`.
+
+## `+` – Combine Characters
+
+Now we can concat characters to new words.
+
+```js
+// can be written using []+ only:
+"undefined"[4] // "f"
+"undefined"[5] // "i"
+"undefined"[6] // "n"
+"undefined"[3] // "d"
+
+// combine using +
+"f"+"i"+"n"+"d" // "find"
+```
+
+## `"e"` – Numbers in exponential notation
+
+As we have the character "e" from "undefined", we can use exponential notation to construct very big numbers and get a reference to `Infinity`:
+
+```js
++("1e309")         //  Infinity
++("1e309") +[]     // "Infinity"
++("11e100")        //  1.1+e101
++("11e100") +[]    // "1.1+e101"   (gives us `.`)
++("0.0000001")     //  1e-7
++("0.0000001") +[] // "1e-7"       (gives us `-`)
+```
+
+Resulting chars: 
+
+`I`,`f`,`i`,`n`,`t`,`y`,`.`,`+`,`-`.
+
+
+## `[]["method"]` – Access Methods
+
+Newly combinded characters can form method names. These can be accessed using the square brackets notation:
+
+```js
+[]["f"+"i"+"n"+"d"] // where "f" is the first char of "false" and so on
+[]["find"]          // same as the dot syntax:
+[] .find
+```
+
+*Note*: With the characters from "undefined", "NaN" and "Infinity", the only method we are able to find in the objects we have is `Array.prototype.find`.
+
+## `method+[]` – Get Method Definitions
+
+We can cast a method to a String and get its definition as a String:
+
+```js
+[]["find"] +[]
+```
+
+This will return the following String:
+
+```js
+"function find() { [native code] }"
+```
+
+*Note*: String representations of native functions are not part of the ECMAScript standard and slightly differ between browsers. For example, Firefox will output a slightly different string with additional line breaks using `\n`.
+
+Resulting characters: 
+
+* `a`,`c`,`d`,`e`,`f`,`i`,`n`,`o`,`t`,`u`,`v`
+* ` `, `{`, `}`, `(`, `)`, `[`,`]`
+
+Resulting methods: 
+
+* `.concat` 
+* `.find`.
+
+## `!` – Logical NOT operator
+
+This is the fourth character in the original JSFuck set and used to create booleans. 
+
+
+### `!X` – Cast to Boolean
+
+The logical "Not" operator can be used to create booelans `false` and `true`:
+
+```js
+![]  // false
+!![] // true
+```
+
+### `!X+[]` – Get "true" and "false"
+
+Booleans can be casted to string:
+
+```js
+![]  +[] // "false"
+!![] +[] // "true"
+```
+
+This will give us access to more characters:
+
+`a`, `e`, `f`, `l`, `r`, `s`, `t`, `u`.
+
+And together with the set above, we will have `{}()[]+. INacdefilnorstuvy` with access to these methods:
+
+* `call` 
+* `concat`
+* `constructor`
+* `entries`
+* `every`
+* `fill`
+* `filter`
+* `find`
+* `fontcolor`
+* `includes`
+* `italics`
+* `reduce`
+* `reverse`
+* `slice` 
+* `sort`
+
+*Important:* We should better take one of the symbols `=`, `>` or `<` to create booleans, because they are more powerful (see section "Alternatives" below).
+
+## `X["constructor"]` – Primitive wrappers names
+
+With `.constructor` we have a reference to the function that created the instance. For primitives values, it returns the corresponding built-in wrappers:
+
+```js
+0       ["constructor"] // Number
+""      ["constructor"] // String
+[]      ["constructor"] // Array
+false   ["constructor"] // Boolean
+[].find ["constructor"] // Function
+```
+
+Use `+[]` to convert them to strings and retrieve their function name in order to get more chars: 
+
+```js
+0["constructor"]+[] === "function Number() { ..." // gives chars m and b
+```
+
+New chars available :
+`m`, `b`, `S`, `g`, `B`, `A`, `F`.
+
+… and more methods and properties:
+
+* `arguments`
+* `big`
+* `bind`
+* `bold`
+* `name`
+* `small`
+* `some`
+* `sub`
+* `substr`
+* `substring`
+* `toString` 
+* `trim`
+
+
+## `()` – Parenthesis 
+
+### Calling Methods
+
+Since we have access to methods, we can call them to get more power. To do this we need to introduce two more symbols `(` and `)` here.
+
+Example without arguments:
+
+```js
+""["fontcolor"]()   // "<font color="undefined"></font>"
+[]["entries"]() +[] // "[object Array Iterator]"
+```
+
+New characters:
+
+`j`, `<`, `>`, `=`, `"`, `/`
+
+
+### `number.toString(x)` – Getting any lowercase letter
+
+Number's `toString` method has an optional argument specifying the base to use, between 2 and 36. With base 36, the output is displayed with every number and lowercase letter, so we can retrieve any *lowercase* letter from base 36:
+
+```js
+"h" === 17["toString"](36)
+"x" === 33["toString"](36)
+...
+```
+Exposed characters: `abcdefghijklmnopqrstuvwxyz`
+
+### `Function("code")()` – Evaluate Code
+
+Function constructor is the master key : it takes a String as argument and returns a new anonymous function with this string as the function body. So it basically lets you evaluate any code as a String. This is like `eval`, without the need for a reference to the global scope (a.k.a. `window`). We can get it with `[].find ["constructor"]`.
+
+This is the first major step and an essential part of a JS-to-JSFuck compiler.
+...
+
+### `Function("return this")()` – window 
+
+When evaluating a fresh new `function anonymous() { return this }`, we get in return the invocation context which is a reference to the global scope here: `window`
+
+Getting a reference to `window` is another huge step forward for JSFuck. With the brackets characters, we could only dig in the available objects: numbers, arrays, some functions... With a reference to the global scope, we now have access to any global variable and the inner properties of these globals.
+
+
+---
+ 
+
+
+# Alternatives
+
+
+## Combine Characters
+
+Use `.concat` to combine strings:
+
+```js
+"f"["concat"]("i")["concat"]("l")["concat"]("l") // fill
+```
+
+Problem: We need to combibe "c", "o", "n", "c", "a" and "t" to get "concat". 
+
+## Booleans
+
+The `!` might be replaced by with more "powerful" characters:
+
+### `=` – Boolean + Assign Values
+
+```js
+X == X // true
+X == Y // false
+X = Y  // assign a new value
+```
+
+### `>` – Boolean + Create Numbers
+
+```js 
+X < Y  // true
+X < X  // false
+X << Y // number
+```
+
+A more complex example is to get character "f" with `[]>+` only:
+
+```js
+[[ []&lt;[] ] + [] ] [[]&lt;&lt;[]] [[]&lt;&lt;[]]
+[[ false ] + [] ] [     0] [     0]
+[ "false"       ] [     0] [     0]
+  "false"                  [     0]
+```
+
+## Numbers
+
+Use booleans and bitshift operators to create numbers:
+
+```js
+true >> false         // 1
+true << true          // 2
+true << true << true  // 4
+```
+
+Problem: Some number (like `5`) are harder to get. But it is possible when using strings, eg `"11" >> true`. 
+
+## Execute Function
+
+### Using Backticks
+
+Instead of using opening and closing parentheses, we could use backticks ` to execute functions. In ES6 they can be used to interpolate strings and tagged template literals.
+
+```js
+([]["entries"]``).constructor // Object
+```
+
+This would give us characters from "Object" and access to its methods.
+
+Unfortunately, we can only pass a single string (from our basic alphabet eg. `[]!+`) as the parameter. It is not possible to call methods with multiple arguments or precompiled string. To do that, we have to use expression interpolation using `${}` which would introduce new characters.
+
+The possibilities of backticks were discussed in detail [in the Gitter chat room](https://gitter.im/aemkei/jsfuck).
+
+### Mapping `toString`
+
+Another approach executing functions without parentheses would be to map the `.toString` or `.toValue` method and call implicitly.
+
+```js
+A=[]
+A["toString"]=A["pop"]
+A+"" // will execute A.pop
+```
+
+Note: There is no way to pass arguments and it requires to `=` be present in our basic alphabet. And it only works for methods that return basic types.
+
+So far the only use-case is to wire `.toSource` in Firefox to get special characters like the backslash `\`. 
+
+
+# Further Readings
 
+JSFuck was not the first approach! Many people around the world are trying to break the so-called "Wall".
 
-[![Analytics](https://ga-beacon.appspot.com/UA-57649-14/aemkei/jsfuck)](https://github.com/igrigorik/ga-beacon)
+* [Esolang Wiki: JSFuck](https://esolangs.org/wiki/JSFuck) 
+* [sla.ckers.org](http://sla.ckers.org/forum/read.php?24,32930) – Original Discussion
+* [Xchars.js](http://slides.com/sylvainpv/xchars-js/) – Sylvain Pollet-Villard
+* [Non Alphanumeric JavaScript](http://patriciopalladino.com/blog/2012/08/09/non-alphanumeric-javascript.html) – Patricio Palladino
+* [Non-alphanumeric code](http://www.businessinfo.co.uk/labs/talk/Nonalpha.pdf) – Gareth Heyes
+* [Executing non-alphanumeric JavaScript without parenthesis](http://blog.portswigger.net/2016/07/executing-non-alphanumeric-javascript.html) – Portswigger