Как стать автором
Обновить

Комментарии 37

Пончики я люблю больше

Кажется логичным для таких штук использовать самописное расширение к самому обыкновенному Хрому, чтобы сразу пройти мимо всех попыток зацепиться за какую-то несущественную мелочь в интерпретации кода.

как вы перемещаете мышь, с какой скоростью нажимаете-отпускаете клавишу при наборе текста

Тут у меня самого был забавный кейс. Пытался лет 5 назад отловить ботов на сайте букмекера по эвристикам в поведении, и самая большая вероятность вышла у игроков, которые явно не были ботами, но много ставили на киберспорт. В принципе, все логично. Фанаты киберспорта это люди, которые умеют быстро и эффективно использовать мышь и клавиатуру + с высокой вероятностью сидят на сайте с мощного компьютера с хорошим интернетом. Поэтому, ещё вопрос, кто быстрее, - они, или бот, крутящийся на виртуалке за $5/мес, и сидящий на сайте через прокси)

Или вся его работа строится на предположении о том, что по сайту бродят только настоящие люди?

А это, к слову, очень интересный вопрос. В нем кроется причина того, почему 3-rd party антифроды, как правило, достаточно неэффективное говно в сравнении с хорошим in-house. Ключ к качественной разметке кроется в доступе к транзакционным данным бизнеса. Если у тебя есть 1 млрд пользовательских сессий без связей между собой, то превратить их в разметку достаточно сложно. Но, когда к каждой из этих сессий привязана полная история пользователя, то уже на основе долгосрочной истории пользователя понять, попадает он в категорию "точно бот или фродер", "точно не бот", "мало данных -> из выборки лучше выкинуть" намного проще.

PS: а вообще, сам факт, что для вещей типа продажи кроссовок используют такие методы, достаточно омерзителен. Несправедливо, что всегда будет юзеры, которые страдают просто из-за того, что у них какой-то экзотический браузер, редкий монитор со странным разрешением, или нелогичная таймзона из-за того, что человек работает с этого компьютера с другой страной. Хочется верить, что когда-то что акамай, что их партнёры, ответят по закону за дискриминацию потребителей на основе каких-то странных несущественных параметров

Несправедливо, что всегда будет юзеры, которые страдают просто из-за того, что у них какой-то экзотический браузер, редкий монитор со странным разрешением, или нелогичная таймзона из-за того, что человек работает с этого компьютера с другой страной.

Откуда вывод о том, что банятся редкие конфиги?

В этом суть подобных систем. Не видел, как работает именно эта изнутри, но видел подобные (которые собирают достаточно большой вектор из параметров браузера, начиная от очевидных, вроде разрешения экрана, и заканчивая странными, вроде результата исполнения фрагмента кода, который нарушает стандарт js, после чего на сервере пытается классифицировать бот/не бот).

Настроить такую систему (что машинным обучением, что эвристиками) без false positive невозможно. Никогда не знаешь, один из индикаторов отклонился от кластера легитимных юзеров потому, что ботовод забыл его корректно сделать, или потому, что у человека редкий конфиг.

вроде результата исполнения фрагмента кода, который нарушает стандарт js

Если не ошибаюсь, то бет365 когда-то давно подобным промышлял, хотя может чего путаю... Тем не менее, у этой БК в своё время были самые весёлые обнаружения ботов, например, метод querySelectorAll(), который использовался ботами для поиска элементов, они переопределяли так, что при его использовании запускался бесконечный цикл и браузер падал)

А так да, у антиботов бывает достаточно ложных срабатываний даже на обычных пользователей. Именно поэтому нам иногда приходится прокликивать те капчи, которые для нас не предназначены. Та же капча от PerimeterX(press and hold) зачастую срабатывает на юзерах, даже если сам антибот настроен на "средние" проверки.

Сурово! Снимаю шляпу :-)

Эх, еще бы понять как Cloudflare определяет ботов. У меня только этим получилось его пробить. Но как оно работает, слабо понимаю.

