Web Reversing Guide

A comprehensive guide to web application reverse engineering

View on GitHub

Understanding JavaScript Quirks

JavaScript is powerful but certainly has its flaws. Its design includes features that can lead to unexpected behavior if not understood. Let’s explore some of its quirks…

Weakly Typed

JavaScript is dynamically and weakly typed, meaning variables can change types implicitly during operations.

Unlike strongly typed languages, JavaScript performs automatic type conversions (coercion) in expressions:

let x = 10;    // Number
x = "hello";   // Now a string (no error)

This can lead to strange results…

Weird Behavior from Type Inference

There is so much strange behaviour I could write an essay on this alone, I would encourage you to check out:

But lets cover some of the simple things. JavaScript’s type coercion rules determine how operators behave:

// Number + Number -> Addition
console.log(2 + 3);      // 5

// Boolean + Number -> Addition (Boolean converted to 0/1)
console.log(true + 5);   // 6 (true -> 1)

// Boolean + Boolean -> Addition
console.log(true + false); // 1 (1 + 0)

// Number + String -> Concatenation
console.log(5 + "5");    // "55"

// String + Boolean -> Concatenation
console.log("Hi" + true); // "Hitrue"

// String + String -> Concatenation
console.log("a" + "b");  // "ab"

Looking into JSF*ck

An real application of this behaviour is JSF*ck. JSF*ck is an esoteric subset of JavaScript that uses only six characters:

To write executable code, exploiting JavaScript’s coercion rules:

How letters can be extracted from coerced strings:

// 'a' is at index 1 in "false":
console.log((![]+[])[+!+[]]); // "a"

How evaluation is handled via constructors in order to execute arbitrary code:

(() => {}).constructor("console.log('Hello world!')")()

In JavaScript all functions have constructors, which are used to build functions; due to the “everything is an object” nature of JavaScript, we can access that property on every single function.

How does JSF*ck abuse this:

[]["filter"]["constructor"]( CODE )()

Here JSF*ck is doing the following:

Since we can coerce arbitrary strings through type coercion, we can build functions from just the aformentioned 6 characters. What this looks like:

