Поиск в реестре Windows, рекомендации

Добрый день! Уважаемые читатели и гости одного из популярнейших блогов посвященных системному администрированию Pyatilistnik.org. В прошлый раз мы с вами успешно восстановили данные на RAW диске и защищенном GPT разделе, тем самым сохранив свои цифровые активы. Сегодня я вам хочу показать еще одну полезную вещь, которая просто незаменима в практике системного администратора, а именно речь пойдет про поиск в реестре Windows, как его правильнее организовать, какие методы вы можете применять, думаю, что будет интересно.

Методы поиска в реестре Windows

  • Regscanner
  • Registry Finder
  • Через текстовый редактор
  • Через PowerShell

Поиск по редактору реестра

  • В редакторе реестра для того, чтобы начать поиск вам необходимо либо в меню правки выбрать соответствующий пункт
  • или же нажать сочетание клавиш CTRL+F для открытия окна поиска, когда вы найдете первый результат и он вас не устроит вы можете продолжить поиск нажав клавишу F3.

Поиск в реестре Windows, рекомендации

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

Поиск в реестре Windows через regscanner

Regscanner – это удобная утилита входящая в состав пакета NirSof, мы например, с помощью него смотрели сохраненные пароли браузеров.

  • Для поиска по реестру откройте Regscanner.exe
  • В окне “Regystry San Options” вы можете выбрать: “Find String” – искомое значение и “Don’t load more than” – количество выводимых строк (максимальное)
  • Задать временные промежутки, по умолчанию стоит значение “No time filter”, означающее, что поиск будет идти по всем ключам созданным, но вы можете искать только в записях созданных не позднее n-го количества дней (Show only Registry keys modified in the last) или наоборот записи измененные за определенный период времени.

Поиск в реестре Windows, рекомендации

Нажимаем кнопку “Scan” и запускаем поиск. В итоге я получил сразу сводную таблицу со всеми значениями заданными при поиске.

Поиск в реестре Windows, рекомендации

Поиск в реестре Windows через Registry Finder

Registry Finder позволяет просматривать локальный реестр; создавать, удалять, переименовывать ключи и значения; изменить значения как естественный тип данных (строка, многострочный, DWORD) или как двоичные данные. Разрешено открывать несколько окон реестра. В следующий раз, когда вы запустите Registry Finder, эти окна будут открыты с теми же ключами, что и раньше.

Поиск в реестре Windows, рекомендации

Поиск в реестре Windows, рекомендации

Поиск в реестре Windows, рекомендации

Поиск в реестре Windows, рекомендации

Поиск в реестре Windows, рекомендации

Командная строка Registry Finder

Registry Finder имеет ряд параметров командной строки, которые можно использовать для настройки его поведения.

  • –help – Печатает справочное сообщение.
  • –navigate arg – Определяет раздел реестра для навигации. Если для этого параметра установлено значение «буфер обмена», то путь берется из буфера обмена.
  • –reopenLocal arg – Восстановить или не открывать ранние локальные окна реестра при запуске Registry Finder (arg: true или false, по умолчанию true).
  • –reopenRemote arg – Восстановить или не открывать ранее удаленные окна реестра (arg: true или false, по умолчанию true).
  • –dataFolder arg – Определяет папку для хранения настроек и отмены истории.
  • –import arg – Импортирует указанный файл .reg в реестр.
  • Работа всегда выполняется в отдельном экземпляре (то есть подразумевается –multiInst).
  • –importSilent Не отображать подтверждение импорта.
  • –multiInst Когда экземпляр Registry Finder уже запущен, запускается новый экземпляр. По умолчанию запущенный экземпляр активируется вместо запуска другого.

Четвертый метод поиска по реестру Windows

Представим себе ситуацию, что у вас под рукой не оказалось специальных программ по поиску, но нужно быстро получить общую картину, тут вы можете поступить таким образом. В открытом окне “Редактора реестра” щелкаем правым кликом по значку компьютера и выбираем экспорт