Ещё можно подумать, что все данные, которые собирает акамай, нужны лишь для идентификации пользователя, а выводы об автоматизации делают алгоритмы искусственного интеллекта на основе поведенческих факторов(как вы перемещаете мышь, с какой скоростью нажимаете-отпускаете клавишу при наборе текста и тд...).

Всегда так было и вот опять?

Но на каких данных обучается ИИ, если антибот не способен отделить пользователя от бота?

Разметкой же не боты занимаются?

Если идентифицированный по отпечатку пользователь скачивает всю категорию товаров ежедневно на протяжении месяцев, то тут конечно нужен суперИИ, чтобы определить бота)

Или вся его работа строится на предположении о том, что по сайту бродят только настоящие люди?

Вот где в вашем реинженеринге это предположение?

***

К чему вся эта детективная история, если никаких выводов по существу не получено? Нельзя же считать результатом вывод о том, что антибот собирает отпечатки?)

Подделка отпечатков все равно делается без оглядки на то, как их тестируют те или иные антиботы. Только из принципиальной возможности скрыть обман.

Всегда так было и вот опять?

Не всегда. Вернее не только. Достаточно посмотреть в сторону какого-нибудь Shape Security или Kasada хотя бы, которые проводят более глубокие проверки на эмуляцию параметров. Кстати, ботгуард гугла даже этим занимается, хотя кому-кому, а вот ему-то вообще на такое внимание обращать не нужно)

Тому же яндексу(о нём ещё поговорим скорее всего) тоже бы не помешало повнимательнее смотреть за эмуляцией. Потому как одни накручивают ПФ, а другие вынуждены платить за какую-нибудь рекламу, чтобы поднять свой сайт повыше.

Кстати, некоторые рекламные сети, например AdScore, тоже делают более глубокие проверки браузера, чтобы не показывать рекламу абы кому.

Если идентифицированный по отпечатку пользователь скачивает всю категорию товаров ежедневно на протяжении месяцев, то тут конечно нужен суперИИ, чтобы определить бота)

Ну вот один, не совсем аккуратный(ну или не парится просто), скачивает, а другой тихо сидит в сторонке, не отсвечивает и "нагуливает" историю, чтобы закосить под человека, а в нужный момент берёт и выкупает товар, который только-только появился "на полке". В это же мгновение подтягиваются подобные ему друзья и за 10 минут сметают всё. Это я утрирую, конечно, но всё-таки

Нельзя же считать результатом вывод о том, что антибот собирает отпечатки?)

Мне кажется, это к акамаю больше претензия) Я же не виноват, что он ничем более с клиентской стороны через JS не занимается.

Да и в целом, сам процесс деобфускации тоже должен быть интересен людям. Ведь часто приходится пытаться найти как генерируется тот или иной параметр, если сайт не предоставляет официального апи...

Подделка отпечатков все равно делается без оглядки на то, как их тестируют те или иные антиботы.

Кто их так подделывает? Если бы антидетект браузеры их так подделывали, то никто бы ими не пользовался, а пользовались бы обычными расширениями. Зачем подделывать, условно говоря, только screen.width, если антибот может сравнить это дело с CSS Media Queries через MediaQueryList.prototype.matches(), а ещё посмотреть ширину document.body.clientWidth или отрисовать что-нибудь во всю ширину и взять значение? Плюсом ко всему, через JS можно обнаружить и наличие автоматизации, то есть самой CDP-сессии, которая и управляет что selenium'ом, что playwright'ом, что puppeteer'ом. Нет смысла просто эмулировать отпечатки ради отпечатков. Нужно ещё и озаботиться тем, чтобы их эмуляция не была обнаружена, а для этого не помешает "почитать" скрипты антиботов, ради которых, собственно, отпечатки и подделываются.

Ваш глубокий системный подход в домене js удивительно контрастирует с подходом к анализу защиты на основе идентификации пользователя.

проверки на эмуляцию параметров

