На нашем форуме и не только, с некоторой периодичностью люди интересуются алгоритмом генерации "защитного кода" в файле Secure Preferences для браузера Google Chrome.
Зачем он браузеру? Этот код используется для проверки целостности настроек расширений и некоторых других параметров, проще говоря - HMAC. Зачем он людям? Вероятно, это необходимый этап для тихой установки расширений или изменения настроек браузера. Давайте разберемся, где и как происходит генерация этих HMAC'ов.
Для начала заглянем в исходный код проекта Chromium. Беглый поиск по слову hash вывел меня на файл pref_hash_calculator.cc. И, что характерно, именно здесь все и происходит. Процитирую код основных методов, которые отвечают за генерацию:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
std::string PrefHashCalculator::Calculate(const std::string& path, const base::Value* value) const { return GetDigestString(seed_, GetMessage(device_id_, path, ValueAsString(value))); } // Concatenates |device_id|, |path|, and |value_as_string| to give the hash input. std::string GetMessage(const std::string& device_id, const std::string& path, const std::string& value_as_string) { std::string message; message.reserve(device_id.size() + path.size() + value_as_string.size()); message.append(device_id); message.append(path); message.append(value_as_string); return message; } // Calculates an HMAC of |message| using |key|, encoded as a hexadecimal string. std::string GetDigestString(const std::string& key, const std::string& message) { crypto::HMAC hmac(crypto::HMAC::SHA256); std::vector<uint8> digest(hmac.DigestLength()); if (!hmac.Init(key) || !hmac.Sign(message, &digest[0], digest.size())) { NOTREACHED(); return std::string(); } return base::HexEncode(&digest[0], digest.size()); } |
Авторское форматирование было задвинуто подальше, так как у меня личная неприязнь к такому стилю. Код выглядит довольно простым, осталось понять, что вообще подается на вход. Чтобы не скачивать весь исходный код Chromium и не собирать его, поступим следующим образом: поставим официальный Chrome, скачаем один лишь файл pref_hash_calculator.cc и укажем в Visual Studio путь к отладочным символам для Google Chrome:
1 |
https://chromium-browser-symsrv.commondatastorage.googleapis.com |
Все готово к исследованию. Запускаем браузер, атачимся к процессу, ждем, пока прогрузятся отладочные символы (можно в настройках указать загрузку символов только для модуля chrome.dll, этого будет достаточно), открываем файл pref_hash_calculator.cc в MSVC и ставим брейкпоинт на методе Calculate. Теперь нам необходимо совершить какое-нибудь действие, которое приведет к вычислению хэша, например, установить произвольное расширение из Chrome Web Store. Устанавливаем и попадем на наш брейкопинт.
Мы видим значения seed_ (перевел в hex для удобства):
1 |
e748f336d85ea5f9dcdf25d8f347a65b4cdf667600f02df6724a2af18a212d26b788a25086910cf3a90313696871f3dc05823730c91df8ba5c4fd9c884b505a8 |
И device_id:
1 |
7CD6D9C7354E9165A3A4CBE097021669F4C026E7AA578B0CA9 |
Причем seed_ - постоянная величина (но, скорее всего, может меняться от версии к версии), а device_id - уникальный идентификатор компьютера. Откуда берется seed_? Не вдаваясь в подробности поиска, скажу, что он содержится в файле resources.pak, который находится в директории с браузером. Формат содержимого файла известный и давно описан, например, тут. Давайте попробуем самостоятельно извлечь seed_ из resources.pak. Для этого я напишу простенький скрипт на Perl:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
use strict; use warnings; use File::Basename; use Fcntl ':seek'; use constant NL => $^O eq 'MSWin32' ? "\015\012" : "\012"; $| = 1; if(scalar @ARGV != 1) { print "Usage: " , basename(__FILE__), " resources.pak", NL; exit 1; } open my $fh, '<', $ARGV[0] or die $!; # Читаем заголовок resources.pak и извлекаем информацию о версии, кол-ве ресурсов и кодировке # 4 byte version number + 4 byte number of resources + 1 byte encoding read $fh, my $header, 9; my ($version, $resources_total, $encoding) = unpack 'VVC', $header; print "Version: $version", NL, "Resources: $resources_total", NL, "Encoding: ", $encoding, NL, NL; # Перечисляем ресурсы и их смещения в файле # 2 byte resource id + 4 byte resource offset in file # Учитываем ресурс с ID 0, означающий конец списка my ($last_id, $last_offset) = (0, 0); for(my $i = 0; $i < $resources_total + 1; $i++) { read $fh, $header, 6; my ($id, $offset) = unpack 'SV', $header; if($last_id) { my $size = $offset - $last_offset; # Делаем предположение, что seed всегда состоит из 64 символов if($size == 64) { print "ID: $last_id", NL, "Offset: $last_offset", NL, "Size: $size", NL; seek $fh, $last_offset, SEEK_SET; read $fh, my $data, 64; print "Resource HEX data: ", unpack('H*', $data), NL; exit 0; } } $last_id = $id; $last_offset = $offset; if($id == 0) { last; } } |
Делаем тестовый прогон и узнаем, что seed_ содержится в ресурсе с ID 609, который скорее всего тоже меняется.
Теперь нам необходимо получить device_id. Откуда его берет Chrome? Не буду вас утомлять отладчиком, просто скажу, что нас интересует функция GetMachineId из файла machine_id.cc. Приведу ее исходный код на всякий случай:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
bool GetMachineId(std::string* machine_id) { if (!machine_id) return false; static std::string calculated_id; static bool calculated = false; if (calculated) { *machine_id = calculated_id; return true; } base::string16 sid_string; int volume_id; if (!GetRawMachineId(&sid_string, &volume_id)) return false; if (!testing::GetMachineIdImpl(sid_string, volume_id, machine_id)) return false; calculated = true; calculated_id = *machine_id; return true; } |
Этот код является частью сторонней библиотеки RLZ. Я не стал особо копаться в логике вызовов, а просто выдрал код, немного подредактировал и сделал из него отдельный файл, который можно смело собирать и тестировать под Windows (генерация device_id отличается в зависимости от ОС). Ссылка на проект для Microsoft Visual Studio 2013 в конце статьи.
Итак, у нас есть seed_, device_id, осталось обратить свое внимание на два оставшихся аргумента, которые передаются в GetMessage - это path и value. Зайдем сразу внутрь функции GetMessage и посмотрим, что она формирует.
Мы видим, что path содержит путь к настройкам расширения в Secure Preferences:
1 |
extensions.settings.aapocclcgogkmnckokdopfmhonfmgoek |
А value (value_as_string) - настройки расширения в JSON:
1 |
{"ack_external":true,"app_launcher_ordinal":"zs","creation_flags":137,"from_bookmark":false,"from_webstore":true,"initial_keybindings_set":true,"install_time":"13074357069686027","lastpingday":"13074332401422358","location":1,"manifest":{"api_console_project_id":"889782162350","app":{"launch":{"local_path":"main.html"}},"container":"GOOGLE_DRIVE","current_locale":"en_US","default_locale":"en_US","description":"Create and edit presentations ","icons":{"128":"icon_128.png","16":"icon_16.png"},"key":"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDLOGW2Hoztw8m2z6SmCjm7y4Oe2o6aRqO+niYKCXhZab572by7acqFIFF0On3e3a967SwNijsTx2n+7Mt3KqWzEKtnwUZqzHYSsdZZK64vWIHIduawP0EICWRMf2RGIBEdDC6I1zErtcDiSrJWeRlnb0DHWXDXlt1YseM7RiON9wIDAQAB","manifest_version":2,"name":"Google Slides","offline_enabled":true,"update_url":"https://clients2.google.com/service/update2/crx","version":"0.9"},"page_ordinal":"n","path":"aapocclcgogkmnckokdopfmhonfmgoek\\0.9_0","state":1,"was_installed_by_default":true,"was_installed_by_oem":false} |
Подытожим логику вычисления:
1 2 3 4 |
key = seed_ message = device_id + extension_path + extension_settings hmac(message, key) |
В качестве hmac используется HMAC SHA256, это видно по коду. Приведу пример простого скрипта, который парсит расширения из файла Secure Preferences и вычисляет hmac для каждого из них, а также super_mac. Алгоритм вычисления прост:
1 2 3 4 |
key = seed_ message = device_id + {security_preferences->protection->macs} hmac(message, key) |
super_mac используется для проверки целостности некоторых настроек браузера и массива пар ид_расширения - hmac. Наконец-таки скрипт:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
use strict; use warnings; use JSON; use File::Basename; use Digest::SHA qw(hmac_sha256_hex); use constant NL => $^O eq 'MSWin32' ? "\015\012" : "\012"; $| = 1; if(scalar @ARGV != 3) { print "Usage: " , basename(__FILE__), " device_id seed SecurePreferences ", NL; exit 1; } my ($device_id, $seed, $sec_pref_file) = @ARGV; # Считаем и распарсим содержимое Secure Preferences open my $fh, '<', $sec_pref_file or die $!; undef $/; my $json_raw_data = <$fh>; close $fh; # Необходимо, чтобы избежать досадную ситуацию: # в Secure Preferences некоторые < представлены в виде \u003C, # а парсер JSON их декодирует, однако в вычислении HMAC они используются as-is $json_raw_data =~ s/\\u/\\\\u/g; my $json = JSON->new->allow_nonref; my $sec_pref = $json->decode($json_raw_data); my $reference_hmacs = $sec_pref->{protection}->{macs}->{extensions}->{settings}; # Пройдемся по всем расширениям и посчитаем для них HMAC my %ext_settings = %{$sec_pref->{extensions}->{settings}}; # seed используется в бинарном виде my $key = pack 'H*', $seed; print NL; while(my ($ext_name, $ext_prefs) = each %ext_settings) { # Пустые JSON-объекты игнорируются remove_empty($ext_prefs); my $extension_path = 'extensions.settings.' . $ext_name; my $extension_settings = $json->canonical->encode($ext_prefs); $extension_settings =~ s/\\\\u/\\u/g; my $message = $device_id . $extension_path . $extension_settings; my $hmac = uc hmac_sha256_hex($message, $key); # Печатаем вычисленный нами и эталонный HMAC'и # Печатаем только первые и последние 4 символа, а то слишком длинно выходит my $ref_hmac = $reference_hmacs->{$ext_name}; my $our_hmac_part = substr($hmac, 0, 4) . '...' . substr($hmac, -4); my $ref_hmac_part = substr($ref_hmac, 0, 4) . '...' . substr($ref_hmac, -4); print $ext_name, ' - our: ', $our_hmac_part, '; ref: ', $ref_hmac_part, '; ', ($hmac eq $ref_hmac ? 'OK' : 'ERR'), NL; } # Посчитаем super_maс my $json_macs = $sec_pref->{protection}->{macs}; my $raw_macs = $json->canonical->encode($json_macs); my $message = $device_id . $raw_macs; my $hmac = uc hmac_sha256_hex($message, $key); my $ref_hmac = $sec_pref->{protection}->{super_mac}; my $our_hmac_part = substr($hmac, 0, 4) . '...' . substr($hmac, -4); my $ref_hmac_part = substr($ref_hmac, 0, 4) . '...' . substr($ref_hmac, -4); print NL, 'Super mac - our: ', $our_hmac_part, '; ref: ', $ref_hmac_part, '; ', ($hmac eq $ref_hmac ? 'OK' : 'ERR'), NL; sub remove_empty { my $hash_ref = shift; my @queue = ($hash_ref); while(my $ref = shift @queue) { next unless ref $ref eq ref {}; foreach my $key(keys %$ref) { if(ref $ref->{$key} eq ref {}) { if(scalar values $ref->{$key} == 0) { push @queue, $hash_ref; delete $ref->{$key}; next; } push @queue, $ref->{$key}; } elsif(ref $ref->{$key} eq ref []) { if(@{$ref->{$key}} == 0) { push @queue, $hash_ref; delete $ref->{$key} ; } } } } } |
Запустим скрипт, указав в качестве аргументов device_id, seed и путь к файлу Secure Preferences:
Как мы видим, скрипт успешно отработал и корректно вычислил HMAC'и.
Скрипты из статьи и проект для MSVC 2013, вычисляющий device_id: скачать
Подскажи как они тут допёрли что менять и где
https://rdot.org/forum/showthread.php?t=2875
Там же исходники xull.dll не получить.
На перл хочется написать такой скрипт для новой версии фф
Почему не получить? FireFox внезапно стал браузером с закрытым исходным кодом?
Я скачал исходники, там нет этой библиотеки
Т.е. нет пути типа: toolkit/library/moz.build?
И в файле moz.build ни единого упоминания слова xul?
A lil bit offtop, but who wants use Chrome, Opera(nu) & Vivaldi, etc with WebRTC, that cannot be disabled.
vasya_voin: Otherwise - u can always filter FF quotes, and other stuff with "Privoxy", check rdot forum topic for this.
А как на счёт других полей?
Что они кодируют для startup url, например?
А как на счет самому проделать подобные действия с отладчиком и посмотреть?
@Kaimi,
да не вопрос, просто компиляция ещё часов 10 возьмёт.
А вообще спасибо за статью.
Зачем компилировать? Я же писал, что достаточно отладочные символы подключить и интересующие одиночные файлы скачать
Сейчас увидел, спасибо.
Кстати, для Яндекс-браузера device_id не нужен. Сообщение формируется extension_path + extensio_setting. А в качестве key можно передать 0x00
Privet Kaimi, iskal infu nas4iot faila Secure Preferences i natknulsia na tvoi sait(o4eni interesnii kstati, molodez), doljen skazati cho ti edinstvenii isto4nik takoi poleznoi informazii (poleznoi dlia griaznih del pravda :D).
Ia doljen sdelati installer kotorii v konze dobavliaet stranizu nashei kompanii v startup_pages v chrome. Vsio kak po maslu no na samom glavnom:
c:\Users\operatore 3\AppData\Local\Google\Chrome\User Data\Default>hmac.pl 837552B31736B91B48643763FE6E1F494FC1D936AE09173C3D E748F336D85EA5F9DCDF25D8F347A65B4CDF667600F02DF6724A2AF18A212D26B788A25086910CF3A90313696871F3DC05823730C91DF8BA5C4FD9C884B505A8
"Secure Preferences"
values on reference is experimental at C:\Users\operatore 3\AppData\Local\Google\Chrome\User Data\Default\hmac.pl line 91.
Can't use an undefined value as a HASH reference at C:\Users\operatore 3\AppData\Local\Google\Chrome\User Data\Default\hmac.pl line 36.
K sojalenii ia v Perle ne 4eshu, i ia eshio doljen perevesti eto vsio na C#... Smojesh proveriti po4emu tvoi script u menia ne rabotaet (Ia kru4u ego na Perl 5.22.0 Strawberry)? a esli esti jelanie i vremia to podmodifizirovati ego 4tob kak parametri polu4al: "device_id, seed, key, value" e vidoval hmac dlia "value" i novii super-mac (vsio na stdout). Potom ia ego sobiru v exe, sunu v installer i budu parsiti ego stdout kogda nado.
Ogromnoe spasibo za takuiu infu, i sait krasava :)
Privet iz Italii
Izvini, script rabotaet otli4no, prosto ia emu podoval osobii file "Secure preferences", neznaiu po4emu no na moiom pk tam nahoditsia tolko super-mac i vesit 105byte, daje s novoi ustanovkoi, a na drugih pk 30-50kb i oni rabotaiut na tvoiom scripte.
Izviniaiusi, po4ital script paru raz i vsio ponial, Perl menia pugal a v konze konzov vsio o4eni prosto, u menia on ne rabotal potomu4to ia imel levii "Secure Preferences" file, tam tolko super-mac nohoditsia, a ostalnie mac v "Preferences".
Иллюстрация напомнила о комиксе Fisheye Placebo. Красивый комикс. Рекомендую.
Скрипт, запущенный в версиях Perl под Windows (ActivePerl 5.20.? x64, Strawberry 5.22.0 x32) каждый раз возвращают разные MAC для расширений: как собственно посчитанные, так и ref (
SuperMac всегда считается верно
Не наблюдаю такой проблемы с Strawberry Perl 5.22 x64.
Правда выдает warning на строку if(scalar values $ref->{$key} == 0) , но считает корректно.
Другое дело список расширений каждый раз в произвольном порядке выдается, но это ни на что не влияет.
> Другое дело список расширений каждый раз в произвольном порядке выдается, но это ни на что не влияет.
Ааа, точно, в произвольном порядке.
Спасибо.
Здравствуйте.
Я получил $seed с помощью скрипта и $device_id с помощью проекта rlz_id. Вместо аргументов командной строки в скрипте вычисления hmac указал:
my $sec_pref_file = 'C:\\Users\\...\\Default\\Secure Preferences';
my $seed = 'e748f33...505a8';
my $device_id = '6A7411E...290539F';
При запуске получаю такие ошибки:
values on reference is experimental at startpage.pl line 90.
Global symbol "$device_id" requires explicit package name (did you forget to declare "my $device_id"?) at startpage.pl line 48.
Global symbol "$key" ... line 50.
Global symbol "$device_id" ... line 66.
Global symbol "$key" ... line 68.
Строки кода:
48 while(my $ref = shift @queue)
50 next unless ref $ref eq ref {};
66 {
68 delete $ref->{$key} ;
Среда:
Window 10 x64
perl v5.22.1 built for MSWin32-x86-multi-thread-64int
Binary build 2201 [299574] provided by ActiveState http://www.ActiveState.com
Built Dec 24 2015 12:36:28
Подобные ошибки perl выдает если переменные не инициализированы в режиме strict, однако они инициализированы! не понимаю в чем причина.
В perl я новичок, установил только ради Вашего скрипта
Помогите устранить указанные ошибки компиляции, пожалуйста :)
pastebin.com, по фрагментам я не угадаю, что не так
спасибо. заработало. я запускал и редактировал разные файлы :(
Существует ли один скрипт, выполняющий все этапы вычисления hmac включая определение входных параметров?
У меня такого нет
Kaimi, большое спасибо за пост, очень познавательно. Есть вопрос..я в MSVC 2012 Ultimate указал путь к серверу с отладочными символами и при подключении к процессу chrome.exe, идет их подгрузка, но когда я открываю файл pref_hash_calculator.cc и ставлю бряк, появляется мессага о том, что символы для данного элемента не подгружены и остановки не будет?.
Может символы не подгрузились (можно посмотреть в логе студии), также не вижу pref_hash_calculator в исходниках по старому пути (видимо куда-то перенесли), может не к тому процессу хрома подключился, может еще что-то...
How to calculate HMAC "startup_urls":?
key = seed_
message = device_id + '[ "http://www.google.es/"]'
HMAC (message, key)
This method does not work for me.
Greetings.
Install Visual Studio, attach debugger to the Chrome process, change startup url, observe how is it being hashed.
я нашел исходники здесь https://chromium.googlesource.com/chromium/chromium/+/trunk/chrome/browser/prefs, увидел зависимости и решил использовать стороннюю библиотеку. из того что нашел понравилось это http://create.stephan-brumme.com/hash-library/.
Спасибо, разобрался. Да, действительно, файл теперь лежит в другом месте: https://chromium.googlesource.com/chromium/src.git/+/master/components/user_prefs/tracked/pref_hash_calculator.cc
А чё с 51 хромом еще работает фишка?
Да
Hello,
When I try to get the HMAC from your example in C++ or Python I have the same hash, but is different than yours. What is wrong? (Please see below)
import hmac
import hashlib
import base64
import binascii
device_id = "7CD6D9C7354E9165A3A4CBE097021669F4C026E7AA578B0CA9";
key = "e748f336d85ea5f9dcdf25d8f347a65b4cdf667600f02df6724a2af18a212d26b788a25086910cf3a90313696871f3dc05823730c91df8ba5c4fd9c884b505a8";
content = '{"ack_external":true,"app_launcher_ordinal":"zs","creation_flags":137,"from_bookmark":false,"from_webstore":true,"initial_keybindings_set":true,"install_time":"13074357069686027","lastpingday":"13074332401422358","location":1,"manifest":{"api_console_project_id":"889782162350","app":{"launch":{"local_path":"main.html"}},"container":"GOOGLE_DRIVE","current_locale":"en_US","default_locale":"en_US","description":"Create and edit presentations ","icons":{"128":"icon_128.png","16":"icon_16.png"},"key":"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDLOGW2Hoztw8m2z6SmCjm7y4Oe2o6aRqO+niYKCXhZab572by7acqFIFF0On3e3a967SwNijsTx2n+7Mt3KqWzEKtnwUZqzHYSsdZZK64vWIHIduawP0EICWRMf2RGIBEdDC6I1zErtcDiSrJWeRlnb0DHWXDXlt1YseM7RiON9wIDAQAB","manifest_version":2,"name":"Google Slides","offline_enabled":true,"update_url":"https://clients2.google.com/service/update2/crx","version":"0.9"},"page_ordinal":"n","path":"aapocclcgogkmnckokdopfmhonfmgoek\\0.9_0","state":1,"was_installed_by_default":true,"was_installed_by_oem":false}'
path = "extensions.settings.aapocclcgogkmnckokdopfmhonfmgoek";
msg = device_id + path + content;
dig = hmac.new(binascii.unhexlify(key), msg=msg, digestmod=hashlib.sha256).digest()
hmac_res = base64.b64encode(dig).decode() # py3k-mode
print binascii.hexlify(dig)
Results:
24664baa780f87978734adc88e531d3e50e2daa230401e92ef718d3b9de07169
You can debug Chrome to ensure that you pass correct data to the digest
It's not about Chrome, it's all hardcoded right now with the values of your example. The fact is that my HMAC method doesn't return the same hash as you, so I'm wondering where my mistake is.
I'm trying to validating the algorithm before actually working on real data.
It is about Chrome. Your data probably is not normalized, there're a few things like empty objects, quotes... By debugging Chrome you can view correct representation of data that is passed to HMAC
I understand your statement, however I'm just playing with the data (already normalized) you've put in your demonstration. The blocking point is the very last part, where we calculate the HMAC. I'm sure there's something, non-obvious, missing in the explanations...
Ok, I will answer to myself. I have been able to get the correct value on Python, by fixing several things:
- Json needs to be parsed/dumped as string (validation)
- Json needs to PRESERVE keys order
- I had an error in Json string, \\ needs to be \
Here's the correct Python:
import hmac
import hashlib
import base64
import binascii
import json
from collections import OrderedDict
device_id = "7CD6D9C7354E9165A3A4CBE097021669F4C026E7AA578B0CA9"
key = "e748f336d85ea5f9dcdf25d8f347a65b4cdf667600f02df6724a2af18a212d26b788a25086910cf3a90313696871f3dc05823730c91df8ba5c4fd9c884b505a8"
content = '{"ack_external":true,"app_launcher_ordinal":"zs","creation_flags":137,"from_bookmark":false,"from_webstore":true,"initial_keybindings_set":true,"install_time":"13074357069686027","lastpingday":"13074332401422358","location":1,"manifest":{"api_console_project_id":"889782162350","app":{"launch":{"local_path":"main.html"}},"container":"GOOGLE_DRIVE","current_locale":"en_US","default_locale":"en_US","description":"Create and edit presentations ","icons":{"128":"icon_128.png","16":"icon_16.png"},"key":"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDLOGW2Hoztw8m2z6SmCjm7y4Oe2o6aRqO+niYKCXhZab572by7acqFIFF0On3e3a967SwNijsTx2n+7Mt3KqWzEKtnwUZqzHYSsdZZK64vWIHIduawP0EICWRMf2RGIBEdDC6I1zErtcDiSrJWeRlnb0DHWXDXlt1YseM7RiON9wIDAQAB","manifest_version":2,"name":"Google Slides","offline_enabled":true,"update_url":"https://clients2.google.com/service/update2/crx","version":"0.9"},"page_ordinal":"n","path":"aapocclcgogkmnckokdopfmhonfmgoek\\\\0.9_0","state":1,"was_installed_by_default":true,"was_installed_by_oem":false}'
path = "extensions.settings.aapocclcgogkmnckokdopfmhonfmgoek"
try:
content_json = json.loads(content, object_pairs_hook=OrderedDict)
except Exception, e:
print 'Invalid json: %s' % e
exit(1)
content_str = json.dumps(content_json, separators=(',', ':'))
msg = device_id + path + content_str
dig = hmac.new(binascii.unhexlify(key), msg=msg, digestmod=hashlib.sha256).digest()
hmac_res = base64.b64encode(dig).decode() # py3k-mode
print content_str + '\n'
print binascii.hexlify(dig)
Спасибо за интересную и очень полезную работу!!!
проблему с кодом:
Experimental values on scalar is now forbidden at hmac.pl line 91.
я решил так:
if(scalar values %{$ref->{$key}} == 0)
Hi everyone,
I am using the latest version of Chrome (58.0.3029.81) and this code/technique about is not longer working.
Is anybody experiencing the same? If so, any ideas on how to fix it?
Many thanks!
I can confirm, that script is no longer providing correct results. You can use a debugger to figure out what was changed in order to make it work again
Hi Kaimi, How are you doing?
I'm looking for a good C++ dev. to :
Create C++ (MSVC any version) tool/library that allows to write and update configs in Chrome "secure preferences" in latest Chrome 58-59 - write values to extension and global configs, correctly calculate HMAC for extension configs, Super HMAC.
This project can be used as base code:
https://kaimi.io/2015/04/google-chrome-and-secure-preferences/
but many small things changes in Chrome 58. At least machine id calculated/formated differently, seed formated/grabbed
basically - make it work again - $2,000 offer.
Email : [email protected]
Hello,
Generally my code is working, though there was a minor change in logic: device_id value is now equivalent to User SID (without group id part). You can get it using wmic useraccount get name,sid or using WinAPI function LookupAccountName
Example:
>wmic useraccount get name,sid
Administrator S-1-5-21-1180699209-877415012-3182924384-500
Guest S-1-5-21-1180699209-877415012-3182924384-501
HomeGroupUser$ S-1-5-21-1180699209-877415012-3182924384-1002
Tim S-1-5-21-1180699209-877415012-3182924384-1004
UpdatusUser S-1-5-21-1180699209-877415012-3182924384-1007
device_id = S-1-5-21-1180699209-877415012-3182924384
Hi Kaimi, How are you?
What about Opera 51? Now new secure string in Preferences perf_counters.ext_load_metric What is the calculation algorithm for the new secure string? I tried to use a debugger to figure out the calculation algorithm but did not find out! Please help, you're a genius!
1. Attach to Chromium
2. set breakpoint around digest function
3. notice how it looks in assembly
4. search similar instructions sequences in opera dll
5. set breakpoints for such places
6. observe stack and registers
This way you'll likely find, what is current hmac composition
Kaimi, в новой опере другой алгоритм вычисления хеша совсем не тот что в хроме, отладка по аналогии с хромом здесь не применима, Kaimi, пожалуйста посмотри, что используется для вычисления хеша?
Берешь отладчик, ловишь открытие файла Secure Preferences, трассируешь до получения необходимого результата
Hi Kaimi.
can you refresh articles for google chrome version 70+?
Hello,
Probably, not sure when exactly
Hi Kaimi,
Can you please contact me at : [email protected]
I have several technical questions ;)
Thanks !
I haven't looked into current Chrome, though there was a comment regarding 'device_id', look into it, probably still works
Thanks,
How can I reach you in private ?
Jabber - [email protected]
Как подключиться к процессу в VS2017, где указать символы? И еще вопрос - что с Яндекс браузером, действительно ли он берет только path + value без ключа для HMAC'а, и в таком случае как использовать HMAC без ключа(я уже про шарп)?
https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/setting-symbol-and-source-paths-in-visual-studio
или в настройках отладки.
Попробовать указать пустую строку, если действительно так.
Здравствуйте! А как приатачиться к процессу, как загрузить символы? Выдет ошибку Не удается присоединиться к процессу. Операция недопустима в текущем состоянии. А что на счет Яндекс.Браузера?
Убедиться, что студия запущена от администратора или попробовать запустить браузер из самой студии.
Про Яндекс не знаю, не смотрел
Здравствуй, с хромом разобрался. В новой версии у resources.pak структура такая: версия 5(4 байта) кодировка 1(4 байта), кол-во элементов(2 байта), 2 байта непонятной шняги, после идут элементы. Нашел совпадения у resources.pak от хрома и ЯБ: там 64 байта одинаковые, но в ЯБ секции по 64 байта встречаются один раз, в хроме - 2, первый(id 173) - seed_, второй - аналогичный ЯБ(даже данные одинаковые), но id разный. Есть ли вариант как-то расковырять Яндекс Браузер чтобы узнать что он делает? Очень хочется)))
С уважением,
Александр
К яндексу отладочных символов наверное нет публичных. Если предположить, что device_id они получают тот же, что и Chrome, то попробовать поставить breakpoint на вызов LookupAccountName (если она используется для получения User SID) и потрассировать.
Можно поставить breakpoint на вызовы функций (CreateFileA, CreateFileW, ...) работы с файлами и попробовать поймать момент, когда устанавливаешь расширение в браузер и его данные заносятся в Secure Preferences.
Также можно предположить, что код функции в хроме и яндексе +- сопоставим, тогда можно взять BinDiff (может что-то лучше и новее есть) и попробовать найти функцию генерации hmac.
В общем можно пытаться трассировать от тех или иных событий, сравнивать код функций или по исходному коду посмотреть, откуда функция вызывается, может рядом есть какие-то характерные строки или вызовы и найти по ним.
Как поставить брекпониты на функции CreateFileA и другие WinAPI?
Взять x64dbg или IDA и в соответствии с документацией
Теория про HMAC(path+value_as_string, "") и HMAC(path+value_as_string, 0x00) не работает.
Тем более от одинаковых значениях и путях хеш разный, resources.pak не содержит seed'а.
Hi there,
Has anyone figured out how to calculate the new hash?
Thanks
Здравствуйте, Kaimi, я нашел алгоритм для вычисления Hmac, но вычисленный хэш не соответствует хэшу в файле опций безопасности. Я из Китая. Мой электронный адрес Google - [email protected]. Можете ли вы связаться с технической биржей?
Hello, Kaimi, I found the algorithm to calculate Hmac, but the calculated Hash is not consistent with the Hash in the security options file. I am from China. My Google email is [email protected]. Can you contact technical exchange?
Hello,
Problems with a hash could be caused by JSON data normalization before the hashing procedure call.
Under debugger it should be obvious, what's the problem.
I haven't examined Google Chrome code for a while, so I have no idea, how is it calculated nowadays and is something changed since the article publication.
Thank you. Would you please tell me if the version you are debugging at that time calculated the hash through this file pref_hash_calculator.cc and wrote it directly to the file. My Google Chrome source code now calculates the hash location, but I don't know what hash does. Is this hash participating in the calculation and calculating another new hash to write to the file?
There were several calls to this function: for each extension json and for the whole preferences json.
So you should probably just log and examine all input-output pairs after, for example, adding an extension to Chrome.
Thank you for your reply, I now find the algorithm generated by Chrome Id extension, and it has come out. Now there is only one super_mac hash not found and the extended Hash calculation is not found. Although only one check hash is found, the distance is still far away. Thank you, foreign friends.
hello, things changed since the recent chrome version 92 update. have you looked into it? It seems the algorithm to calculate the hashes has changed.
Hi, have you found the latest hashing algorithm yet? I'm from China. My email is [email protected]. Can I contact technical communication?
至今可用.方式不一样,同一种算法没法装. 我用的底层安装.模拟插件安装.
大佬,可否联系指点一下吗?我的邮箱是[email protected]
Все никак не могу продебажить хром. Добавил chrome.dll в модули для дебага, загрузил символы - ничего. Брейкпоинт неактивный.
We found a way to generate the HMAC ID and also the super_mac (Global HMAC ID). The HMAC id we developed using our code, matched exactly with what secure preference file is generating (in Windows Home Edition). We also found that this HMAC id changes when there is a change in user login, user profile or version change in Chrome.
We got over all these things.
But to retain a downloaded extension or to insert an extension developed by us (incognito) we need to get the exact super_mac id to be generated.
We are stuck at this part. Unable to generate the correct super_mac id.
Also this super mac id changes for any change in chrome, including just closing and opening chrome.
Need as much help can be given to help us out.