Поиск в реестре Windows, рекомендации

В типе файла задаем TXT и указываем имя файла, после чего нажимаем сохранить. Ждем пару минут, после чего получаем выгруженные все значения с путями в ваш текстовый файл.

Больше проверок:  Журнал учета проверок юридических лиц

Поиск в реестре Windows, рекомендации

Открываем текстовый файл любым редактором и спокойно используем поиск по нему, это луче чем стандартный поиск через редактор.

Поиск в реестре Windows, рекомендации

То же самое можно сделать и с помощью скрипта вот с таким содержимым:

В результате чего у вас на диске C:Search_Reg.txt по которому вы так же легко осуществите поиск.

Поиск в реестре Windows, рекомендации

Поиск в реестре Windows через PowerShell

В PowerShell можно воспользоваться вот такой конструкцией:

Поиск в реестре Windows, рекомендации

На этом у меня все, мы с вами разобрали массу способов поиска ключей в реестре по нужным параметрам. С вами был Иван Семин, автор и создатель IT портала Pyatilistnik.org.

Поиск в реестре Windows, рекомендации

«Эй ты, функция. Да, я к тебе обращаюсь. При очистке не забудь, пожалуйста, восстановить все мои регистры. Да, и этот тоже, ты что, думаешь, в Linux попала?»

Вот краткое описание проблемы, с которой я столкнулся. ABI (Application Binary Interface) платформы требует от функций, чтобы они сохраняли значения определённых регистров и восстанавливали их в случае использования, однако набор восстанавливаемых регистров зависит от платформы, и правила в Linux отличаются от правил в Windows. Возможно, поэтому я столкнулся с повреждением регистров Chrome в Windows. Но давайте начнём с самого начала.

Меня попросили изучить баг вылета в Chrome. Вылет чётко коррелировал с инъецированием сторонних DLL в процессы Chrome (а их мы не можем поддерживать и не поддерживаем), поэтому была высока вероятность того, что причиной стали эти сторонние DLL, но мне всё равно хотелось понять, что же происходит.

Мои коллеги исследовали этот баг ранее и добавили несколько дополнительных тестов, поэтому вылет был изолирован до этого псевдокода (настоящий код находится здесь):

Показанный выше код представляет собой долго работающий цикл, выполняющий множество действий. В конце каждой итерации он вызывает функцию и перемещает умный указатель на параметры функции, что должно обнулять указатель. Вылет происходил, когда конструкция CHECK замечала, что указатель на источник на самом деле не был обнулён. В таком случае мы намеренно устраивали вылет, чтобы избежать повреждения памяти.

Изучить этот баг меня заставило любопытное поведение последних двух строк. Как мы можем обнулить указатель в одной строке кода, а потом в следующей строке обнаружить, что он ненулевой? Даже если виновники — сторонние DLL, как им удаётся это сделать? Я проверил наличие модификаций байтов кода рядом с вылетом и ничего не нашёл, так как же? Мне хотелось это понять.

Истина таится в дампе вылета

Простите за перемешивание метафор; суть в том, что перед запуском цикла компилятор решил обнулить регистр XMM7 (один из регистров SSE). Затем в конце каждой итерации цикла он использует XMM7 для обнуления m_ptr (хранящегося по адресу rsp+50h). Компилятор ожидал, что XMM7 останется обнулённым, но это было не так.

Я изучил большое количество дампов вылетов, чтобы посмотреть, есть ли какой-то паттерн в значениях внутри XMM7. Вот четыре из найденных мной значений:

  • 96 12 54 91 ca c8 18 ef 98 e8 77 c9 6e 5d ce ee
  • c5 1e 15 13 00 a0 94 5b 37 a5 f3 55 a8 7e 8d 7d
  • 54 39 1f 15 3e bf 13 3e 58 98 fd 6d 64 a3 5a 27
  • 04 df 90 27 02 94 4c ed 73 65 1d 61 af da 33 36

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

ABI — это важно

Поиск в реестре Windows, рекомендации

