К сожалению, в ближайшие 7 минут прочтения данной статьи мы ещё больше будем способствовать его распространению (в некотором смысле), и за бутылочкой рома порассуждаем, почему же со старых добрых давних времён собственно растёт пиратство.
Внимание!
Авторы рекомендуют гражданам с неуравновешенном психикой, лицам до 18 лет, а так-же кормящим мамам от полного прочтения данной статьи ВОЗДЕРЖАТЬСЯ. Статья длинная #оченьмногобукав.
(про кормящих мам не знаю почему, просто так написал, не спрашивайте зачем).
В предыдущей серии
А началось всё конечно же с первой публикации. IT-специалисты требуют хлеба и зрелищ технических подробностей и нюансов при «взломе» (пусть это будет явный реферанс в сторону CRACKlab) браузера Google Chrome и работе его последних версий в Windows 7 (SP1) ...и само собой со стороны автора было бы некрасивым оставить уважаемую публику непросвещенной в данном вопросе (одобрительные возгласы). Однако, побудило написать продолжение отнюдь не это.
После двух дней стек комментариев к первой статье наполнился эпичным срачем джентльменским диалогом с самой корпорацией Google LLC. Точнее с главным(?) инженером Google, который зарегистрирован на Хабре. Диалог содержит основные тезисы, почему Google отказалась от поддержки Windows 7. Эти тезисы мы используем как основу нашей публикации. Со своей стороны, как искренне «доброго самаритянина», болеющего за простых пользователей Windows 7 (Windows XP/Server 2003, да и вообще всех остальных версий Windows и даже Linux), у меня свой взгляд на вещи, подкрепленный технической составляющей — отладчиком x64dbg (привет mr.exodia), немного халявным дизассемблером IDAPro (спасибо Ильфаку), утилитой для редактирования исполняемых .exe/.dll-файлов PE COFF формата PE Tools (жму руку, Jupiter), просмоторщиком таблицы импорта PE COFF формата Dependency Walker (просто спасибо) и MSVC.
Кроме нашего диалога с инженером Google (полагаю, при необходимости он сам расскажет о себе и ответит на ваши вопросы), для полного погружения в уютную атмосферу нашей пиратской бухты рекомендую настоятельно ознакомиться (орфография и пунктуация сохранены), а то и причаститься:
«Требую разработчиков продлить поддержку Chrome на Windows 7 до 2025 года»
«Исследование: Google и другие поисковики действительно становятся хуже»
«Почему с каждой новой версией Windows от нее усиливается усталость»
See in my Github
Официально Google прекратила поддержку Windows 7/8/8.1/2012/R2 ровно год назад - версия браузера под номером 109.0.5414.165 (13 сентября 2023 года) является последней на данный момент для операционной системы Windows 7. Официально? Да обломится Брин:
Всё! Теперь Роскомнадзор впаяет Google полный 100% оборотный штраф за распространение фейков (fake) об окончании поддержки Windows 7.
#1: 3 года! Три года!
Прежде чем перейти к технической части, в которой требуется хотя бы поверхностное понимание формата PE COFF, ассемблера, отладки, WinAPI, CLSID/IID, system32 dlls, bridged dll API-MS_XP, KERNEL64, и всех остальных фокусов с таблицей импорта (IMAGE_IMPORT_DIRECTORY) Google Chrome/Chromium нарушая при этом целостность файлов браузера, обратимся к первому утверждению инженера Google — MicroSoft перестала поддерживать Windows 7 три года назад, дальше тянуть не можем/не умеем/не хотим (нужное подчеркнуть). Стоить отметить, что рассматриваемое утверждение не лишено здравого смысла на первый взгляд...однако для реверс-инженера это всего лишь фикция (ширма), за которой скрывается отвратительное отношение корпораций к своим конечным пользователям.
Начало декабря, 2019 год. Всего несколько часов остаётся до отключения компанией Sony DADC AG серверов онлайн-активации (SecuROM PA) для игры Tron: Evolution (ПК). Причина банальна: студия Disney оплатила аренду серверов с активацией SecuROM PA в ещё более далёком 2009 году на 10 лет вперёд...которые уже прошли. В продлении сроков работы онлайн-активации SecuROM PA студия Disney не заинтересована. А что это значит для честных и самых счастливых обладателей лицензионных копий игры TRON: Evolution? Правильный ответ: начиная с декабря 2019 года в лицензионную копию TRON: Evolution чисто физически невозможно играть по причине отключенных серверов онлайн-активации SecuROM PA. Вишенка на торте - даже в 2020 году после отключения SecuROM PA, по сообщениям некоторых пользователей лицензионную копию TRON: Evolution до сих пор можно было купить. Нет! Серьезно! Вы покупаете то, что не будет работать! Таким забавным образом, честные пользователи остаются у разбитого корыта за свои собственные деньги.
Да, Google конечно явно не сдирает с Вас денег за пользование своим браузером — он делает это неявно через рекламу, слежку и сбор телеметрии. Хотя получается что и этих денег то ему хватает максимум на 3 года. Может Google перенять опыт у студии Disney и заняться выпуском мультфильмов для детей младшего возраста? Или монетизировать просмотр Baby Shark? Тогда бы глядишь и срок поддержки Windows 7 сдвинулся дальше 2025 года, чего и добивается пользователь от корпорации по ссылке выше. В обоих случаях ситуация неприятная для конечного пользователя: одного просто вынуждают отказаться от игры TRON: Evolution спустя 10 лет, на второго компания, обладающая капитализацией что-то около $1,4 трлн долларов забивает ещё быстрее в 3,33333333333333333333 (3 в периоде) раза. И это при том, что количество активных пользователей «семёрки» в конце 2022 года - около 100 млн человек по всему земному шару(!), а сама Windows 7 — ОДНА ИЗ ЛУЧШИХ операционных систем, что выпустила Microsoft за все свои годы существования. Многие читатели сейчас спросят — какое дело мне до денег Google? Они, как и Disney, сами зарабатывают и распоряжаются. С точки зрения обычного пользователя меня это не интересует, мне важно чтобы последняя версия браузера или TRON: Evolution запускался без вопросов на Windows 7. С точки зрения реверс-инженера и честного человека мне важно поставить акцент, как некрасиво Google зарабатывает эти деньги. Не говоря уже о многочисленных судебных тяжбах и претензиях от Американских/Европейских регулирующих органов. Да и сама постановка вопроса довольно комична в принципе - представьте что прошло 3 года (или 10 лет в случае Disney), и вот наступает тот «судный день» когда Сергей Брин или все сразу «эффективные менеджеры» корпорации останутся в одном нижнем белье на улице потому что не хватило денег на поддержку Windows 7...хотя был временной промежуток когда разработчики Google поддерживали сразу все оси от Windows XP до Windows 10 (версия под номером 49 это март 2016 года). Выглядит довольно абсурдно по крайней мере для «эффективных менеджеров» с их главой, а вот то что простые разработчики корпораций ютятся в будках Сан-Франциско и питаются дошираками это вполне обыденность почему-то.
[Klaus Badelt and Hans Zimmer - "He's a Pirate"]
Само собой, как и с Google, мы не смогли пройти мимо безвыходной ситуации TRON: Evolution - вынув шпагу и бросив вызов Sony DADC AG, пришли на помощь простым игрокам: 80_PA SecuROM keygen БЕЗ необходимости знать serial number.
Если уважаемый читатель полагает, что TRON: Evolution — единственная игра, где отключены сервера онлайн‑активации SecuROM PA, то это весьма огромное заблуждение! Собрав библиотеку ровно из 1000 игр (защищенных SecuROM 7 и 8 версии, 2005-2016 годы) почти половина из них (~450 игр) в 2024 году не может быть активирована законным лицензионным способом. Даже на официальном сайте поддержки Sony DADC AG некоторые игры (Unheilig, phase-6, Alice in Wonderland, Volbeat), присутствующие в списке популярных «тайтлов», лишились собственных страниц поддержки — равно как и покупатели данных игр. В прямом смысле, чтобы поиграть, легальный пользователь превращается в Captain Jack Sparrow.
Впрочем, Sony DADC AG SecuROM и DENUVO (StarForce, SafeDisk and etc) это отдельная тема для большого и очень интересного разговора. Мы лишь поверхностно подвергли сомнению ещё одно утверждение инженера Google — забота корпорации об пользователях стоит на первом месте. Во всех рассмотренных случаях, подозреваю, имеет место прецедент ущемления права конечного пользователя с точки зрения, как минимум, американского законодательства. Было бы неплохо, если кто-то знающий дал реальную юридическую оценку действиям Google или Sony DADC AG.
#2: Всё ради безопасности!
Security. Так вы и здесь лукавите!
Инженер Google: Windows 7 ужасна с точки зрения безопасности, но вот Windows 10 это аж прям эталон.
Во-первых, тоже самое слышал лет 20 назад: «Windows 98 ужасна с точки зрения безопасности, но вот Windows XP это аж прям эталон». И все эти песни о главном будут спеты после выхода Windows 12, но уже для пользователей Windows 10 - вы сидите на дырявой «десятке», нужно быстро переходить на супер-защищенную «двенашку», поддержка Windows 10 продлится ещё 3 года. Конечно, безопасность совершенствуется и это нельзя не признать, вот только преподносится такой «security upgrade» под соусом, когда новая операционная система у Microsoft не взлетела, а «эффективным менеджерам» нужно показывать красивые графики перед инвесторами.
Следующим, с технической точки зрения показателен случай с world-famous CVE-2021-40444 (Microsoft Office, MSHTML RCE): она успешно пробивала Windows 10/11, но не функционировала полностью на Windows 7/XP/Windows Server 2003, вследствие чего заражение этих операционных систем не могло произойти в принципе. Лишь немного намекну, что автор в данном случае знает несоизмеримо больше, чем кто-то может подумать и мне смешно читать 95% отчетов про данную CVE, в которых написана каша по причине непонимания сути уязвимости, COM-технологии, реализации ActiveX контейнера в самом документе Microsoft Office, интерфейса IPropertyBag и тп.
Идём дальше. Песочница (SANDBOX) браузера Chromium (Chrome) существует условно в трёх ипостасях:
Основной. CreateRestrictedToken в chromium/sandbox/win/src/restricted_token_utils.cc, shared-секции через DACL, UpdateProcThreadAttribute, CreateFileMapping, NtOpenSection, PlatformSharedMemoryRegion::Create() chromium/base/memory/platform_shared_memory_region_win.cc — так это вообще времена Windows XP/Windows Server 2003. Частично проапгрейжено ещё в Windows Vista и всё.
Песочница для AppX. Но Windows Store с Windows Runtime Activate это только с плиточного интерфейса Windows 8 и к «семёрке» никакого отношения не имеет — попросту такая песочница не востребована там от слова «совсем».
Митигации (Process Mitigation). Эти появились опять таки с Windows 8 — тем не менее, Google всё равно зачем-то исключила Windows 8/8.1 из списка поддерживаемых после официальной 109 версии. Первые две митигации (ProcessDEPPolicy, ProcessASLRPolicy) — опять времена Windows XP/Windows 2003 Server (Microsoft EMET), но в более удобном виде для программиста известны в Windows Vista/7. В Windows 10 добавили только пару новых, связанных с запуском подписанных DLL. Сама суть митигаций не нова — аналогичная техника применялась в детищах Евгения Валентиновича (и не только) со времен Windows XP. Только, как и в случае с несколькими рабочими столами (multi-desktop) на Linux (существовали до момента появления «десятки» лет 20), Microsoft скопировала готовую идею у конкурентов. Не, ну а что - вы тут удивляетесь, что пацаны совсем недавно дошли до встроеного архиватора-распаковщика.
Раз уж мы вскользь упомянули антивирусные решения, то не лишним будет отметить следующее. Имея на руках статистику известной антивирусной компании, с уверенностью могу утверждать, что проблемы в тех же 95% случаев идут от самого пользователя, который машинально запускает всё, что попало ему через электронную почту или небезопасные интернет сайты. Второй бедой нашего пользователя является использование простых паролей для SSH и остальных remote desktop. Собственно этим и пользуются авторы всяких Emotet. Очевидно, что версия Windows не играет здесь ключевой роли — пользователь всё равно запустит вложение годовойотчётбухгалтерияоктябрь.pdf.exe или КатяСрочноРаспечатай.docx.js на любой версии Windows.
Конечно, последствия могут быть несколько разными, но:
абсолютное большинство ВПО это обычные майнеры или шифровальщики без каких либо встроенных дополнительных возможностей пробива или самораспространения;
антивирусные решения за столько лет научились действовать вперёд и одинаково эффективно работают, как на Windows 7, так и на Windows 10;
неочевидный фактор — среди большинства вирусописателей бытует миф о том, что десятка уже давно захватила 99% всего на планете Земля, а предыдущими версиями Windows никто не пользуется. Вследствие чего возникает забавный казус, суть которого в том, что при линковке никто не заморачивается с правкой major/minor OS‑версии Image Optional‑заголовка PE COFF формата + про современные версии пакетов Microsoft Runtime Redistributable (отсуствуют в принципе на версиях Windows XP/2003/7) никто из них не знает вообще. Описываемая ситуация — зеркало анекдота про неработающий вирус в Linux'е и в реальности оно имело место быть неоднократно! В этом не сложно убедиться самому, если скопировать тот же
explorer.exe
(Проводник) из Windows 10 в среду Windows 7.
Если Вы пользуетесь Windows XP/2003/7 до сих пор, то необходимо закрыть все потенциально небезопасные порты типа 135, 445 и тд, а также отключить службу print spooler, если Вам реально не нужна печать. Не лишним будет отключить все остальные неиспользуемые службы. Для закрытия портов в графическом режиме используйте утилиту WWDC (Windows Worms Doors Cleaner).
Несколько спорным является факт заметного ухудшения производительности при навешивании новых слоёв безопасности. Со стороны железа, Intel аналогичным образом вносит свой отрицательный вклад в производительность ради безопастности.
В качестве завершения абзаца про безопасность, хотелось бы задаться простым вопросом — «если у Вас так всё великолепно в новых версиях Windows 10/11 с безопасностью и со стабильностью, с Ваших же слов, то какой смысл собирать и слать такое дикое количество телеметрии??» И кстати, не туда воюют наши любители блокировать всё и вся — протокол Nexus нужно заблочить лет 10 назад. Так к слову.
#3: legacy, legacy... legacy-xxxgacy
Здесь не совсем понимаю, что именно понимается под legacy. Создание окна с заголовком «legacy»?!
Задаёмся новым банальным вопросом - чем отличается уже упомянутый выше explorer.exe
в Windows 11 (и даже в 12) от своего собрата в Windows XP?? Ответ: да ничем принципиально! Модель взаимодействия с COM-обьектами через интерфейсы (IID) IShellFolder и IShellFolder2 тянется с Windows 2000. Сами COM-объекты это вообще 1993 год или около того. С точки зрения инженера Google это наверняка очень дикое legacy. Ну что ж, открываем отладчик/дизассемблер (в последнюю очередь вспоминаем, что существует исходный код, ага) и видим — с версии 118 (октябрь 2023 года) появился вызов legacy WinAPI CoCreateInstance (создание нового экземпляра COM-объекта) с параметрами CLSID {4991D34B-80A1-4291-83B6-3328366B9097}
& IID - {5CE34C0D-0DC9-4C1F-897C-DAA1B78CEE7C}
используя всю мощь OleViewDotNet переводим на родной древнеэльфийский: обычная Windows Update служба Background Intelligent Transfer Control Class 1.0 (BITS) и IBackgroundCopyManager — так выкачивали трояны в 2008 году. Нечто похожее, судя по всему, делает новая фукнция автообновления Chrome плагинов, которая использует службу BITS для соединения с сомнительного вида URL‑адресом (может различаться от версии браузера):
http://edgedl.me.gvt1.com/edgedl/diffgen-puffin/lmelglejhemejginpboagddgdfbepgmp/{абырвалг}
Если кому-то интересно, whois можете сами пробить MarkMonitor, Inc. От греха подальше выпилил её (на самом деле, кораптились extensions) в своих версиях для Windows 7. Примерно тоже самое сделали разработчики MS EDGE, Opera и Brave.
Нет, если серьезно, догадываюсь, что под legacy разработчики Google пытаются «крошить батон» в сторону:
\System32\MFPlat.DLL (Media Foundation Platform DLL) и DXGI (DXDVA) - но здесь довольно нелепо, так как Microsoft разработала перечисленные технологии в Windows Vista/7, как полноценный мультимедийный стек и логическую замену DirectX 2D (примерно так работает, поправьте, если не совсем корректно) - ничего принципиально нового до сих пор не предвидится наверное если кто-то не пойдет Linux-way путём через VDPAU и OpenGL.
DirectX 9 (d3d9). По умолчанию, используется самой Windows или как универсальный вариант, если недоступен DirectX 10 и выше. Как бы не очень хорошо, если браузер останется без аппаратного ускорения совсем.
В конце концов, ну хочет Google отделить legacy код DirectX 9 (или что там под legacy кодом ещё подразумевается у Вас) от нового DirectX 11 — подсмотрите уже НАКОНЕЦ как это делают в игровой индустрии лет 15! У Вас chrome.dll грузится динамически через LoadLibraryW из жестко импортируемой chrome_elf.dll. Что мешает вывести этот legacy из chrome.dll в chrome_legacy.dll и грузить одну из двух dll, значительно сократив размер основной chrome.dll (вот вам и оптимизация потребляемой RAM памяти)?! Возможно, суммарный размер двух dll из‑за флагов оптимизации будет выше, чем одной chrome.dll, но ведь грузим мы что‑то одно (или legacy в случае какой‑то аварии у пользователя или обычный современный вариант). Или это нереально из‑за того, что в корпорации не осталось программистов, которые смогли осилить такое большое разделение?!
Таким незамысловатым способом мы плавно переходим к размерам.
#4: Размер chrome.dll имеет значение
В первой своей статье успел пошутить про chrome.dll, накрытый DENUVO — 220 Мегабайт для одного файла PE COFF формата это знаете слишком. С точки зрения реверса, если загрузить обсуждаемую DLL в IDAPro, то весь анализ файла займёт у дизассемблера около 5 часов.
Попытка накрыть многострадальный chrome.dll протектором VMProtect Ultimate (зачем это нужно?:) ) заняла 15 минут загрузки в утилиту и 25 минут компиляции/упаковки с максимальными опциями защиты — вместо накрытого файла протектор выдал в конце ошибку «Stream read error». Пиратство победило и здесь!
Цифры дают осознание утверждения инженера Google о необходимости контроля разрастающейся кодовой базы браузера (тезис прозвучал в самом конце, когда предыдущие не очень сработали). Ну что же, специально для читателей Хабра простая диаграмма, как менялся размер (кодовая база) chrome.dll в мегабайтах на протяжении нескольких ключевых версий:
Пусть выводы из диаграммы каждый читатель для себя сам делает. Для себя лишь отметил факт отсутствия в 110 версии каких либо ощутимых улучшений в плане компактности кодовой базы браузера (какой смысл тогда было убирать поддержку Windows 7 ???).
Техническая часть.
Если читатель всё таки дошёл до указанного местоположения, осилив всё что написано выше, то он прекрасно поймёт что пропатчить браузер в бинарном коде достаточно просто. Исходя из размера chrome.dll — ничего на стыке 109-110 версий Chrome не поменялось принципиально. DXGI с DXDVA и DirectX 9 с 11 никуда не делись - render страниц чисто физически заработает. Sandbox заработает (правда, несколько позже). Если что-то и аффектится, то какая-то «мелочёвка» типа расширенных возможностей управления электропитанием, а также чисто специфических вспомогательных функций Windows 8-10. AppX сразу выкидываем за борт.
Как помните из первой части, хотел завести актуальную, на тот момент, 114 версию за один вечер без лишних заморочек (типа «на коленках»). Первым делом требовалось выяснить, много ли добавили новых WinAPI в chrome.exe && chrome_elf.dll && chrome.dll.
Используя Dependency Walker быстро накидал небольшую табличку отсутствующих WinAPI, а так же пары системных dll'ок. Пробежавшись по их новому функционалу, стало очевидно что их можно банально за'NOP'ить в ассемблерном коде, а в CPU регистре общего назначения RAX/EAX вернуть или ошибку или успешное выполнение в зависимости от функции, в которой они используются.
NOP'ить вызовы в бинарном коде это хорошо, но ещё оставалась таблица импорта PE COFF — в ней ASCII строками-константами располагаются названия отсутствующих WinAPI и загрузчик Windows будет пытаться их найти. Но ведь они уже никак не используются в нашем патченном коде! Дело за малым - учитывая тот факт, что мы не должны выйти за пределы оригинальной ASCII строки («GetProcessMitigationPolicy» - 27 символов), требуется подобрать короткий и безопасный вариант названия WinAPI, который присутствует начиная с Windows XP. Для kernel32.dll нет ничего проще - Beep. Аналогичным образом подбираются названия WinAPI и для пары остальных DLL.
Из полученного выше списка особняком стояла WinAPI DiscardVirtualMemory — прямо в коде браузера под неё существовал полный аналог вызова через старый добрый VirtualAlloc. Буквально при написании этих строк обратился к исходному коду chromium, чтобы выяснить подробности. Подробности заставили широко улыбнуться — комментарии в исходном коде гласили:
// DiscardVirtualMemory is buggy in Win10 SP0, so fall back to MEM_RESET on
// failure.
buggy и Win10 - так, напомнило постоянные новости, какой «дичи» не было даже в ранних билдах «семёрки». Ну да ладно! Сейчас не об этом. Суть в другом - для некоторых новых функций WinAPI есть стандартные аналоги, пусть даже работающие чуть медленней (Use DiscardVirtualMemory when available because it releases faster than MEM_RESET). Пригодится ли это нам? Определённо!
Из недостающих dll'ок упоминуть разве что API-MS-WIN-SHCORE-SCALING-L1-1-1.dll, в которой требовалось переписать под Windows 7 процедуру скалирования (scale) для окон/монитора. GetDeviceCaps и расчёт через DPI — да это даже на Windows XP заработает.
Логи браузера
После того, как работа над недостающими WinAPI и dll'ками была завершена, последовала первая попытка завести браузер Chrome 114 в среде Windows 7. Вызываем chrome.exe — визуально ошибок никаких нет, повляется буквально на секунду заголовок окна и сразу исчезает, т.е. вроде как запустилось и сразу же грохнулось. Ясно! Нужны логи браузера: --enable-logging --v=7
Стоп! А что у нас с песочницей (SANDBOX) - похоже она не функционирует. Покопавшись в отладчике, быстро пришёл к выводу, что возиться с песочницей придётся довольно долго (явно больше одного вечера), так как код был мне не знаком, а саму технологию представлял себе не совсем чётко (ReadProcessMemory/WriteProcessMemory, shared-секции и прочие трюки с ntdll насмотрелся в избытке ломая SecuROM и ему подобных). Добавляем ещё в качестве аргумента --no-sandbox
, запускаем нашу «балалайку» опять и валим в %LOCALAPPDATA%\Google\Chrome\User Data
для просмотра chrome_debug.log
в Notepad++ или 010 Editor.
Скажу сразу — проблема логов браузера в том, что нужной информации там может попросту не быть. Браузер остановится на инструкции ud2, если повезёт — исключение подхватит система и подсветит нужное место, в самом худшем варианте — какой-то из процессов аварийно завершается...почему он завершился? Зачем он завершился? Как он завершился? Что вообще произошло? Да кто его знает! С последним, решение нашлось, когда вспомнил о существовании GetExitCodeProcess (перед ней должен быть вызов CreateProcessW или CreateProcessAsUserW для sandbox). Но это концовка, а начало? --wait-for-debugger-children
мне не понравилась из-за того что тайминги по RPC «просираются» и получается полная ерунда. Забегая наперёд, использовал уже отработанный вариант с MessageBox и DllMain(), только в своей KERNEL64.DLL чтобы по человечески присоединится к одному из двух нужных процессов (gpu или render).
Собственно описываемый случай это следующая ошибка совместимости с Windows 7 для которой в логах было лишь упоминание:
[6264:4924:0701/003015.755:FATAL:gpu_data_manager_impl_private.cc(431)] GPU process isn't usable. Goodbye.
Ну что же, очень информативно и невероятно полезно! Не добившись первопричины Goodbye в головном процессе chrome.exe, пришлось потратить несколько часов, чтобы нормально отладить --type=gpu-process
. Только тогда понял, что после создания некоторой таблицы открытых хендлов (HANDLE), происходит их валидация (GetHandleVerifier), которая «фейлится» на shared-секциях. В Chrome 114 исправление выглядело традиционными NOP. Только спустя пару месяцев, при починке песочницы более осознанно разобрался в сути ошибки (кусок с условием if
выкинули в 110 версии):
// static
PlatformSharedMemoryRegion PlatformSharedMemoryRegion::Create(Mode mode,
size_t size) {
// TODO(crbug.com/210609): NaCl forces us to round up 64k here, wasting 32k
// per mapping on average.
static const size_t kSectionSize = 65536;
...
std::u16string name;
if (win::GetVersion() < win::Version::WIN8_1) {
// Windows < 8.1 ignores DACLs on certain unnamed objects (like shared
// sections). So, we generate a random name when we need to enforce
// read-only.
/*
Windows < 8.1 игнорирует DACL для некоторых неименованных объектов (like shared sections).
Поэтому мы генерируем случайное имя, когда нам нужно обеспечить только для чтения.
*/
uint64_t rand_values[4];
RandBytes(&rand_values, sizeof(rand_values));
name = ASCIIToUTF16(StringPrintf("CrSharedMem_%016llx%016llx%016llx%016llx",
rand_values[0], rand_values[1],
rand_values[2], rand_values[3]));
DCHECK(!name.empty());
}
Тем не менее, даже после живительной «починки» NOP'ами функционала GetHandleVerifier, браузер упорно не хотел запускаться, поэтому листаем лог ошибок далее по ключевому слову ERROR.
[1380:3396:0127/174930.071:ERROR:check.cc(297)] Check failed: false. NOTREACHED log messages are omitted in official builds. Sorry!
Интуиция сразу подсказала, что не нравится версия Windows 7, однако из-за такой ерунды Chrome падать точно не будет. На всякий случай, извиняюсь за выражение, «заткнул рот» фукнции проверки версии Windows и побежал дальше по списку.
DNS registry watch failed to start
В RegNotifyChangeKeyValue начиная с Windows 8 добавили флаг REG_NOTIFY_THREAD_AGNOSTIC. Но watcher в registry.cc не знает, что мы в «семёрке». Выпиливаем неподдерживаемый флаг исправляя байт 01
на 00
и о чудо! Ошибки как и не было.
После всех этих правок стек ERROR исчерпался, но даже и близко не увидел хотя бы начальной вкладки браузера. Удалось установить, что render процесс браузера падал с ошибкой C0000005 (ACCESS_VIOLATION) - вот только chrome_debug.log
молчал.
Microsoft DirectX 12. IID_IDWriteFactory3.
Как ни странно, здесь оказалось ещё проще чтения логов. x64dbg отловил в chrome.dll место, где происходило исключение доступа. Браузер пытался вызвать какую-то функцию, но вместо адреса FARPROC там был ноль (NULL). После разведки stack call и окресностей ACCESS_VIOLATION удалось затрофеить строки «DWriteFontProxyImpl::InitializeDirectWrite», «dwrite,fonts». Забавным фактом было использвание IDAPro, вместо открытого исходного кода chromium (были некоторые опасения, что код может не совпасть или его попросту может не быть в открытом репозитории):
v3 = "DWriteFontProxyImpl::InitializeDirectWrite";
(**v8)(v8, &IDWriteFactory2, a1 + 0x20);
v10 = (a1 + 0x28);
v11 = *(a1 + 24);
v12 = *(a1 + 40);
if ( v12 )
{
*v10 = 0i64;
(*(*v12 + 16i64))(v12);
}
(**v11)(v11, &IDWriteFactory3, a1 + 0x28);
В итоге с помощью IDAPro вытащил три интерфейса (IID), которые пытается вызывать создаваемое браузером устройство DirectX:
{B859EE5A-D838-4B5B-A2E8-1ADC7D93DB48}
IID_DWriteFactory{0439FC60-CA44-4994-8DEE-3A9AF7B732EC}
IID_DWriteFactory2{9A1B41C3-D3BB-466A-87FC-FE67556A3B65}
IID_IDWriteFactory3
Из трёх только IID_DWriteFactory доступен в Windows 7 (DirectX 11). Исключение происходит на IID_IDWriteFactory3, который появился в Windows 10 (DirectX 12). Недолго думая, меняем {9A1B41C3-D3BB-466A-87FC-FE67556A3B65}
на {B859EE5A-D838-4B5B-A2E8-1ADC7D93DB48}
(примечательно, что буквально пару недель назад нарисовался другой путь с костылями от самой Microsoft). Для нашего случая важно понимать один ньюанс — в зависимости от наследования IID_IDWriteFactory3 (наследуются от IID_IDWriteFactory2, который наследуется от IID_IDWriteFactory, который наследуется от IID_IUknown), есть вероятность нарваться на отсутствие имплементации его методов в IID_IDWriteFactory и получить новую серию ACCESS_VIOLATION. Тем не менее, даже такой правки хватило для запуска Chrome 114 в Windows 7 с последующим серфингом по просторам всемирной сети.
Bridged DLLs
После успеха Chrome 114, вылезли из под плиток и начали писать воодушевленные пользователи Windows 8, требующие справедливости Google и по отношению к ним. Собственно изначально прекрасно понимал, что концепт заNOPить недостающие вызовы WinAPI и забить их в таблице импорта универсальным Beep идея так себе и годится только как быстрое временное решение «на коленке». Обращение «плиточников» заострило проблему — количество недостающих WinAPI между Windows 8 и 10 можно было пересчитать по пальцам одной руки. В «восьмёрке» присутствовали митигации, AppX, свежие фитчи DirectX 11.1 для наложения текстур — причин выпиливать поддержку браузером 8/8.1 не было ВООБЩЕ никаких. Ввиду того, что в отличие от supermium мы можем только ограниченно править бинарный код браузера в .exe/.dll, решение напрашивалось само собой: проксировать у себя недостающие WinAPI и в зависимости от их наличия в оригинальных DLL, вызывать напрямую готовую реализацию. Здесь не буду подробно останавливаться, так как готовая реализация Bridged DLLs открыта в собственном отдельном репозитории.
Реакция Google LLC
Официально её не было. Инженер Google так-же всеми силами пытался дать понять, что нейтрален ко «всей происходящей вакханалии».
Тем не менее загрузив в отладчик следующую 117 версию, понял что реакция есть.
ProcessPrng появилась в таблице экспорта bcryptprimitives.dll только с Windows 10. Ну да ладно, может она действительно круче чем обычный rand()/srand() (хотя все пути идут в KUSER_SHARED_DATA). Не суть.
«Озадачали» три вещи, связаннные с ProcessPrng:
Описываемый кусок кода вспихнули абсолютно во все .exe/.dll браузера и вызывается он постоянно. Реально ли это нужно в chrome_proxy.exe, elevation_service.exe, notification_helper.exe или chrome_pwa_launcher.exe? Stack guard без GetProcessPrng() работает изначально.
Сама реализация выглядит мягко говоря странной. Какой смысл в использовании динамической подгрузки LoadLibraryW/GetProcAddress? Ведь вы сами уже год назад отказались от поддержки Windows 7/8/8.1 — линкуйте в основную таблицу импорта PE COFF файла или DELAY_IMPORT_TABLE, как это делается во всём остальном коде повсеместно и вызывайте без 100-200 байт лишнего кода. Почему нельзя пойти дальше используя LoadLibraryExW с флагом LOAD_LIBRARY_SEARCH_SYSTEM32 для большей безопастности?
Название LPCWSTR для LoadLibraryW это две UNICODE строки: «bcryptprimitives.dll» и «bcryptprimitives» (выберите что-то одно). Кусок кода дублируется два раза. Зачем?
Да, слова о необходимости контроля кодовой базы были сказаны инжнером Google.
Различия между Chrome, MS EDGE, Opera и BRAVE
MS EDGE технически гораздо более развит (Невероятно!)Они в таблице msedge.dll импорта сразу нативные фукнции ntdll импортируют), чем все остальные. Сказывается тот факт, что Microsoft лучше и тоньше знает своё детище (Windows). Кроме упомянутой в предыдущем абзаце ProcessPrng в MS EDGE дополнительно требуется пропатчить аналогичный кусок кода, только с RtlGetDeviceFamilyInfoEnum (ntdll.dll) — для Windows 7 просто возвращаем ноль 0. И опять же подозрение, что динамическая загрузка вставлена специально, как дешевая палка в колёса. Немного по другому функционирует просмотр PDF в песочнице.
MS EDGE, Opera и BRAVE не используют код, который отправляет различную статистику на сервера Google — упомянутого ранее вызова службы BITS со всякими http://edgedl.me.gvt1.com
ни в одном из них не было.
В остальном, каждый добавляет уже свой индивидуальный фукнционал в открытый код Chromium.
Различия между x64 и x86 версиями браузера
Для x86 (32 разрядной версии) требуется дополнительно править фукнционал песочницы (sandbox). Обьяснятеся это различием длин ассемблерного кода для низкоуровневых нативных фукнций типа NtOpenFile в Windows 7 и Windows 10.
Это ntdll.NtOpenFile для Windows 7 (+15 это 21 байт в десятичной системе счисления):
$ ==> | B8 30000000 | mov eax,30 | NtOpenFile
$+5 | 33C9 | xor ecx,ecx |
$+7 | 8D5424 04 | lea edx,dword ptr ss:[esp+4] |
$+B | 64:FF15 C0000000 | call dword ptr fs:[C0] | [dword ptr fs:[000000C0]]
$+12 | 83C4 04 | add esp,4 |
$+15 | C2 1800 | ret 18 |
Это ntdll.NtOpenFile для Windows 10 (+C это 12 байт в десятичной системе счисления):
$ ==> | B8 33000000 | mov eax,33 | NtOpenFile
$+5 | BA 408AA877 | mov edx,ntdll.77A88A40 | 77A88A40:
$+A | FFD2 | call edx |
$+C | C2 1800 | ret 18 |
В случае «семерки», длина ntdll.NtOpenFile (и всех остальных Nt, которые используются песочницей) оказывается на 9 байт больше.
К чему это вещаю? После 110 версии браузера песочница читает (ReadProcessMemory) в создаваемом children-процессе фиксированное количество байт, которое равно 16. В случае Windows 7 кусок ассемблерного кода ntdll.NtOpenFile размером 5 байт (21-16) теряется при чтении, что приводит к фатальным последствиям в children-процессе. Происходит данное недоразумение где-то в районе chromium/sandbox/win/src/service_resolver_32.cc. Если уважаемый читатель полагает, что в бинарном виде поправить реализацию ServiceResolverThunk::SaveOriginalFunction куда сложнее, чем перекомпилировать в том же supermium — это заблуждение. Расширяем стек, вместо 16 байт читаем сразу 32 байта, перебиваем указатели на локальные переменные, заставляем memcpy копировать больший (в два раза) объём данных. Да что там, смотрите сами на прилагаемой картинке из отладчика x64dbg.
Brave Software
Обратил внимание на присутствие Brave среди участников. Понимаю, будем звучать немного странно, но почему бы Вам один раз не пойти против устоявшихся правил (выпустить в 2024 году хотя бы одну современную версию для Windows 7), ведь пользователи ценят такой подход.
inc eax
Да, знаю прекрасно что существуют https://github.com/win32ss/supermium с https://github.com/ungoogled-software/ungoogled-chromium и горячо поддерживаю ребят.
Наличие таких проектов лишний раз напоминает о том, что Google свернул «куда-то не туда» с Manifest V3 и «прочими радостями», которые многократно упомянуты по ссылкам в самом самом начале этого длинного текста с картинками. Каждый инкремент major‑версии браузера Google не приносит каких либо ощутимых нововведений, поэтому воспринимается как очередной «Рекламный выпуск». Проанализировав всю полученную информацию возможно у кого‑то из читателей возникнет мысль: «а востребованы ли сегодня в 2024 году такие огромные корпорации, если мы (конечные пользователи) уже за них создаём сами себе комфортные условия работы?» или «Как так получается, что большие корпорации сами создают почву для разрастания пиратства?»
Vol.
#3: https://habr.com/ru/articles/817561/
СПАСИБО ЗА ВНИМАНИЕ!