PEB Walk
Evadindo IAT com PEB Walk
Hoje em dia, se você usar direto as APIs do Windows (tipo VirtualAllocEx, CreateRemoteThread, etc.), seu binário vai ser cravado fácil por qualquer EDR ou AV mais decente. Isso acontece porque essas APIs aparecem na IAT (Import Address Table), que é basicamente um "print" do que seu código chama. E aí, qualquer analista ou ferramenta que lê PE consegue sacar o comportamento do binário só olhando ali.
As informações que você encontrar neste post, técnicas, códigos, provas de conceito ou qualquer outra coisa são estritamente para fins educacionais.
Mas tem um jeito de burlar isso: PEB Walk.
Por padrão, quando queremos por exemplo começar uma analise estática de um possível malware, é extremamente interessante, ver as importações que esse programa realiza. como por exemplo, se a gente compilar um código simples, usando a API, MessageBoxA, para imprimir uma mensagem:
#include <windows.h>
int main() {
MessageBoxA(NULL, "Hello, World!", "My Message Box", MB_OK);
return 0;
}Se a gente olhar as importações desse código em C, já compilado vamos ver, que a gente consegue ver com facilidade que o programa está importando a MessageBoxA, ficando visível na IAT do programa.

Em contrapartida se a gente, olhar as importações de outro programa que executa essa mesma função para chamar MessageBoxA para a impressão de uma mensagem, mas dessa fez com o PEB walk implementado, vamos ver que ao tentar acessar a IAT do programa, não vamos estar conseguindo assim ver a importação da MessageBoxA Dessa forma, por exemplo um analista não consegue ter uma ideia do comportamento do programa se depender da lista IAT.
Por que fazer PEB Walk?
A lógica é simples:
Você não quer deixar rastro na IAT.
E consegue diminuir a taxa de detecção baseada em assinatura estática.
E isso por si só, por pouco que pareça, já é importante para um desenvolvedor de malware.
Entendendo o PEB
Quando um processo é criado, o Windows aloca uma estrutura interna chamada PEB. Dentro dela, tem um campo Ldr que aponta pra outra estrutura chamada _PEB_LDR_DATA, que tem uma lista com todas as DLLs carregadas:


Essa lista se chama InLoadOrderModuleList. E cada item nela é um LDR_DATA_TABLE_ENTRY, que tem o caminho da DLL e a DllBase, ou seja, o endereço onde a DLL tá na memória.

Um exemplo prático que poderíamos realizar para ver isso, é usar o WinDBG anexar ele ao um processo em execução, e digitar !peb então assim vamos estar conseguindo ver o campo Ldr.InMemoryOrderModuleList que vai estar mostrando assim a lista de DLLs carregadas para o processo atual:

Tá, mas como acessar o PEB?
Então, como o malware (ou qualquer outro código de baixo nível) pode acessar essa estrutura?
Uma das formas é fazendo acesso direto via assembly inline (montagem embutida no código), utilizando registradores de segmento que apontam para estruturas internas do processo.
Se o programa for em 32 bits, a linha em assembly seria basicamente:
E em 64 bits:
Mas o que é fs e gs?
fs e gs?Esses são registradores de segmento usados pelo Windows para apontar para o início de estruturas internas por thread:
Em 32 bits, o registrador
fsaponta para o início do TEB (Thread Environment Block).Em 64 bits, o registrador usado é o
gs.
O que é o TEB?
O TEB (Thread Environment Block) é uma estrutura que contém informações específicas da thread atual — como:
ID da thread,
ponteiro para o PEB do processo ao qual pertence,
dados de exceção,
pilha de chamada,
e por ai vai. Ou seja: quando fazemos
fs:[0x30](em 32 bits) ougs:[0x60](em 64 bits), estamos acessando um campo dentro do TEB no caso oProcessEnvironmentBlockque aponta diretamente para a estrutura PEB — a estrutura que vai conter informações globais do processo, como pode ser visto nessa imagem de exemplo:

Resumindo
Definindo a estrutura do PEB:
Definindo a estrutura PEB_LDR_DATA:
Para obter o endereço da Tabela de Dados do Carregador, tudo o que precisamos fazer é ler o deslocamento Ldr da estrutura PEB:
O que esse código faz?
Primeiro, ele acessa o PEB do processo atual usando o registrador de segmento (
__readgsqword(0x60)em 64 bits).Depois, pega o campo
Ldrdo PEB, que aponta para a estruturaPEB_LDR_DATA.Com isso, já temos acesso à lista de módulos carregados pelo processo, que é o ponto de partida para o PEB Walk.
Esse acesso é feito totalmente em tempo de execução, sem depender da IAT, dificultando a análise estática.
Isso em assembly seria assim:
Definindo a estrutura LDR_DATA_TABLE_ENTRY:
Como mencionado anteriormente, é possível assumir a ordem dos 3 primeiros módulos para um aplicativo nativo. Portanto, o código mais simples para obter a entrada do módulo para o executável atual, ntdll e kernel32 é o seguinte.
O que esse código faz?
LDR_DATA_TABLE_ENTRY *main_module = (LDR_DATA_TABLE_ENTRY *)ldr->InLoadOrderModuleList.Flink;Aqui, acessamos o primeiro elemento da listaInLoadOrderModuleList, que está dentro da estruturaPEB_LDR_DATA.
Flinké um ponteiro para o próximo item da lista (o primeiro módulo carregado). Esse primeiro item normalmente representa o executável principal do processo (ou seja, o próprio.exeque está rodando).
LDR_DATA_TABLE_ENTRY *ntdll = (LDR_DATA_TABLE_ENTRY *)main_module->InLoadOrderLinks.Flink;Agora, pegamos o campoInLoadOrderLinks.Flinkdo primeiro módulo (o executável). Isso nos leva ao próximo módulo carregado, que geralmente é ontdll.dll. Cada módulo na lista tem um campoInLoadOrderLinksque aponta para o próximo módulo, formando uma lista encadeada.
LDR_DATA_TABLE_ENTRY *kernel32 = (LDR_DATA_TABLE_ENTRY *)ntdll->InLoadOrderLinks.Flink;Repetimos o processo: pegamos o próximo da lista, que normalmente é okernel32.dll. Assim, caminhando de um item para o próximo usando o campoFlink, conseguimos acessar os módulos carregados na ordem em que o Windows os adicionou.
Em assembly seria assim:
O código C a seguir demonstra como procurar a entrada do módulo para kernelbase.dll:
Conclusão
O PEB Walk é uma técnica poderosa para acessar informações sobre módulos carregados em um processo Windows sem depender da Import Address Table (IAT). Ao navegar manualmente pelas estruturas internas do sistema operacional, como o PEB, PEB_LDR_DATA e LDR_DATA_TABLE_ENTRY, é possível localizar e interagir com DLLs e funções de forma discreta, dificultando a análise estática e a detecção por antivírus.
Essa abordagem é amplamente utilizada em desenvolvimento de malware e também pode ser útil para pesquisadores de segurança e engenheiros reversos que desejam entender melhor o funcionamento interno dos processos no Windows.
Dominar o PEB Walk abre portas para uma compreensão mais profunda do Windows Internals e permite criar soluções mais sofisticadas, seja para fins de pesquisa, análise ou desenvolvimento de ferramentas avançadas.
Last updated