Функции DoLotsOfStuff и ImportantFunction, а также все функции, которые они вызывают, в соответствии с требованиями Windows ABI, обязаны сохранять XMM7 (в Linux такого требования нет). Если они используют его, то обязаны его восстановить. Но одна из них этого не делала (или повреждалось место в стеке, где они хранились, но это кажется менее вероятным). В большинстве вылетов в процессе Chrome присутствовали сторонние DLL. Предположительно, эти DLL должны выполнять перехват функций Chrome или операционной системы, а их инъецируемый код, предположительно, повреждал XMM7.

Больше проверок:  Права бизнеса при внеплановой проверке

Я написал об этом твит, пытаясь узнать теории о том, как это могло происходить. Среди прочих ответов с рассуждениями об ISR, DPC и драйверах я увидел ответ от человека, с которым никогда раньше не общался. Если вкратце, он сказал: «А как насчёт этого кода Chromium?»

Я увидел этот твит с моего домашнего ноутбука, а когда пошёл проверить на рабочей машине, автор уже его удалил. Моё любопытство разыгралось, поэтому я написал ему в личку. Он ответил, что код показался ему подозрительным, но потом он понял, что проблему разработчики осознали и что этот код на самом деле не компилируется в Chrome в Windows. В этом и сложность поиска неверного использования XMM7 в исходном коде Chromium — ссылок слишком много (более 17 тысяч), и большинство из них к делу не относится.

Затем он сказал, что перешёл к анализу двоичного файла при помощи IDA Pro
и обнаружил пару функций, попавших в chrome.dll, но не восстанавливавших XMM7. После этого он отправил ссылки на исходный код, который действительно выглядел как реальные баги. Именно в таком случае анализировать двоичные файлы на самом деле проще, чем «читать исходники», потому что в машинном коде все макросы и #ifdef уже обработаны, и в нём видно именно то, что и есть на самом деле.

Я решил воспроизвести его работу при помощи dumpbin /disasm и простого кода на Python для сканирования вывода. Для каждой функции в Chrome (найденной поиском глобальных символов в дизассемблированном выводе) мой скрипт проверял, использовался ли XMM7 без сохранения. Изначально я проверял, записывался ли он относительно rsp перед его первым использованием, но выяснил, что он записывается относительно rax и rbp, поэтому ослабил требования эвристики. Мой скрипт всё равно выдавал ложноположительные срабатывания и мог также выдавать ложноотрицательные, но работал достаточно хорошо, чтобы быть полезным.

Несмотря на первоначальное предположение о том, что баг вызван сторонними разработчиками, мой простой скрипт нашёл множество подозрительных функций. Обнаружилось приблизительно три категории функций, в которых первое использование XMM7 не восстанавливало его:

  • Функции наподобие dav1d_iflipadst_16x8_internal_16bpc_sse4 (отсюда?), являющиеся функциями внутреннего использования для библиотеки dav1d. Все эти функции вызываются обёртками, сохраняющими и восстанавливающими XMM7, то есть с ними всё было в порядке.
  • Функции наподобие __longjmp_internal, которые по определению восстанавливали все долговременные регистры, чтобы они могли возвратиться к предыдущему состоянию выполнения.
  • Встроенный в Chromium забагованный код.

Поиск в реестре Windows, рекомендации

Функция ScaleRowUp2_Bilinear_12_SSSE3 в WebRTC записывала в XMM7 константу 0x0008000800080008 без предварительного сохранения. Это баг, и он может вызывать вылеты, но я знал, что он не был причиной этого вылета, поскольку наблюдавшиеся мной значения XMM7 были сильно случайными. Я отправил отчёт о проблеме автору, он зарегистрировал баг и устранил его в течение 24 часов.

