Google Chrome и Secure Preferences

На нашем форуме и не только, с некоторой периодичностью люди интересуются алгоритмом генерации «защитного кода» в файле Secure Preferences для браузера Google Chrome.
Зачем он браузеру? Этот код используется для проверки целостности настроек расширений и некоторых других параметров, проще говоря — HMAC. Зачем он людям? Вероятно, это необходимый этап для тихой установки расширений или изменения настроек браузера. Давайте разберемся, где и как происходит генерация этих HMAC’ов.

Для начала заглянем в исходный код проекта Chromium. Беглый поиск по слову hash вывел меня на файл pref_hash_calculator.cc. И, что характерно, именно здесь все и происходит. Процитирую код основных методов, которые отвечают за генерацию:

Авторское форматирование было задвинуто подальше, так как у меня личная неприязнь к такому стилю. Код выглядит довольно простым, осталось понять, что вообще подается на вход. Чтобы не скачивать весь исходный код Chromium и не собирать его, поступим следующим образом: поставим официальный Chrome, скачаем один лишь файл pref_hash_calculator.cc и укажем в Visual Studio путь к отладочным символам для Google Chrome:

Все готово к исследованию. Запускаем браузер, атачимся к процессу, ждем, пока прогрузятся отладочные символы (можно в настройках указать загрузку символов только для модуля chrome.dll, этого будет достаточно), открываем файл pref_hash_calculator.cc в MSVC и ставим брейкпоинт на методе Calculate. Теперь нам необходимо совершить какое-нибудь действие, которое приведет к вычислению хэша, например, установить произвольное расширение из Chrome Web Store. Устанавливаем и попадем на наш брейкопинт.

Мы видим значения seed_ (перевел в hex для удобства):

И device_id:

Причем seed_ — постоянная величина (но, скорее всего, может меняться от версии к версии), а device_id — уникальный идентификатор компьютера. Откуда берется seed_? Не вдаваясь в подробности поиска, скажу, что он содержится в файле resources.pak, который находится в директории с браузером. Формат содержимого файла известный и давно описан, например, тут. Давайте попробуем самостоятельно извлечь seed_ из resources.pak. Для этого я напишу простенький скрипт на Perl:

Делаем тестовый прогон и узнаем, что seed_ содержится в ресурсе с ID 609, который скорее всего тоже меняется.

Теперь нам необходимо получить device_id. Откуда его берет Chrome? Не буду вас утомлять отладчиком, просто скажу, что нас интересует функция GetMachineId из файла machine_id.cc. Приведу ее исходный код на всякий случай:

Этот код является частью сторонней библиотеки RLZ. Я не стал особо копаться в логике вызовов, а просто выдрал код, немного подредактировал и сделал из него отдельный файл, который можно смело собирать и тестировать под Windows (генерация device_id отличается в зависимости от ОС). Ссылка на проект для Microsoft Visual Studio 2013 в конце статьи.
Итак, у нас есть seed_, device_id, осталось обратить свое внимание на два оставшихся аргумента, которые передаются в GetMessage — это path и value. Зайдем сразу внутрь функции GetMessage и посмотрим, что она формирует.

Мы видим, что path содержит путь к настройкам расширения в Secure Preferences:

А value (value_as_string) — настройки расширения в JSON:

Подытожим логику вычисления:

В качестве hmac используется HMAC SHA256, это видно по коду. Приведу пример простого скрипта, который парсит расширения из файла Secure Preferences и вычисляет hmac для каждого из них, а также super_mac. Алгоритм вычисления прост:

super_mac используется для проверки целостности некоторых настроек браузера и массива пар ид_расширения — hmac. Наконец-таки скрипт:

Запустим скрипт, указав в качестве аргументов device_id, seed и путь к файлу Secure Preferences:

Как мы видим, скрипт успешно отработал и корректно вычислил HMAC’и.

Скрипты из статьи и проект для MSVC 2013, вычисляющий device_id: скачать

Оставьте первый комментарий

Оставить комментарий

Ваш электронный адрес не будет опубликован.


*