Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
Browser-Pwning- — Правильная хорошо структурированная документация для начала работы с pwning Chrome и pwning V8. | Kitploit
Инструменты/GitHubGitHub/spiralbl0ck/browser-pwning-
Анализ уязвимостейЭксплуатацияОбратная инженерияВеб-безопасностьОбучение и ОбразованиеЭксплуатация Бинарных Файлов
GitHubspiralbl0ck/browser-pwning-

Browser-Pwning-

Правильная хорошо структурированная документация для начала работы с pwning Chrome и pwning V8.

Репозиторий
19719484 лет назадПроверено Kitploit

Популярное

Смотреть все →

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

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться

Browser-Pwning

Правильно структурированная документация для начала изучения chrome pwning & v8 pwning

Structure of document

Как организован этот документ

  1. Мотивация
  2. Актуальный учебный материал

Мотивация

Браузеры — одна из самых используемых технологий сегодня. На каждом серийном компьютере, если мы просто подключим и будем использовать, увидим установленный браузер. Именно поэтому с точки зрения атакующего и модели угроз очень выгодно, если атакующий способен скомпрометировать браузер через вредоносную страницу. Учитывая вышеизложенные аргументы, я выбираю для изучения JavaScript-движок Google, в частности v8.

Учитывая огромный масштаб проекта v8, в качестве отправной точки я выбираю интерпретатор, а именно d8. Хотя по d8 уже проведено множество исследований, мы надеемся найти хотя бы одну ошибку, а если нет — иметь возможность продвинуться в исследовании эксплуатации браузеров, поскольку v8 предоставляет отправную точку для базовых стратегий разработки эксплойтов, используемых при эксплуатации браузеров.

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

Если заглянуть под капот, мы увидим, что этот движок используется и в MicrosoftEdge, так что есть шанс получить несколько вознаграждений за bug bounty. В качестве базовой операционной системы исследователь будет использовать смесь Windows и Linux, поскольку нет ограничений на получение шелла — ошибки v8 позволяют выполнять код через wasm-страницы, и это не привязано к какой-либо конкретной платформе.

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

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

  • Изучить, составить карту, освоить внутренние структуры, используемые движком V8, и ключевые точки архитектуры Chrome
  • Изучить и освоить базовые процедуры, необходимые для эксплуатации браузера

Изучить, составить карту, освоить внутренние структуры, используемые движком V8, и ключевые точки архитектуры Chrome

На первом этапе проекта необходимо собрать как можно больше знаний об архитектуре Chrome и о том, как каждый компонент взаимодействует с другими. Чтобы лучше понять это, нам нужно разбить проект Chromium на несколько подкомпонентов, чтобы мы могли изолировать всё и проанализировать должным образом. Точнее, на сколько подкомпонентов разбивается каждый из следующих компонентов

  • Архитектура V8
  • Архитектура Chromium
  • Архитектура Blink

Теперь самый логичный первый шаг — понять архитектуру Chromium. Итак, мы хотим эксплуатировать браузер, но что происходит, когда мы впервые запускаем браузер? После запуска исполняемого файла Chromium этот исполняемый файл запускает несколько процессов.

Порядок и их названия следующие:

Первый называется content-процесс. Что делает этот процесс?

  • Он известен как стартовый процесс.
  • он также является главным процессом
  • он отвечает за запуск собственно главного процесса, который называется browser-процессом

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

  • Итак, как минимум в Windows Chromium работает следующим образом: он компилирует файлы в DLL, а затем загружает её в память. Таким образом, основная логика браузера Chromium находится в chromium.dll.
    Это также подтверждается кодом
    2.
    Это взято из chrome_exe_main_win.cc, и если вам интересно прочитать весь код, он находится в chromium/src/chrome/app. Дальше по ходу выполнения мы видим, что он вызывает MakeMainDllLoader(), чтобы вызвать класс загрузчика DLL, после чего запускает «загрузчик», то есть загружает chrome.dll, и при необходимости перезапускает его с нужными командными строками. Чтобы продолжить анализ загрузчика, нужно понять его код, который находится в том же каталоге в файле mail_dll_loader_win.cc. Прокрутив файл до самого конца, мы видим вызов MakeMainDllLoader, который в зависимости от вашей версии вызывает ChromeDllLoader или ChromiumDllLoader.
    3
    Мы видим, что ChromiumDllLoader — это класс, который наследуется от MainDllLoader. Из определения видно, что этот класс просто загружает DLL на основе аргументов, переданных в командную строку, и типа процесса
    6.
    Анализируя метод Launch, мы можем понять некоторые вещи, которые происходят до запуска chrome.dll: Из этого комментария мы можем понять, что "// Launching is a matter of loading the right dll and calling the entry point. // Derived classes can add custom code in the OnBeforeLaunch callback." Запуск Chrome — это загрузка набора DLL, которые фактически выполняют работу. Во-вторых, он принимает аргументы, переданные в командную строку, а затем инициализирует службы песочницы.
    q.
    Сначала он проверяет, является ли браузер инициатором инициализации песочницы, затем проверяет, был ли процесс, вызвавший инициализацию песочницы, вызван как служба облачной печати. Он также проверяет, был ли передан --no-sandbox бинарнику, что в основном сообщает бинарнику, что не нужно запускаться в песочнице. Он проверяет, было ли установлено что-либо из этого, и если какое-либо из условий истинно, вызывает песочницу с соответствующими опциями. Затем в конце мы добираемся до
    8
    что нам и интересно — это обёртка для вызова chrome_main.

  • Теперь посмотрим, что он делает. Откроем chromium.dll в binja Основываясь на этой картинке с https://blogs.igalia.com/jaragunde/files/2019/03/chrome-init-sequence.png, мы имеем приблизительное представление о том, что искать в binja
    Это так граф выглядит в binja
    research.
    Чтобы лучше отследить его, поищите функцию ChromeMain. Это основная (она же ядро) логика Chrome. Внутри неё мы видим вышеупомянутые фазы того, как chrome.dll работает при запуске:
    Здесь мы видим, что сначала он вызывает некоторые функции, такие как sub_180001420,sub_180017020,sub_180017020, которые выполняют проверки, чтобы выяснить детали того, как Chrome был установлен/скомпилирован. Используя исходный код, мы можем отследить их атрибуты. Первая функция, sub_180001420, соответствует UmaHistogramEnumeration, далее у нас есть sub_180017020, которая является InitializeFromPrimaryModule, а третья и последняя sub_180017020 — это chrome_main_delegate.
    Мы постоянно повторяем chrome_main_delegate, но так и не определили, каково его назначение. ChromeMainDelegate — это класс, который наследуется от ContentMainDelegate и в основном предоставляет функции, связанные с запуском, и обработку вызовов процессов. !Если хотите, вы можете реализовать собственный интерфейс ContentMainDelegate, чтобы изменить поведение модуля Content по умолчанию, и использовать собственный класс ChromeMainDelegate в Chromium для настройки поведения процесса запуска.
    Capture Внутри него есть несколько вызовов функций, которые выполняют XOR над некоторыми областями данных и объединяют их с некоторым реестром, чтобы получить некоторые параметры запуска Chrome . Также обратите внимание, что функция sub_180001510 создаёт ссылку на scoped pointer с двумя колбэками. Не особенно важное действие, но интересно узнать, что такое BindStateBase. Мы будем часто встречать его в базовом коде Chrome. Теперь вы можете задаться вопросом, что делают последние три строки, а именно делают. Итак, первая строка в основном создаёт для замыканий (Closures). Что такое замыкание (closure) вообще?! Ну, если цитировать mozilla dev: "замыкание — это комбинация функции, объединённой вместе со ссылками на её окружающее состояние (лексическое окружение). Другими словами, замыкание даёт вам доступ к области видимости внешней функции из внутренней. В JavaScript замыкания создаются при каждом создании функции, в момент создания функции." Если говорить человеческим языком, это функция внутри функции, которая обращается к переменной внутри внешней функции. Например: . Итак, по сути, это гарантирует, что замыкание будет выполнено. А остальные две строки просто задают определённое поведение для дампов, когда chrome — вставь сюда Идём дальше: он проверяет свою версию во время выполнения, и если она не совпадает, он падает, и мы переходим к разбору командной строки Заглянув внутрь sub_184171800, мы видим, что она не такая уж большая Сначала она принимает аргументы, переданные текущему процессу, затем вызывает функцию, которая принимает StringPiece — по сути, класс-обёртку для std::string, но немного более крутую, и эта функция в основном проверяет, был ли бинарник вызван в режиме headless, сравнивает, является ли имя запущенного бинарника chrome, проверяет, установлена ли USE_HEADLESS_CHROME, и затем переходит к следующему шагу, который называется content main. Основываясь на предоставленных аргументах, задача content main — запустить соответствующую оболочку. Если мы не передаём никаких аргументов оболочке, поток выполнения переходит к . Чтобы понять, что он делает, нам нужно обратиться к его исходному коду. Мы можем найти его в Нам придётся прокрутить до самого низа, и там мы найдём определение функции ContentMain. Там мы видим, что она вызывает две функции. Одна инициализирует ContentMainRunner — класс, который обрабатывает всё «создание процессов» в контексте создания браузерного IPC, SQLite, сети и всего остального. А другая в основном проверяет тип подпроцессов и передаёт его классу ContentMainRunner. Теперь давайте сделаем шаг назад, чтобы понять поток кода. Сначала рассмотрим RunContentProcess, поскольку ContentMainRunner довольно сложен. Первое, что он делает, — создаёт GlobalActivityTracker. Омг !!! вы угадали, Google следит за вами :))) Нет, шучу, пожалуйста, не подавайте на меня в суд, Google. Но если серьёзно, он отслеживает каждый поток (это трекер потоков) и делает пару милых вещей для улучшения отладки, например: что по сути означает, что для каждого потока будет уникальное целое число, используемое в качестве идентификатора, чтобы лучше понять, что привело к падению процесса. напр.:``` kTypeIdActivityTracker = 0x5D7381AF + 4, // SHA1(ActivityTracker) v4 kTypeIdUserDataRecord = 0x615EDDD7 + 3, // SHA1(UserDataRecord) v3 kTypeIdGlobalLogMessage = 0x4CF434F9 + 1, // SHA1(GlobalLogMessage) v1 kTypeIdProcessDataRecord = kTypeIdUserDataRecord + 0x100,

root@kitploit:~
отслеживание стадии жизненного цикла процесса, которая определяется как```
// The phases are generic and may have meaning to the tracker.
PROCESS_PHASE_UNKNOWN = 0,
PROCESS_LAUNCHED = 1,
PROCESS_LAUNCH_FAILED = 2,
PROCESS_EXITED_CLEANLY = 10,
PROCESS_EXITED_WITH_CODE = 11,
// Add here whatever is useful for analysis.
PROCESS_SHUTDOWN_STARTED = 100,
PROCESS_MAIN_LOOP_STARTED = 101,