DyadicBilinearQuarterDownsampler_sse в openh264 тоже использовала XMM7 без его сохранения. Видеокодеки часто обрабатывают значения с высокой энтропией, поэтому возможно это могло создавать виденные мной случайные значения (спойлер: причина была не в этом) и это определённо было неправильно. Я зарегистрировал баг, а затем решил устранить его. Внедрение этого исправления вызвало пару сложностей:

  • Баг находился в файле на языке ассемблера, использовавшем множество макросов для обеспечения кроссплатформенной корректности. Поэтому мне пришлось выяснять (изучая соседние функции) нужные заклинания для сохранения регистров при необходимости. Это было не так уж сложно, но всегда странно писать код на языке, который, по сути, я совершенно не знаю. Распознавание паттернов — наше всё. Как бы то ни было, исправление в две строки сработало.
  • Устранение бага в openh264 не помогло Chrome сразу же, поскольку Chromium использует фиксированные копии сторонних библиотек. Поэтому мне нужно было «накатить» последнюю версию openh264. Иногда используется автоматическая утилита, выполняющая это с регулярными промежутками, но у openh264 её не было. Последний раз openh264 выкатывали шесть месяцев назад, а в промежутке кто-то переместил публичные файлы заголовков в новую папку. Так как Chromium и другой сторонний проект (WebRTC) включали в себя заголовки из этой переименованной папки, чтобы не сломать ничего в WebRTC или Chromium, требовался процесс из восьми этапов (один, два, три, четыре, пять, шесть, семь, восемь). По сути, методика заключалась в условных включениях в WebRTC и в ожидании автоматического накатывания WebRTC в Chromium и наоборот.
Больше проверок:  План проверок, запланированных на 2023 год

Проблемы WebRTC и openh264 были настоящими багами, а их устранение, вероятно, предотвратит будущие вылеты в Chromium, однако они никак не затрагивали исследуемый мной баг. Вылеты продолжались. По-прежнему наиболее вероятным объяснением было стороннее ПО.

Поиск в реестре Windows, рекомендации

Было множество намёков на то, какой тип стороннего ПО может быть проблемой. Это было нечто, создающее данные с высокой рандомизацией. Существовала очевидная корреляция со сторонним ПО шифрования диска. Один пользователь, с которым я исследовал вылеты, использовал сторонний продукт для шифрования диска, а Microsoft заметила корреляцию с задачами, заставляющими работать файловую систему. Были предприняты попытки связаться с поставщиком ПО.

Мы связались с поставщиком (McAfee/Trellix) и он выпустил исправление для продукта Drive Encryption.

Я рад, что первопричина была устранена, но ещё бы мне хотелось, чтобы разработчики, работающие над продуктом, в котором используется язык ассемблера, могли выполнять аудит своего кода, чтобы убедиться, что он соответствует требованиям Windows ABI. Это не первый случай такого класса багов и определённо не последний.

Моя мотивация

Я решил написать эту статью, потому что мне показалось, что это приключение было интересным, но ещё и потому, что оно ещё не закончено. Могут быть и другие регистры, которые неправильно сохраняются и восстанавливаются в Chromium. Могут существовать другие проекты, делающие эту ошибку, иногда незнакомые с различиями между ABI Linux и Windows. Любые правила ПО, которые не тестируются и не применяются принудительно, неизбежно будут сломаны, а мне неизвестны способы структурированного тестирования для выявления нарушений ABI. Похоже, появление новых багов этого типа неизбежно.

Итог

Эти вылеты начали происходить примерно с версии M91 браузера Chrome. Поначалу они выглядели как баг Chrome, но теперь кажется, что больше вероятность того, что компилятор или код Chromium изменился так, что стал уязвим к повреждению регистра XMM7, которое и так уже происходило в экосистеме. До M91 браузер Chrome вообще не использовал XMM7 в функции RunWorker (я проверял), а начиная с M91 генерация кода изменилась (смена компилятора?) и функция начала полагаться на то, что XMM7 часами оставался обнулённым. Поэтому пожалуйста, восстанавливайте регистры, завершив с ними работу.

И снова спасибо Dougall за демонстрацию проблемы и за то, что вдохновил меня изучить её глубже.