Интересно было бы понять каким именно образом ядро Windows проверяет собственный код на попытку внесения изменений, не правда ли? Ведь современные операционные системы определенно должны иметь механизмы защиты целостности на фоне многочисленных попыток аудитории внедриться в код ядра, одни руткиты чего стоят. К примеру, в 32-разрядной системе (x86) Windows (начиная с версии Vista), вполне официально присутствуют опции включения/отключения проверки целостности компонентов, участвующих в процессе запуска операционной системы: это флаги загрузки ENABLE_INTEGRITY_CHECKS и TESTSIGNING. В этой же версии ОС в ядре появилась новая функция, носящая название SepInitializeCodeIntegrity и фактически являющаяся контейнером (оберткой) для передачи управления функции CiInitialize (экспортируемой библиотекой ci.dll). В случае, когда проверка целостности включена в операционной системе, код функции SepInitializeCodeIntegrity внутри себя выполняет вызов функции CiInitialize, при отключенной же проверке обращения к функциям данной библиотеки не происходит. Помимо своего собственного кода, ядро ntoskrnl.exe производит проверку некоторых других критичных для системы модулей: драйверов этапа загрузки (флаг BOOT_START), системных драйверов (флаг SYSTEM_START), и драйверов, подгружаемых уже в процессе функционирования операционной системы (флаги DEMAND_START, AUTO_START). Целостность кода загружаемых ядром исполняемых образов проверяется двумя ядерными функциями:
- Функция SeValidateImageHeader (контейнер к функции CiValidateImageHeader из ci.dll) -- вызывается на этапе отображения исполняемого образа в адресное пространство ядра.
- Функция SeValidateImageData (контейнер к функции CiValidateImageData из ci.dll) -- вызывается на стадии загрузки модуля ядра.
Все эти проверки крайне осложняют жизнь начинающего исследователя, поэтому в данной статье мы рассмотрим один из способов отключения проверки целостности ядра ntoskrnl, путем внесения изменений в бинарную сборку ядра. И перво-наперво хотелось бы обратить особое внимание на то, что в ходе загрузки ОС, на этапе работы модуля winload.exe, он загружает одну из версий ядра (в зависимости от ряда условий):
- ntoskrnl.exe -- (1 ядро ЦП);
- ntkrnlmp.exe -- (N ядер ЦП, SMP);
- ntkrnlpa.exe -- (1 ядро ЦП, PAE);
- ntkrpamp.exe -- (N ядер ЦП, SMP, PAE);
Все эти разновидности ядра для различных аппаратных конфигураций размещены в системной поддиректории %SystemRoot%\System32\. Важно понимать, что по приведенной в данной статье методике необходимо пропатчить ту версию ядра, которая актуальна именно для вашей системы, поскольку простая модификация файла ntoskrnl.exe не всегда дает результат. В дополнение, сигнатуры кода в разных версиях ядра могут отличаться, тем не менее, я не спроста привожу в статье части исходного кода изменяемых функций, дабы по аналогии можно было всегда найти требуемый участок кода.
Функция SepInitializeCodeIntegrity
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 |
PAGE:0056E93E _SepInitializeCodeIntegrity@0 proc near PAGE:0056E93E 33 C0 xor eax, eax PAGE:0056E940 38 05 0C 32 53 00 cmp _InitIsWinPEMode, al PAGE:0056E946 0F 94 C1 setz cl PAGE:0056E949 88 0D 7C D3 53 00 mov _g_CiEnabled, cl PAGE:0056E94F 84 C9 test cl, cl PAGE:0056E951 74 66 jz short locret_56E9B9 PAGE:0056E953 53 push ebx PAGE:0056E954 56 push esi PAGE:0056E955 57 push edi PAGE:0056E956 BE 70 D3 53 00 mov esi, offset _g_CiCallbacks PAGE:0056E95B 8B FE mov edi, esi PAGE:0056E95D AB stosd PAGE:0056E95E AB stosd PAGE:0056E95F AB stosd PAGE:0056E960 A1 34 49 56 00 mov eax, ds:_KeLoaderBlock PAGE:0056E965 6A 06 push 6 PAGE:0056E967 5B pop ebx PAGE:0056E968 85 C0 test eax, eax PAGE:0056E96A 74 37 jz short loc_56E9A3 PAGE:0056E96C 83 78 54 00 cmp dword ptr [eax+54h], 0 PAGE:0056E970 74 31 jz short loc_56E9A3 PAGE:0056E972 68 20 82 5F 00 push offset aDisable_integr ; "DISABLE_INTEGRITY_CHECKS" PAGE:0056E977 FF 70 54 push dword ptr [eax+54h] ; char * PAGE:0056E97A E8 40 00 00 00 call _SepIsOptionPresent@8 PAGE:0056E97F 85 C0 test eax, eax PAGE:0056E981 74 02 jz short loc_56E985 PAGE:0056E983 33 DB xor ebx, ebx PAGE:0056E985 PAGE:0056E985 loc_56E985: PAGE:0056E985 A1 34 49 56 00 mov eax, ds:_KeLoaderBlock PAGE:0056E98A 68 40 82 5F 00 push offset aTestsigning ; "TESTSIGNING" PAGE:0056E98F FF 70 54 push dword ptr [eax+54h] ; char * PAGE:0056E992 E8 28 00 00 00 call _SepIsOptionPresent@8 PAGE:0056E997 85 C0 test eax, eax PAGE:0056E999 A1 34 49 56 00 mov eax, ds:_KeLoaderBlock PAGE:0056E99E 74 03 jz short loc_56E9A3 PAGE:0056E9A0 83 CB 08 or ebx, 8 PAGE:0056E9A3 PAGE:0056E9A3 loc_56E9A3: PAGE:0056E9A3 PAGE:0056E9A3 8B C8 mov ecx, eax PAGE:0056E9A5 83 C0 20 add eax, 20h PAGE:0056E9A8 F7 D9 neg ecx PAGE:0056E9AA 1B C9 sbb ecx, ecx PAGE:0056E9AC 56 push esi PAGE:0056E9AD 23 C8 and ecx, eax PAGE:0056E9AF 51 push ecx PAGE:0056E9B0 53 push ebx PAGE:0056E9B1 E8 74 5C E9 FF call _CiInitialize@12 PAGE:0056E9B6 5F pop edi PAGE:0056E9B7 5E pop esi PAGE:0056E9B8 5B pop ebx PAGE:0056E9B9 PAGE:0056E9B9 locret_56E9B9: PAGE:0056E9B9 C3 retn PAGE:0056E9B9 _SepInitializeCodeIntegrity@0 endp |
заменяем первый байт опкодом EB (jmp xx).
Функция SeValidateImageHeader
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 |
PAGE:005CE6DF _SeValidateImageHeader@20 proc near PAGE:005CE6DF PAGE:005CE6DF PAGE:005CE6DF arg_0 = dword ptr 8 PAGE:005CE6DF arg_4 = dword ptr 0Ch PAGE:005CE6DF arg_8 = dword ptr 10h PAGE:005CE6DF arg_C = dword ptr 14h PAGE:005CE6DF PAGE:005CE6DF 8B FF mov edi, edi PAGE:005CE6E1 55 push ebp PAGE:005CE6E2 8B EC mov ebp, esp PAGE:005CE6E4 80 3D 7C D3 53 00 00 cmp _g_CiEnabled, 0 PAGE:005CE6EB 75 20 jnz short loc_5CE70D PAGE:005CE6ED 68 53 65 50 68 push 68506553h ; Tag PAGE:005CE6F2 6A 01 push 1 ; NumberOfBytes PAGE:005CE6F4 6A 01 push 1 ; PoolType PAGE:005CE6F6 E8 0A F9 F4 FF call _ExAllocatePoolWithTag@12 PAGE:005CE6FB 89 06 mov [esi], eax PAGE:005CE6FD F7 D8 neg eax PAGE:005CE6FF 1B C0 sbb eax, eax PAGE:005CE701 25 E9 FF FF 3F and eax, 3FFFFFE9h PAGE:005CE706 05 17 00 00 C0 add eax, 0C0000017h PAGE:005CE70B EB 1F jmp short loc_5CE72C PAGE:005CE70D ; ------------------------------------------------------- PAGE:005CE70D PAGE:005CE70D loc_5CE70D: PAGE:005CE70D A1 70 D3 53 00 mov eax, _g_CiCallbacks PAGE:005CE712 85 C0 test eax, eax PAGE:005CE714 75 07 jnz short loc_5CE71D PAGE:005CE716 B8 28 04 00 C0 mov eax, 0C0000428h PAGE:005CE71B EB 0F jmp short loc_5CE72C PAGE:005CE71D ; ------------------------------------------------------- PAGE:005CE71D PAGE:005CE71D loc_5CE71D: PAGE:005CE71D 56 push esi PAGE:005CE71E FF 75 14 push [ebp+arg_C] PAGE:005CE721 FF 75 10 push [ebp+arg_8] PAGE:005CE724 FF 75 0C push [ebp+arg_4] PAGE:005CE727 FF 75 08 push [ebp+arg_0] PAGE:005CE72A FF D0 call eax ; _g_CiCallbacks PAGE:005CE72C PAGE:005CE72C loc_5CE72C: PAGE:005CE72C PAGE:005CE72C 5D pop ebp PAGE:005CE72D C2 10 00 retn 10h PAGE:005CE72D _SeValidateImageHeader@20 endp |
заменяем опкодами 90 90 (nop, nop)
Функция SeValidateImageData
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 |
PAGE:005CDC64 _SeValidateImageData@16 proc near PAGE:005CDC64 PAGE:005CDC64 PAGE:005CDC64 arg_0 = dword ptr 8 PAGE:005CDC64 arg_4 = dword ptr 0Ch PAGE:005CDC64 arg_8 = dword ptr 10h PAGE:005CDC64 arg_C = dword ptr 14h PAGE:005CDC64 PAGE:005CDC64 8B FF mov edi, edi PAGE:005CDC66 55 push ebp PAGE:005CDC67 8B EC mov ebp, esp PAGE:005CDC69 80 3D 7C D3 53 00 00 cmp _g_CiEnabled, 0 PAGE:005CDC70 75 04 jnz short loc_5CDC76 PAGE:005CDC72 33 C0 xor eax, eax PAGE:005CDC74 EB 1E jmp short loc_5CDC94 PAGE:005CDC76 ; ------------------------------------------------------- PAGE:005CDC76 PAGE:005CDC76 loc_5CDC76: PAGE:005CDC76 A1 74 D3 53 00 mov eax, dword_53D374 PAGE:005CDC7B 85 C0 test eax, eax PAGE:005CDC7D 75 07 jnz short loc_5CDC86 PAGE:005CDC7F B8 28 04 00 C0 mov eax, 0C0000428h PAGE:005CDC84 EB 0E jmp short loc_5CDC94 PAGE:005CDC86 ; ------------------------------------------------------- PAGE:005CDC86 PAGE:005CDC86 loc_5CDC86: PAGE:005CDC86 FF 75 14 push [ebp+arg_C] PAGE:005CDC89 FF 75 10 push [ebp+arg_8] PAGE:005CDC8C FF 75 0C push [ebp+arg_4] PAGE:005CDC8F FF 75 08 push [ebp+arg_0] PAGE:005CDC92 FF D0 call eax ; dword_53D374 PAGE:005CDC94 PAGE:005CDC94 loc_5CDC94: PAGE:005CDC94 PAGE:005CDC94 5D pop ebp PAGE:005CDC95 C2 10 00 retn 10h PAGE:005CDC95 _SeValidateImageData@16 endp |
заменяем опкодами 90 90 (nop, nop).
После выполнения всех приведенных выше модификаций кода ядра, происходит отключение проверки целостности ядра ntoskrnl.exe, ядро перестает реагировать на вносимые в исполняемый модуль изменения. Тем не менее, описанное выше решение несколько своеобразно, поскольку фактически создает видимость установленных опций отключения проверки целостности и выставленного тестового режима работы операционной системы, поэтому для 64-битных версий наверняка потребуется доработка алгоритма!!
Checksum
заголовка PE) изменяемых файлов. Осуществляется это посредством утилиты LordPE или любого аналогичного редактора PE-модулей, содержащего аналогичную функцию.Заключение
Но на этом процесс отключения проверки целостности не заканчивается. После всех описанных модификаций ядра, система при загрузке "валится" в синий экран с ошибкой BSOD 0000008E где-то в недрах функции I_PEVerityBootDrivers из библиотеки ci.dll. Поэтому, теперь мы переходим к очередному этапу, на котором будут выполняться изменения кода библиотеки ci.dll.
Спасибо за статью. Приятно было почитать. Получил удовольствие.
спасибо за оценку, сохранил на всякий случай в виде заметки.. вдруг еще пригодится :)
Здравствуйте, вы можете ответить что содержит код ошибки во время установки Windows 10? Проблема проверки оперативной памяти или видео памяти?
скриншот экрана https://disk.yandex.ru/i/yCmPRbpyxw7piA
здравствуйте! ссылку не видно!
За две недели никто не ответил, только удалил и вот
https://disk.yandex.ru/i/-IwYE1GhSBrUaA
а дамп есть? он расположен в c:\windows\, файл memory.dmp
дампа нет, это на этапе установки Windows 10 на ноутбук. Или дам есть и на этапе установки?
на этапе установки не пишется, похоже.
а какая редакция/версия win10?
windows-10-build-9780-x86 пробовал притянуть на Pentium 3, видимо проходит проверка процессора на наличие SSE3 и NX. На ютубе есть видео Pentium 3, но те патчи что выложены приводят к такой ошибке.
а, ноут старый? это вы пытаетесь на него один из ранних билдов Win10 поставить?
Да, ноут старый Celeron M 370. Windows 8 на него тоже не ставится, но пропатченные НТкернел позволяет установится и стабильно работать. кроме случаев когда в программе жестко прописано наличие SSE3. Видимо система проверят что установлен процессор без этой поддержки и просто не дает работать. Возможно со временем и Windows 10 пропатчат.
Сборку 9860 х86 нельзя взломать. Можно только взломать ci.dll. Попытка взломать bootmgr и winload.exe всегда приводят к синему экрану. Сборку 9860 х86 можно загрузить в текущую дату но только через меню, которое каждый раз надо вызывать и нажимать 7, а без этого (загрузка в нормальном режиме) нереально. Замок в этой сборке на bootmgr и winload.exe поставили хороший, но не на ci.dll