Исходные данные: Windows 7, процесс, работающий от лица администратора и нить процесса SYSTEM
Проблема: при попытке открытия нити получаем STATUS_ACCESS_DENIED
Расследование: Security Descriptor нити позволяет ее отрывать с достачно широкими правами:
Трассируем nt!NtOpenThread до функции nt!ObpIncrementHandleCountEx, которая вызывает обработчик nt!PspThreadOpen (обработчик создания описателей объектов, типа "нить"). В теле nt!PspThreadOpen видим (псевдо-код):
NTSTATUS __stdcall PspThreadOpen(<...>) { <...> if ( PrevMode == 1 && !(TargetProcess->Flags2 & 0x800) && ThreadObject->Tcb.Process->Flags2 & 0x800 && GrantedAccess & 0xFF3FD ) { result = 0xC0000022; // == STATUS_ACCESS_DENIED } else <...>
Маска 0x800 - проверка флага защищенного процесса. А процесс SYSTEM как раз защищенный:
Именно из-за этого и ошибка.
Ссылки по protected-процессам:
- MSDN: Process Creation Flags - CREATE_PROTECTED_PROCESS
- TechNet: Inside the Windows Vista Kernel: Part 3 - Protected Processes
- MSDN: Protecting Anti-Malware Services
- И ряд постов из блога Alex Ionescu: Why Protected Processes Are A Bad Idea, The Evolution of Protected Processes Part 1: Pass-the-Hash Mitigations in Windows 8.1, The Evolution of Protected Processes Part 2: Exploit/Jailbreak Mitigations, Unkillable Processes and Protected Services, Protected Processes Part 3 : Windows PKI Internals
Updated (30.09.2016)
Все вышеперечисленное ограничения на открытие описателей касаются, в том числе, и объекта процесса. Например на Windows 7 за создание описателя на процесс отвечает PspProcessOpen с таким псевдо-кодом:
if ( PrevMode == 1 && !_bittest(&DestinationProcess->Flags2, 11) && _bittest(&OpenedProcess->Flags2, 11) && GrantedAccess & 0xFE7FE ) { result = STATUS_ACCESS_DENIED; }
Но с приходом Windows 10.0.14393 в ядре появилась поддержка Linux-процессов (Windows Subsystem for Linux, WSL), которые называются Pico-процессами. И эти PICO-процессы обрабатываются по аналогии с защищенными процессами (псевдо-кодо из Windows 10.0.14393):
- PspThreadOpen
|| OpenedThread->PicoContext && !DestinationProcess_->PicoContext && PrevMode && ~*(_DWORD *)&PspPicoProviderRoutines[0x4C] & GrantedAccess ) { result = STATUS_ACCESS_DENIED; }
- PspProcessOpen
|| OpenedProcess->PicoContext && !DestinationProcess->PicoContext && PrevMode && ~*(_DWORD *)&PspPicoProviderRoutines[0x48] & GrantedAccess ) { result = STATUS_ACCESS_DENIED; }
То есть из Win32-процесса (не Pico) можно открыть объект Pico-процесса максимум с правами PROCESS_TERMINATE | PROCESS_QUERY_LIMITED_INFORMATION | SYNCHRONIZE.
А из Win32-процесса (не Pico) можно открыть объект нити Pico-процесса максимум с правами THREAD_TERMINATE | THREAD_QUERY_LIMITED_INFORMATION | SYNCHRONIZE.
ΞρεΤΙκ