
Nous avons développé lors d'une de nos missions un anti-rootkit pour Windows. Une des fonctionnalités kernel de ce dernier liée à la détection de processus cachés est détaillée dans ce présent billet.
Nous étudierons plus particulièrement une technique qui permet notamment de détecter le très célèbre Futo Enhanced. Pour rappel, ce rootkit va jusqu'à supprimer l'entrée du processus à cacher de la PspCidTable, table utilisée par le noyau Windows pour stocker threads et processus du système.
Détecter Futo Enhanced est très simple si l'on cherche sa signature en mémoire. C'est évidemment sans aucun intérêt puisque la méthodologie n'est pas générique. Nous avons donc préféré cumuler les techniques de récupération d'information et faire une corrélation de ces informations. La solution présentée ici permet de récupérer une liste de structures EPROCESS correspondant aux processus actifs sur le système.
Première étape: récupérer l'adresse de cette fameuse table. On analyse d'abord en mémoire la fonction PsLookupProcessByProcessId. Comme son nom l'indique, cette fonction retourne la structure EPROCESS correspondant au pid donné en argument (note intéressante, les pids sous Windows sont multiples de 4, car ils servent d'offset pour cette table).
Voici un extrait de cette fonction dans lequel on retrouve bien la valeur courante de la PspCidTable :
805c9446 8bff mov edi,edi
805c9448 55 push ebp
805c9449 8bec mov ebp,esp
[...]
805c945e ff35e0a25580 push dword ptr [nt!PspCidTable (8055a2e0)]
La PspCidTable contient la liste des EPROCESS, mais aussi la liste des ETHREAD, structures contenant des informations sur chacun des threads actifs du système d'exploitation.
Seconde étape: récupérer toutes les entrées "valides" de cette table (les entrées inutilisées ou en phase de suppression contiennent un "flag"). Les entrées sont de ce type :
typedef struct _TABLE_ENTRY {
DWORD object;
ACCESS_MASK security;
};
Il reste ensuite à différencier les ETHREAD des EPROCESS. Plusieurs solutions existent, la meilleure étant d'en implémenter le maximum (comme toutes les récupérations d'information). Une méthode très simple à mettre en place est de considérer la structure comme une structure ETHREAD, d'en sortir le champ correspondant à la service table, et de le comparer aux deux seules valeurs possibles, à savoir la service table classique et celle des GUI threads. Si la valeur ne correspond pas, il y a de fortes chances que ce soit une structure EPROCESS.
lkd> dt nt!_KTHREAD 88dc85e0
[...]
+0x0e0 ServiceTable : 0x80552fe0
[...]
Nous voila enfin avec une liste des structures pointant vers les threads actuellement actifs sur la machine. Ces threads étant liés à un processus, il suffit de rechercher dans la structure l'information suivante (l'offset est dépendant de la version du système, il est ici à titre informatif) :
lkd> dt nt!_ETHREAD
[...]
+0x220 ThreadsProcess : Ptr32 _EPROCESS
[...]
Après avoir récupéré les pointeurs EPROCESS de ces structures, si un processus non présent dans les précédents listings apparait, il s'avère alors suspicieux.
C'est en cumulant des techniques de ce type qu'on parvient à détecter la plupart des codes malveillants. Le concept est simple, pousser plus loin que le créateur de rootkit.