[][(![]+[])[+!+[]]+(!![]+[])[+[]]][([][(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((!![]+[])[+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+!+[]]+(+[![]]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+!+[]]]+(!![]+[])[!+[]+!+[]+!+[]]+(+(!+[]+!+[]+!+[]+[+!+[]]))[(!![]+[])[+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([]+[])[([][(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]][([][[]]+[])[+!+[]]+(![]+[])[+!+[]]+((+[])[([][(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]+[])[+!+[]+[+!+[]]]+(!![]+[])[!+[]+!+[]+!+[]]]](!+[]+!+[]+!+[]+[!+[]+!+[]])+(![]+[])[+!+[]]+(![]+[])[!+[]+!+[]])()([+!+[]]+[])

Simple attack vector

Overriding eval we can make the browser do all the reconstruction for us.

function evalDecode(source) {
  let _eval = globalThis.eval;
  globalThis.eval = (code) => (globalThis.eval = _eval, code);
  return _eval(source);
}

const code = `[][(![]+[])[+!+[]]+(!![]+[])[+[]]][([][(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((!![]+[])[+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+!+[]]+(+[![]]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+!+[]]]+(!![]+[])[!+[]+!+[]+!+[]]+(+(!+[]+!+[]+!+[]+[+!+[]]))[(!![]+[])[+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([]+[])[([][(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]][([][[]]+[])[+!+[]]+(![]+[])[+!+[]]+((+[])[([][(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]+[])[+!+[]+[+!+[]]]+(!![]+[])[!+[]+!+[]+!+[]]]](!+[]+!+[]+!+[]+[!+[]+!+[]])+(![]+[])[+!+[]]+(![]+[])[!+[]+!+[]])()((![]+[])[+!+[]]+(!![]+[])[+!+[]]+([][(!![]+[])[!+[]+!+[]+!+[]]+([][[]]+[])[+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(!![]+[])[!+[]+!+[]+!+[]]+(![]+[])[!+[]+!+[]+!+[]]]()+[])[!+[]+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+!+[]]+(+[![]]+[+(+!+[]+(!+[]+[])[!+[]+!+[]+!+[]]+[+!+[]]+[+[]]+[+[]]+[+[]])])[+!+[]+[+[]]]+(+[![]]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+!+[]]]+([![]]+[][[]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(+(!+[]+!+[]+[+!+[]]+[+!+[]]))[(!![]+[])[+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([]+[])[([][(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]][([][[]]+[])[+!+[]]+(![]+[])[+!+[]]+((+[])[([][(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]+[])[+!+[]+[+!+[]]]+(!![]+[])[!+[]+!+[]+!+[]]]](!+[]+!+[]+!+[]+[+!+[]])[+!+[]]+([][[]]+[])[+[]]+(!![]+[])[+[]])`;
console.log(evalDecode(code));

Other Strange Quirks

Values are truthy if they evaluate to true in a boolean context, but aren’t necessarily equal to true:

if ("0") { 
  console.log("Runs"); // "0" is truthy
}
console.log("0" == true); // false ("0" -> 0, true -> 1 -> 0 ≠ 1)

Falsy values include false, 0, “”, null, undefined, and NaN. However, comparisons can be misleading:

console.log([] == false); // true ([] -> "" -> 0, false -> 0)
console.log(!![]);        // true ([] is truthy)

Challenge (5 points)

// I seem to have lost my flag inside this weird datastructure, can you extract the charcodes and re-assemble it?
let l = {
  [{}]: {}
};
Function.constructor.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.apply((function() {
  l[{}].k = arguments.callee.caller.toString().match(/constructor\.(.+)(?=apply)/)[0].split("call").length, l["[object Object]"]["[object Object]"] = {}, Function.constructor.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.apply((function() {
    l[{}][{}].k = arguments.callee.caller.toString().match(/constructor\.(.+)(?=apply)/)[0].split("call").length, l["[object Object]"]["[object Object]"]["[object Object]"] = {}, Function.constructor.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.apply((function() {
      l[{}][{}][{}].k = arguments.callee.caller.toString().match(/constructor\.(.+)(?=apply)/)[0].split("call").length, l["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"] = {}, Function.constructor.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.apply((function() {
        l[{}][{}][{}][{}].k = arguments.callee.caller.toString().match(/constructor\.(.+)(?=apply)/)[0].split("call").length, l["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"] = {}, Function.constructor.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.apply((function() {
          l[{}][{}][{}][{}][{}].k = arguments.callee.caller.toString().match(/constructor\.(.+)(?=apply)/)[0].split("call").length, l["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"] = {}, Function.constructor.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.apply((function() {
            l[{}][{}][{}][{}][{}][{}].k = arguments.callee.caller.toString().match(/constructor\.(.+)(?=apply)/)[0].split("call").length, l["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"] = {}, Function.constructor.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.apply((function() {
              l[{}][{}][{}][{}][{}][{}][{}].k = arguments.callee.caller.toString().match(/constructor\.(.+)(?=apply)/)[0].split("call").length, l["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"] = {}, Function.constructor.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.apply((function() {
                l[{}][{}][{}][{}][{}][{}][{}][{}].k = arguments.callee.caller.toString().match(/constructor\.(.+)(?=apply)/)[0].split("call").length, l["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"] = {}, Function.constructor.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.apply((function() {
                  l[{}][{}][{}][{}][{}][{}][{}][{}][{}].k = arguments.callee.caller.toString().match(/constructor\.(.+)(?=apply)/)[0].split("call").length, l["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"] = {}, Function.constructor.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.apply((function() {
                    l[{}][{}][{}][{}][{}][{}][{}][{}][{}][{}].k = arguments.callee.caller.toString().match(/constructor\.(.+)(?=apply)/)[0].split("call").length, l["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"] = {}, Function.constructor.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.apply((function() {
                      l[{}][{}][{}][{}][{}][{}][{}][{}][{}][{}][{}].k = arguments.callee.caller.toString().match(/constructor\.(.+)(?=apply)/)[0].split("call").length, l["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"] = {}, Function.constructor.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.apply((function() {
                        l[{}][{}][{}][{}][{}][{}][{}][{}][{}][{}][{}][{}].k = arguments.callee.caller.toString().match(/constructor\.(.+)(?=apply)/)[0].split("call").length, l["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"] = {}, Function.constructor.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.apply((function() {
                          l[{}][{}][{}][{}][{}][{}][{}][{}][{}][{}][{}][{}][{}].k = arguments.callee.caller.toString().match(/constructor\.(.+)(?=apply)/)[0].split("call").length, l["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"] = {}, Function.constructor.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.apply((function() {
                            l[{}][{}][{}][{}][{}][{}][{}][{}][{}][{}][{}][{}][{}][{}].k = arguments.callee.caller.toString().match(/constructor\.(.+)(?=apply)/)[0].split("call").length, l["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"] = {}, Function.constructor.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.apply((function() {
                              l[{}][{}][{}][{}][{}][{}][{}][{}][{}][{}][{}][{}][{}][{}][{}].k = arguments.callee.caller.toString().match(/constructor\.(.+)(?=apply)/)[0].split("call").length, l["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"] = {}, Function.constructor.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.apply((function() {
                                l[{}][{}][{}][{}][{}][{}][{}][{}][{}][{}][{}][{}][{}][{}][{}][{}].k = arguments.callee.caller.toString().match(/constructor\.(.+)(?=apply)/)[0].split("call").length, l["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"] = {}, Function.constructor.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.apply((function() {
                                  l[{}][{}][{}][{}][{}][{}][{}][{}][{}][{}][{}][{}][{}][{}][{}][{}][{}].k = arguments.callee.caller.toString().match(/constructor\.(.+)(?=apply)/)[0].split("call").length, l["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"] = {}, Function.constructor.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.apply((function() {
                                    l[{}][{}][{}][{}][{}][{}][{}][{}][{}][{}][{}][{}][{}][{}][{}][{}][{}][{}].k = arguments.callee.caller.toString().match(/constructor\.(.+)(?=apply)/)[0].split("call").length, l["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"]["[object Object]"] = {}, Function.constructor.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.call.apply((function() {
                                      l[{}][{}][{}][{}][{}][{}][{}][{}][{}][{}][{}][{}][{}][{}][{}][{}][{}][{}][{}].k = arguments.callee.caller.toString().match(/constructor\.(.+)(?=apply)/)[0].split("call").length
                                    }))
                                  }))
                                }))
                              }))
                            }))
                          }))
                        }))
                      }))
                    }))
                  }))
                }))
              }))
            }))
          }))
        }))
      }))
    }))
  }))
})); 
console.log(l);

Hints (spoilers):

Hint 1 Charcodes correspond to the quantity of "call"s per function.
Hint 2 You can modify the code to add the charcodes to something more easily converted to a string.

← Previous Chapter | Next Chapter ->