Windows Internals I
Windows Internals
Windows Internals mostra o funcionamento interno do sistema operacional Windows e quais são as principais partes do seu núcleo. Com um foco amplo na área de hacking e red team, o conhecimento sobre este tópico pode ser usado para ocultar e executar código, evitar detecções e encadear outras técnicas ou explorações.
Alguns componentes do backend do Windows englobados por este tópico são os processos, formatos de arquivo, COM (Componente Objeto Model), programação de tarefas, sistema de I/O, etc.
Kernel Mode vs User Mode
O privilégio no sistema Windows é dividido em dois modos: kernel mode e user mode. São melhor representados na imagem abaixo.
O user-mode: executa aplicativos dos usuário com acesso limitado aos recursos do sistema. Atua de Ring 1 até Ring 3.
O kernel-mode: possui acesso direto ao hardware e aos recursos do sistema principal. Atua apenas em Ring 0 e não são operados diretamente pelos programas.
Transferência de Privilégio
Em algum momento o programa precisará interagir com o kernel-mode para garantir que o programa funcione corretamente através da alocação de memórias, gravação direta no disco e modificação de permissões da memória. Para fazer isso de maneira segura, o Windows segue 3 etapas para transferir as instruções para o modo kernel.
As etaps são:
Win32 API → Native API → Kernel.
Wind32 API
São construídas com DLLs (Dynamic Link Librarys — como kernel32.dll) e cada DLL inclui funções para fazer chamadas e invocar a Native API para transferir a execução para ao kernal mode. Geralmente este termo se refere tanato a arquitetura de 32-bits quanto a de 64-bits.
DLLs
São bibliotecas compartilhadas que contêm código e dados usados por vários aplicativos simultaneamente. Fornecem as funções da Win32 API, permitindo que os programas vinculem e usem dinamicamente essas bibliotecas.
Native API
É responsável por fazer a transição do user-mode para kernel-mode através de chamadas da instrução System Call (syscall) que reside em cada função Native API encontrada em NTDLL.dll.
System Calls (syscalls)
A instrução syscall é feita por aplicações em user-mode para o kernel-mode. Essas chamadas permitem que os aplicativos executem operações privilegiadas, como: entrada e saída de arquivos, criação de processos e gerenciamento e alocação de memória.
Precisa ser especificada com um número especial (armazenado no registro eax de 32 bits) que o kernel requer para executar a rotina correta.
Esse número é chamado de System Service Number (SSN) ecom ele o modo kernel executa algumas operações matemáticas e sabe qual sub-rotina kernel ele precisa executar para atender o requisito de programa.
System Service Dispatch Table
A SSDT é uma tabela especial que reside no kernel-mode e é responsável por corresponder o número de syscall recebido pela Native API à uma sub-rotina do kernel que foi necessária para atender a solicitação de aplicação. O SSDT corresponde o SSN para sua respectiva sub-rotina através das seguintes operações matemáticas:
- KiServiceTableAddress = Endereço do início da tabela SSDT.
- rotinaOffset = SSN que foi passado da Native API.
EDR Hooking
É um mecanismo de defesa também conhecido como API Hooking. Quando um processo é criado, uma das primeiras coisas que são carregadas e alocadas no espaço de endereço virtual do processo é o ntdll.dll, a DLL que inclui todas as funções da Native API.
Durante a inicialização do processo em um ambiente que apresenta EDR (Endpoint Detection and Response), um código é injetado pelo próprio EDR com algumas funções dentro do ntdll que redirecionam o fluxo de execução à DLL do EDR, o que permitirá que ele intercepte cada solicitação de Native API, inspecione o conteúdo e o contexto para o fluxo de execução e, de acordo com algumas regras ou assinaturas, verifique se há algum problema.
Em seguida, o EDR decidirá se o programa tenta executar algum tipo de ação maliciosa, como a injeção de processo e, neste caso, acaba bloqueando a caminho até o syscall.
Fluxo de execução com o EDR Hooking:
Outro exemplo com a mesma função:
Observando as imagens acima, pode-se observar como o fluxo de execução está sendo redirecionado ao tentar executar uma função Hooked Native API chamada “NtAllocateMemory()”, uma função Native API usada para alocar memória virtual adicional a um processo.
A seguir, através de um Disasembler (WinDbg), observa-se o jmp para uma seção de código EDR.
Abaixo há uma comparação entre um ambiente com e sem EDR, respectivamente.
Direct Syscalls
Uma das maneiras de evitar o EDR Hooking é atráves do Direct Syscall. Em vez de obter o código necessário no contexto das Native APIs para a transição do user-mode para o kernel-mode através do ntdll.dll, há a criação manual da função Native API que o programa deve percorrer, executando manualmente a instrução syscall e a transferência do fluxo de execução para o kernel-mode sem chamar as funções Hooked Native APIs.
O único problema disso é que os SSN (System Service Number) não são os mesmos entre as versões do Windows e isso pode fazer o Direct Syscall uma técnica mais difícil de implementar se não pudermos dizer qual SSN precisamos de fato.
Essa é uma técnica inteligente, mas infelizmente está sendo detectada por AVs e EDRs. O motivo da detecção é porque ao chamar diretamente a instrução Syscall no programa principal, é sinalizada como um COI (Indicador de Compromisso) por fornecedores de AV.
Indirect Syscalls
É semelhante às syscalls diretas, mas apresenta uma diferença. Em vez de chamar diretamente a instrução Syscall do nosso programa, resolvemos o endereço da instrução Syscall dentro do NTDLL.dll e fazemos o programa saltar para o endereço da instrução Syscall dentro do NTDLL.dll e executar Syscall a partir daí. Isto irá ignorar os alertas do COI (Indicador de Compromisso) pelos AVs ao executar.
O EDR nunca pode fazer Hook na própria instrução syscall. Isso é importante porque o EDR nunca pode nos impedir de executar a syscall na memória em ntdll.dll usando Indirect Syscalls.
Deixe um comentário