SYSENTER, stepping into da ring0
Vous avez sans doute déjà rencontré cette instruction en tracant sous Olly sans vraiment trop vous y intéressé et pourtant c’est une des plus importante de votre OS. Que peut-elle bien faire pour être si importante et pourquoi elle semble ne rien faire. Ivanlef0u votre détective préféré s’est penché sur cette affaire.
Dans un call à une API native comme par exemple ZwCreateFile on peut voir :
7C91D682 > B8 25000000 MOV EAX,25 7C91D687 BA 0003FE7F MOV EDX,7FFE0300 7C91D68C FF12 CALL NEAR DWORD PTR DS:[EDX] //EDX pointe sur 0x7C91EB8B 7C91D68E C2 2C00 RET 2C On arrive ici avec le call 7C91EB8B > 8BD4 MOV EDX,ESP 7C91EB8D 0F34 SYSENTER 7C91EB8F 90 NOP 7C91EB90 90 NOP 7C91EB91 90 NOP 7C91EB92 90 NOP 7C91EB93 90 NOP 7C91EB94 > C3 RET
En fait l’instruction SYSINTER à pour rôle de de faire un appel système. Dans notre exemple le code qui sera lancé sera celui de NtCreateFile de ntoskrnl.exe. Bon c’est cool tout ca mais comment on sait qu’on appel NtCreateFile, hé bien vous voyez le « mov eax, 0×25″, 0×25 correspond à l’indice de la fonction dans la SSDT (System Service Descriptor Table), une sorte de table d’exportation pour les fonctions systèmes.
Par contre l’appel à la SSDT n’est pas fait directement par SYSENTER, une routine du noyau (KiSystemService) se charge de retrouver l’adresse de la fonction dans la SSDT. Alors comment fait donc SYSENTER pour jumper sur KiSystemService ? En fait elle utilise les MSR (Model Specific Register), ceux-ci servent à des opérations spéciales sur le processeur. L’intruction SYSENTER utilise les 3 suivants :
- MSR_SYSENTER_CS 0×00000174
- MSR_SYSENTER_ESP 0×00000175
- MSR_SYSENTER_EIP 0×00000176
Voir le manuel « Intel® 64 and IA-32 Architectures Software Developer’s Manual Volume 2B Instruction Set Reference, N-Z »
Le MSR_SYSENTER_EIP contient l’adresse de la fonction KiSystemService (0x0804de6f0 chez moi), on trouve dans le MSR_SYSENTER_ESP l’adresse de notre nouvelle Kernel stack (0x0f88ab000 chez moi) enfin le nouveau segment de code MSR_SYSENTER_CS celui-ci n’a pas vraiment d’utilité.
Avant les appels systèmes étaient effectué avec l’interruption int 0x2E, SYSENTER la remplacé pour des raisons de rapididé.
Alors imaginons qu’on puisse modifier ces fameux MSR :), on pourrait donc faire exécuter notre code en ring0 !
He bien cela est possible ! Avec l’API natice NtSystemDebugControl on peut lire et écrire les MSR.
On lui donne une petite structure :
typedef struct _MSR_STRUCT { DWORD MsrNum; // MSR number DWORD NotUsed; // Never accessed by the kernel DWORD MsrLo; // IN (write) or OUT (read): Low 32 bits of MSR DWORD MsrHi; // IN (write) or OUT (read): High 32 bits of MSR } MSR_STRUCT, *PMSR_STRUCT;
Structure formée par Reversing du ntoskrnl evidemment …
Apràs il suffit de sauvegarder le MSR_SYSENTER_EIP courant puis on lui dit de pointer sur le morceaux de code que l’on veut lancer en ring0, on appel SYSENTER et hop ! Pour quitter on n’oublie pas de le restaurer bien sur !!!!
Bon clairement il faut codé un shellcode ring0, le mien ne fait que retrouver l’adresse de la structure ETHREAD courante mais au final on peut faire ce qu’on veut dans notre noyau, suffit de s’y mettre :}
Voici le code avec pas mal d’infos dedans et le binaire.
http://ivanlef0u.fr/repo/MSR.rar
Have fun.
4 comments février 4th, 2007