Хабрахабр

Три коротких истории о реестре Windows

Добрый день, уважаемые читатели.

Вряд ли найдется человек, который не слышал о нем. Реестр — это одна из самых заметных и значительных систем Windows. Но время от времени появляется что-то новое, что показывает мне, как я был неправ. Занимаясь программированием под Windows уже около 20 лет, я думал, что знаю о нем все. Поэтому сегодня я хочу рассказать вам о необычных способах работы с реестром, которые я встречал, исследуя руткиты, и которые удивили меня.

История первая. Имена значений и ключей реестра

Все мы знаем, что в Windows существуют некоторые правила именования объектов, будь то файлы, каталоги или ключи реестра. Имена файлов не могут содержать символ “\”. Имена не могут быть пустыми. У имен есть некоторые ограничения по длине и т. д.

И тут заключается наша ошибка. Невольно мы распространяем эти ограничения на все системы Windows и соблюдаем их при работе с реестром. Например, в имени значений можно использовать символ “\” В реестре ограничений при создании имен на удивление мало.

Удивлены? Нет? Тогда что вы скажете, если я покажу вам, что в имени значения можно использовать символ “\0”? Да-да, именно нулевой символ. Тот самый, который традиционно используется для указания конца строки.

Для этого нам понадобится функция NtSetValueKey, экспортируемая из ntdll.dll

HKEY hKey = 0;
RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\Run", &hKey); UNICODE_STRING uName;
uName.Buffer = L"Test\0Zero";
uName.MaxLen = uName.Length = 9 * sizeof(wchar_t); NTSTATUS status = 0; status = NtSetValueKey( hKey, &uName, 0, REG_SZ, (void*)lpData, DataSize); RegCloseKey(hKey);

Для выполнения функции NtSetValueKey вам понадобятся права администратора. В результате у вас в реестре появится значение с именем Test\0Zero.

к. Некоторые разработчики Microsoft тоже будут удивлены, т. стандартный редактор реестра не может отобразить такое необычное значение реестра.

История вторая

Вторая история, которую я вам сегодня расскажу, произошла в 2013 году.

В «Лаборатории Касперского» я являюсь членом команды, которая, помимо всего прочего, создает Kaspersky Rescue Disk. Вначале небольшое отступление. И для проверки правильности работы этого механизма мы используем множество тестов. Для лечения Windows из-под Linux нам необходимо самостоятельно разбирать файлы реестра. Среди них есть один достаточно простой:

  • Под Windows записываем в реестре тестовые значения.
  • Копируем файл куста реестра в тестовый каталог.
  • Запускаем программу, выполняющую удаление тестовых значений.
  • Загружаем модифицированный куст в реестр для проверки правильности удаления.

И вот в один прекрасный день мы обновили на тестовом стенде Windows до версии 8.1, и тест перестал удалять проверочные значения. Как же так, удивился я. Скопировал файл с кустом реестра к себе на рабочий компьютер — нет значений! Моя первая мысль: нужно добавить в тест Flush измененных ключей. Добавил вызов RegFlushKey, перезапустил тест — нет значений!

Но, как оказалось, прав я был лишь частично. Неужели RegFlushKey не работает, задумался я.

1 компания Microsoft изменила механизм сохранения изменений в реестр. Фокус оказался в том, что в Windows 8. В Windows 8. Раньше все изменения реестра накапливались в памяти, а потом, при закрытии ключа, при выполнении RegFlushKey или по истечении некоторого времени система сохраняла изменения в файл куста реестра. LOG, . 1 изменения вместо файла куста реестра сохраняются в одноименные файлы с расширениями . LOG2, а мой код эти файлы в те времена игнорировал. LOG1 и .

И лишь после этого Windows начинает задачу интеграции изменений в основной файл. В этих файлах изменения накапливаются около часа. Вызов функции RegFlushKey к запуску задачи Reconciliation не приводит. Эта задача называется Reconciliation, и она запускается либо раз в 40 минут, либо при завершении работы Windows. Для принудительного запуска задачи интеграции изменений нужно вызвать ZwSetSystemInformation с недокументированным аргументом SystemRegistryReconciliationInformation.

ZwSetSystemInformation( 0x9b, //SystemRegistryReconciliationInformation NULL, 0);

Для выполнения функции ZwSetSystemInformation вам понадобятся права администратора. А архитектура исполняемого файла должна совпадать с архитектурой системы. Вызвать эту функцию из 32-битной программы в 64-битной Windows не получится.

История третья

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

Создавал свой файл SYSTEM и периодически сохранял в него с помощью функции RegSaveKey ветку HKLM/System. Драйвер руткита при запуске переименовывал файл куста реестра SYSTEM в HARDWARE. При перезагрузке Windows система загружала файл SYSTEM и запускала драйвер руткита. При сохранении он восстанавливал свои ключи. Красиво. Красиво?

Wanted

P.S. У нас тут ищут разработчика-исследователя в команду, которая пилит анти-спамовый движок, а еще нужен инженер по тестированию.

Показать больше

Похожие публикации

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»