Форум программистов, компьютерный форум, киберфорум
_lunar_
Войти
Регистрация
Восстановить пароль
Карта форума Блоги Сообщество Поиск Заказать работу  
Рейтинг: 5.00. Голосов: 2.

Объекты операционной системы. Часть 4: Отладчик уровня ядра WinDbg

Запись от _lunar_ размещена 24.12.2021 в 19:41
Обновил(-а) _lunar_ 18.01.2022 в 16:20

Объекты операционной системы. Часть 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, если вылезет вот такая ошибка
Нажмите на изображение для увеличения
Название: 0.png
Просмотров: 226
Размер:	20.9 Кб
ID:	7328
то скачайте эту библиотеку 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
Нажмите на изображение для увеличения
Название: 0.5.png
Просмотров: 223
Размер:	15.7 Кб
ID:	7330
Дождитесь окончания загрузки символов (в командной строке должна появиться надпись 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
Нажмите на изображение для увеличения
Название: 1.png
Просмотров: 242
Размер:	44.9 Кб
ID:	7327
Дождитесь окончания загрузки символов (в командной строке должна появиться надпись lkd>, что означает, что отладчик готов к принятию команд).

Так как отладчик сейчас работает в режиме ядра ОС, то эксперименты будем ставить над самым главным процессом - ядром операционной системы System.
Итак, первой командой, которой мы воспользуемся, это !process
Она выводит базовую информацию о процессе: сессию в которой он работает, идентификатор, родительский процесс, количество открытых дескрипторов этим процессом.
Давайте введем команду !process 0 0 System
Нажмите на изображение для увеличения
Название: 2.png
Просмотров: 261
Размер:	64.0 Кб
ID:	7331
Отлично! Теперь у нас есть значение объекта процесса System PROCESS fffffa80048d8040
Для того, чтобы понять что находится в этом объекте, необходимо получить заголовок этого объекта (ObjectHeader).
В отладчике WinDbg для этого предусмотрена команда !object
Соответственно введём эту команду и значение того объекта, у которого требуется получить заголовок !object fffffa80048d8040
Нажмите на изображение для увеличения
Название: 3.png
Просмотров: 238
Размер:	60.6 Кб
ID:	7332
Теперь у нас есть значение заголовка объекта процесса System ObjectHeader: fffffa80048d8010 (new version)
Зная это значение, можно посмотреть что содержится в структуре _OBJECT_HEADER
Воспользуемся следующей командой, которой передадим значение заголовка объекта dt nt!_object_header fffffa80048d8010
Нажмите на изображение для увеличения
Название: 4.png
Просмотров: 243
Размер:	45.6 Кб
ID:	7334
Самыми интересными полями этой структуры являются TypeIndex и SecurityDescriptor.
Начнём с SecurityDescriptor : 0xfffff8a0`0000464b.
Это указатель на структуру, содержащую уже знакомые нам ACL (SACL и DACL), а также их ACE, SID группы и владельца и их флаги.
Введем специальную команду, чтобы отобразить содержимое структуры, находящейся по значению SecurityDescriptor: !sd 0xfffff8a0`0000464b & -10
Нажмите на изображение для увеличения
Название: 5.png
Просмотров: 268
Размер:	84.5 Кб
ID:	7335
Заметьте, что KernelExplorer, кроме вывода этой информации, также выводит более детализированную информацию, в частности по структуре ACTRL_ALIST.
Данная структура является недокументированной, и собирать её содержимое достаточно сложно, видимо в Microsoft не стали заморачиваться, а ведь там есть очень ценная и уникальная информация по правам доступа каждого ACE (ACTRL_ACCESS_ENTRY)
Нажмите на изображение для увеличения
Название: 5.5.png
Просмотров: 281
Размер:	36.2 Кб
ID:	7336
Теперь давайте разберемся, что такое TypeIndex : 0x7.
TypeIndex это индекс указателя на структуру _OBJECT_TYPE в таблице ObTypeIndexTable.
Давайте посмотрим что это за таблица ObTypeIndexTable, находящаяся в ядре ОС. Для этого введём команду dps nt!ObTypeIndexTable
Нажмите на изображение для увеличения
Название: 6.png
Просмотров: 236
Размер:	64.7 Кб
ID:	7337
Так как эксперименты проводятся на 64 битной ОС, соответственно значения являются 8-ми байтовыми.
Обратите внимание: второе значение является ошибочным 00000000BAD0B0B0.
Что это такое? Это заплатка (patchGuard) от эксплойта вида
Нажмите на изображение для увеличения
Название: 8.png
Просмотров: 251
Размер:	13.9 Кб
ID:	7339
В Windows 7 существовал способ, позволяющий через shellcode получить контроль на объектами ядра в таблице ObTypeIndexTable.
После patchGuard все обращения ко второму значению приводили к ошибке вида BAD ObjectHeader.
В Windows 8.1 исправили этот баг непосредственно в коде ядра, тем самым представив метаданные следующим образом
Нажмите на изображение для увеличения
Название: 9.png
Просмотров: 243
Размер:	9.9 Кб
ID:	7340
Но давайте вернёмся к TypeIndex и его значению 0x7.
Начав отсчитывать от первого нулевого значения (нулевой индекс) до седьмого индекса (восьмого значения) в таблице ObTypeIndexTable, мы попадаем на значение fffffa80048769b0. Пока запомним его.
Для того, чтобы посмотреть содержимое структуры _OBJECT_TYPE воспользуемся специальной командой, в которой происходит арифметическое действие над таблицей с учетом индекса 7 и размерности значения, находящегося по этому индексу (8 байт)
dt nt!_OBJECT_TYPE poi(nt!ObTypeIndexTable + (7 * 8))
Нажмите на изображение для увеличения
Название: 7.png
Просмотров: 234
Размер:	63.9 Кб
ID:	7338
Первым делом посмотрите на поле Name : _UNICODE_STRING "Process".
Вернитесь в скриншоту, где мы использовали команду !object - поле Type: (fffffa80048769b0) Process: данный объект ядра является Process.
А теперь посмотрите на поле TypeList : _LIST_ENTRY (0xfffffa80`048769b0). Точно такое же значение, которое мы запомнили чуть раньше.
Поздравляю, мы получили валидный индекс процесса System (ядра ОС) в таблице ObTypeIndexTable.

Теперь вернёмся к Windows 10/11 и попробуем определить индекс в таблице ObTypeIndexTable. Вот что мы получим в итоге
Нажмите на изображение для увеличения
Название: 10.png
Просмотров: 270
Размер:	23.6 Кб
ID:	7343
TypeIndex в Windows 10/11 зашифрован.
Кроме того, в Windows 10 21H2 диапазон индексов лежит в промежутке [0...68]
Кликните здесь для просмотра всего текста
Код:
TypeName                         | TypeIndex
---------------------------------|----------
(null)                           |  0
                                 |  1
Type                             |  2
Directory                        |  3
SymbolicLink                     |  4
Token                            |  5
Job                              |  6
Process                          |  7
Thread                           |  8
Partition                        |  9
UserApcReserve                   | 10
IoCompletionReserve              | 11
ActivityReference                | 12
PsSiloContextPaged               | 13
PsSiloContextNonPaged            | 14
DebugObject                      | 15
Event                            | 16
Mutant                           | 17
Callback                         | 18
Semaphore                        | 19
Timer                            | 20
IRTimer                          | 21
Profile                          | 22
KeyedEvent                       | 23
WindowStation                    | 24
Desktop                          | 25
Composition                      | 26
RawInputManager                  | 27
CoreMessaging                    | 28
ActivationObject                 | 29
TpWorkerFactory                  | 30
Adapter                          | 31
Controller                       | 32
Device                           | 33
Driver                           | 34
IoCompletion                     | 35
WaitCompletionPacket             | 36
File                             | 37
TmTm                             | 38
TmTx                             | 39
TmRm                             | 40
TmEn                             | 41
Section                          | 42
Session                          | 43
Key                              | 44
RegistryTransaction              | 45
ALPC Port                        | 46
EnergyTracker                    | 47
PowerRequest                     | 48
WmiGuid                          | 49
EtwRegistration                  | 50
EtwSessionDemuxEntry             | 51
EtwConsumer                      | 52
CoverageSampler                  | 53
DmaAdapter                       | 54
PcwObject                        | 55
FilterConnectionPort             | 56
FilterCommunicationPort          | 57
NdisCmState                      | 58
DxgkSharedResource               | 59
DxgkSharedKeyedMutexObject       | 60
DxgkSharedSyncObject             | 61
DxgkSharedSwapChainObject        | 62
DxgkDisplayManagerObject         | 63
DxgkCurrentDxgThreadObject       | 64 // Only in Windows 10
DxgkSharedProtectedSessionObject | 65
DxgkSharedBundleObject           | 66
DxgkCompositionObject            | 67
VRegConfigurationContext         | 68

а 0x4E это 78, что уже означает выход за допустимый диапазон.
Кстати в Windows 11 21H2 диапазон индексов был расширен
Кликните здесь для просмотра всего текста
Код:
TypeName                         | TypeIndex
---------------------------------|----------
(null)                           |  0
                                 |  1
Type                             |  2
Directory                        |  3
SymbolicLink                     |  4
Token                            |  5
Job                              |  6
Process                          |  7
Thread                           |  8
Partition                        |  9
UserApcReserve                   | 10
IoCompletionReserve              | 11
ActivityReference                | 12
ProcessStateChange               | 13  // Only in Windows 11
ThreadStateChange                | 14  // Only in Windows 11
PsSiloContextPaged               | 15
PsSiloContextNonPaged            | 16
DebugObject                      | 17
Event                            | 18
Mutant                           | 19
Callback                         | 20
Semaphore                        | 21
Timer                            | 22
IRTimer                          | 23
Profile                          | 24
KeyedEvent                       | 25
WindowStation                    | 26
Desktop                          | 27
Composition                      | 28
RawInputManager                  | 29
CoreMessaging                    | 30
ActivationObject                 | 31
TpWorkerFactory                  | 32
Adapter                          | 33
Controller                       | 34
Device                           | 35
Driver                           | 36
IoCompletion                     | 37
WaitCompletionPacket             | 38
File                             | 39
IoRing                           | 40  // Only in Windows 11
TmTm                             | 41
TmTx                             | 42
TmRm                             | 43
TmEn                             | 44
Section                          | 45
Session                          | 46
Key                              | 47
RegistryTransaction              | 48
ALPC Port                        | 49
EnergyTracker                    | 50
PowerRequest                     | 51
WmiGuid                          | 52
EtwRegistration                  | 53
EtwSessionDemuxEntry             | 54
EtwConsumer                      | 55
CoverageSampler                  | 56
DmaAdapter                       | 57
PcwObject                        | 58
FilterConnectionPort             | 59
FilterCommunicationPort          | 60
NdisCmState                      | 61
DxgkSharedResource               | 62
DxgkSharedKeyedMutexObject       | 63
DxgkSharedSyncObject             | 64
DxgkSharedSwapChainObject        | 65
DxgkDisplayManagerObject         | 66
DxgkSharedProtectedSessionObject | 67
DxgkSharedBundleObject           | 68
DxgkCompositionObject            | 69
VRegConfigurationContext         | 70

Касаемо новых объектов ядра в Windows 11, могу порекомендовать почитать вот этот материал
ProcessStateChange и ThreadStateChange - Thread and Process State Change
IoRing - I/O Rings – When One I/O Operation is Not Enough

А это таблица индексов объектов ядра Windows 7
Кликните здесь для просмотра всего текста
Код:
TypeName                         | TypeIndex
---------------------------------|----------
(null)                           |  0
BAD0B0B0                         |  1
Type                             |  2
Directory                        |  3
SymbolicLink                     |  4
Token                            |  5
Job                              |  6
Process                          |  7
Thread                           |  8
UserApcReserve                   |  9
IoCompletionReserve              | 10
DebugObject                      | 11
Event                            | 12
EventPair                        | 13 // Only in Windows 7
Mutant                           | 14
Callback                         | 15
Semaphore                        | 16
Timer                            | 17
Profile                          | 18
KeyedEvent                       | 19
WindowStation                    | 20
Desktop                          | 21
TpWorkerFactory                  | 22
Adapter                          | 23
Controller                       | 24
Device                           | 25
Driver                           | 26
IoCompletion                     | 27
File                             | 28
TmTm                             | 29
TmTx                             | 30
TmRm                             | 31
TmEn                             | 32
Section                          | 33
Session                          | 34
Key                              | 35
ALPC Port                        | 36
PowerRequest                     | 37
WmiGuid                          | 38
EtwRegistration                  | 39
EtwConsumer                      | 40
FilterConnectionPort             | 41
FilterCommunicationPort          | 42
PcwObject                        | 43

В Microsoft посчитали, что такой лёгкий доступ к таблице индексов ObTypeIndexTable недопустим и постарались запутать исследователей.
Но их защита простояла недолго, достаточно быстро был найден способ получения валидного индекса, довольно нетрадиционным способом.

Во-первых, исследователи ядра начали искать фрагменты кода, которые имеют что-то общее со структурой _OBJECT_TYPE
Код:
lkd> x nt!ob*type*
fffff806`2bc21f8c nt!ObpCreateDefaultObjectTypeSD (void)
fffff806`2bc218d0 nt!ObCreateObjectTypeEx (void)
fffff806`2bd82214 nt!ObEnumerateObjectsByType (ObEnumerateObjectsByType)
fffff806`2c024ef0 nt!ObpTypeObjectType = <no type information>
fffff806`2c024ee0 nt!ObpDirectoryObjectType = <no type information>
fffff806`2c107470 nt!ObTypeIndexTable = <no type information>
fffff806`2bb23b28 nt!ObQueryTypeInfo (ObQueryTypeInfo)
fffff806`2bc21ef8 nt!ObpInitObjectTypeSD (ObpInitObjectTypeSD)
fffff806`2be36038 nt!ObpObjectTypesPathString = <no type information>
fffff806`2bd82a60 nt!ObpDestroyTypeArray (ObpDestroyTypeArray)
fffff806`2bd8295c nt!ObpCreateTypeArray (ObpCreateTypeArray)
fffff806`2bf54aa0 nt!ObpTypeMapping = <no type information>
fffff806`2be36028 nt!ObpObjectTypesNameString = <no type information>
fffff806`2baa3cc0 nt!ObGetObjectType (ObGetObjectType)
fffff806`2c024e20 nt!ObpTypeDirectoryObject = <no type information>
fffff806`2bc218b0 nt!ObCreateObjectType (ObCreateObjectType)
fffff806`2c024ee8 nt!ObpSymbolicLinkObjectType = <no type information>
fffff806`2c024620 nt!ObpObjectTypes = <no type information>
fffff806`2bd82d3c nt!ObQueryTypeName (ObQueryTypeName)
Поиски выявили интересную функцию, которую нельзя было упускать из виду только лишь из-за ее названия nt!ObGetObjectType.
Затем было решено посмотреть на её мнемонику ассемблерного кода
Код:
lkd> uf nt!ObGetObjectType
nt!ObGetObjectType:
fffff806`2baa3cc0 488d41d0        lea     rax,[rcx-30h]
fffff806`2baa3cc4 0fb649e8        movzx   ecx,byte ptr [rcx-18h]
fffff806`2baa3cc8 48c1e808        shr     rax,8
fffff806`2baa3ccc 0fb6c0          movzx   eax,al
fffff806`2baa3ccf 4833c1          xor     rax,rcx
fffff806`2baa3cd2 0fb60d2f2f6600  movzx   ecx,byte ptr [nt!ObHeaderCookie (fffff806`2c106c08)]
fffff806`2baa3cd9 4833c1          xor     rax,rcx
fffff806`2baa3cdc 488d0d8d376600  lea     rcx,[nt!ObTypeIndexTable (fffff806`2c107470)]
fffff806`2baa3ce3 488b04c1        mov     rax,qword ptr [rcx+rax*8]
fffff806`2baa3ce7 c3              ret
Функция ObGetObjectType принимает адрес объекта в качестве аргумента и выполняет следующие действия:
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))
Нажмите на изображение для увеличения
Название: 11.png
Просмотров: 246
Размер:	40.5 Кб
ID:	7345

Ну чтож, на этом я хотел бы поставить точку в изучении объектов операционной системы Windows.
Конечно же это только верхушка айсберга, и внутреннее устройство ОС Windows куда сложнее того, что я показал здесь.
Но главное, мы научились вскрывать то, что Microsoft зашифровала, причём на уровне ядра.
Размещено в Без категории
Показов 2684 Комментарии 0
Всего комментариев 0
Комментарии
 
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru