Периодически, как правило во вторую среду месяца, можно услышать истории о том, что Windows после очередного обновления перестает загружаться, показывая синий экран смерти. В большинстве случаев причиной такой ситуации оказывается либо руткит, либо специфичное системное ПО, фривольно обращающееся со внутренними структурами ОС. Винят, конечно, все равно обновление, ведь «до него все работало».
Периодически, как правило во вторую среду месяца, можно услышать истории о том, что Windows после очередного обновления перестает загружаться, показывая синий экран смерти. В большинстве случаев причиной такой ситуации оказывается либо руткит, либо специфичное системное ПО, фривольно обращающееся со внутренними структурами ОС. Винят, конечно, все равно обновление, ведь «до него все работало». С таким отношением не удивительно, что «Майкрософт» не поощряет использование всего, что не документировано. В какой-то момент, а именно с релизом Windows Server 2003, MS заняла более активную позицию в вопросе борьбы с чудо-поделками сторонних разработчиков. Тогда появился механизм защиты целостности ядра — kernel patch protection, более известный как PatchGuard.
typedef struct _IMAGE_RUNTIME_FUNCTION_ENTRY { uint32_t BeginAddress;
// Начало функции uint32_t EndAddress; // Конец функции union { uint32_t UnwindInfoAddress;
// Указатель на данные, используемые для раскрутки стека и uint32_t UnwindData;
// обработки исключений }; }
_IMAGE_RUNTIME_FUNCTION_ENTRY, *_PIMAGE_RUNTIME_FUNCTION_ENTRY;
... -(call)-> Phase1InitializationDiscard -(call)-> KeInitAmd64SpecificState
-(exception)-> KiFilterFiberContext
... -(call)-> Phase1InitializationDiscard -(call)-> sub_14071815C
-(call)-> ExpLicenseWatchInitWorker -(call)-> KiFilterFiberContext
__int64 KeInitAmd64SpecificState() { signed int v0; // edx@2 __int64 result; // rax@2 //
В безопасном режиме PatchGuard не работает
if ( !InitSafeBootMode ) { v0 = __ROR4__(KdPitchDebugger | KdDebuggerNotPresent, 1);
// При отсутствии отладчика деление вызовет исключение (переполнение при делении на -1),
// обработчиком которого как раз будет KiFilterFiberContext result =
(v0 / ((KdPitchDebugger | KdDebuggerNotPresent) != 0 ? -1 : 17)); } return result; }
NTSTATUS (*KiFilterFiberContext)(PVOID pFilterparam); BOOLEAN ForgetAboutPG;
// KiServiceTablesLocked == KiFilterParam KiFilterParam = KiInitialPcr.Prcb.HalReserved[1];
KiInitialPcr.Prcb.HalReserved[1] = NULL; KiFilterFiberContext = KiInitialPcr.Prcb.HalReserved[0];
KiInitialPcr.Prcb.HalReserved[0] = NULL; ForgetAboutPG = (InitSafeBootMode != 0)
| (KUSER_SHARED_DATA.KdDebuggerEnabled >> 1);
// 96% случаев if (__rdtsc() % 100 > 3) ForgetAboutPG |= 1;
if (!ForgetAboutPG && KiFilterFiberContext(KiFilterParam) != 1)
KeBugCheckEx(SYSTEM_LICENSE_VIOLATION, 0x42424242, 0xC000026A, 0, 0); }
BOOLEAN KiFilterFiberContext(PVOID pKiFilterParam)
{ BOOLEAN Result = TRUE; DWORD64 dwDpcIdx1 = __rdtsc() % 13;
// Выбор DPC, в которой будет осуществляться проверка DWORD64 dwRand2 = __rdtsc() % 10;
// 50 на 50, что создастся второй контекст DWORD64 dwMethod1 = __rdtsc() % 6;
// Выбор метода запуска проверки AntiDebug(); Result = KiInitializePatchGuardContext(dwDpcIdx,
dwMethod1, (dwRand2 < 6) + 1, pKiFilterParam, TRUE);
if (dwRand2 < 6) { DWORD64 dwDpcIdx2 = __rdtsc() % 13; DWORD64 dwMethod2 = __rdtsc() % 6;
do { dwMethod2 = __rdtsc() % 6; } while ((dwMethod1 != 0) && (dwMethod1 == dwMethod2));
Result = KiInitializePatchGuardContext(dwDpcIdx2, dwMethod2, 2, pKiFilterParam, FALSE);
} AntiDebug(); return Result; }
cli xor eax, eax cmp byte ptr cs:KdDebuggerNotPresent,
al jnz short loc_140F3CFBD jmp short loc_140F3CFBB sti
cli sidt fword ptr [rbp+320h] lidt fword ptr [rbp+228h] mov dr7,
r13 lidt fword ptr [rbp+320h] sti
ExpTimerDpcRoutine -> KiCustomAccessRoutine0 -> KiCustomRecurseRoutine0… KiCustomRecurseRoutineN
IopTimerDispatch -> KiCustomAccessRoutine1 -> KiCustomRecurseRoutine1… KiCustomRecurseRoutineN
IopIrpStackProfilerTimer -> KiCustomAccessRoutine2 -> KiCustomRecurseRoutine2… KiCustomRecurseRoutineN
PopThermalZoneDpc -> KiCustomAccessRoutine3 -> KiCustomRecurseRoutine3… KiCustomRecurseRoutineN
CmpEnableLazyFlushDpcRoutine -> KiCustomAccessRoutine4 -> KiCustomRecurseRoutine4… KiCustomRecurseRoutineN
CmpLazyFlushDpcRoutine -> KiCustomAccessRoutine5 -> KiCustomRecurseRoutine5… KiCustomRecurseRoutineN
KiBalanceSetManagerDeferredRoutine -> KiCustomAccessRoutine6 -> KiCustomRecurseRoutine6… KiCustomRecurseRoutineN
ExpTimeRefreshDpcRoutine -> KiCustomAccessRoutine7 -> KiCustomRecurseRoutine7… KiCustomRecurseRoutineN
ExpTimeZoneDpcRoutine -> KiCustomAccessRoutine8 -> KiCustomRecurseRoutine8… KiCustomRecurseRoutineN
ExpCenturyDpcRoutine -> KiCustomAccessRoutine9 -> KiCustomRecurseRoutine9… KiCustomRecurseRoutineN
... --> Phase1InitializationDiscard --> CcInitializeCacheManager --> CcInitializeBcbProfiler