Исходные данные: 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.
ΞρεΤΙκ