Почему (! [] + []) [+!! [] + []] создает "a"

Мне интересно понять внутренности JavaScript. Я попытался прочитать источник для SpiderMonkey и Rhino, но это довольно сложно обернуть вокруг меня.

Я спрашиваю: почему что-то вроде

  • (![]+[])[+!![]+[]] произведите "a"
  • (Å=[],[µ=!Å+Å][µ[È=++Å+Å+Å]+({}+Å)[Ç=!!Å+µ,ª=Ç[Å]+Ç[+!Å],Å]+ª])()[µ[Å]+µ[Å+Å]+Ç[È]+ª](Å) произведите alert(1)?

Источник: http://sla.ckers.org/forum/read.php?24,32930,page=1.

В этом форуме есть еще много примеров особенностей JavaScript, и я хотел бы знать, как это работает с точки зрения программирования в отношении безопасности веб-приложений.

Ответ 1

Почему (![]+[])[+!![]+[]] создает "a"

шаг за шагом: это анализируется в: (![]+[]) и [+!![]+[]]. Первый бит уже был объяснен artemb: [] - это массив. Отрицая его, ![] оценивает логическое значение, false - то, как работает !, когда оно применяется к тому, что не является null или undefined. Опять же, как указано artemb, добавление этого +[] заставляет логическое преобразование в строку. Это потому, что + является оператором конкатенации строк. Булевский false затем преобразуется в его строковое представление, "false".

Затем второй бит [+!![]+[]]. Прежде всего, внешние [ и ] служат для обработки предыдущей строки, которую мы просто поддерживаем, равным "false" как массив символов. Поместив целочисленный индекс внутри [ и ], вы получите символ в определенном индексе. Итак, остается +!![]+[] Это состоит из 4 частей: +, !![], + и []. Оценивается первый !![]. Мы уже видели, что ![] является булевым false, поэтому новый ! отрицает его и дает true. Следующее, что происходит, это то, что применяется + in +!![], и, применяя +, он преобразует логическое true в числовое представление, которое является 1 (so +true is 1) Следующий ниже +[] возвращает строку из этого 1, давая "1", но это не имеет смысла, более короткое выражение (![]+[])[+!![]] уже создает a. Добавление +[] тоже не повредит, получившееся выражение просто ["1"] вместо [1]. Моя догадка заключается в том, что когда [] применяется к массиву, все, что находится внутри [], будет принудительно введено в число, которое для "1" дало бы 1 снова. Таким образом, в любом случае +!![]+[] оценивается до 1, делая окончательное выражение: "false"[1], который говорит: gimme символ в индексе 1 из строки "false", и поскольку по умолчанию массивы начинаются с 0 в javascript, это второй символ "false" и a.

Ответ 2

Если вы хотите понять, почему эти странные выражения работают так, как они, вы можете открыть консоль firebug и провести эксперимент самостоятельно. Я сделал, и я получил, что ![] is false, !![] is true, добавление массива к логическому значению (false+[] или true+[]) создает строку-версию этого значения (false+[]="false").

Таким образом, выражение сводится к следующему:

"false"["1"] 

который, очевидно, "a"

Ответ 3

Почему (! [] + []) [+!! [] + []] создает "a"

  • !expr - вызывает ToBoolean на expr и переворачивает логическое значение. Другими словами, значения правды, такие как пустой массив, будут выдавать false при использовании с оператором not.
  • a + b - Оба выражения запускаются через внутренний ToPrimitive. Если результирующее значение является строкой, выполняется конкатенация строк. В противном случае примитивы запускаются через ToNumber и добавляются. ToPrimitive для объектов (включая массивы) будет пытаться toString и valueOf. Array.prototype.toString действует как вызов соединения без параметров. Таким образом, ![] + [] = false + "" = "false"
  • !![] == true, унарный оператор plus преобразует выражение в число, поэтому 1. И снова массив преобразуется в "", поэтому +!![]+[] == "1".
  • Выражение сводится к ("false")["1"] == "a"

Другое выражение можно сварить аналогичным образом. Он использует строки unicode, чтобы испортить его, и это длиннее, но так же просто, как "разобрать".

Ответ 4

Я рекомендую вам получить и прочитать:

  • Стандарт ECMAScript (ECMA 262), 5-е издание
  • Документ Adobe под названием "Обзор AVM 2", который объясняет архитектуру виртуальной машины AVM2, на которой выполняется Adobe Flash и ее ActionScript.