Объекты операционной системы. Часть 4: Отладчик уровня ядра WinDbg
Запись от _lunar_ размещена 24.12.2021 в 19:41
Показов 3267
Комментарии 0
Объекты операционной системы. Часть 1: Общие сведения Объекты операционной системы. Часть 2: Объект ядра Объекты операционной системы. Часть 3: Уровень целостности В этой части я решил показать самые интересные, на мой взгляд, возможности ядерного отладчика WinDbg. Но сначала немного слов о том, как его установить и как им пользоваться. В этом блоге я буду показывать работу отладчика WinDbg сразу для двух операционных: Windows 7 (x64) и Windows 10/11 (x64). Почему две ОС? По двум причинам: 1. Windows 7 всё ещё остаётся актуальной; 2. Работа ядер этих ОС имеет большие различия, которые несомненно вызывают интерес, и которые мы увидим на примерах. Итак, начнём с Windows 7. Здесь всё просто, идём на MSDN, качаем Windows 11 WDK (прямая ссылка на online установщик) и устанавливаем по умолчанию в папку Program Files (x86). После установки отладчик WinDbg будет располагаться по пути: Program Files (x86)\Windows Kits\10\Debuggers\x64 Попробуйте запустить windbg.exe, если вылезет вот такая ошибка то скачайте эту библиотеку api-ms-win-core-sysinfo-l1-2-0.rar и положите в туже папку, где находится windbg.exe, ещё раз проверьте запускается ли отладчик. Теперь, чтобы воспользоваться именно KernelMode отладкой необходимо выполнить три шага: 1. В BIOS отключите опцию SecureBoot (должно быть Disabled), если такой опции в BIOS нет, то переходите ко второму шагу. 2. Запустите командную строку (cmd.exe) от имени администратора и введите следующую команду bcdedit -debug on , должна быть надпись об успешном выполнении команды.3. Перезагрузите компьютер. Запустите windbg.exe от имени администратора. В меню нажмите File -> Kernel Degug... -> выберите Local и нажмите OK Дождитесь окончания загрузки символов (в командной строке должна появиться надпись lkd> , что означает, что отладчик готов к принятию команд).Теперь установка и настройка для Windows 10/11. В этих ОС можно выбрать какой отладчик устанавливать: - тот же, что и описанный в Windows 7 из пакета Windows 11 WDK; - либо из магазина Microsoft Store WinDbg Preview, который также можно найти и в самом магазине. Лично я предпочитаю WinDbg Preview, у него неплохой интерактивный GUI, да и сам интерфейс куда более приятный и современный. Настройка аналогична трем шагам из Windows 7: выключить SecureBoot, включить debug on и перезагрузить компьютер. Из Пуска запустите WinDbg Preview от имени администратора. В меню нажмите File -> Attach to kernel -> выберите Local и нажмите OK Дождитесь окончания загрузки символов (в командной строке должна появиться надпись lkd> , что означает, что отладчик готов к принятию команд).Так как отладчик сейчас работает в режиме ядра ОС, то эксперименты будем ставить над самым главным процессом - ядром операционной системы System. Итак, первой командой, которой мы воспользуемся, это !process Она выводит базовую информацию о процессе: сессию в которой он работает, идентификатор, родительский процесс, количество открытых дескрипторов этим процессом. Давайте введем команду !process 0 0 System Отлично! Теперь у нас есть значение объекта процесса System PROCESS fffffa80048d8040 Для того, чтобы понять что находится в этом объекте, необходимо получить заголовок этого объекта (ObjectHeader). В отладчике WinDbg для этого предусмотрена команда !object Соответственно введём эту команду и значение того объекта, у которого требуется получить заголовок !object fffffa80048d8040 Теперь у нас есть значение заголовка объекта процесса System ObjectHeader: fffffa80048d8010 (new version) Зная это значение, можно посмотреть что содержится в структуре _OBJECT_HEADER Воспользуемся следующей командой, которой передадим значение заголовка объекта dt nt!_object_header fffffa80048d8010 Самыми интересными полями этой структуры являются TypeIndex и SecurityDescriptor. Начнём с SecurityDescriptor : 0xfffff8a0`0000464b. Это указатель на структуру, содержащую уже знакомые нам ACL (SACL и DACL), а также их ACE, SID группы и владельца и их флаги. Введем специальную команду, чтобы отобразить содержимое структуры, находящейся по значению SecurityDescriptor: !sd 0xfffff8a0`0000464b & -10 Заметьте, что KernelExplorer, кроме вывода этой информации, также выводит более детализированную информацию, в частности по структуре ACTRL_ALIST. Данная структура является недокументированной, и собирать её содержимое достаточно сложно, видимо в Microsoft не стали заморачиваться, а ведь там есть очень ценная и уникальная информация по правам доступа каждого ACE (ACTRL_ACCESS_ENTRY) Теперь давайте разберемся, что такое TypeIndex : 0x7. TypeIndex это индекс указателя на структуру _OBJECT_TYPE в таблице ObTypeIndexTable. Давайте посмотрим что это за таблица ObTypeIndexTable, находящаяся в ядре ОС. Для этого введём команду dps nt!ObTypeIndexTable Так как эксперименты проводятся на 64 битной ОС, соответственно значения являются 8-ми байтовыми. Обратите внимание: второе значение является ошибочным 00000000BAD0B0B0. Что это такое? Это заплатка (patchGuard) от эксплойта вида В Windows 7 существовал способ, позволяющий через shellcode получить контроль на объектами ядра в таблице ObTypeIndexTable. После patchGuard все обращения ко второму значению приводили к ошибке вида BAD ObjectHeader. В Windows 8.1 исправили этот баг непосредственно в коде ядра, тем самым представив метаданные следующим образом Но давайте вернёмся к TypeIndex и его значению 0x7. Начав отсчитывать от первого нулевого значения (нулевой индекс) до седьмого индекса (восьмого значения) в таблице ObTypeIndexTable, мы попадаем на значение fffffa80048769b0. Пока запомним его. Для того, чтобы посмотреть содержимое структуры _OBJECT_TYPE воспользуемся специальной командой, в которой происходит арифметическое действие над таблицей с учетом индекса 7 и размерности значения, находящегося по этому индексу (8 байт) dt nt!_OBJECT_TYPE poi(nt!ObTypeIndexTable + (7 * 8)) Первым делом посмотрите на поле Name : _UNICODE_STRING "Process". Вернитесь в скриншоту, где мы использовали команду !object - поле Type: (fffffa80048769b0) Process: данный объект ядра является Process. А теперь посмотрите на поле TypeList : _LIST_ENTRY (0xfffffa80`048769b0). Точно такое же значение, которое мы запомнили чуть раньше. Поздравляю, мы получили валидный индекс процесса System (ядра ОС) в таблице ObTypeIndexTable. Теперь вернёмся к Windows 10/11 и попробуем определить индекс в таблице ObTypeIndexTable. Вот что мы получим в итоге TypeIndex в Windows 10/11 зашифрован. Кроме того, в Windows 10 21H2 диапазон индексов лежит в промежутке [0...68] Кликните здесь для просмотра всего текста
а 0x4E это 78, что уже означает выход за допустимый диапазон. Кстати в Windows 11 21H2 диапазон индексов был расширен Кликните здесь для просмотра всего текста
Касаемо новых объектов ядра в Windows 11, могу порекомендовать почитать вот этот материал ProcessStateChange и ThreadStateChange - Thread and Process State Change IoRing - I/O Rings – When One I/O Operation is Not Enough А это таблица индексов объектов ядра Windows 7 Кликните здесь для просмотра всего текста
В Microsoft посчитали, что такой лёгкий доступ к таблице индексов ObTypeIndexTable недопустим и постарались запутать исследователей. Но их защита простояла недолго, достаточно быстро был найден способ получения валидного индекса, довольно нетрадиционным способом. Во-первых, исследователи ядра начали искать фрагменты кода, которые имеют что-то общее со структурой _OBJECT_TYPE
Затем было решено посмотреть на её мнемонику ассемблерного кода
1. Код вычисляет адрес структуры _OBJECT_HEADER путем вычитания 0x30 из адреса памяти объекта, переданного в качестве аргумента. 0x30 это смещение от начала объекта до его заголовка в 64 битных ОС. В 32 битных ОС это смещение равняется 0x18. 2. Код выполняет операцию XOR для значения TypeIndex со вторым младшим байтом адреса структуры _OBJECT_HEADER, вычисленного на предыдущем шаге. 3. Затем код выполняет операцию XOR для результата из второго шага с байтом по адресу ObHeaderCookie. 4. Наконец результат операций XOR используется как индекс в ObTypeIndexTable и возвращает указатель на структуру _OBJECT_TYPE по этому индексу. Теперь более простым языком, чтобы было понятно. У нас есть объект PROCESS ffffc4052a8df040 процесса System, определенный после выполнения команды !process 0 0 System От его значения мы отнимаем смещение до начала заголовка объекта: ffffc4052a8df040 - 0x30 = ffffc4052a8df010 Отсчёт байт начинается справа налево. Таким образом второй младший байт это 0xf0 (ffffc4052a8d f0 10). Затем, необходимо выполнить команду db nt!ObHeaderCookie l1 чтобы определить байт в cookie, он равен 0xb9.TypeIndex в зашифрованном виде равен 0x4e. Теперь у нас есть все необходимые данные, они же ключи для расшифровки закодированного индекса методом XOR. Введём следующую команду: ? f0 ^ 4e ^ b9 В итоге получаем расшифрованный TypeIndex: 0x7 для процесса System как и в случае с Windows 7. Выведем таблицу ObTypeIndexTable командой dps nt!ObTypeIndexTable (как видите BAD ObjectHeader в Windows 10/11 уже нет).Остаётся лишь только проверить имя Name : _UNICODE_STRING "Process" и адреса в TypeList : _LIST_ENTRY (0xffffc405`2a8bf380), командой dt nt!_OBJECT_TYPE poi(nt!ObTypeIndexTable + (7 * 8)) Ну чтож, на этом я хотел бы поставить точку в изучении объектов операционной системы Windows. Конечно же это только верхушка айсберга, и внутреннее устройство ОС Windows куда сложнее того, что я показал здесь. Но главное, мы научились вскрывать то, что Microsoft зашифровала, причём на уровне ядра. |
Размещено в Без категории
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Всего комментариев 0
Комментарии