
Дізнайтесь більше про нові кар'єрні можливості в EchoUA. Цікаві проекти, ринкова оплата, гарний колектив. Надсилайте резюме та приєднуйтеся до нас.
JavaScript – це одночасно дивна і чудова мова, яка дозволяє нам писати абсолютно маячний код, що є валідним. Він намагається допомагати нам, конвертуючи величини в потрібні типи залежно від того, як ми з ними працюємо.
Якщо ми додаємо рядок до чогось, результат буде конвертований в рядок.
Якщо ми припишемо ліворуч від чогось плюс або мінус, буде зроблена спроба конвертації рядка в число.
Якщо на щось навісити логічне заперечення, результат буде представлений як логічна величина.
Ми можемо використати це і творити магію, використовуючи лише ці символи: [
, ]
, (
, )
, !
і +
. Якщо Ви читаєте статтю не з мобільного пристрою, то можете відкрити консоль у браузері й виконувати весь код там.
Розпочнемо із засад. Те, що варто запам’ятати:
- Префікс
!
конвертує в Boolean. - Префікс
+
конвертує в число. - Складання з
[]
конвертує в рядок.
Ось приклад:
![] === false+[] === 0[]+[] === ""
Крім того, треба знати, що символи з рядка можна отримувати в такий спосіб:
"hello"[0] === "h"
Також запам’ятайте, що числа можна отримувати складанням інших чисел у рядковому виді та конвертацією результату в числовий формат:
+("1" + " 1") === 11
Спробуємо використати розглянуті властивості й отримати букву a
.
![] === false![]+[] === "false"+!![] === 1------------------------ (![]+[])[+!![]] === "a" // same as " false"[1]
Потішно!
Таким чином, шляхом нехитрих махінацій ми можемо отримати всі букви зі слів true
і false
. a
, e
, f
, l
, r
, s
, t
, u
. Добре, а чи можемо ми взяти букви ще десь?
Ну, ще є undefined
, який і можна отримати, зробивши щось безглузде, на кшталт [][[]]
. Конвертація в рядок дасть нам букви d
, i
і n
.
[][[]] + [] === "undefined"
Використовуючи ці букви, можна скласти слова fill
, filter
і find
. Звичайно, є й інші доступні слова, але цінність цих слів полягає в тому, що вони – методи масивів. Це означає, що вони є частиною об’єкта Array
і їх можна викликати прямо для масивів-сутностей. Наприклад, [2,1].sort ()
.
Крім того, треба пам’ятати, що властивості об’єкта в JS можна використати як через точку, так і через квадратні дужки. Оскільки методи масиву – це властивості об’єкта Array, ми можемо викликати їх, використовуючи дужки замість точки.
Інакше кажучи, [2,1]["sort"]()
– це те саме, що й [2,1].sort ()
.
Давайте подивимося, що станеться, коли ми спробуємо використати один з доступних нам методів, не викликаючи його.
[]["fill"]
Це видасть function fill (){ [native code] }
. Конвертуємо заголовок методу в рядок:
[]["fill"]+[] === "function fill (){ [native code] }"
І отримаємо нові символи: c
, o
, v
, (
, )
, {
, [
, ]
, }
,
.
З літер c
та o
, можемо скласти слово constructor
. constructor
– це метод, який є в усіх JS-об’єктів, і він повертає їх функцію-конструктор.
Отримаємо рядкове представлення всіх конструкторів наших об’єктів:
true["constructor"] + [] === "function Boolean (){ [native code] }" 0["constructor"] + [] === "function Number (){ [native code] }" ""["constructor"] + [] === "function String (){ [native code] }"
[]["constructor"] + [] === "function Array (){ [native code] }"
З цих рядків ми можемо поповнити наш арсенал наступними символами: B
, N
, S
, A
, m
, g
, y
.
Тепер ми складемо "toString"
, функцію, яку можна використати з квадратними дужками. Тільки цього разу ми викличемо її.
(10)["toString"]() === "10"
Тепер ми вже можемо конвертувати в рядок все, що завгодно, оскільки нам це допоможе?
Якщо я скажу Вам, що метод toString
типу Number
володіє секретним аргументом radix
, який міняє основу поверненого числа перед конвертацією в рядок. Дивіться:
(12)["toString"](10) === "12" // base 10 - normal to us (12)["toString"](2) === "1100" // base 2, or binary, for 12 (12)["toString"](8) === "14" // base 8 (octonary) for 12 (12)["toString"](16) === "c" // hex for 12
Навіщо зупинятися на 16? Максимум – це 36, чого вистачає на всі символи 0 -
9
і a -
z
. Тепер ми можемо отримати будь-яку цифру або літеру:
(10)["toString"](36) === "a" (35)["toString"](36) === "z"
Відмінно! Постає запитання: “Як же пунктуаційні символи і заголовні літери?”. Йдемо далі!
Залежно від того, де Ви виконуєте свій JS-код, він може отримувати, а може і не отримувати доступ до заздалегідь визначених об’єктів і даних. Є вірогідність, що при запуску в браузері Ви зможете отримати доступ до обгорткових методів HTML.
Наприклад, bold
– це метод String, що обертає рядок на тег <b>.
"test"["bold"]() === "test"
Це дасть нам символи <
, >
і /
.
Можливо, Ви чули про функцію escape
. По суті, вона конвертує рядок в URI-формат, який можуть розпізнати браузери. Якщо ми передамо їй пропуск, то отримаємо %20
. Передамо <
– отримаємо %3С
. Ця заголовна C
дуже важлива для отримання інших символів.
Завдяки їй ми можемо використати функцію fromCharCode
, що повертає символ Юні-коду за цим десятковим представленням. Вона є частиною об’єкта String, який можна отримати, викликавши конструктор будь-якого рядка.w
""["constructor"]["fromCharCode"](65) === "A"""["constructor"]["fromCharCode"](46) === "".
Для отримання десяткових представлень символів можна використати сайт Unicode lookup.
Добре, тепер ми можемо написати що завгодно у вигляді рядка і виконати будь-яку функцію, яка належить типам Array, String, Number, Boolean або Object, через їх конструктори. Немало для 6 символів. Це ще не кінець.
Запитання: Чим є конструктор будь-якої функції?
Відповідь: function Function (){ [native code] }
, справжній об’єкт Function.
[]["fill"]["constructor"] === Function
Використовуючи його, ми можемо передати рядок коду, щоб створити реальну функцію.
Function ("alert ('test')");
Отримаємо:
Function anonymous (){ alert ('test')}
Що можна викликати відразу ж, просто додавши наприкінці ()
. Так, тепер ми можемо виконувати рядки коду!
Ось тепер все!
Ми можемо отримати доступ до будь-якого символу, об’єднувати їх у валідний код і виконувати його. Це означає, що JS є повною, за Тьюрінгом, мовою із 6 символів [
, ]
, (
, )
, +
і !
.
Не вірите? Запустіть це в консолі:
Якщо Ви читаєте статтю з мобільного пристрою, код вищий – це виконувана функція alert ("wtf")
.
Ось інструмент, який може автоматизувати конверсію, а ось так він переводить кожен символ.
Ну і як це може згодитися?
Ніяк eBay нещодавно “нахімічив” щось у коді, й продавці змогли вбудовувати виконуваний JS у свої сторінки, використовуючи тільки ці символи, але такі атаки дуже рідкісні. Можна подумати про обфускацію, але, будемо чесними, є кращі методи.
Дякую за увагу!
Переклад статті “A Javascript journey with only six characters”
Київ, Харків, Одеса, Дніпро, Запоріжжя, Кривий Ріг, Вінниця, Херсон, Черкаси, Житомир, Хмельницький, Чернівці, Рівне, Івано-Франківськ, Кременчук, Тернопіль, Луцьк, Ужгород, Кам'янець-Подільський, Стрий - за статистикою саме з цих міст програмісти найбільше переїжджають працювати до Львова. А Ви розглядаєте relocate?