jsfuck

repository·main·Indexed 27 days ago

https://github.com/aemkei/jsfuck

An esoteric programming style and library (version 0.5.0) that allows writing valid JavaScript using only six characters: []()!+. It is used for educational purposes and obfuscation, providing a way to execute arbitrary code in both browsers and Node.js by leveraging JavaScript's atomic parts, type casting, and the Function constructor.

Tokens
1.9K
Snippets
8
Records
16
Agent score
44%

What's inside jsfuck

  1. Overview of JSFuck

    main
    JSFuck is an esoteric and educational programming style based on the atomic parts of JavaScript. It uses only six different characters ([]()!+) to write and execute code. It is environment-agnostic and can be run in both browsers and Node.js.
  2. Evaluate arbitrary code using the Function constructor

    main

    The Function constructor is the primary mechanism for executing arbitrary code in JSFuck. It takes a string as an argument and returns a new function. You can access the constructor via []["find"]["constructor"].

    To get a reference to the global scope (window in browsers), evaluate return this:

    []["find"]["constructor"]("return this")() // returns window
  3. Use the Array Wrapping Trick to Isolate Expressions

    main

    By wrapping an expression in an array and accessing index zero [X][0], you can use brackets to replace parentheses () to isolate expressions and apply operators.

    [X][0]           // X
    ++[ ++[ ++[X][0] ][0] ][0] // X + 3
  4. Access Methods via String Concatenation

    main
    You can construct method names as strings and access them using bracket notation. For example, to access Array.prototype.find, you can concatenate characters to form the string "find" and use []["find"].
  5. Call methods in a 'flow way' (chaining)

    main

    To chain multiple method calls where each subsequent call uses the result of the previous one (simulating obj.method1().method2()), use a combination of .split(), .concat(), and .reduce() with .apply().

    For strings, to achieve "truefalse".replace("true","1").replace("false","0"):

    "truefalse"
      ["split"]()["concat"]([["true"]["concat"]("1")])["reduce"](""["replace"]["apply"]["bind"](""["replace"]))
      ["split"]()["concat"]([["false"]["concat"]("0")])["reduce"](""["replace"]["apply"]["bind"](""["replace"]))

    For arrays, the technique is more complex and requires wrapping the initial array to allow for chaining. To achieve [3,4,5].slice(1,2).concat(6):

    ["3"]["concat"](4)["concat"](5)
        ["map"]([""["constructor"]])["concat"]([[""[""]]])["0"]["slice"](-1)
        ["concat"]([[1]["concat"](2)])["reduce"]([""["slice"]["apply"]["bind"]([""["slice"]])])
        ["concat"](6)
    "truefalse"
      ["split"]()["concat"]([["true"]["concat"]("1")])["reduce"](""["replace"]["apply"]["bind"](""["replace"]))
      ["split"]()["concat"]([["false"]["concat"]("0")])["reduce"](""["replace"]["apply"]["bind"](""["replace"]))
  6. Call methods with multiple arguments

    main

    To call a method with more than one argument using only JSFuck symbols, use the .reduce() and .bind() technique. This allows you to pass arguments by binding the method to its context and then reducing over an array of arguments.

    For example, to call [1,2,3].slice(1,2), you can use:

    [1,2].reduce([].slice.bind([1,2,3]))

    To call a string method like "truefalse".replace("true", "1"):

    ["true", "1"].reduce("".replace.bind("truefalse"))
    ["true", "1"].reduce("".replace.bind("truefalse"))
  7. Use the Plus Sign `+` for Numbers and Strings

    main

    The + operator is used for casting, addition, and concatenation.

    Casting and Math:

    • +[] casts to the number 0.
    • ++[ 0 ][ 0 ] increments a value (results in 1).
    • +[][[]] casts undefined to NaN.

    String Operations:

    • []+[] results in an empty string "".
    • +[] results in the string "0".
    • [][[]]+[] results in the string "undefined".
    • ++[][[]]+[] results in the string "NaN".
    • ++[[]][+[]]+[] results in the string "1".
    +[] // 0
    ++[ 0  ][  0  ] // 1
    +[][[]] // NaN
    [] +[] // ""
    +[] +[] // "0"
  8. Use Logical NOT `!` to Create Booleans

    main

    The ! operator is used to cast values to booleans.

    • ![] results in false.
    • !![] results in true.

    Booleans can then be cast to strings using +[] to get "false" or "true", providing access to additional characters like a, e, f, l, r, s, t, u.

    ![] // false
    !![] // true
    ![] +[] // "false"
  9. Access Primitive Wrappers via `.constructor`

    main
    Using the .constructor property on a primitive allows you to access its corresponding built-in wrapper (e.g., Number, String, Boolean). Casting these constructors to strings with +[] allows you to extract even more characters.
  10. Use Brackets `[]` for Array Literals and Property Access

    main

    Brackets are used to create arrays and access properties or methods.

    Array Literals:

    • [] creates an empty array.
    • [[]] creates an array containing another array.

    Property/Method Access:

    • [X][i] allows accessing properties or methods (e.g., []["length"] or []["fill"]).
    • [][[]] returns undefined (equivalent to [][""]).
    []   // an empty array
    [[]] // an array with one element (another array)
    [][[]] // undefined
  11. Retrieve lowercase letters using toString(36)

    main

    You can retrieve any lowercase letter from a to z by using the toString method on a number with a base of 36.

    Example:

    10["toString"](36) // "a"
    35["toString"](36) // "z"
    10["toString"](36) // "a"