Это же другое. Море народа парсит по учебникам 10-летней давности на curl и python. То есть для защиты от 95% фрода достаточно посмотреть маркеры реальности браузера. Если кто-то лезет неприкрыто селениумом или прочими playwright`ами, то никакие отпечатки не нужны, и так же уши торчат. Ну то есть это начальный уровень защиты, когда "здрасьте, я не браузер" или "а я уже не curl, я состоявшийся селениум".

Просто вы встретили в одном продукте обе технологии и почему-то смешали теплое с мягким.

сам процесс деобфускации

Это чистое искусство, да. Как собирать 5 кубиков рубика, жонглируя ими. Респект и уважуха!

Кто их так подделывает?

В смысле? Кому данные нужны, те и подделывают. Например, первый в гугле.

антидетект браузеры их подделывали

Они же не для этого вообще. Они трекинг предотвращают в парадигме честных меток. Отпечатки вообще из другой вселенной.

Зачем подделывать только screen

Я не настоящий сварщик и не знаю → при какой атаке на данные актуальны параметры экрана?

Как бы направление мысли вроде улавливаю, но пример (наверное) не актуальный.

Почему бы просто не отказаться от хедлес и не показать честно размер своего экрана? Может вам, как человеку искусства, принципиально обманывать антибота во всем, но практический смысл этих усилий мне недоступен.

Да, без хедлес дороже. Но в сравнении с затратами на загрузку графики это незначительные затраты. А загрузка графики это мастхев, без нее вменяемые юзеры не серфят, только боты.

самой CDP-сессии

Ну так на ней же свет клином не сошелся, есть и другие способы управления браузерами.

чтобы их эмуляция не была обнаружена

Вообще, от статьи такое впечатление, что вы выше этого.

Эмуляция должна быть необнаружима в принципе. А не в текущем варианте конкретного антибота. Завтра придет второй, третий, пятый, каждый день будете эмуляцию изобретать? Антиботы же не совсем дураки пишут, что, они не догадаются как их будут обманывать?

P.S.

"нагуливает" историю

Вы же понимаете, что 1) история - это один из десятков штрихов отпечатка и кардинально ситуацию не меняет и 2) нагулянная история, выбивающаяся из статистики на территории выбранного IP - тоже вполне себе маркер.

и за 10 минут сметают всё

Это идеальные клиенты маркетплейса.

Вы правда думаете, что магазины борются с покупателями, которые покупают без затрат времени и рекламных бюджетов?

В смысле? Кому данные нужны, те и подделывают. Например, первый в гугле.

Мы, видимо, друг-друга не совсем понимаем и говорим о разных вещах. По вашей же ссылке и располагает то, о чём я говорил - не эмуляция ради эмуляции, а такая эмуляция, чтобы её было сложнее обнаружить. Посмотрите в репозитории на то, как переопределяются объекты. Вместо того, чтобы просто "прописать" им заранее собранные значения, используется вагон логики, который пытается скрыться от антиботов: переопределение toString(), обработка стека ошибок, правильный триггер ошибок в зависимости от вызова геттера. Например, если я переопределю свойство navigator.webdriver так(чтобы попытаться себя не обнаружить):

Object.defineProperty(Navigator.prototype, 'webdriver', {
  get: () => false
})

То смогу вызвать геттер следующим образом:

В реальности же, без переопределения свойство выдаст ошибку:

error

Антибот может проверить это и сделать вывод, что свойство эмулировано.

По этой причине и существует другая версия с патченным хромиумом, чтобы на такие проверки не попадаться.

Я не настоящий сварщик и не знаю → при какой атаке на данные актуальны параметры экрана?

Как бы направление мысли вроде улавливаю, но пример (наверное) не актуальный.

Да, пример абстрактный. Правильнее использовать своё разрешение и не беспокоиться ни о чём. Но даже здесь можно допустить ошибку, если я решу выставить в playwright разрешение 1920x1080 следующим образом:

const context = await browser.newContext({
  viewport: {
    width: 1920,
    height: 1080
  }
});

В таком случае параметр screen.height будет равен screen.availHeight, что не является правдой для обычного хрома, и меня обнаружат.

Эмуляция должна быть необнаружима в принципе. А не в текущем варианте конкретного антибота. Завтра придет второй, третий, пятый, каждый день будете эмуляцию изобретать? Антиботы же не совсем дураки пишут, что, они не догадаются как их будут обманывать?

Достаточно посмотреть ветку знаменитого стелс плагина, чтобы понять, что очень сложно сделать "не обнаруживаемую эмуляцию". Как там выражаются: "это бесконечная игра в кошки-мышки". Сегодня антиботы обнаруживают одно, завтра их обходят, они обнаруживают другое, их снова обходят и так далее...

Вы правда думаете, что магазины борются с покупателями, которые покупают без затрат времени и рекламных бюджетов?

Иногда боты вредят бизнесу. Ну и вот статейка есть об этом

Получается без патча самого хромиума, нет вообще вариантов спрятать webdriver?

Есть, но придётся очень сильно заморачиваться + поддерживать это решение. Поэтому проще либо юзать патченное, либо вообще реальный браузер через расширение.

Если речь идет об этом расширении, то тоже следует быть аккуратным. Он переопределяет некоторые методы в объекте window(alert(), prompt()), также добавляет функцию getFrameLocation(), которой изначально в браузере нет.

Да, вас не забанят, в привычном понимании этого слова, но пару лишних капч могут попросить прокликать)

Да, правильно написал @ionicman. Можно и через JS "спрятать", но это потребует немалых трудов, порой очень немалых. Патченный хромиум тоже не панацея, ведь постоянно появляются новые способы обнаружения.

Плюс переопределения методов через JS как раз в том, что такое решение проще поддерживать при обновлении движка браузера. Но, если честно, селениум "из коробки" я бы для обхода антиботов не использовал. Слишком уж он отличается от обычного браузера. А ваша задача не "быть уникальным", а "быть как все".

Стоит сейчас обратить внимание на новый headless режим.

 новый headless

В чем разница? Там не написано вроде.

В любом случае, хедлес маркер бота. Хоть новый, хоть старый.

В чем разница? Там не написано вроде.

Вот материал есть, если самому в хромиум лезть не хочется

В любом случае, хедлес маркер бота. Хоть новый, хоть старый.

У людей разные задачи, для которых подходят разные инструменты. Условно говоря, никому не надо заморачиваться с патчингом хромиума, чтобы пробить клаудфлеер, но с помощью стелс плагина никто не пойдёт всерьёз регистрировать аккаунты гугла...

I’m not going to share any new detection signals as I used to do.

Вот жук)))

Вот материал есть

Спасибо огромное!

У людей разные задачи

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

Вот жук)))

Он работает в datadome. Даже если бы он захотел чем-нибудь поделиться, то нового бы ничего не сказал. Их антибот - это, наверное, одно из самых худших решений на рынке

можно использовать антидетект браузеры и через их апи подключатся с playwright

Посмотрите в репозитории

Вот там я вижу, что наивный подход с переопределением - это подход давно минувших дней.

Довольно быстро до участников проекта дошло, что

скрыться от антиботов: переопределение toString()

→ очень глупо. Т.к. если атака держится на toString, то вместо нее будет использоваться custom версия, которая будет подгружаться в случайном месте в случайное время под случайным названием.

То есть поддерживать переопределение → очень трудозатратно.

И перешли к другому варианту:

 другая версия с патченным хромиумом

В этом варианте js видит ровно то, что должен видеть. Никакого больше геморроя.

Вариант настолько успешен оказался, что авторам стало некогда и неинтересно поддерживать открытый проект)

Ну а школота, она продолжает трахаться с переопределением) Потому что денег на профессиональные инструменты не имеет.

И вот это

игра в кошки-мышки

относится не к переопределению. Это уже к тому, что еще можно включить в отпечаток. Запатчили хедлес, запатчили вебдрайвер? Но придумали идентифицировать по canvas. Запатчили канвас → стали смотреть набор шрифтов. Потом смайлики. Но не 100500 вариантов спрятать toString)))

Вот там я вижу, что наивный подход с переопределением - это подход давно минувших дней.

Само собой, но антиботами до сих пор это проверяется, а людьми используется

И перешли к другому варианту:

И мы переходим к тому, что для того, чтобы что-то пропатчить, нужно знать что именно патчить. Потому что одни и те же штуки через JS можно просмотреть разными способами. И эта другая версия с патченным хромиумом светится только в путь. Да, не toString, но другими вещами

Никакого больше геморроя.

Его никогда в таких вещах меньше не становится)

Это уже к тому, что еще можно включить в отпечаток.

Вот из статьи прекрасно видно, что именно акамай включает в отпечаток. Правда за пару лет мало что изменилось...

Но не 100500 вариантов спрятать toString)))

Да я для примера... Их здесь вагон можно привести

это проверяется, а людьми используется

Это вы про стелс плагин называете "используется"? Как видно из количества незакрытых багов, подход с переопределением давно не работает и работать больше никогда не будет. Этот вектор атаки полностью блокирован.

версия с патченным хромиумом светится

Насколько я понимаю, js может увидеть только то, что показывает ему браузер. В нормальной ситуации браузер передает в js либо то, что ему отдает Win API (пример - размер экрана), либо то что сам посчитал (пример - юзерагент).

То есть при надевании чужого отпечатка js вроде бы не имеет инструментов для проверки того, что браузер подделал все.

Что же там светится?

за пару лет мало что изменилось

Может просто дискуссия между нападением и обороной ушла из публичного поля? Тех, кто способен патчить хромиум, их мало и далеко не все хотят делиться опытом. Чаще они хотят его продавать) Тем более ставки серьезно выросли после того, как школота со стелс плагином и прочими фейкбраузерами отвалилась.

Это вы про стелс плагин называете "используется"?

Сообщество живое, вопросы регулярно задаются. Да, используется.

Как видно из количества незакрытых багов, подход с переопределением давно не работает и работать больше никогда не будет.

Я могу применяя лишь один JS обойти и клаудфлеер, акамай, и имперву, и периметр, и шейп...

Этот вектор атаки полностью блокирован.

Его никогда не заблокировать. Может быть в контексте стелс плагина всё и заблокировано, но как подход - нет.

То есть при надевании чужого отпечатка js вроде бы не имеет инструментов для проверки того, что браузер подделал все

Если движок вашего хромиума 110, а вы "надели" чужой отпечаток от хромиума 109, то обнаружить это раз плюнуть. Например, достаточно посмотреть свойства объекта window - Object.getOwnPropertyNames(window). От версии к версии набор будет отличаться. Сюда можно приплести ещё много чего, те же CSS стили.

И экран можно понять что не ваш, и тем более канвас, и шрифты и тд... Даже если вы всё это внутри хромиума переопределили. Вот даже в моём примере недостаточно просто пропатчить Object.getOwnPropertyNames(), чтобы он выдавал в зависимости от юа определённые наборы данных. Я могу определить какое-нибудь свойство во фрейме и при сборе свойств проверять, что оно там есть. Простым патчем этой функции здесь не обойдёшься. Надо знать как все WebAPI друг с другом связаны. А поскольку знать всего нельзя, то и существует эта бесконечная игра с детектами. Поэтому я и сказал: "чтобы пропатчить, нужно знать что именно патчить." А узнать это можно ориентируясь на проверки антиботов.

Что же там светится?

В контексте того репозитория и использования хромиума с патчами вместе с puppeteer всякие штуки по типу Runtime.Enable, Network.Enable и прочее очень просто обнаруживаются. Ну и само собой то, что я только что написал. Там во многих уклонениях сделана треть(а то и меньше) от того, что нужно.

Может просто дискуссия между нападением и обороной ушла из публичного поля?

Нет, эта дискуссия живее всех живых. Достаточно почитать сообщества разработчиков ботов для тех же кроссовок.

Тех, кто способен патчить хромиум, их мало и далеко не все хотят делиться опытом.

Я вот не хочу, да. Тем не менее, материалов для обучения достаточно.

школота со стелс плагином и прочими фейкбраузерами отвалилась

Я всё-таки ещё раз хочу заметить, что у людей разные задачи. Кому-то и стелс плагин всё ещё подходит. А кому-то изначально не подошёл, но он сам пофиксил в нём нужные баги и пользуется. И всех их называть "школотой" как-то не очень. Эта "школота" свои сайты в топ в том же яндексе накруткой продвигает.

Спасибо вам большое, познавательно.

В таком случае параметр screen.height будет равен screen.availHeight, что не является правдой для обычного хрома, и меня обнаружат.

Разве в полном экране не так? (F11)

Написать свой интерпретатор JS - снимаю шляпу. Я тоже раньше пытался это сделать. Знаю насколько это высокоинтеллектуальная работёнка)

И да, поддерживаю, побольше бы таких статей на хабре и хабр был-бы торт.

Знаю насколько это высокоинтеллектуальная работёнка)

Соглашусь с тем, что написать хороший AST интерпретатор это задачка со звёздочкой, но приведённая мной реализация интеллектом вроде не очень пахнет)

Спецификация EcmaScript охала бы и ахала, если бы видела, как моё творчество скрипт выполняет

Проделана гигантская работа! Спасибо:) Писали как-то с товарищами декомпилятор байткода nodeJS - знаю о чём говорю.

Тоже хочется рассмотреть подобную тему с байткодом. Много антиботов сейчас используют именно эту схему обфускации через виртуализацию. Компилируют свой JS в байткод, а со стороны клиента реализуют на JS вм, которая этот байткод крутит)

Вау, не представляю насколько это тяжело было.

Напомнило курсовую, когда пришлось писать антивирус на полиморфик вирус (сам себя переписывает при заражении). Эта зараза отняла у меня месяц жизни, да еще и во времена, когда о виртуалках мы не знали, и приходилось винду каждый день переустанавливать, ибо вирус гробил системные файлы быстрее, чем я с ним боролся.

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

Мне доставило большое удовольствие комментировать этот материал, потому, что несмотря на ряд фундаментальных ошибок, он, тем не менее, пытается общаться грамотным языком спецификации языка JS, но не на языке выдуманных абстракций подобных областей видимости, хостинга, контекста this и прочей чепухи которых в JS нет.

Под спойлером часть комментариев по сути сказанного

Да. Мы сами обойдём дерево и выполним в нём каждый узел. Если внимательно посмотреть на скрипт, то в нём используется некоторое подмножество JS. Вы, может, заметили, что там какой-то ES3 с var-переменными, без всяких новомодных rest-spread операторов, стрелочных функций и так далее.

А еще можно было бы воспользоваться DevTools протоколом, который предоставляет тот самый DevTools. Впрочем это лишило бы нас удовольствия наконец узнать как именно JS описан в спецификации.

 

Чтобы выполнить узел VariableDeclaration

Узел VariableDeclaration это `foo = 10`, но не `var foo = 10`
Более того, чтобы было яснее, например в строке const foo = 10 будет ровно такое же VariableDeclaration как и в строке var foo = 10 как и в строке let foo = 10

   

ищем имя в текущей области видимости, если имя существует, то получаем значение по этому имени, а если не существует

Это требует особых пояснений. Потому, что многие привыкли думать, будто бы значение undefined или null эквивалентно `не существует`.

 

Если переменная не найдена и там, то мы получаем знаменитую ошибку "ReferenceError - variable "foo" is not defined".

Мы получаем ошибку Uncaught ReferenceError: foo is not defined.
Никаких сообщений про variable там нет и быть не может.

 

record - это хранилище для переменных. Представляет собой объект, ключи которого являются именами переменных, а значения - данные, которые связаны с этими именами. parent - ссылка на родительское окружение

Рекорд это запись которая хранит в том числе имена идентификаторов. Кроме этого это запись которая хранит большое количество вспомогательной информации.

 

Мы просто в текущий объект record добавляем пару имя-значение.

Это неверно.

 

Финальный код класса Environment

О котором обязательно стоит сказать, что он работает правильно исключительно в случае variableStatement + AssigmentExpression и StatementList.
И совершенно неверно работает при любых LexicalDeclaration (о чем сказано было автором в начале материала) и StatementList как Statement от FunctionStatementList в случае если это Block Statement (о чем автором было не сказано и ниже в совем материале он совершенно запуталася в этом).

 

Контекст исполнения

Это абстрактное понятие, которое используется для обозначение того, какое Enviroment в настоящий момент используется как текущее. Что Вы и сделали.

 

Наш контекст будет содержать два свойства - thisValue и, собственно, Environment

И тут вы ошибаетесь, потому, что в вашем случае this зависит только от execution context, что справедливо для strict mode. В non strict this может зависеть от Object Environment или with statement.

 

Да, это не мираж. thisValue ссылается на window, а поле record класса GlobalEnvironment тоже инициализировано window. Так оно в JavaScript и работает.

Нет, оно работает в JS не так. ВЫ описали частный случай, который в большинстве случаев будет удовлетворять условиям до ES5.
Когда появились LexicalDeclaration, логика поведения в рамках Global Environment Record сильно изменилась: Любая Lexical Declaration попадает в Lexical Enviroment Record текущего Execuion Context. И никогда не будет отображена в Globlal Object. Простое доказательство этому:

let theLet=10;
window['theLet']; // undefined
var theVar=10; 
window['theVar']; // 10

 

Присваивание

В спецификации обозначается как assignment expression, и это совсем не то что написал автор руководства:

var a = 12213;
a = 100;
a; // 100

это все не assignment expression. 1 строка - это variable statement c variable expression с initializer. Второе это variable expression + initializer; третье это просто RunTime semantics для идентификатора.

Семантика Assigmetn Operator описана вот тут

 

ThisExpression ObjectExpression ArrayExpression

Ничего подобного в спецификация языка JS (Ecma) нет и быть не может. В данном случае это следует понимать как определенный уровень упрощения, и не ждать соответствия спецификации.

 

ConditionalExpression

никак не соответствует заявленной в начале руководства цели <ES5. Что просто нужно интерпретировать как то факт, что на самом деле автор говорил о некотором достаточном SCOPE Ecma Statement & Declaration, но не как о четком следовании стандарту.

 

Ох уж этот hoisting... Вспомнили? var-переменные и функции "поднимаются" вверх перед тем, как код будет выполнен. Если говорить про наш случай, то сначала мы должны заполнить окружение, а только потом выполнять тело блока.

Идентификаторы заявленные благодаря var statemant никакого отношение к hoistable не имеют. Hoistable это исключительно function declaration, generator declaration и их async вариации.

 

Создадим отдельный метод для подъёма переменных:

Не существует подьема переменных. Тут у автора случилась каша в голове между ES5, strict mode и тем что действительно называется hoistable.

Термин hoistable относится только к функциям или генераторам. И действительно имеет разное поведение в зависимости от FunctionStatemantList и BlockStatemant вне зависимости от Strict mode, но в зависимости от того какой стандарт мы используем.

В случае ES5+ hoistable в рамках function statemant list приведет к генерации в function enviroment record имени идентификатора без привязывания его к функциональному обьекту в том случае, если он окажется внтури block statemant.
Убедиться в этом легко на простом примере:

( 
  function doTest() {
	doTest2()
	{
		function doTest2() {}
	}
  } 
)() //Uncaught TypeError: doTest2 is not a function

Что говорит о инициализации идентификатора, но отсутствии привязки его к функциональному объекту.

 

Это важно! Мы должны просто добавить переменные в текущее окружение, но не нужно присваивать им никакие значения.

Это очередное упрощение, не соответствующее спецификации. Связывание идентификатора с undefined - уже есть связывание со значением.

Формулировка же - создать идентификатор, но не связывать его со значением, действительно появилась с ES5+ и именно это и обозначает.

Инициализация же идентификатора, в том числе и primitive vale undefined происходит тут

 

Казалось бы всё хорошо, но мы много где наврали. Изолированный контекст исполнения создают только функции, поэтому такой код должен быть обработан

Такой код должен быть обработан действительно потому, что exucation context создается только для hoistable declaration (потому они так и называются) И ошибка в вашем коде, связана с тем, что вы все перепутали. Потому, что в ES5+ BLockStatemant создает только LexicalEnviroment и только в случае RunTime семантики. То есть то, что Вы нагородили в своем коде никакого отношения к спецификации не имеет. НО прекрасно работает в Вашем случае.

 

Что такое функция? Это именованный блок кода, который можно параметризировать какими-нибудь параметрами. Грубо говоря, мы хотим сохранить набор инструкций под определённым именем, а затем в какой-то момент начать его выполнение.

Тут автора понесло. Все что он сказал является почти чепухой. Функция в JS это конструкция которая в случая RunTime Semantics обязательно создает Execution Context в рамках которого и происходит выполнения кода.

То что описал автор, может быть создано в рамках Labeled Block Statemant. При этом Runtime Sematics такого кода никогда не приведет к созданию Execution Context, но приведет к созданию новой Lexical Environment, которая заменит существующую в текущем Execution Context.

 

ExecutionContext, как мы помним, состоит из значения thisValue, а также окружения - Environment. Перед выполнением тела функции это окружение заполняется переданными аргументами

Execution Context не имеет никакого отношения к this. К неявной установке this имеет отношение только RunTime Semantica для MemberExpression в случае CallExpression. Environment действительно имеет связь с this но только для случая использования with statement.

 

Нам осталось реализовать ReturnStatement. На самом деле он прост, но есть нюанс. После выполнения оператора return выполнение блока кода должно остановиться. Но блоков может быть вагон

Тут автор окончательно запутался, не понимая в чем разница между Return Statement и Evaluation RunTime Shematics для BlockStatemant.

 

И так далее и тому подобное.

Автор материала доставил мне большое удовольствие, за возможность поговорить на языке спецификации в рамках языка JavaScript.

И я уверен, что если плотнее поговорить с автором руководства, то все недоразумения обозначенные мной выше, были бы гарантировано приведены в порядок. Уже хотя бы потому, что автор ставил себе задачей объяснить суть глазами спецификации, что ему прекрасно удалось.

Спасибо за такой развернутый ответ !

Важно было бы сказать, что реализуемая машина, крайне далека от той, которая удовлетворяет современной спецификации.

Вообще, в изначальной версии статьи всё это было) Потом исчезло, потому что не хотелось пугать читателей тем, что мы будем писать какой-то там интерпретатор. Нужно было хоть как-то прокрутить скрипт.

Но я оставил фразу

Также, мы используем множество грязных хаков при разработке, которые облегчат нам этот нудный процесс

Названия же узлов и конструкции были просто взяты из парсера babel, который для удобства использования добавляет некоторую отсебятину. Задача была в том, чтобы люди поняли что откуда берётся и почему так написано. В конечном счёте, как мне кажется, это получилось, потому что написание всего кода свелось к системе "посмотреть в astexplorer-перенести на бумагу"

Моя ошибка, видимо, в том, что я использовал "слова" из спецификации. Не нужно было и этого делать.

А еще можно было бы воспользоваться DevTools протоколом, который предоставляет тот самый DevTools.

Это отличный вариант(лучше нашего), но рассказ про применение CDP к деобфускации я припас на потом, а в этом материале хотелось сохранить более выраженную связь с предыдущей статьёй.

Я приблизительно так и предположил. Потому стартлся лишний раз подчеркнуть, что мои _заявления о проблемах соответствия_ с высокой долей вероятности связаны именно с єтим.

Тем не менее, еще раз спасибо Вам за материал.

Зарегистрируйтесь на Хабре , чтобы оставить комментарий

Публикации

Истории