
Unhooking correct de la section .text de ntdll via l'API native. Contrairement à d'autres unhookers, celui-ci ne laisse pas 2 ntdll chargées. x86/x64/wow64 pris en charge.
Dé-hooking correct de la section .text de ntdll via l'API native. x86/x64/wow64 pris en charge.
Le programme parcourt le PEB pour localiser l'adresse de base de ntdll.dll et analyse manuellement la table d'exportation PE pour résoudre les fonctions de l'API NT sans toucher à la table d'adresses d'importation. Il utilise ensuite NtOpenFile pour ouvrir le ntdll.dll propre depuis le disque, crée un objet section avec NtCreateSection, et le mappe dans le processus avec NtMapViewOfSection pour obtenir une source de dé-hooking sans réellement charger une seconde dll via LoadLibrary. La section .text hookée est passée en PAGE_EXECUTE_READWRITE via NtProtectVirtualMemory, le .text propre est copié par-dessus la section hookée avec un memcpy personnalisé, puis la protection est restaurée avec les indicateurs d'origine. Après une vérification octet par octet que le dé-hooking a fonctionné, la copie propre est correctement dé-mappée avec NtUnmapViewOfSection afin qu'aucun second ntdll ne reste chargé en mémoire.
La plupart des codes de dé-hooking publics sont littéralement copiés-collés depuis la même source poubelle (comme l'exemple d'ired.team et pratiquement tous les outils d'unhook open source sur GitHub) et présentent des problèmes majeurs qui les rendent inutiles face à un véritable EDR. Ils utilisent VirtualProtect au lieu des API natives, ce qui annule tout l'intérêt puisque vous appelez des fonctions hookées pour dé-hooker des fonctions, ils définissent des permissions RWX sur la section .text, ce qui est un énorme IOC que les EDR signalent immédiatement, et ils ne dé-mappent pas réellement la copie propre car CloseHandle sur un mapping de section ne libère pas la mémoire. Il faut UnmapViewOfFile ou NtUnmapViewOfSection, mais tout le monde oublie cette partie, donc ils laissent deux copies de ntdll chargées dans le processus, ce qui est essentiellement un énorme panneau néon indiquant « je suis un malware ». Ils essaient aussi d'utiliser FreeLibrary sur le ntdll principal, ce qui ne fonctionne même pas et provoque des fuites de handles, et en plus ils changent la protection en RWX deux fois inutilement alors qu'une seule suffit si vous la restaurez correctement.
Cette implémentation corrige les bugs courants des codes de dé-hooking publics en utilisant des API natives partout (NtOpenFile, NtCreateSection, NtMapViewOfSection, NtProtectVirtualMemory), en dé-mappant correctement la copie propre avec NtUnmapViewOfSection pour éviter de laisser deux copies de ntdll chargées, en n'utilisant pas FreeLibrary sur le ntdll principal, et en vérifiant le succès par comparaison mémoire. Cependant, elle n'évite PAS les IOC fondamentaux que les EDR modernes détectent. Utiliser NtOpenFile sur C:\Windows\System32\ntdll.dll est un IOC qui est journalisé, NtCreateSection avec SEC_IMAGE pointant vers ntdll.dll est suivi via ETW, modifier la protection mémoire de la section .text de ntdll est un énorme drapeau rouge même avec des API natives, et écrire dans .text est détectable via les callbacks d'écriture mémoire. Cette technique est bien connue et les EDR modernes comme CrowdStrike et SentinelOne ont des signatures pour l'ensemble du motif. Les EDR avancés comme Microsoft Defender for Endpoint et Elastic n'utilisent même plus de hooks en mode utilisateur car ils s'appuient sur des callbacks noyau et la télémétrie ETW, donc le dé-hooking ne fait littéralement rien contre eux. Cela fonctionne contre les EDR basiques qui n'utilisent que des hooks inline et les anciens produits de sécurité, mais échoue contre tout ce qui comporte des composants en mode noyau ou une analyse comportementale. De meilleures alternatives incluent les syscalls directs où vous n'appelez jamais de fonctions hookées en premier lieu, heaven's gate pour traverser la frontière wow64, l'extraction manuelle des syscalls depuis le .text de ntdll au runtime, ou simplement éviter entièrement les API suspectes, car le dé-hooking en 2024/2025 est généralement une technique morte face aux vrais EDR d'entreprise.
Fonctionne sur les processus natifs x64, les processus natifs x86 et les processus wow64 (x86 sur Windows x64). Il détecte automatiquement wow64 et utilise le bon répertoire système (System32 vs SysWOW64) pour que vous n'ayez pas à y penser.
Seule la section .text de ntdll.dll est touchée car c'est là que vit tout le code réel des fonctions et là où les hooks EDR sont placés sous forme de hooks de fonction inline (instructions jmp aux prologues des fonctions). Les autres sections comme .data et .rdata sont laissées tranquilles car il n'y a aucune raison d'y toucher et cela ne ferait que créer plus d'IOC sans bénéfice.
cl /EHsc /std:c++17 main.cpp /Fe:unhook.exe
ou peu importe, n'importe quel compilateur c++ moderne fonctionne. nécessite windows.h et winternl.h.
L'accès non autorisé à des systèmes informatiques est illégal. Utilisez-le uniquement sur des systèmes que vous possédez ou pour lesquels vous avez l'autorisation de tester. La prison fédérale est bien réelle.
Le code utilise la macro CONTAINING_RECORD pour parcourir correctement les listes LDR, accède au PEB via les registres de segment (gs sur x64, fs sur x86), effectue une recherche en dur de la section .text par comparaison de noms, ce qui pourrait être plus élégant mais bon, ça marche, gère les erreurs via les codes NTSTATUS et la macro NT_SUCCESS, et enveloppe les opérations mémoire dans un try/except SEH pour la sécurité. Si vous ne savez pas lire le c++ et comprendre les internals du format PE, vous ne devriez probablement pas utiliser ça de toute façon.