
correto desenganchamento da seção .text do ntdll via API nativa. diferente de outros unhookers, isso não deixa 2 ntdlls carregados. suporta x86/x64/wow64.
desengancho adequado da seção .text do ntdll via api nativa. suporte a x86/x64/wow64.
O programa percorre o PEB para localizar o endereço base da ntdll.dll e analisa manualmente a tabela de exportação do PE para resolver funções da API NT sem tocar na Tabela de Endereços de Importação. Em seguida, usa NtOpenFile para abrir a ntdll.dll limpa do disco, cria um objeto de seção com NtCreateSection e o mapeia no processo com NtMapViewOfSection para obter uma fonte de desengancho sem realmente carregar uma segunda dll via LoadLibrary. A seção .text com gancho é alterada para PAGE_EXECUTE_READWRITE via NtProtectVirtualMemory, o .text limpo é copiado sobre o com gancho com um memcpy personalizado, e então a proteção é restaurada para os flags originais. Após verificação byte a byte de que o desengancho funcionou, a cópia limpa é desmapeada corretamente com NtUnmapViewOfSection para que não reste uma segunda ntdll carregada na memória.
A maioria dos códigos de desengancho públicos é literalmente copiada e colada da mesma fonte lixo (como o exemplo do ired.team e praticamente todo desenganchador open source no github) e tem problemas enormes que os tornam inúteis contra qualquer EDR real. Eles usam VirtualProtect em vez de APIs nativas, o que anula todo o propósito, já que você está chamando funções com gancho para desenganchar funções; definem permissões RWX na seção .text, o que é um IOC enorme que os EDRs sinalizam imediatamente; e não desmapeiam a cópia limpa porque CloseHandle em um mapeamento de seção não libera a memória. Você precisa de UnmapViewOfFile ou NtUnmapViewOfSection, mas todo mundo esquece essa parte, então deixam duas cópias de ntdll carregadas no processo, o que é basicamente um letreiro de neon gigante dizendo "sou malware". Eles também tentam usar FreeLibrary na ntdll principal, o que nem funciona e causa vazamentos de handle, além de mudarem a proteção para RWX duas vezes desnecessariamente, quando uma vez é suficiente se você restaurá-la corretamente.
Esta implementação corrige os bugs comuns em códigos públicos de desengancho usando APIs nativas do começo ao fim (NtOpenFile, NtCreateSection, NtMapViewOfSection, NtProtectVirtualMemory), desmapeando corretamente a cópia limpa com NtUnmapViewOfSection para evitar deixar duas cópias de ntdll carregadas, não usando FreeLibrary na ntdll principal e verificando o sucesso por comparação de memória. No entanto, ela NÃO evita os IOCs fundamentais que os EDRs modernos detectam. Usar NtOpenFile em C:\Windows\System32\ntdll.dll é um IOC que é registrado, NtCreateSection com SEC_IMAGE apontando para ntdll.dll é rastreado via ETW, modificar a proteção de memória na seção .text da ntdll é uma bandeira vermelha enorme mesmo com APIs nativas, e escrever no .text é detectável via callbacks de escrita na memória. Essa técnica é bem conhecida e EDRs modernos como CrowdStrike e SentinelOne têm assinaturas para todo o padrão. EDRs avançados como Microsoft Defender for Endpoint e Elastic nem usam mais ganchos em modo de usuário, pois dependem de callbacks do kernel e telemetria ETW, então desenganchar não faz absolutamente nada contra eles. Isso funciona contra EDRs básicos que só usam ganchos inline e produtos de segurança mais antigos, mas falha contra qualquer coisa com componentes em modo kernel ou análise comportamental. Alternativas melhores incluem syscalls diretos, onde você nunca chama funções com gancho; heaven's gate para travessia de limite wow64; extração manual de syscall do .text da ntdll em tempo de execução; ou simplesmente evitar APIs suspeitas por completo, já que desenganchar em 2024/2025 é geralmente uma técnica morta contra EDRs corporativos reais.
Funciona em processos nativos x64, processos nativos x86 e processos wow64 (x86 em Windows x64). Detecta automaticamente wow64 e usa o diretório de sistema correto (System32 vs SysWOW64) para que você não precise pensar nisso.
Apenas a seção .text da ntdll.dll é tocada, porque é onde todo o código real das funções reside e onde os ganchos do EDR são colocados como ganchos de função inline (instruções jmp nos prólogos das funções). Outras seções como .data e .rdata são deixadas em paz porque não há motivo para tocá-las e isso só cria mais IOCs sem benefício.
cl /EHsc /std:c++17 main.cpp /Fe:unhook.exe
ou qualquer coisa, qualquer compilador C++ moderno funciona. Precisa de windows.h e winternl.h.
acesso não autorizado a sistemas de computador é ilegal. use apenas em sistemas que você possui ou para os quais tem autorização para testar. a prisão federal é real.
O código usa a macro CONTAINING_RECORD para percorrer corretamente as listas LDR, acessa o PEB via registradores de segmento (gs no x64, fs no x86), faz busca hardcoded da seção .text por comparação de nome (poderia ser mais elegante, mas funciona), trata erros via códigos NTSTATUS e a macro NT_SUCCESS, e envolve operações de memória em try/except SEH para segurança. Se você não consegue ler C++ e entender os internos do formato PE, provavelmente não deveria estar usando isso de qualquer forma.