регистрируют как можно скорее выход процесса, сохраняют информацию о модуле, то есть когда загружается модуль (компонент Chromium), и, по сути, та же функциональность повторяется, но для разных потоков и классов. Если вам интересно, вы можете найти это в chromium/src/base/debug/activity_tracker.h
Затем проверяется, вызывалась ли "Main()" ранее. Я думаю, здесь имеется в виду, вызывалась ли ранее ChromeMain(). По сути, проверяется, были ли переданы какие-либо аргументы процессу контента, с которыми он был вызван. И если они были, они гарантируют, что процесс браузера получит те же аргументы. Затем они проверяют особенности платформы, и в случае обнаружения Windows инициализируют собственный обработчик с помощью CreateATLModuleIfNeeded, затем та же история: проверка особенностей платформы, и они передают аргументы с помощью SetupCRT, и мы доходим до части, где инициализируем IPC, чтобы можно было общаться с другими процессами после того, как мы их породили. Вот код, отвечающий за это. Мы не будем вдаваться в его подробности, так как вернёмся к этому позже и обсудим механизм IPC Chrome более детально. Пока просто знайте: это механизм, обеспечивающий взаимодействие между мультиархитектурными процессами Chrome. И если вы не знаете, что означает IPC, — это межпроцессное взаимодействие (inter process communication).
mojo.
Затем он «пересылает», а точнее задаёт аргументы для UI с помощью ui::RegisterPathProvider, вызывает трекер и получает результат через content_main_runner->Initialize(std::move(params)), создаёт родительскую консоль (я думаю, имеется в виду, что создаётся родительский процесс), выполняет ещё несколько проверок, и затем мы подходим к важной части: Capture2 .
Здесь мы видим вызов функции IsSubprocess. Capture3 По сути, чтобы избежать старого шаблонного кода, она в одной функции проверяет тип процесса, полученного из командной строки, и если был передан какой-либо параметр, она выбирает из следующего и создаёт соответствующий процесс.``` return type == switches::kGpuProcess || type == switches::kPpapiPluginProcess || type == switches::kRendererProcess || type == switches::kUtilityProcess || type == switches::kZygoteProcess;

root@kitploit:~
Оттуда мы переходим к `content_main_runner->Run();`, который по сути и делает всю магию. Давайте заглянем под капот. Итак, `content_main_runner` — это класс `ContentMainRunner`, ну.., который можно найти в `content\app\content_main_runner_impl.cc`  
Чтобы реально понять поток выполнения для этого, нам нужно рассматривать его снизу вверх. И, как уже было сказано, мы снова прокручиваем вниз и обнаруживаем, что на самом деле `ContentMainRunner::Create()` вызывает `ContentMainRunnerImpl::Create()`; что даёт нам понимание того, что на самом деле нам придётся искать определение `ContentMainRunnerImpl`, а не `ContentMainRunner`, которое мы находим в `content_main_runner_impl.h` в той же уже упомянутой папке.  
![Capture 4PNG](https://assets.kitploit.com/production/public/readmes/44338/e9d376e47b9cae2e6795e824b4205c91abf4347bfc1c39f9c4da9b4e282d2a47.png)  
Мы видим, что он наследуется от `ContentMainRunner`, и видны его основные методы. На самом деле здесь не так уж много всего, поскольку его поведение в основном переопределяется в `content_main_runner_impl.cc`
Внутри `content_main_runner_impl.cc`, внутри метода run, он сначала делает некоторые проверки с помощью `DCHECK` (что это за функция, чёрт возьми? (```The CHECK() macro will cause an immediate crash if its condition is not met. DCHECK() is like CHECK() but is only compiled in when DCHECK_IS_ON is true (debug builds and some bot configurations, but not end-user builds).``` цитаты из google docs :) )), чтобы убедиться, что установлены `is_initialized`, `content_main_params_`, `is_shutdown_`.  
![Capture6](https://assets.kitploit.com/production/public/readmes/44338/97a2fe6cd17558505598c61d0c4e410bab035cd1cb1909328e0128e0dcb38143.png)   
После этого он получает аргументы и определяет тип, о котором я упоминал ранее![Capture7](https://assets.kitploit.com/production/public/readmes/44338/e99107372da2e525f9097db604ed957d4e4c44d230d92bb3a3a030eb0a7f5bf8.png)  
Затем, в случае, если мы не можем его найти, мы вызываем `InitializeFieldTrialAndFeatureList()`  `delegate_->PostFieldTrialInitialization();` и отправляем это как сообщение через mojo.  
![Capture8](https://assets.kitploit.com/production/public/readmes/44338/838d2099d0f3df872fbcf756068da9305bf8ba93025988048a6a15b717169fe4.png) .  
Далее он устанавливает кое-что для ui![Capturze](https://assets.kitploit.com/production/public/readmes/44338/87c4249f834a3a9e235dbff90fe0810a6d441d074212d3c380f22b05de1a17d3.png)  
опять же на основе того, что было передано в командной строке, и вызывает `RegisterMainThreadFactories`, что является обёрткой для `RegisterUtilityMainThreadFactory`, которая только устанавливает `g_utility_main_thread_factory`, которая, судя по названию, создаёт главный поток, который является своего рода watcher'ом для остальных потоков, и наконец запускает браузерный процесс. ![Captu1re](https://assets.kitploit.com/production/public/readmes/44338/dae032f719f4c78e3d1e0a7564d10bbdb5861410393b5f8a7539ca3383001351.png)

Если вы мне не верите, вот Chromium, дизассемблированный в binja, и мы также увидим немного анализа памяти этого. 
Нам повезло: у нас есть chome.exe.pdb, который даёт нам отладочные символы, и нам не придётся мучиться при реверсе бинарника.
Поскольку мы работаем с chrome на windows, главной точкой входа для программы является wWinMain:
Вот как выглядит граф
![Captur3e](https://assets.kitploit.com/production/public/readmes/44338/eaa592d79ebca8ee99ab66cfcc2dfe0be97670d89f354514dd6d4a08b56b6826.png).  
Сама функция огромная, и поэтому я покажу только необходимые её части. После ряда инициализаций мы доходим до места, где вызывается `MakeMainDllLoader()`  
![Capture4](https://assets.kitploit.com/production/public/readmes/44338/d241275cc35a2beaaf9d3c62d25983471ec9e3027ff14307a9fa2e1605c3d337.png), а что она делает, мы уже объяснили. Итак, как нам динамически отладить chrome и доказать всё, что я уже упомянул? Сначала мы загружаем его в windbg, затем используем lm и ищем имя исполняемого файла. После этого мы ищем функцию с именем chrome!MakeMainDllLoader, ставим точку останова и позволяем выполнению идти.![Captu2re](https://assets.kitploit.com/production/public/readmes/44338/a337333caf8ad82226b6db8751ed4354ee04e02c66646fb417d84dbcd385584a.png). Заходим внутрь неё ![Captu11re](https://assets.kitploit.com/production/public/readmes/44338/7204fe3097ce7fead87ec6e763cd58b95577b06d7d4dc437cdd85c8917a5a23f.png) даём ей выполняться, пока она не дойдёт до ret, и выходим из неё, попадая в chrome!wWinMain+0x764 ![Captur33e](https://assets.kitploit.com/production/public/readmes/44338/0dffe422210e01aa2da14a3830c358ac38ddefddc32449d21ccb2ef84b4ed60a.png). Затем мы позволяем ей выполняться до chrome!MainDllLoader::Launch и входим в неё. Оттуда мы ставим bp на chrome!MainDllLoader::Load, чтобы увидеть, как chrome.dll загружается в память. И, как мы видим, одной из первых загруженных вещей была chrome.dll ![Captu123re](https://assets.kitploit.com/production/public/readmes/44338/592d31f64ced75f56dfb16ae9fcddf0404ae4e625b7a55ada0422e125de984e3.png) Отсюда ход анализа тот же, и полный анализ памяти останется как упражнение для читателя. Для особой цели я выполню анализ до того момента, когда процесс content почти завершён, и прямо перед запуском браузерного процесса я остановлюсь. Цель этого — просто показать, как ipc начинает взаимодействовать между процессами. Теперь после загрузки dll нам нужно найти инструкцию call rax. Я вывел 0x40 инструкций из текущего eip после загрузки dll.![Captur123e](https://assets.kitploit.com/production/public/readmes/44338/899f6fb7532d0914f486c10f15bd10df0538ac530a64cd31bafa8bfc258c6a64.png). По этому адресу находится то, что мы ищем, а именно chrome!ChromeMain.![Capture123123](https://assets.kitploit.com/production/public/readmes/44338/0bd3b9459247450b124bc84d82e2fe99784b47ff28de673f64bf8695db945d96.png)
Оттуда мы хотим поставить точку останова на ![zCapture](https://assets.kitploit.com/production/public/readmes/44338/54fe080cf64daba53afb58c6ad40057408ebc79120b45adba7691fc534d33578.png), что по сути является большой проверкой перед переходом в content!content::ContentMain. Оттуда мы хотим перейти через несколько инструкций и попасть в content!content::ContentMain. Мы хотим войти внутрь и остановиться на content!content::RunContentProcess![Captuare](https://assets.kitploit.com/production/public/readmes/44338/bd16901788ef952a6f7165f90082abf6618f392bea6de968d24062590db681d2.png) мы хотим войти внутрь и поставить bp на content!content::ContentMainRunnerImpl::Run+0x430, и как только мы перешагнём через ![Capture442](https://assets.kitploit.com/production/public/readmes/44338/30ac05cc6d66cca61b8d471983093be82e4cd6dd93318ad2696c642bad841933.png) мы видим запуск mojo ipc и делаем вывод, что следующий процесс, а именно браузерный процесс, отвечает за фактическую реализацию браузера и обработку всех остальных процессов.![Captu1243re](https://assets.kitploit.com/production/public/readmes/44338/684e3466f25b57c74e3f1d48013f94157bc7b4058dd31ce5cfc2613966563c9d.png) 

===============================================================================================

2.
В прошлый раз мы остановились после понимания content-процесса. Сегодня мы займёмся браузерным процессом.
Это процесс, который запускается после content-процесса, и это второй процесс из запускаемых chrome.
Давайте кратко его опишем:
* Мы можем считать его основным процессом, поскольку content-процесс — это скорее процедура инициализации и проверка зависимостей, и он запускается content-процессом.
* Он остаётся живым на протяжении всего времени жизни браузера.
* Он является центральным координатором всех процессов и работает с наивысшим уровнем привилегий, доступным браузеру.
* Поскольку он работает с наивысшими привилегиями, в случае, если другим процессам нужно выполнить операцию более высокого уровня, этот запрос обрабатывается браузерным процессом.
* Он управляет такими функциями, как адресная строка, закладки и кнопки назад/вперёд/перезагрузки. Поскольку это самый привилегированный процесс, он не доверяет данным, переданным ему любым из других процессов.
* Также обрабатывает привилегированные операции, такие как UI, сеть или файловое хранилище, для других процессов при необходимости.  
Теперь, когда мы вкратце знаем, что он делает, пора углубиться в него:
Наш путь начинается в `src\content\app` в файле под названием content_main_runner_impl.cc, в функции `int ContentMainRunnerImpl::RunBrowser(MainFunctionParams main_params,bool start_minimal_browser)`, и первой операцией, которую она выполняет, как мы видим, является `TRACE_EVENT_INSTANT0`![Captureq](https://assets.kitploit.com/production/public/readmes/44338/a00d341147931a7d9de17cec692eeb0b695feca87309a6f0ba3700517e5d13dd.png) .  
Что это? И вообще, что такое trace-функция? Если мы перейдём по ссылке https://lwn.net/Articles/379903/, то увидим, что они определяют это так ![Captur12348e](https://assets.kitploit.com/production/public/readmes/44338/c9f56f4e9bdcdd919eb5d3962909a3faa878ac5681a9227e92b27eb865bff5d8.png), немного абстрагируясь, мы можем прийти к выводу, что trace-функция — это функция, которая записывает данные в конкретной точке кадра стека. Она делает не только запись стека выполнения функции, но и может записывать локальные переменные последней выполненной функции. Теперь, когда мы знаем, что такое trace-функция, посмотрим, что делает наша. 
Если мы перейдём по ссылке https://chromium.googlesource.com/chromium/src/base/trace_event/common/+/refs/heads/main/trace_event_common.h, то увидим, что они определяют её как функцию, единственная цель которой — «отслеживание производительности приложения и использования ресурсов». Углубляясь дальше, чтобы понять, что она делает, мы видим, что это макрос, и он определён так ![Captureqq](https://assets.kitploit.com/production/public/readmes/44338/21eedc48fe46a60b7d3993678c5cad552353145afbc46c16d3272e92a9046be1.png). Чуть выше макроса мы видим краткое определение, которое говорит, что он немедленно записывает одно событие с именем «name» с 0, 1 или 2 аргументами. И если категория соответствующего события не включена, он ничего не делает. Мы видим, что в качестве параметров у нас есть «startup» как основная категория, и как подсистема — «ContentMainRunnerImpl::RunBrowser(begin)», а третий параметр — `TRACE_EVENT_SCOPE_THREAD`, который равен `#define TRACE_EVENT_SCOPE_THREAD (static_cast<unsigned char>(2 << 2))`; я думаю, что, судя по значению, это идентификатор соответствующего мгновенного события. По сути, это просто трассирует (логирует) тот факт, что мы вошли в функцию RunBrowser. Затем у нас есть проверка, запущен ли уже главный цикл браузера, и если он уже запущен, мы выходим из функции ![Capturage](https://assets.kitploit.com/production/public/readmes/44338/7641b12af010d647dbadb291d12ca0c20b3c7a2170cefe05fbff2cfb6f609c88.png) . Затем мы устанавливаем флаг, и после этого мы попадаем в довольно интересную часть кода. Мы проверяем, есть ли поддержка механизма mojo_ipc, и если есть, мы используем ShouldCreateFeatureList, который создаёт список функций с разными процессами, пытается их инициализировать и, наконец, пытается инициализировать функции mojo.![Capture123123123](https://assets.kitploit.com/production/public/readmes/44338/7bc27c995b7db489dee90771343bfea5effc59c3da26c128dd78421d322030c0.png). Затем мы создаём пул потоков.![Captur``e](https://assets.kitploit.com/production/public/readmes/44338/f7f16fc6636f9f6340816a2be60cade841ed3524db4936f58347c203b43a2f3c.png) Что такое пул потоков?!? Цитируя википедию: «паттерн проектирования программного обеспечения для достижения параллелизма выполнения в компьютерной программе». Более корректно объясняется так: «пул потоков поддерживает несколько потоков, ожидающих задачи для параллельного выполнения под управлением супервизорной программы» (это тоже цитата из википедии). Если объяснить более наглядно, представьте две линии людей, работающих на фабрике. Назовём их линия a и линия b. Все они управляются начальником. Назовём его линия c. Теперь линия b должна ждать, пока линия a закончит свою работу, и получить уведомление от линии c, чтобы начать работать. То же самое касается линии a. И это пул потоков. Вот также небольшой пример на C ![Captuqweqre](https://assets.kitploit.com/production/public/readmes/44338/8e536782a06d3d08683f7714499c1c2d51747e7253e3b972e657babe4aeb5413.png). Это бесстыдно взято с https://stackoverflow.com/questions/15752659/thread-pooling-in-c11 . Далее у нас есть вызов `PreBrowserMain();`, который выполняет некоторую специфичную для платформы инициализацию, и после этого мы доходим до момента, где вызывается `BrowserTaskExecutor::Create()`;  
![Capture](https://assets.kitploit.com/production/public/readmes/44338/5f93ce2d99e7357045a446799952dfb74422a1f91293c1fe60ac280784b63a54.png). Давайте подробно разберём, что он делает, так как имя довольно интересное, и, полагаясь на обоснованное предположение, можно понять, что это может быть интересно. Наш обходной путь начинается внутри файла content/browser/scheduler/browser_task_executor.h, где мы обнаруживаем, что `BrowserTaskExecutor` — это класс, который должен «сопоставлять base::TaskTraits с фактическими очередями задач для браузерного процесса». Пройдём немного дальше по файлу, и сначала мы видим  ![Capturea](https://assets.kitploit.com/production/public/readmes/44338/2afcfd256eb9112346bf7d2486b5a006dcd783b43738e3a9db669650c9808768.png) он наследуется от `BaseBrowserTaskExecutor`. Теперь, чтобы понять, что такое `BrowserTaskExecutor`, нужно понять `BaseBrowserTaskExecutor`. Мы видим, что он наследуется от `TaskExecutor`. К счастью для нас, мы видим, что он переопределяет методы `TaskExecutor` с переопределяемым свойством, что означает, что они будут переопределены другими вызовами методов позже. Но для любопытных: мы можем найти его в base/task/task_executor.h, и если мы его изучим, то узнаем, что `TaskExecutor` — это класс, который «может выполнять Tasks с определённым идентификатором расширения TaskTraits» ![Captureb](https://assets.kitploit.com/production/public/readmes/44338/99ed031aad78ad64ec17e4d109850f4be243342074bd46f9ecd1494be7e7b82f.png)  .  
Что такое task и что такое tasktraits. Мы уже упоминали, что такое task, но для освежения: это один из процессов chrome, а теперь что такое TaskTraits? Они находятся в base/task/task_traits.h и определяются следующим образом: «инкапсулируют информацию о задаче, которая помогает пулу потоков принимать лучшие решения о планировании». Возвращаясь к нашему `BrowserTaskExecutor`. Метод, который мы вызываем, — это Create(), и его анализ выглядит следующим образом ![browsertask_create](https://assets.kitploit.com/production/public/readmes/44338/c8cf0292e6e94a4681eaa19b9b2376c1a883ccf3ef627b6b7601cda246337c85.png) 
сначала проверяется, нужно ли выполнять текущую задачу из SingleThreadTaskRunner. То есть нужно ли выполнять эту задачу с использованием независимого потока. Мы делаем это, получая указатель на tls. Затем мы инициализируем ui и потоковый планировщик. По сути, здесь мы инициализируем планировщик для будущих событий, связанных с ui.![browser2](https://assets.kitploit.com/production/public/readmes/44338/8c060bc8985259819bb6d06d5f4e3cc9f6934e0e18a6242b86fdc7100975a060.png).  
И это всё для этой функции. Продолжая анализ content_main_runner_impl.cc, мы переходим сюда.![CreateVariationsIdsProvider](https://assets.kitploit.com/production/public/readmes/44338/d74fd0ea150a2217f8add998c72736864714acd35f7d83f0dd9c219f60b46441.png)  
Ищем файл класса variations ids provider, мы находим его в `components/variations/variations_ids_provider.h`, и там видим кое-что довольно интересное. Он включает файл `.mojom.h`. Его определение можно найти в `Debug/gen/components/variations/` variations.mojom.h, что означает, что он относится к механизму ipc. Теперь, просматривая фактическое определение класса, мы видим комментарий, который гласит: «Вспомогательный класс для поддержания состояния клиентских экспериментов и метрик, передаваемых в пользовательских HTTP-заголовках запросов». Изучив его поведение и исходное определение, мы делаем вывод, что он просто используется как маркер для функции, который отмечает, что «параметр signed-in передаётся в GetClientDataHeaders()», что означает, что где-то в стеке выполнения есть вызов GetClientDataHeaders, и позже он будет вызван с параметром. Затем мы выполняем     `delegate_->PostEarlyInitialization(!!main_params.ui_task);`, что просто отправляет через mojo ipc сообщение о необходимости запуска задач ui. Мы делаем ещё инициализацию ![b](https://assets.kitploit.com/production/public/readmes/44338/5bbff517ff5783f1c180bb958543735aeca90d562c9bf261bea81a35b2ff713b.png) и затем переходим к вызову RunBrowserProcessMain. ![a](https://assets.kitploit.com/production/public/readmes/44338/03a4459cbeb526e7a5e8d8a89e4829411647b8ca58d1692c116c353499bacaf6.png) . Если вы, как и я, надеялись, что именно здесь мы увидим запуск gui, вы ошибаетесь. Цитата от мастера Угвея ![8ae6dca28db7d3afa6f483349c879962a437435d3e852e3fea35ef422acb95c1_3](https://assets.kitploit.com/production/public/readmes/44338/9b4c6b1664c8747f4093bc7c739bdd560c234e3f2cb4648ca3314f36eac82708.jpg). Затем мы идём и делаем ещё несколько проверок, и мы попадаем в BrowserMain![c](https://assets.kitploit.com/production/public/readmes/44338/f5377d34d6990bd090884c7ce476f9f2cda4b67fd4d7c4f035cae5f0ee59fabd.png). Проходя по нему, он выполняет некоторую трассировку, и затем мы попадаем в![init](https://assets.kitploit.com/production/public/readmes/44338/120c08c504cfc2cb6bf6f2d7e4486eb0507e8e86c83d08a1d4adb7491c41e465.png) место, где мы фактически запускаем gui. Теперь, если вы мне не верите, вам придётся немного потерпеть до динамического анализа. Затем мы переходим к методу Run, который как раз то, что нам интересно, а после него мы перейдём к следующему пункту понимания браузерного процесса. Но пока давайте сделаем ещё один короткий крюк и исследуем, как создаётся метод Initialize. Сразу видно, что он трассирует выполнение метода init, и перед этим создаёт гистограмму![Capturez](https://assets.kitploit.com/production/public/readmes/44338/61086f31ec19789871368cf64034bdad22045c4aac46a8779a707150b4682a9e.png). Затем мы проверяем флаг initialization_started_, чтобы увидеть, дошли ли мы до стадии инициализации, и если нет, мы инициализируем skia — графическую библиотеку, используемую chrome, запускаем «таймер» для подсчёта секунд, потраченных на выполнение этого метода, для последующего использования в гистограмме, проверяем, передали ли мы бинарю параметр ожидания подключения отладчика к процессу, и, наконец, запускаем notification_service_, который, по обоснованному предположению, уведомит главный watcher пула потоков о том, когда запускать сервис. ![Captureaaa](https://assets.kitploit.com/production/public/readmes/44338/cce1c5850fc1c34bebd75e905ba733d1f46ddaab581bed2b6f2f5016c81bcac0.png). Затем мы инициализируем необходимые шрифты для chrome и создаём mainbrowserloop, который является координатором всех процессов, и мы перепрыгиваем через три метода, которые не представляют для нас интереса:

  main_loop_->CreateStartupTasks();
  int result_code = main_loop_->GetResultCode(); 

отсюда нам интересно зайти в CreateStartupTasks. Оттуда мы смотрим на content\browser\browser_main_loop.cc, нас интересует   startup_task_runner_->RunAllTasksNow();, который находится внутри метода CreateStartupTasks. startup_task_runner_ — это `StartupTaskRunner`, который находится в том же каталоге внутри файла startup_task_runner.cc. Теперь, если мы изучим метод RunAllTasksNow, мы увидим, что он просто перебирает все задачи и выполняет их![run](https://assets.kitploit.com/production/public/readmes/44338/3a4991537194491011f922d45981a178c4fe40c3e6f19533750bc07490d13370.png)

 ==========================================================================================
         Время для динамического анализаТеперь, чтобы поймать рендерер, нам нужно будет запустить бинарник в windbg. Это легко достигается через File->Open Executable и передачей --renderer-startup-dialog --no-sandbox --wait-for-debugger-children=renderer --renderer-process-limit=1 в качестве аргументов.![start](https://assets.kitploit.com/production/public/readmes/44338/622dfa07937a4b2f8f347b92110d8f80c93782c8c2419ead5ced38797a52e41b.png). Затем мы ставим bp на content!content::StartupTaskRunner::RunAllTasksNow+0x88, чтобы поймать IPC-сообщения и позже рендерер. Просто для справки: так должен выглядеть ваш отладчик после однократного запуска ![content](https://assets.kitploit.com/production/public/readmes/44338/c675643ca1a6ab2ab4e010b4bc2fc544070a9dea29450c6ce672329c6504474f.png) . Вы должны увидеть сообщение о том, что Chrome запущен в полноценном браузерном режиме. Оттуда вы считаете от одного до пяти, то есть запускаете его ещё четыре раза. И тогда вы должны увидеть что-то вроде ![debuugz](https://assets.kitploit.com/production/public/readmes/44338/dbd42e19a6f1c7c66d9302868af8517395db1203d4201ada448deae6c7d65082.png). Я рекомендую использовать procmon, чтобы вы могли отслеживать процесс рендерера при его запуске. После этого вы подключаете его к другому отладчику, и если вы использовали указанные выше аргументы, вы должны увидеть всплывающее окно с PID рендерера![helk](https://assets.kitploit.com/production/public/readmes/44338/6eceef790edb2a7b4c9f1c1c0a6ddaf8e5943193f6d6c2678b7985a159d88193.png). Оттуда вы захотите поставить bp на base!base::RunLoop::Run. К сожалению, по какой-то причине нельзя поставить breakpoint на content!content::RendererMain. Возможно, потому что мы подключаемся к процессу сразу после того, как он выходит из функции RendererMain, и он выполняется потоком. В любом случае, вот как выглядит IPC после четырёх запусков.![ipc1](https://assets.kitploit.com/production/public/readmes/44338/f3ecb9c43685a150e1b030e45b3409fde22f73caf8cb3e65ad3749283fe5190e.png). Это указывает на то, что GUI запущен. А вот как выглядит IPC после запуска процесса рендерера.![renderer4](https://assets.kitploit.com/production/public/readmes/44338/88cba847d07fdf5fff64022151e616c38b40b6869669b57b697c4e4704a55e21.png). Затем мы ставим bp на 
content!content::StartupTaskRunner::RunAllTasksNow+0x88 и content!content::RunOtherNamedProcessTypeMain. Пусть он работает.

 
 ============================================================================================================
 
 3. Теперь, что касается второй части анализа процесса браузера: мы дошли до момента, когда сможем понимать и отлаживать рендерер, но пока не пойдём туда. Я специально оставил ещё одну функцию для анализа после RunBrowserProcessMain — теоретически она идёт после RunBrowser, но, как вы помните, RunBrowser — это обёртка над RunBrowserProcessMain. Итак, я оставил за кадром то, что в файле content_main_runner_impl.cc в папке src/content/app есть ещё одна функция, которая вызывается после того, как мы порождаем рендерер, и называется RunOtherNamedProcessTypeMain. Этот процесс отвечает за запуск всех остальных процессов.![Captureother](https://assets.kitploit.com/production/public/readmes/44338/ff1888433235c48d23fff69a795e2c82dec9ddb5c1e82cd87faabe75264c0aa8.png). Теперь давайте разберёмся, что происходит в коде. Мы видим, что её прототип выглядит так ![Capturzaqe](https://assets.kitploit.com/production/public/readmes/44338/11ccd1d1fb5002f660d12b22b2f07c818fe33bcd8547fcd3433b998c88aaec80.png), что указывает на то, что она принимает аргументы, переданные в cmdline, ожидаемый тип процесса и делегат Chrome. Затем мы переходим к началу функции, где есть макроопределение для проверки особенностей платформы и определения, для какого процесса создавать обработчик событий. То есть проверяется, выполняет ли она некие функции для консольного процесса или для процесса браузера. ![Capturqqqqqqqqe](https://assets.kitploit.com/production/public/readmes/44338/2d3a600011753b06d460126b40b0efc7d9d037665d1cecaf6157a56828644faa.png). Затем мы итерируем по переданным процессам, сравниваем со списком известных процессов и запускаем соответствующий процесс. ![Captuqaxzcre](https://assets.kitploit.com/production/public/readmes/44338/8806bd2644c3f2403b720e3ab145c05228d2f876549c3220e8e30cc3fbde7e92.png) Если мы не находим соответствующий процесс, значит, это кастомный процесс, реализованный кем-то.![Captureshaveica](https://assets.kitploit.com/production/public/readmes/44338/8e6f6ac907e65b05431214e4a65eb4284683b9b5a6c747dedfcbc64f978daaf0.png)
Вот ссылка на реализацию кастомного процесса, и мы будем использовать этот пример для второй части динамического анализа. https://bitbucket.org/chromiumembedded/cef/wiki/Tutorial . 

=====================================================================

Динамический анализ
 
Первая часть динамического анализа начинается так: сначала запустите из cmd.exe с правами администратора следующую команду: windbg.exe chrome.exe -G -o --renderer-startup-dialog --no-sandbox --wait-for-debugger-children=renderer --renderer-process-limit=1 --allow-pre-commit-input --allow-sandbox-debugging . После этого установите .childdbg 1, чтобы мы могли отлаживать новые порождённые дочерние процессы. По сути, приведённая выше команда означает «убедиться, что вы подключены ко всем дочерним процессам». Отдельное спасибо @spoofyroot и @_coreDump за то, что указали мне правильное направление в многопроцессной отладке. Вот как это должно выглядеть после установки .childdbg 1 ![debugzzzzzz](https://assets.kitploit.com/production/public/readmes/44338/768870a772194a3f32a00be9ed2b7b2e17f5d7253da51975309a1125680ce119.png) Так как мне не удалось каким-либо другим способом запечатлеть, что происходит дальше, я снял видео, в котором объясню, что происходит дальше. https://streamable.com/9t4iof . По сути, после того как мы в последний раз запускаем content!content::StartupTaskRunner::RunAllTasksNow+0x88, мы порождаем новые процессы, которые обрабатывают некоторые IPC-вещи, и нам придётся продолжать ставить bp на content!content::RunContentProcess, пока он не сработает. Это то, что я называю «осознанным методом проб и ошибок» :)) . 

 
=====================================================================

4. Анализ рендерера
 
!Дисклеймер
    Хотя мы будем анализировать код рендерера, мы также немного окунёмся в код Blink, чтобы правильно понять, что происходит в рендерере.

Пока я писал эту часть курса, я понял, что забыл кратко описать, что это такое и зачем мы вообще в это смотрим. Как мы знаем, это третий процесс, запускаемый Chromium, и он называется рендерером. Но почему он называется «рендерером»? Он так называется потому, что его работа — рендерить (рисовать) всё, что мы видим на веб-сайте. По сути, это причина, по которой ваша таблица выглядит как таблица, когда вы заходите на веб-сайт, или ваш CSS позволяет настраивать фрагмент текста. Или почему ваш JS способен творить чёрную магию*. Ещё одна важная причина, по которой мы анализируем это, — именно отсюда берётся большинство багов. Будь то HTML, CSS, JS или любой другой компонент, все они находятся в разделе Blink на chrome bugs.chromium.org.

   
* Существует несколько процессов рендерера. Отдельный процесс для каждой вкладки, открытой в данный момент в браузере.
 
* Этот процесс управляет всем, что находится внутри самой вкладки веб-сайта.
 
* Начиная с 2018 года iframe получил обновление, благодаря которому все они могут иметь вкладки. И каждая вкладка iframe имеет отдельный процесс рендерера. Это называется Site-Isolation.
* Его задача — разбирать веб-сайт, отрисовывать на экране то, что находится внутри веб-сайта, например таблицы, изображения, а также выполнять JavaScript.
* Он находится в песочнице (sandbox).
* В его основе лежит движок рендеринга под названием Blink.
* Создаёт и обрабатывает схемы URL, такие как: chrome://, devtools://, chrome-error://.
* Инициализирует движок Blink, который фактически выполняет весь парсинг и основную работу для процесса рендерера.
 
 
В прошлый раз мы завершили анализ процесса браузера, и теперь настал момент, которого все мы ждали, — перейти к анализу рендерера. Когда я экспериментировал с Chromium, мне удалось вызвать крах, и я получил следующий стек-трейс. ![numberunu](https://assets.kitploit.com/production/public/readmes/44338/f2630f0d90cc14b1cd00e65da78a62e6879789c2bbd76914cf96a60e7598ce7d.png) Исходя из этого, мы знаем, что наш путь начинается с content::RendererMain, который находится в `\content\renderer\renderer_main.cc` . Как вы догадались, отправная точка — RendererMain. Давайте начнём с анализа того, как она определена, и немного заглянем внутрь неё ![rendereranalysis](https://assets.kitploit.com/production/public/readmes/44338/2a5dd98c5dee7df60650563bf0c07d9fc7fcba9322a81ef46f1a4b57a7dfe5be.png) . Мы видим, что она принимает параметр типа MainFunctionParams, что означает, что эта функция принимает переданные бинарнику аргументы. Далее мы добавляем точку трассировки, чтобы знать, что мы дошли до вызова RendererMain, а затем разыменовываем значение parameters и сохраняем его в command_line. Затем у нас есть несколько макросов, которые проверяют специфичную для платформы архитектуру, которые мы можем игнорировать  ![macro](https://assets.kitploit.com/production/public/readmes/44338/bc66a44c8a54f70658fcddae67df178adb913d01feec405cedbe4ddb5d16eac6.png), мы проверяем значение, переданное в kTimeZoneForTesting, — это часовой пояс для тестирования, а затем мы знакомимся с новым классом и типом данных под названием ICU. 
 ![habarnam](https://assets.kitploit.com/production/public/readmes/44338/d289a7befe64a2b1114f8e06266ba6475f7db0ef4ac356a522911e861fa75c08.png)
Теперь, если мы поищем, где находится определение этого, мы приходим на https://unicode-org.github.io/icu-docs . Если мы посмотрим на начало файла, где находится директива include, мы увидим, что это сторонняя библиотека. Итак, до сих пор мы знаем, что это сторонняя библиотека, которая занимается интернациональными компонентами для Unicode, то есть мы используем её для поддержки Unicode. Ок, но что делает эта функция? Заглянув на https://unicode-org.github.io/icu-docs , мы видим ![icu](https://assets.kitploit.com/production/public/readmes/44338/ad73d2a9b1d8656816f2982cc6587a14bce9766251fc64430cb313789b46f4ee.png), то есть она устанавливает часовой пояс по умолчанию на основе того, что мы передали в качестве параметров. Затем мы инициализируем библиотеку Skia и обрабатываем --renderer-startup-dialog 
![curumare](https://assets.kitploit.com/production/public/readmes/44338/702d8f539ca85edb1ae59697341a01f04389e06e6e498e7a1334cfad02e252e2.png). Затем нас встречает новый класс RendererMainPlatformDelegate.![delegaterenderer](https://assets.kitploit.com/production/public/readmes/44338/d731ed1f19a1fafea38b72fa2e1497290d67e08401df5edfc28399ff6ea5a740.png)

Что это делает? Что ж, во-первых, нужно уточнить, что это абстрактный класс, зависящий от платформы. В нашем случае он находится в /content/renderer внутри файла renderer_main_platform_delegate_win.cc . Выглядит он так 
 ![rendererhelper](https://assets.kitploit.com/production/public/readmes/44338/0485301ff6d305f624279d1a525f1c825089f0e3ff3a7f0085eb5ad7392fbd24.png). Итак, мы можем заключить, что это вспомогательная функция, которая включает sandbox, а в случае передачи --no-sandbox выполняет необходимые действия — и на этом всё. Затем мы устанавливаем имя нашего потока в CrRendererMain![name](https://assets.kitploit.com/production/public/readmes/44338/742fe969e84708598663853d3c02f4cc59018df41e333cc9ec91dd17e49a2ad5.png). Затем мы встречаем ещё один новый класс под названием RenderThread. ![renderthread](https://assets.kitploit.com/production/public/readmes/44338/6e55410f6d599d6d150e2919462909dbe2420662a068fac9f2699c0d8878f4d4.png)
Опять же, поскольку мы в основном не знаем, что он делает, давайте немного его изучим. Наш путь к пониманию того, как выглядит RendererThread, начинается с content/public/renderer/render_thread.h. Заглянув внутрь файла render_thread.h, мы видим, что он определён так ![fain_de_an](https://assets.kitploit.com/production/public/readmes/44338/e7d383ccbcabd6ae781af9e4d17a8ab917e98907506b371bc93f45e78e630c73.png). Из всего этого файла нас интересует IsMainThread, который определён в файле rendere_thread.cc и выглядит так ![rendererrrrr](https://assets.kitploit.com/production/public/readmes/44338/63f12c226fa518ad874a559c04f45a8c786aeec8a8fd718eccd559e680b15aee.png) (добавить длинное описание этого механизма). Продолжая анализ кода рендерера, мы видим самый ожидаемый момент: наконец-то мы видим код Blink. Первый из них — он инициализирует библиотеку.![blink](https://assets.kitploit.com/production/public/readmes/44338/fb534f9bde56b9c68d0c05f815ef94e4c7bbf5cddcb16bbfaaff56a75156f21c.png). За кулисами функция выглядит так ![blink2](https://assets.kitploit.com/production/public/readmes/44338/f53753b2451d0f753ed3923a05c359a28735348873cd4671da761778502d6672.png). Теперь возникает естественный вопрос: что это за классы, чёрт возьми? Что такое WTF и Platform. К счастью, документация Blink действительно рассказывает нам, что это.
 https://docs.google.com/document/d/1aitSOucL0VHZa9Z2vbRJSyAIsAz24kX8LFByQ5xQnUg/edit . Глядя на «Directory structure and dependencies», мы можем сделать вывод, что platform — это класс, который помогает с геометрией и графикой. Теперь о классах WTF и Partitions. Документация Blink также говорит о WTF: он происходит из Web Template Framework и в значительной степени является «обёрткой» над STL-библиотекой, например: «это базовая библиотека для Blink, предоставляющая множество базовых функциональностей, таких как контейнеры, строковые библиотеки, механизмы подсчёта ссылок, функторы, примитивы потоков и т.д.» (цитаты из документации Blink (https://chromium.googlesource.com/chromium/src/+/refs/heads/main/third_party/blink/renderer/platform/wtf/README.md)).Добавь ещё деталей о Blink.
 Ок, продолжая анализ renderer_main.cc, мы снова видим нечто, о чём мы не знаем, что оно делает, и это ![schedulerchrome](https://assets.kitploit.com/production/public/readmes/44338/55024776fdbf2c9495b0266d28ae8433538497624724504a4903601b792fb983.png) Добавь детали завтра.Затем мы вызываем ![a;a](https://assets.kitploit.com/production/public/readmes/44338/f2a61eaa5512e8ac3badfbc780f86c342cafda8372af2f6c008cb80507fa4e9c.png).Затем мы проверяем, включили ли мы поддержку плагинов при компиляции, и если да — загружаем их.
![huila](https://assets.kitploit.com/production/public/readmes/44338/7b51d932acce11c8d367808a938f5c8af4a9f8e9720dd9321bdc05237485d2aa.png) Затем мы выполняем ещё несколько проверок, которые я решил пропустить, потому что объяснение становится довольно длинным, и на данном этапе они не обязательны. Но в версии TL;DR это проверка того, включать ли sandbox перед инициализацией RenderProcess.И затем мы наконец добираемся до  ![final](https://assets.kitploit.com/production/public/readmes/44338/1e4ea62032e862e25736f59014bfc8e8903a2007a75b6b77d27878e33ecd48b6.png). (добавь остальные детали об остальных функциях). Хотя это и не конец анализа рендерера, мы можем считать это отправной точкой собственно анализа рендерера, потому что, как мы увидим позже, здесь происходит большая часть интересного, так что можно считать это кодом рендерера. Нас интересует RenderThreadImpl, который выглядит так ![bitch_please](https://assets.kitploit.com/production/public/readmes/44338/d58479f510698f2a27ebb3cf15387fb4f5a8970a165d4c451e01fb2d83b536ef.png). Из всего этого кода нас интересует функция Init(), которая выглядит так:
 ![yeee](https://assets.kitploit.com/production/public/readmes/44338/5f7e2779325766d3a7a367a6fe7b4388014cc921b27d0645a762d558ba790238.png), но она гораздо длиннее. :) К сожалению, мы не можем захватить её на одном скриншоте, поэтому мы захватили её начало. Кроме того, всё, что происходит после InitializeWebKit(), не очень нас интересует, поскольку большая часть этого — просто IPC-общение с GPU-процессом, который сейчас не в нашем поле зрения. Нам улыбнулась удача, потому что в этой функции мы также поймали одну из интересующих нас функций, а именно InitializeWebKit(), которая опять же выглядит так ![blink3](https://assets.kitploit.com/production/public/readmes/44338/db3ea73c39662df6c46b3ca99039a029da60ced698b23a3d4870cd19aa56cfd0.png). Мы немного отклонимся от нашей задачи объяснения renderer_main.cc, чтобы лучше понять, что происходит внутри InitializeWebKit. Я знаю, что это сложно понять, но потерпите, пока мы пытаемся навести порядок в этом бардаке. Итак, мы видим, что InitializeWebKit() начинается с взятия всех аргументов, переданных этому процессу, затем мы проверяем, включили ли мы при компиляции -dENABLE_VTUNE_JIT_INTERFACE, и если да, то проверяем переданный в cmdline параметр enable-vtune-support. Что это за хрень? Мы поискали в Google и нашли ссылку на https://www.intel.com/content/www/us/en/develop/documentation/vtune-help/top.html , и на этой странице сказано: «это инструмент анализа производительности для последовательных и многопоточных приложений». Так что, TL;DR, это то, что улучшает производительность вашего Chrome.Затем мы инициализируем Blink ![blininit](https://assets.kitploit.com/production/public/readmes/44338/adf0c7b62a95e9fb9b9ab173000234c79d6371c53585555597069d7ee8059b9b.png). Теперь, чтобы понять процесс инициализации Blink, давайте кратко объясним, поскольку в следующей главе мы рассмотрим Blink подробно. Нас встречает ещё один незнакомый класс — RendererBlinkPlatformImpl, который выглядит так 
![RENDERETHREADINML](https://assets.kitploit.com/production/public/readmes/44338/f274dbb509aee456eda88dd3734c7967183e0a79b4fd15f5390648a176bcf3cd.png) и находится в 
 content/renderer/renderer_blink_platform_impl.cc . Исходя из названия, мы можем заключить, что это абстрактный класс, который реализуется в зависимости от платформы, и мы также видим, что он наследуется от ![muielumii](https://assets.kitploit.com/production/public/readmes/44338/e99ee9bc21c9dfdec8da178d025c9e2661a92d192625cfc86ce1073bf62cacd4.png) Просматривая, что именно делает RendererBlinkPlatformImpl, мы видим, что он проверяет платформу и затем по результатам проверки устанавливает флаг![kacl](https://assets.kitploit.com/production/public/readmes/44338/9d27c89e80d496dd6e1f48eac0dc89fc9f86c3d2203af5a4e66967cf42000521.png), затем проверяет, является ли текущий поток RendererThread, получая указатель на TLS.


 бла-бла-бла, посмотри, добавить ли ещё контента о классах. Затем мы приходим к тому, чего все мы, возможно, ждали, — это первый кусок кода V8. Вот он ![v8](https://assets.kitploit.com/production/public/readmes/44338/9a7cad1284388b39bdc4a690d51e1bc110edae1d2f3f94513615a333276ca800.png). Что это делает? Прежде всего, мы знаем из документации, что v8::isolate — это экземпляр движка V8. То есть (независимая копия V8 runtime, включая менеджер кучи, сборщик мусора и т.д.), которой недостаточно для выполнения скриптов. Мы видим, что blink::MainThreadIsolate() определён как 
 ![diablo](https://assets.kitploit.com/production/public/readmes/44338/a906a0b07c5591d66c677458b6bbc0b0593e2ea45501fc027a5bdd52a42e715a.png), который находится в файле blink/renderer/platform/bindings/v8_per_isolate_data.cc , и в свою очередь V8PerIsolateData::MainThreadIsolate() выглядит так 
 ![v8x](https://assets.kitploit.com/production/public/readmes/44338/2a7c9d9cf93bbd7fe5f5f40450d8c8ec62f236ca2e210404d895ae7ad26000ca.png) , V8PerIsolateData, который, как вы догадались, тоже является классом, находится в bindings/core/v8/V8PerIsolateData.h и выглядит примерно так ![ahahah](https://assets.kitploit.com/production/public/readmes/44338/14149464fb2f7ccc2775f46a5bb8ad52cacfa21d764084b814cf894e1bccb67e.png)бла-бла-бла, добавь детали. Затем мы проверяем, передали ли мы kDisableThreadedCompositing (завтра добавь, как на самом деле выглядит флаг) в командную строку![compositor](https://assets.kitploit.com/production/public/readmes/44338/a075f0ab5e33b80fc423277d5480fd0819a2bad2e8ea383e7d7a8982b66a6096.png). Если нет — мы запускаем поток компоновщика. Что это такое? Цитируя https://frontendmasters.com/courses/web-performance/the-compositor-thread/ , это поток, чья «единственная задача — рисовать битмапы, отправлять их на GPU и выводить на экран». Затем мы регистрируем так называемую схему.![scheme](https://assets.kitploit.com/production/public/readmes/44338/255b57a5b7b3859d64dbfa1e19c469a3b06ad3b731788d137598d2d623ad2b33.png) В принципе, помните, когда вы просматриваете исходный код, перед URL есть что-то вроде: "view-source:website" . Да, это как раз обрабатывается рендерером. И таких схем больше. Что значит «регистрировать»? Я пока не уверен, но думаю, это означает: «эй, я хочу, чтобы ты обработал это, когда пользователь придёт и сделает это». В любом случае, выглядит это так.![register_real](https://assets.kitploit.com/production/public/readmes/44338/db57b85fe3e1f2e9a073270a3a01dd54b60d429e5551acb7691204c2b34b5da1.png) добавь больше деталей. хорошо, сейчас добавлю детали и для последнего куска кода ![doxxx](https://assets.kitploit.com/production/public/readmes/44338/d944ca271bfe728007601039f78f9e1d1009133df79d7b9573590c94ab03901d.png)
. бла-бла и наконец мы добрались до финальной части renderer_main, обнови с деталями

![finalz](https://assets.kitploit.com/production/public/readmes/44338/cbf43950855fbf0d9d57956eb53f79efd87e660896a810bebbcce366d19aa280.png)

 



 


 
=====================================================================

Динамический анализТеперь, чтобы иметь возможность динамически отлаживать его, если ты такой же новичок, как и я, тебе нужно запустить windbg из cmd.exe следующим образом: windbg.exe chrome.exe -G -o --renderer-startup-dialog --no-sandbox --wait-for-debugger-children=renderer --renderer-process-limit=1 --allow-pre-commit-input --allow-sandbox-debugging --time-zone-for-testing="US/Pacific", и установить .childdbg 1, чтобы можно было отлаживать порождённый дочерний процесс. Далее нужно поставить bp content!content::RendererMain и дать ему выполниться примерно 5 или 6 раз. (измени, чтобы ссылаться на 4-е видео, так понятнее) после этого мы попадаем на ![reaaa](https://assets.kitploit.com/production/public/readmes/44338/a1dc34419754290a575622235cf0bd1c386456707618dbe133f18f09884cb9f9.png). 




![zanbakto3](https://assets.kitploit.com/production/public/readmes/44338/0dd1ef026636b93acad429402213ae8151260b28c9e12de587504d3b1a58e338.png)
![zanbakto](https://assets.kitploit.com/production/public/readmes/44338/d9386c0d504742ad876bb654da6d8116105243108177039f6a64da9ab42782cd.png)
![zanbakto2](https://assets.kitploit.com/production/public/readmes/44338/b659418beff6582fbf15e15e5b63aa2d97519a0eb439268c732593a4b7470ec4.png)


 
 
              
              
![soulk2](https://assets.kitploit.com/production/public/readmes/44338/5d7fd64ab712e9cb34a98045c8d1334738099065158b9d536ead9c640d2ce573.png)
![soukl](https://assets.kitploit.com/production/public/readmes/44338/3a0f297f8e88fbbdc0d8bed8ef77ad51a1260e3839f1e87cba9799b52a1a9473.png)
Скачать инструмент


Capture


Capture9
std::unique_ptr<>
1

crashes.InstallDetails::Get().VersionMismatch()
commandline

commandline2


10

/src/content/app/content_main.cc


Capture