Go to content

API hooking sous Windows pt.2

kernel

Nous avons vu dans un précédent article les hooks possibles au sein d’un processus sous Windows. Nous allons voir maintenant les principales techniques de hooks possibles dans le kernel Windows x86 (sous x64, les techniques diffèrent radicalement à cause de Patch Guard). Nous ne détaillerons pas chaque technique, pour des exemples, voir la partie « Références & Exemples » en bas de page.

Hooks kernel-land (ring 0)

L’intérêt de placer des hooks dans le kernel est multiple, et dépend du contexte de leur emploi :

  • C’est le niveau le plus « bas » possible où placer un hook. Il est donc possible d’intercepter tous les appels de l’userland à une fonction, sans possibilité de contournement, ainsi qu’une très large majorité des appels du kernel.
  • Au niveau kernel, tout (ou presque) est possible.
  • Leur détection ne peut être effectuée que par un code lui-même chargé dans le kernel, donc dans le même espace mémoire, et pouvant potentiellement être corrompu / trompé.

Les hooks kernel-land peuvent être situés à différents endroits, souvent dans une des (nombreuses) tables du kernel :

  • Le hook System Service Descriptor Table1 ou SSDT, consiste à modifier les entrées de la table ServiceTableBase de la structure KeServiceDescriptorTable, qui référence les fonctions Nt* du kernel (généralement les plus critiques, comme NtTerminateProcess, par exemple). Il suffit alors, à l’instar des hooks IAT de modifier l’adresse d’une de ces fonctions pour la faire pointer sur d’autres instructions. La détection passe en vérifiant l’intégrité de cette table (les fonctions doivent pointer pour la plupart dans le module du kernel Windows ntoskrnl).
  • Le hook Interrupt Descriptor Table2 ou IDT, consiste à modifier les entrées des tables (une par coeur de processeur) InterruptDescriptorTable qui référencent les handlers d’interruptions reçues par le processeur (comme par exemple l’interruption 1 qui correspond à un breakpoint hardware). La détection passe aussi en vérifiant l’intégrité de cette table, les 256 entrées étant normalement gérées par le kernel Windows.
  • Le hook Interrupt Request Packet3 ou IRP, consiste lui à modifier la table des fonctions I/O Request Packet d’un module kernel. Cette table référence les adresses des handlers des I/O request packet, utilisés pour gérer des requêtes diverses et variées, que ce soit depuis l’espace utilisateur (ring 3) ou depuis le kernel (ring 0). La détection passe toujours par la vérification de l’intégrité de cette table, en vérifiant que ces handlers sont soit les handlers par défaut (kernel Windows ntoskrnl, ou dans certains cas, d’autres modules comme NDIS.sys), soit dans le module courant.
  • Le hook sysenter4 consiste à modifier le champ SYSENTER_EIP_MSR du Model Specific Register (MSR), définissant le handler des instructions SYSENTER / SYSCALL depuis l’userland, indiquant un appel au kernel (anciennement l’interruption 0x2E). Il est donc possible d’intercepter tous les appels à des fonctions depuis l’espace utilisateur (sauf utilisation d’interruptions 0x2E). Il suffit de vérifier que sa valeur pointe bien dans l’espace mémoire du kernel Windows pour détecter une éventuelle modification.
  • Le hook inline consiste, comme son pendant userland, à poser une indirection sur une fonction en mémoire. Sa détection est identique à celle en ring 3 : il est possible de ne vérifier que les premiers octets de chaque fonction à la recherche d’une indirection (peu fiable), ou de vérifier l’intégrité de la section de code du module en comparant celle du module et celle de son binaire sur le disque (plus fiable).
  • Le hook DKOM5 (pour Direct Kernel Object Manipulation), très spécifique aux rootkits, consiste à modifier des objets du kernel (liste des processus, des threads, des drivers, etc.) en mémoire de façon à cacher des informations. La détection de tels hooks ne peut être effectuée qu’avec une bonne connaissance de la structure de Windows, puisqu’il faut retrouver ces informations dans d’autres structures, ou au sein de certaines fonctions.

Nous avons vu ici les hooks kernel-land que les plus communs, ainsi que quelques idées pour détecter ces derniers de façon automatisée. Leurs avantages et inconvénients par rapport aux hooks userland dépendent du contexte de leur emploi, et chaque type de hook est spécifique à une utilisation donnée.

Par exemple, certains antivirus utilisent des hooks SSDT pour protéger leurs processus de malwares qui chercheraient à les terminer. Des anti-debogueurs effectueront plutôt un hook IDT pour bloquer l’utilisation des breakpoints (interruptions 1 & 3). Certains malwares utiliseront, eux, des hooks inline ou IAT au sein de processus pour tenter d’intercepter des informations sensibles comme des mots de passe, des cookies, etc. On notera que sur les systèmes Windows 64 bits, les drivers doivent être signés numériquement et PatchGuard interdit la modification du kernel (ce qui laisse toutefois quelques techniques réalisables).

Références & exemples :

1- Hook SSDT : http://www.ivanlef0u.tuxfamily.org/?p=63 , http://www.shp-box.fr/blog/en/227

2- Hook IDT : http://www.shp-box.fr/blog/266 , http://uninformed.org/index.cgi?v=8&a=2&p=8

3- Hook IRP : http://www.ivanlef0u.tuxfamily.org/?p=45

4- Hook de l’instruction SYSENTER via la modification du registre MSR :

http://read.pudn.com/downloads151/sourcecode/windows/freedic/655298/SysEnterHook/sysenter.c__.htm

5- Hook DKOM : http://0vercl0k.blogspot.com/2008/02/first-steps-into-ring0.html

Un très bon livre pour s’initier aux hooks kernel-land : http://books.google.fr/books/about/Rootkits.html?id=XKsl5SZyfS4C

Plusieurs types de hooks présentés : http://www.blackhat.com/presentations/bh-jp-08/bh-jp-08-Aiko/bh-jp-08-Aiko-EN.pdf

CONIX