Статья дополняет серию материалов, освещающих методы устранения проблем, приводящих к возникновению критической системной ошибки (BSOD). В материалах раздела рассматриваются ситуации, с которыми я сталкивался лично (в своей практике) и с которыми мне удалось разобраться. STOP-ошибка (STOP error), контроль дефекта (BugCheck) или в простонародье BSOD - фатальный системный сбой операционной системы Windows, являющийся причиной полного прекращения функционирования основных компонентов ядра операционной системы, влекущий за собой потерю динамических не сохраненных пользовательских данных и приводящий к появлению на экране монитора синего экрана смерти (BSOD). Числовое обозначение STOP-ошибки - идентификатор, характеризующий "природу" фатальной системной ошибки, используется при диагностике причины возникшей неполадки. В данной статье речь пойдет о сбое с идентификатором STOP 0000006B.
Теория
STOP 0x0000006B имеет собственную специфику и возникает на ранних стадиях загрузки операционной системы. В момент возникновения сбоя пользователь наблюдает на экране следующее сообщение об фатальной системной ошибке:
В общем случае формат ошибки следующий:
1 2 |
STOP 0x0000006B (0xAAAAAAAA,0xBBBBBBBB,0xCCCCCCCC,0xDDDDDDDD) PROCESS1_INITIALIZATION_FAILED |
где:
Значение | Описание |
---|---|
0xAAAAAAAA | Первый параметр. Статус завершения операции. |
0xBBBBBBBB | Второй параметр. Неофициально - указатель на этап загрузки/инициализации. |
0xCCCCCCCC | Третий параметр. Зарезервировано. |
0xDDDDDDDD | Четвертый параметр. Зарезервировано. |
Вообще загрузка операционной системы представляет собой достаточно сложную процедуру, которая состоит из множества стадий. На одной из начальных стадий загружается непосредственно ядро операционной системы, которое начинает проходить этапы инициализации/создания собственных структур и создания/запуска основных системных процессов, составляющих исполнительную подсистему ядра. Символическое имя ошибки PROCESS1_INITIALIZATION_FAILED (ОШИБКА_ИНИЦИАЛИЗАЦИИ_ПРОЦЕССА1), по идее разработчиков, должно сообщать нам о том, что ошибка STOP 0000006B возникает в ситуации невозможности загрузки/инициализации некоего критичного для загрузки операционной системы модуля. Что означает имя PROCESS1, это процесс, загружаемый на стадии 1 или процесс с номером (идентификатором) 1? И если следовать подобной логике, то зададимся вопросом: процесс №1 это случайно не процесс System? Ведь если брать во внимание высказывание главного разработчика Microsoft Раймонда Чена (Raymond Chen):
..в то время как процесс System имеет PID
=4, то получается, что PROCESS1 и есть System? Далее, опираясь на данные, которые можно получить из исходных кодов ядра, можно утверждать, что на определенном этапе стартует Диспетчер процессов. Диспетчер процессов предназначается для управления процессами в ОС и одной из его задач является загрузка и подготовка (экспорт) функций DLL. На одном из ранних этапов загрузки, при подготовке процесса System, происходит связывание функции основных системных DLL (ntdll.dll и других). Как раз на этом этапе работы и может появляться рассматриваемая нами ошибка: либо по причине повреждения одной из критичных системных DLL, либо из-за разных версий взаимосвязанных DLL, либо по причине несоответствие подписи (подделки) кода некоторых DLL (защита которых реализована в специальном коде ядра операционной системы).
Второй параметр (BugCheckParameter2)
Все найденные мной точки возникновения критической ошибки STOP 0000006B располагаются в коде ядра операционной системы, размещенного в файле ntoskrnl.exe (либо другом ntkr*.exe в зависимости от аппаратной конфигурации станции). Давайте попробуем разобрать каждую из них подробнее.
Второй параметр =2
Первый найденный фрагмент находится внутри функции PsLocateSystemDlls и выглядит он следующим образом:
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 |
. . . E8 35 00 00 00 call @PspLocateSystemDll@12 ; PspLocateSystemDll(x,x,x) 85 C0 test eax, eax 7D 0C jge short loc_587119 85 DB test ebx, ebx 75 11 jnz short loc_587122 8B 0F mov ecx, [edi] F6 41 08 01 test byte ptr [ecx+8], 1 75 12 jnz short loc_58712B loc_587119: ; CODE XREF: PsLocateSystemDlls(x)+44j ; PsLocateSystemDlls(x)+57j 46 inc esi 3B 74 24 0C cmp esi, [esp+10h+var_4] 7E CD jle short loc_5870ED loc_587120: ; CODE XREF: PsLocateSystemDlls(x)+21j 33 C0 xor eax, eax loc_587122: ; CODE XREF: PsLocateSystemDlls(x)+5Bj 5F pop edi 5E pop esi 5B pop ebx 8B E5 mov esp, ebp 5D pop ebp C2 04 00 retn 4 ; --------------------------------------------------------------------------- loc_58712B: ; CODE XREF: PsLocateSystemDlls(x)+63j 6A 00 push 0 ; BugCheckParameter4 56 push esi ; BugCheckParameter3 6A 02 push 2 ; BugCheckParameter2 50 push eax ; BugCheckParameter1 6A 6B push 6Bh ; BugCheckCode E8 CA B9 F5 FF call _KeBugCheckEx@20 ; KeBugCheckEx(x,x,x,x,x) . . . |
Функция PsLocateSystemDll, судя по всему, открывает последовательно все версии библиотеки ntdll.dll (в 64-разрядных системах их несколько) и получает оттуда точки входа функций KiUserApcDispatcher, KiUserExceptionDispatcher, KiUserCallbackDispatcher, RtlRaiseException и некоторых других. Адреса данных процедур необходимы ядру для выполнения основных задач (например, для генерации исключения для процессов пользовательского режима, доставки APC и обратных вызовов графического пользовательского интерфейса win32k.sys).
Второй параметр =3
Следующий фрагмент был найден внутри функции PspLocateSystemDll:
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 |
. . . loc_5871D2: ; CODE XREF: PspLocateSystemDll(x,x,x)+51j ; PspLocateSystemDll(x,x,x)+6Aj FF 75 FC push [ebp+FileHandle] ; FileHandle 8D 45 C4 lea eax, [ebp+ObjectAttributes] 68 00 00 00 02 push 2000000h ; AllocationAttributes 6A 10 push 10h ; SectionPageProtection 53 push ebx ; MaximumSize 50 push eax ; ObjectAttributes BE 1F 00 0F 00 mov esi, 0F001Fh 56 push esi ; DesiredAccess 8D 45 F8 lea eax, [ebp+SectionHandle] 50 push eax ; SectionHandle 89 5D CC mov [ebp+ObjectAttributes.ObjectName], ebx E8 31 70 EB FF call _ZwCreateSection@28 ; ZwCreateSection(x,x,x,x,x,x,x) 53 push ebx FF 75 FC push [ebp+FileHandle] 89 45 F0 mov [ebp+BugCheckParameter1], eax E8 5A 81 0C 00 call _ObCloseHandle@8 ; ObCloseHandle(x,x) 8B 45 F0 mov eax, [ebp+BugCheckParameter1] 3B C3 cmp eax, ebx 7D 16 jge short loc_58721C 38 5D 08 cmp byte ptr [ebp+Object], bl 0F 85 78 01 00 00 jnz loc_587387 53 push ebx ; BugCheckParameter4 53 push ebx ; BugCheckParameter3 6A 03 push 3 ; BugCheckParameter2 loc_587213: ; CODE XREF: PspLocateSystemDll(x,x,x)+265j ; PspLocateSystemDll(x,x,x)+2A2j 50 push eax ; BugCheckParameter1 loc_587214: ; CODE XREF: PspLocateSystemDll(x,x,x)+113j 6A 6B push 6Bh ; BugCheckCode E8 E7 B8 F5 FF call _KeBugCheckEx@20 ; KeBugCheckEx(x,x,x,x,x) . . . |
то есть второй параметр 3! Функция PspLocateSystemDll выполняет инициализацию (заполнение) полей структуры размещаемых в памяти ядра системных библиотек.
Второй параметр =6
Очередной блок размещается внутри функции PspInitializeSystemDlls:
1 2 3 4 5 6 7 8 9 10 11 12 |
. . . loc_7C7614: ; CODE XREF: PspInitializeSystemDlls()+53j 51 push ecx 51 push ecx 51 push ecx 6A 06 push 6 loc_7C7619: ; CODE XREF: PspInitializeSystemDlls()+14Aj 50 push eax 6A 6B push 6Bh E8 C6 BA D1 FF call _KeBugCheck2@24 ; KeBugCheck2(x,x,x,x,x,x) . . . |
то есть второй параметр 6! Похоже функция PspInitializeSystemDlls производит заполнение (инициализацию) полей структуры экспортируемых библиотекой ntdll.dll функций. Она берет базовый адрес образа (ImageBase) каждой доступной в системе версии ntdll.dll и производит разрешение всех экспортируемых функций, а так же производит ряд других манипуляций.
Все параметры =0
И наконец внутри функции Phase1InitializationDiscard имеется такой вот код:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
. . . 56 push esi 6A 02 push 2 E8 B4 C6 FF FF call _PoInitSystem@8 ; PoInitSystem(x,x) 84 C0 test al, al 0F 84 E8 F4 FF FF jz loc_7C8833 E8 BA ED FF FF call _ExInitLicenseData@0 ; ExInitLicenseData() 56 push esi ; StartContext E8 71 CC FF FF call _PsInitSystem@8 ; PsInitSystem(x,x) 84 C0 test al, al 75 07 jnz short loc_7C9361 6A 6B push 6Bh E9 8A F2 FF FF jmp loc_7C85EB . . . loc_7C85EB: ; CODE XREF: Phase1InitializationDiscard(x)+84j ; Phase1InitializationDiscard(x)+296j ... E8 F3 A4 D1 FF call _KeBugCheck@4 ; KeBugCheck(x) . . . |
Судя по приведенному блоку кода, непосредственно перед заталкиванием в стек кода ошибки (значение 6Bh), подготовки четырех параметров перед вызовом функции KeBugCheck не производится. Скорее всего как раз по этой причине, в ряде сбоев, на результирующем синем экране все параметры равны нулю. Как видно из кода, перед возбуждением исключения STOP 0000006B производится проверка результата выполнения функции PsInitSystem. Сама функция фактически представляет собой диспетчер процессов и предназначена для создания структуры процесса, вызывается ядром в ходе инициализации в фазах 0 и 1. Сам останов в этой точке возникает как реакция на нештатное завершение функции PsInitSystem, внутри которой к возникновению ошибки могут приводить следующие события:
- ошибочное завершение ObCreateObjectTypeEx (Создание объекта в пространстве имен);
- ошибочное завершение SeRegisterObjectTypeMandatoryPolicy (Регистрация политики доступа к объекту);
- равенство значений переменных PsPAffinityUpdateLock (?) = PspCidTable (указатель на таблицу описателей, хранящей созданные объекты процессов и нитей);
- ошибочное завершение ExInitializeResourceLite (инициализация ресурса исполняемой подсистемы);
- ошибочное завершение PspCreateProcess (Создание процесса);
- ошибочное завершение ObReferenceObjectByHandle (Поиск объекта по описателю);
- неправильное значение поля PsInitialSystemProcess+1ECh (глобальная переменная, указатель на структуру EPROCESS для процесса System);
- ошибочное завершение PsCreateSystemThread (создание потока, запускающийся в режиме ядра, возврат описателя процесса).
Понятное дело, что глубже весь этот кодовый треш никто не собирается тут анализировать, я просто оставил это здесь для того, что бы вы могли проникнуться неопределенностью вместе со мной :)
Первый параметр (BugCheckParameter1)
Помимо приведенных выше указателей на этапы (второй параметр BugCheckParameter2), в процессе исполнения кода которых произошел сбой, более свободно ориентироваться в причинах проблемы помогает первый параметр. Напомню, что применительно к сбою STOP 0000006B, первый входной параметр (BugCheckParameter1) дает нам статус завершения операции:
Значение первого параметра | Символическое имя | Описание |
---|---|---|
0xC0000034 | STATUS_OBJECT_NAME_NOT_FOUND | Имя объекта не найдено. Проблема часто возникает после сбоя в процессе установки системных обновлений и сообщает о рассинхронизации системных библиотек/драйверов ранних стадий загрузки, в случае когда часть связанных функционалом модулей осталась предыдущих версии, а часть обновилась до последней актуальной. Причиной являются ошибки, возникающие в процессе установки обновления, например пользователь мог жестко прервать процесс, вручную перезагрузившись/отключив питание, не дождавшись завершения установки. |
0xC0000020 | STATUS_INVALID_FILE_FOR_SECTION | Исполняемый образ модуля, участвующего в начальных стадиях загрузки ОС, поврежден, то есть имеет проблемы с одной из секций (в таблице секций). Ошибка может возникать после сбоя в процессе установки обновлений/драйверов в систему, что ведет к повреждению файлов (образов). Так же, ошибка может быть вызвана проблемами загрузки уже существующих драйверов этапа загрузки (BOOT) по множеству причин: поврежденная файловая система, аппаратные проблемы с диском, контроллером. |
0xC000012F | STATUS_INVALID_IMAGE_NOT_MZ | Загрузочный образ не соответствует требуемому формату исполняемых файлов, то есть не содержит сигнатуру MZ в заголовке. Ошибка может возникать после неудачной попытки установки обновлений/драйверов в систему, что влечет за собой повреждение данных. Так же, ошибка может быть вызвана проблемами загрузки уже существующих драйверов этапа загрузки (BOOT) по множеству причин: поврежденная файловая система, аппаратные проблемы с диском, контроллером. |
0xC0000102 | STATUS_FILE_CORRUPT_ERROR | Загрузочный образ поврежден. Ошибка может возникать в следствии ошибки в процессе установки обновлений/драйверов в систему. Так же, ошибка может быть вызвана проблемами загрузки уже существующих драйверов этапа загрузки (BOOT) по множеству причин: поврежденная файловая система, аппаратные проблемы с диском, контроллером. |
0xC0000428 | STATUS_INVALID_IMAGE_HASH | Ошибка контрольной суммы: исполняемый файл, критичный для загрузки ОС, был заменен, его хэш не совпадает с содержащимся в каталоге (.cat). Значение хэша открытого файла отсутствует в записи системного каталога, и файл может быть подделан/поврежден. Обычно это случается при подмене файла ci.dll, ntdll.dll и ряда других. |
Общие причины
- Ошибка обнаружения критичного для загрузки ОС объекта/модуля (драйвера/библиотеки) по причинам: ошибки файловой системы, повреждение носителя информации, ...
- Ошибка инициализации критичного для загрузки ОС объекта/модуля (драйвера/библиотеки): ошибки структуры файла (повреждение данных файла), ошибки файловой системы, повреждение носителя информации, ...;
- Рассинхронизация (несоответствие) версий ядра (файл(ы) ntoskrnl.exe, ntkrnlmp.exe, ntkrnlpa.exe, ntkrpamp.exe) и библиотеки ntdll.dll (обычно после обновлений).
- Иные ошибки, попадающие под общую категорию ошибок инициализации фаз ядра.
Общие варианты решения
В данном заголовке приводятся общие методы восстановления, которые применяются для всех подвидов ошибки STOP 0x0000006B вне зависимости от параметров ошибки (BugCheckParameter1, BugCheckParameter2, BugCheckParameter3, BugCheckParameter4), которые указаны после кода STOP-ошибки в круглых скобках.
- Запуск проверки состояния жесткого диска / файловой системы на предмет наличия ошибок (при помощи команды chkdsk c: /f/r);
- Запуск средства Восстановление запуска из встроенного инструментария Устранение неполадок компьютера, либо с установочного диска или с любого другого средства восстановления.
- Копирование файлов: ntdll.dll, ntoskrnl.exe, ntkrnlmp.exe, ntkrnlpa.exe, ntkrpamp.exe, ci.dll из директории %SystemRoot%\System32\ с работоспособной станции-донора. Тут важно понимать, что все файлы должны быть с одной системы, дабы исключить рассинхронизацию версий;
- Если вы не можете самостоятельно точно определить, какие именно файлы были рассинхронизированы и не помог предыдущий пункт, то можно воспользоваться довольно варварским методом: произвести копирование целиком директорий %SystemRoot%\Winsxs и %SystemRoot%\System32 с работоспособной станции-донора. Тут предварительно на целевой системе надо будет "допилить" безопасность на перечисленных папках: получить владельца и выставить полные права для пользователя Все;
Замена файла %SystemRoot%\system32\codeintegrity\bootcat.cache и директории %SystemRoot%\system32\catroot\{F750E6C3-38EE-11D1-85E5-00C04FC295EE}\ с работоспособной станции. Для замены можно запуститься с любого доступного LiveCD и перенести указанный файл.