Affichage des articles dont le libellé est ring0. Afficher tous les articles
Affichage des articles dont le libellé est ring0. Afficher tous les articles

mercredi 24 décembre 2008

H-CL vous souhaite un joyeux noël !

Un revenant ? Et oui me revoilà back from h3ll après quelques semaines d'inactivités.
Je vais profiter de ce petit article, pour vous racontez mes péripéties. Mais celles-ci ne se déroulent non pas dans les contrées rocheuses avoisinant mon chère kernel, mais belle et bien In Real Life.

Il y a quelques semaines de cela, mon laptop a subit une terrible perte ; un petit texte pour vous contez ces aventures.
Ma maudite machine plutôt jeune et jusqu'à présent assez performante me laissa tomber : un beau matin en l'allumant, j'entends alors de vieux bips systèmes..après quelques recherches de faite il s'avère que c'est ma motherboard :(.

Me voilà face au gouffre, le ciel prêt à s'écraser sur ma tête : obliger de renvoyer la bestiole au sav.

Jusqu'à présent rien de bien grave..
L'unique problème c'est que bien sur je n'ai aucun backup..AUCUN .
Mes neurones en ébullition se rassemblent dans l'espoir de trouver une solution me permettant de sauvegarder mon disque dur..Mais rien ! Si je tente toutes bidouilles avec le disque dur interne du laptop, la garantie saute.

Après un petit coup de fil avec le réparateur, il me propose de sauvegarder un dossier

"Quel dossier je vous sauvegarde monsieur ?"
"Humm, le dossier C:\kernel s'il vous plait !"
"heu..il n'y a pas de dossier kernel"
"le dossier k3rn3l !"

Encore un technicien ignorant le 1337 sp34k1ng.

Mais aujourd'hui je reviens, avec des (merci hzv <3) laptops tout propre, ready, avec backup :] (merci ivan:p).

C'est donc en ce soir de nowel, que je vous propose le début d'un projet qui me tiens plutôt à cœur car à mon avis plus qu'utile.

L'idée n'a rien de transcendante, c'est en fait une espèce de librairie.
Un header contenant quelques fonctions useful quand on aime bien trifouiller son kernel.

L'originalité du projet, je pense, est le fait que tout est réunis dans UN unique fichier : personnellement je trouve que ça simplifie grandement les choses quant à l'utilisation.

Concernant l'avancement du projet ; c'est encore au stade embryonnaire à peine 5 fonctions pour le moment.

Disons que, ça intéressera surement quelques personnes : d'ailleurs si certains on des reports de bugs, ou autres n'hésitez pas à me laisser un commentaire ; j'aimerais bien faire un truc propre et pourquoi pas utilisé ?
Tant que j'y pense, si vous avez des idées de fonctions à implémenter n'hésitez pas encore une fois à laisser un petit mot ; merci :)).

Je vais donc bien sur continuer à poster régulièrement maintenant que tout est rentré dans l'ordre !
En attendant je vous laisse avec mon .h en espérant que ça servira à quelques mangeur de chips fan de black-métal ; ça serait un bon début :)).

-H-CL.h

En tous cas, joyeux noël à vous, passer de bonnes fêtes :).

vendredi 8 août 2008

How to pwn lilxam's toolz :).

Un titre un peu provacateur, mais rien de méchant, juste un petit jeu entre lilxam et moi ; autrement dit mon article n'est pas là pour dénigrer son travail ou autre bien au contraire.
Les avertissements étant fait, rentrons dans le vif du sujet .. :).

Il y a quelques temps, j'ai entamé l'écriture d'un petit post concernant une technique de DKOM aboutissant à caché un processus (plus ou moins bien justement).
Le noyau possède un chainage de structures de type EPROCESS (par une liste doublement chainé à l'offset 0x088), il était donc possible d'unlinker une structure en particulier.
Le processus se retrouvait alors protégé de l'énumération par le taskmgr.exe ou encore ProcessExplorer.
C'est à présent que lilxam entre en jeu.

Peu de temps après mon petit Proof of Concept, il met en place une technique userland permettant d'énumérer les processus malgré la modification des structures en mémoire.
Cet technique en question, très ingénieuse au passage, permettant de récupérer le nom des processus en bruteforçant les PIDs de ceux-ci.
Seulement, tout cela m'interpelle, comment était-il possible de retrouver ce processus, alors qu'il n'était plus présent dans les structures EPROCESS ..?

La réponse ne devrait pas être trop complexe à rechercher ; en effet un commentaire de Ivanlef0u nous donne de précieuses informations : il aborde la présence d'une mystérieuse table prénommé PspCidTable référençant des informations concernant les processus à savoir une translation entres PIDs/TIDs et objet EPROCESS/ETHREAD.

Nous voilà sur la bonne route, sortons IDA afin d'analyser les apis utilisées dans le code de lilxam ; le réel problème étant de savoir comment le système se débrouille pour trouver le processus en question, désassemblons un peu OpenProcess exporté par kernel32.dll.
Nous suivons en premier lieu les appels successif à savoir:

->OpenProcess
-->NtOpenProcess
--->ZwOpenProcess

Nous savons bien que le système afin de permettre l'appel d'un syscall va passer par la SSDT pour retrouver l'adresse de la fonction associé à son numéro de syscall (0x7a pour NtOpenProcess).
Balayons alors ce code à la recherche de la translation PID/TID en objet EPROCESS/ETHREAD :

PAGE:004A9C92 cmp [ebp+var_1A], 0
PAGE:004A9C96 jnz loc_52ADDF
PAGE:004A9C9C cmp [ebp+var_19], 0
PAGE:004A9CA0 jz loc_50F76D
PAGE:004A9CA6 mov [ebp+var_30], esi
PAGE:004A9CA9 cmp [ebp+var_28], esi
PAGE:004A9CAC jnz loc_4D88A0
PAGE:004A9CB2 lea eax, [ebp+var_24]
PAGE:004A9CB5 push eax
PAGE:004A9CB6 push [ebp+var_2C]
PAGE:004A9CB9 call _PsLookupProcessByProcessId@8

L'appel à PsLookupProcessByProcessId est plus que révélateur, son nom en dit assez large sur son rôle et de plus cette fonction est renseigné par la msdn.
Désassemblons cette dernière fonction, notre réponse y est surement caché :).


PAGE:004A9B25 mov edi, edi
PAGE:004A9B27 push ebp
PAGE:004A9B28 mov ebp, esp
PAGE:004A9B2A push ebx
PAGE:004A9B2B push esi
PAGE:004A9B2C mov eax, large fs:124h
PAGE:004A9B32 push [ebp+arg_0]
PAGE:004A9B35 mov esi, eax
PAGE:004A9B37 dec dword ptr [esi+0D4h]
PAGE:004A9B3D push _PspCidTable
PAGE:004A9B43 call _ExMapHandleToPointer@8
PAGE:004A9B48 mov ebx, eax
PAGE:004A9B4A test ebx, ebx


Mais que voyons nous ; notre"PspCidTable".
Arrivé ici nous comprenons alors que les apis qu'utilise notre très cher lilxam ; en particulier OpenProcess se base donc sur cette fameuse table pour retrouver notre processus à partir de son PID.
Sans plus attendre je vous recommande (encore) un article de mon noble jedi ; celui-ci traite de long en large les tables de type HANDLE_TABLE au prototype suivant :


lkd> dt nt!_HANDLE_TABLE
+0x000 TableCode : Uint4B
+0x004 QuotaProcess : Ptr32 _EPROCESS
+0x008 UniqueProcessId : Ptr32 Void
+0x00c HandleTableLock : [4] _EX_PUSH_LOCK
+0x01c HandleTableList : _LIST_ENTRY
+0x024 HandleContentionEvent : _EX_PUSH_LOCK
+0x028 DebugInfo : Ptr32 _HANDLE_TRACE_DEBUG_INFO
+0x02c ExtraInfoPages : Int4B
+0x030 FirstFree : Uint4B
+0x034 LastFree : Uint4B
+0x038 NextHandleNeedingPool : Uint4B
+0x03c HandleCount : Int4B
+0x040 Flags : Uint4B
+0x040 StrictFIFO : Pos 0, 1 Bit


Ce type de table est d'ailleurs presque omni-présent dans les processus ; les handles que gèrent un processus sont stockés dans une table de ce genre.
Celle-ci est accessible à l'offset 0x0c4 :


lkd> dt nt!_EPROCESS
[...]
+0x0c4 ObjectTable : Ptr32 _HANDLE_TABLE


A présent, parlons PspCidTable.
En glanant sur le net, on s'aperçoit assez rapidement qu'il y a quelques années la modification
de cet table était une technique à la pointe dirais-je.
Cependant, je me suis vite rendu compte que mes parents ont entrepris ma construction trop tard :p ; en effet mon implémentation ce chargeait d'enlever l'objet EPROCESS du processus à caché, mais malgrès cela RkUnhooker, anti-rootkit digne de ce nom, trouve toujours le moyen de retrouver l'objet EPROCESS, et donc de permettre le kill de celui-ci :/.
Un peu frustré, je commence à m'interroger sur la technique que RkUnhooker pourrait déployer afin de retrouver ce maudit processus.
En analysant la définition de la structure ETHREAD on peut remarquer qu'il existe un lien avec la structure EPROCESS associé, à l'offset 0x220:

lkd> dt nt!_ETHREAD
[...]
+0x220 ThreadsProcess : Ptr32 _EPROCESS


; on ne peut que se demander
si RkUnhooker ce focalise sur les threads, et remonte au processus par le biais de divers fonctions.
Me voilà repartit dans cette table, afin d'enlever les objets ETHREADs .. après l'implémentation, à ma grande surprise le processus devient inactif ; zombie...

C'est donc à ce moment là que les questions jaillissent à travers mon esprit :

- Comment RkUnhooker remet la main sur mon processus ?
- Quel(s) technique(s) utilise t-il pour cela ?
- Existe t-il un autre endroit où une liste des processus lancées sur le système est disponible ?

Voilà concernant la PspCidTable, ma fonction permet alors de supprimer l'entrée concernant le processus à caché dans la table ; l'outil de lilxam est donc finalement inefficace sur ce coup là .:p.



Comme je le racontais plus haut, cette implémentation est trop maigre pour permettre de leurrer RkUnhooker.
C'est donc ainsi que commence mes recherches sur les techniques existantes permettant la protection d'un processus de l'énumération. Après quelques recherches sur la toile, mon regard s'attarde sur cette technique ; en effet le processus vital csrss.exe contiendrait une liste des processus lancée sur le système.
L'auteur de la technique explique très bien les faits et son analyse est détaillée ; en quelques mots, le processus tiens à jour une liste des processus lancés sur le système sous forme de liste chainée.Il est alors aisé pour nous de pratiquer un unlink ..

Pour un projet personnel, j'ai décidé de porter cette unlink en ring0 ; celle-ci devient alors tout de suite bien plus intéréssante car on est obligé de faire appel à pleins de petites choses pour arrivé à nos fin : du parcours de PE, de l'attachement à l'user-space d'un processus et j'en passe.

Les liens :
-PspCidTable PoC
-UnlinkListEntryInCsrss

Sinan si vous ne savez pas quoi faire, je vous conseil d'aller faire un tour sur le site de la F.A.T.
Cette petite team aux membres bien sympathiques publient des codes et papers vraiment géniaux ( je pense au dernier que j'ai lu ; autrement dit le paper concernant win32.leon par kaze ) ..enfin bref à bookmarker pour ceux qui ne connaissent pas :).

Et si vous en voulez encore un peu, je vous conseil de lire les derniers articles de deux de mes amis :

-Celui de rAsM ; monsieur met en place une technique pouvant servir de base à un potentiel keylogger kernel (a condition de patcher les BSODs :))).

-Celui de Ivanlef0u ; mon s1ths préféré propose un petit article concernant le subsystem csrss en abordant notament les processus consoles.

Pour clore ce petit post, un dernier lien ; celui-ci vient tout droit des dragons asiatiques ..Sudami reverseur de talent continus de nous faire réver en nous proposant de nouvelles techniques de DKOMs ; celle-ci aborde le hook d'une fonction stockée dans la structure liée aux Objects Types Initializers ( ..qui m'avait mis en échec ici ).
Bien evidement, raffolant de ce genre de technique je m'empresse de mettre en place un petit driver capable de placer ce hook mais c'est (du moins chez moi (XP SP2 FR)) un échec.. la routine est apparement bien appelé par le system mais en aucun cas elle empèche la fermeture du processus.
Peut-être que sudami explique les limites de sa technique dans son article, ou que celle-ci est valable avec des pré-requis.. Enfin bon si quelqu'un en sait plus qu'il me contacte :).

Voilà pour ce petit article, en espérant que je vous aurrez appris quelque(s) chose(s),
bonne journée à vous.
PS : Bonne rentrée à ceux qui ne l'ont toujours pas faite.

jeudi 17 juillet 2008

Sudami KillMe PoC.

Je me permets d'écrire un petit post après la publication du dernier article par mon jedi ; il concerne l'analyse d'un driver tout droit venu de l'orient.
En effet, sudami et son blog avait déjà interpellé notre ami Ivan, il contenait les sources d'un rootkit kerneland assez puissant d'après ce que les sources inspiraient.

Cette fois-ci il s'agit d'un PoC concernant une technique de DKOM afin de rendre un processus interminable ; du jamais vu pour ma part.
C'est pour cela qu'en dévorant ce jolie article, je me suis empressé de coder un PoC.

J'ai donc remarquer que lorsque le PoC était "complet", autrement dit toutes les modifications au niveau des structures étaient effectuées le processus était "inerte".
Interminable certes, mais un processus qui ne peux plus rien faire c'est assez embêtant, voir presque inutile (apart pour embeter la victime avec une fenêtre en plein milieu de l'écran..un peu à la sudami :)).
Celui-ci est disponible en fin de page bien évidemment.

Cependant, le fait que le processus était larvaire après avoir appliqué les manipulations de structures kernel, ivan me proposa de jouer en désactivant quelques "protections" afin d'obtenir un processus assez difficile à tuer mais un processus actif, une technique bien utile vous pouvez me croire dans le cadre d'un quelconque malware.
Pour moi l'implentation plus ou moins idéal reste de modifier le champ KernelApcDisable à l'offset 0x0d4 de la structure ETHREAD.
Concernant de plus amples explications concernant ces APCs kernel je vous suggère une petite lecture de l'analyse d'ivan.

Concernant l'activité que je peux avoir sur mon blog ces temps-ci, autrement dit, une activité assez limitée dirons nous, celle-ci est due à mon engagement dans divers projets qui verront leurs concrétisations dans quelques temps (avant la rentré j'esepère) wait and see .

Sinan en attendant je vous conseil quelques liens :

- #carib0u@irc.worldnet.net déjà :p.
- http://joe-is-a-rocknroll-star.blogspot.com/ -> une personne que j'apprécie beaucoup, des écrits clair toussa, continue :).
- http://md5.sh4ka.fr/ -> un service de très grande qualité codé par un très bon ami concernant la recherche de plaintext MD5 ; celui-ci possède en plus d'opérer à des recherches sur de multiples sites du même genre une base de donnée plutôt bien garnis et qui ne cesse de s'aggrandir !
- http://www.rootkit.com/ -> Faut peut-être pas l'oublier :).


Les PoCs :

- SudamiKillMe.c.
- SudamiKillMe Idéal (?).c.


Voilà pour les nouvelles, si vous trouvez mieux concernant cette technique je suis tout à fait preneur sur ce bonne soirée.

vendredi 7 mars 2008

Sur les traces du KLOG.

Bonjour à vous,
Je vous propose aujourd’hui ma petite contribution régulière.
Celle-ci traitera du principe du KLOG, un keylogger kernel programmé par Clandestiny.

Dans cet article, nous allons parler un peu du « comment le KLOG opère t-il ? » afin de nous coder un petit driver perso pour mettre en pratique les choses que l’on vient d’apprendre.

Je vous propose quelques outils pouvant être utile au cours du coding et de l’analyse du KLOG :
- DeviceTree, peut être utile pour observer les devices créer par les drivers par exemple.
- IrpTracker, un outil permettant de « tracker » les IRPs reçus par un device.

Les outils en main, nous pouvons nous attaquer au fonctionnement de l’engin.

Le KLOG dans la place

Vous êtes maintenant préparer à suivre la suite de l’article.
Pour mener à bien son fonctionnement le KLOG va attacher un filter device ( FiDO ) au dessus du device KeyboardClass0 créer par le driver Kbdclass. Le driver KbdClass à pour rôle de fournir une interface entre le sytème et le driver physique :

( Je cite )
The HID class driver does the following:
Provides and manages the upper-level interface that kernel-mode drivers and user-mode applications use to access the HID collections that an input device supports.
The HID class driver transparently manages and routes all communication between upper-level drivers and applications and the underlying input devices that support HID collections. It manages the different data protocols used by different input devices and input queues that support more than one open file on the same HID collection. (!!)
The upper-level interface to HID collections consists of the HID class driver IOCTLs, the HIDClass support routines, and the HIDClass structures.
Communicates with a HID minidriver by calling the minidriver's standard driver routines — see Communicating with a HID Minidriver.
Creates a functional device object (FDO) for HIDClass input devices enumerated by a lower-level bus or port driver.
For example, the HID class driver creates and manages the operations of an FDO that represents a USB HID device enumerated by the system-supplied USB driver stack.
Provides the functionality of a bus driver for the child devices (HID collections) supported by an underlying input device.
The HID class driver creates a physical device object (PDO) for each HID collection supported by an input device and manges the collection's operation.
(juste pour informations)


Il faut aussi savoir que le device KeyboardClass0 est attaché au device anonyme du driver i8042prt. Le driver i8042prt est de type PDO (Pysical Device Object), il gère la gestion de la souris et du clavier. Le HID driver va crée un FDO (Functional Device Object) au dessus du PDO pour fournir une interface entre le sytème et le périphérique.





Le KeyboardClass1 est un clavier virtuel, il ne nous intéresse pas du tout.
Vu que tout le concept repose sur la device stack du driver, nous allons nous renseigner un peu plus sur celle-ci, sortons donc le kd.

kd> !devstack \device\keyboardclass0
!DevObj !DrvObj !DevExt ObjectName
> 816f53a0 \Driver\Kbdclass 816f5458 KeyboardClass0
816f5588 \Driver\i8042prt 816f5640
817d2618 \Driver\ACPI 817da2e8 00000043
!DevNode 81799948 :
DeviceInst is "ACPI\PNP0303\4&5289e18&0"
ServiceName is "i8042prt"
kd> !drvobj \Driver\Kbdclass 3
Driver object (816f5930) is for:
\Driver\Kbdclass
Driver Extension List: (id , addr)

Device Object list:
816d5030 816f53a0 q

DriverEntry: f9d0f610
DriverStartIo: 00000000
DriverUnload: 00000000
AddDevice: f9d0eb02

Dispatch routines:
[00] IRP_MJ_CREATE f9d0bdd8 +0xf9d0bdd8
[01] IRP_MJ_CREATE_NAMED_PIPE 805025e4 nt!IopInvalidDeviceRequest
[02] IRP_MJ_CLOSE f9d0bfe8 +0xf9d0bfe8
[03] IRP_MJ_READ f9d0cc82 +0xf9d0cc82
[04] IRP_MJ_WRITE 805025e4 nt!IopInvalidDeviceRequest
[05] IRP_MJ_QUERY_INFORMATION 805025e4 nt!IopInvalidDeviceRequest
[06] IRP_MJ_SET_INFORMATION 805025e4 nt!IopInvalidDeviceRequest
[07] IRP_MJ_QUERY_EA 805025e4 nt!IopInvalidDeviceRequest
[08] IRP_MJ_SET_EA 805025e4 nt!IopInvalidDeviceRequest
[09] IRP_MJ_FLUSH_BUFFERS f9d0bd50 +0xf9d0bd50
[0a] IRP_MJ_QUERY_VOLUME_INFORMATION 805025e4 nt!IopInvalidDeviceRequest
[0b] IRP_MJ_SET_VOLUME_INFORMATION 805025e4 nt!IopInvalidDeviceRequest
[0c] IRP_MJ_DIRECTORY_CONTROL 805025e4 nt!IopInvalidDeviceRequest
[0d] IRP_MJ_FILE_SYSTEM_CONTROL 805025e4 nt!IopInvalidDeviceRequest
[0e] IRP_MJ_DEVICE_CONTROL f9d0da44 +0xf9d0da44
[0f] IRP_MJ_INTERNAL_DEVICE_CONTROL f9d0d386 +0xf9d0d386
[10] IRP_MJ_SHUTDOWN 805025e4 nt!IopInvalidDeviceRequest
[11] IRP_MJ_LOCK_CONTROL 805025e4 nt!IopInvalidDeviceRequest
[12] IRP_MJ_CLEANUP f9d0bd0c +0xf9d0bd0c
[13] IRP_MJ_CREATE_MAILSLOT 805025e4 nt!IopInvalidDeviceRequest
[14] IRP_MJ_QUERY_SECURITY 805025e4 nt!IopInvalidDeviceRequest
[15] IRP_MJ_SET_SECURITY 805025e4 nt!IopInvalidDeviceRequest
[16] IRP_MJ_POWER f9d0e196 +0xf9d0e196
[17] IRP_MJ_SYSTEM_CONTROL f9d0d844 +0xf9d0d844
[18] IRP_MJ_DEVICE_CHANGE 805025e4 nt!IopInvalidDeviceRequest
[19] IRP_MJ_QUERY_QUOTA 805025e4 nt!IopInvalidDeviceRequest
[1a] IRP_MJ_SET_QUOTA 805025e4 nt!IopInvalidDeviceRequest
[1b] IRP_MJ_PNP f9d0c798 +0xf9d0c798

kd> !devobj 0x816d5030
Device object (816d5030) is for:
KeyboardClass1 \Driver\Kbdclass DriverObject 816f5930
Current Irp 00000000 RefCount 0 Type 0000000b Flags 00002044
Dacl e129e634 DevExt 816d50e8 DevObjExt 816d51c8
ExtensionFlags (0000000000)
AttachedTo (Lower) 816d41e0 \Driver\TermDD
Device queue is not busy.

kd> !devobj 0x816f53a0
Device object (816f53a0) is for:
KeyboardClass0 \Driver\Kbdclass DriverObject 816f5930
Current Irp 00000000 RefCount 0 Type 0000000b Flags 00002044
Dacl e129e634 DevExt 816f5458 DevObjExt 816f5538
ExtensionFlags (0000000000)
AttachedTo (Lower) 816f5588 \Driver\i8042prt
Device queue is not busy.

Nous avons donc nos renseignements sur la device stack, ces infos sont bien sur aussi visibles grâce au programme DeviceTree. Notre device placé au dessus du KeyboardClass0, va donc recevoir les IRPs avant lui.
C’est ici que tout se joue !

Nous allons mettre en place une « Completion Routine » qui sera appelé au retour de l’IRP, c’est-à-dire quand elle contiendra les informations ( les scancodes des touches ) délivré par le driver, le retour de l’IRP est provoqué par l’appel de la fonction IoCompleteRequest dans le driver KbdClass. Cette Completion routine va permettre de lire les IRPs et donc de récupérer les scancodes des touches.

Cependant les personnes qui ont déjà étudiés le KLOG, savent que la tache de les écrire n’est pas si facile. En effet la fonction permettant l’écriture dans le fichier tourne à un IRQL différent, comprenez que écriture dans un fichier demande au système d’être dans un état non-interrompu. Bref pour nous on s’arrête là afin de coder un petit truc personnalisé.Mais Clandestiny gère ce problème en créant un thread kernel tournant à l’IRQL nécessaire.

Je vous propose quelques schémas, les 2 premiers venus tout droit de mon imagination, et le dernier extrait du pdf fournis dans l’archive du KLOG :










Nous avons donc toutes les clés en main pour coder un petit driver .

Control your keyboard.

Au cours de cette partie, notre but va être non pas de lire, mais de modifier les scancodes des lettres, afin de contrôler les touches.Le driver va renvoyé les scancodes de façon a écrire « overclok » quelque soit les touches tapées.

Pour mener a bien notre projet, nous allons créer un device par le biais de la fonction IoCreateDevice(), puis l’attacher avec IoAttachDevice() sur \Device\KeyboardClass0.
Petite précision pour le IoCreateDevice(), nous allons utilisé un de ces paramètres afin de faire transiter une structure personnalisée. En effet nous devons garder à l’esprit que les IRP doivent être envoyées au driver KbdClass, pour cela il faut connaître l’adresse du device \Device\KeyboardClass0, l’I/O Manager fournit pour chaque device une structure personnalisé appelée DeviceExtension permettant au programmeur d’y ajouter des infos. Dans notre cas nous allons donc juste avoir un champ avec à pointeur sur le device KeyboardClass0.





Nous devons bien évidemment remplir le tableau MajorFunction pour handler des fonctions à appeler selon les IRPs reçus.
Celles intéressantes sont les IRP_MJ_READ.

Notre fonction qui sera appelée lors de la réception d’une telle IRP doit mettre en place la Completion Routine grâce à la fonction IoSetCompletionRoutine() puis nous « relayons » les IRPs au device d’en dessous.

En ce qui concerne notre la Completion Routine c’est en quelque sorte le cœur de notre driver, car en effet c’est ici que la modification ou la lecture des IRPs aura lieu.

Pour ma part j’ai choisis d’aller remplacer les scancodes des touches de manière a former le mot « overclok » lors de l’appuie sur les touches de votre clavier.

Un petit screenshot :





Je vous propose aussi de lire un article rédigé par Ivanlef0u sur sa tentative de modification du KLOG.
Il a modifié quelques petits trucs sur la version qu’il propose, à savoir le support des claviers français et le hidalgo du driver dans la PsLoadedModuleList.

Voici le lien :
- KLOG -> http://www.ivanlef0u.tuxfamily.org/?p=17.

A présent je vous propose mon petit code :
- OwnzYourKeyboard.c.

C’est finit pour aujourd’hui en espérant vous avoir divertis un petit peu, encore merci au personne qui m’ont aidé à la réalisation de cet article etc.

PS : Je tiens aussi à passer un petit coup de pub pour des amis.
Tout d'abord l'ouverture du site perso de shaka ou sevieron, un site internet rassemblant des écrits qui seront rédigés par lui même concernant de multiples domaines liés a l'informatique.
Ensuite l'ouverture de deux blogs de deux autres personnes que j'apprécie beaucoup, il s'agit de KPCR et de santabug.
En espérant que ces blogs et ce site seront tenus à jour par les auteurs, et que les articles apparaitront d'ici peu :).
Bonne chance à vous, voici les liens ajouter à la blogrollz :

- Shaka Web Site -> http://shaka.n0ne.org/.
- Santabug's blog -> http://santabug.blogspot.com/.
- KPCR's blog -> http://kpcr.blogspot.com/.

Cya.

jeudi 21 février 2008

First steps into ring0.

Bonjour à tous,
Je profite de mes petites vacances pour attaquer la programmation de driver.
Cela me trottait dans la tête depuis pas mal de temps enfaite, je vous dévoile alors aujourd'hui mes premier pas dans ce nouveau monde.

Conseils préliminaires :

- Je vous recommande encore une fois, l'utilisation massive de machines virtuels, et de snapshots.
Tout simplement, parce que les Blues Screen Of Death (abrégé BSOD) arrivent très rapidement.

- Ensuite, tout comme dans l'userland (ring3), des outils de debugs sont les bienvenus, je vous conseille donc d'installer les "Debugging Tools for Windows".

- Pour pouvoir mener vos test sur les drivers, je vous recommande "Driver Loader" qui va permettre d'enregistrer votre driver au sein du système.
Vous pouvez ensuite le lancer avec aisance par le biais de la commande "net" :

net start votredriver

Le programme "WinObj" peut aussi vous être utile.

- Et bien sur, le WDK (Windows Driver Kit)!
Cette iso va contenir de la documentation très bien faite, les librairies nécessaires au développement de vos drivers, ..tous ce que vous aurez besoins pour coder vos drivers en tout cas :).
Je cite :

"The Windows Driver Kit (WDK) is a fully integrated driver development system for the Microsoft Windows family of operating systems. It contains the Windows DDK and tests that Microsoft uses to test the stability and reliability of the Windows operating system."
source : http://www.microsoft.com/whdc/devtools/WDK/AboutWDK.mspx.

Voilà tout pour le moment.
Je vous propose à présent, quelques lignes sur la configuration du debuggeur de kernel (kd).


Debug your fucking vm.



Pour pouvoir debugguer vos futurs driver, ou votre kernel, vous avez besoin d'un serveur prêt à être debugguer, ou une machine virtuel.
En ce qui me concerne j'ai choisis la solution machine virtuel, cela est bien plus simple.
Afin de connecter le kd à votre machine virtuel il va falloir tout d'abord ajouter un Port série à votre vm.



On choisit ensuite de faire transiter les données par un named pipe.




On configure la connection de la named pipe avec le port série.




N'oublions pas de cliquer sur le bouton "Advanced" et de cochez "Yield CPU on poll".
Une fois configurer notre port série, on va modifier un petit peu le boot.ini pour que la machine supporte le remote debugging.
Vous ouvrez donc le boot.ini avec notepad++ par exemple, vous copiez collez la ligne dans le [Operating systems] qui existe déjà, vous vous retrouvez avec deux lignes identiques.
Vous rajoutez sur l'une des deux cela :

/debug /debugport=COM1:

Je me retrouve avec un boot.ini qui ressemble à cela :

multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft Windows XP Professionnel" /noexecute=optin /fastdetect /kernel=oemkrnl.exe
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft Windows XP Professionnel" /noexecute=optin /fastdetect /kernel=oemkrnl.exe /debug /debugport=COM1:

A présent, on redemare notre vm..et là au boot, nous avons le choix entre un démarrage classsique, et un démarrage avec le debug activé!



Il est temps de sortir WinDbg.
Vous allez dans le menu "File"->"Kernel Debug" et on va le configurer pour que les données entre la vm et le debug transite par le named pipe.




On valide, et Break (CTR+Break), et vous devriez vous retrouvez avec le prompt du kd.




Je vous conseil aussi de télécharger les symbols : http://msdl.microsoft.com/download/symbols.
Ensuite vous vous creez une variable d'environnement qui porte le nom :

_NT_SYMBOL_PATH

et comme valeur :

SRV*C:\Symbols*http://msdl.microsoft.com/download/symbols

Vous êtes donc prêt à debugguer vos drivers !
Ceci dit je vous donne un peu de documentations :

- Si vous voulez connecter virtualpc a windbg -> http://therecyclebin.wordpress.com/2007/06/11/kernel-debugging-windbg-and-virtual-pc/.
- Windbg -> http://software.rkuster.com/.
- WDK -> http://connect.microsoft.com/.

Introduction

"One Ring to rule them all, One Ring to find them, One Ring to bring them all and in the darkness bind them." The Fellowhip of the Ring, J. R. R. TOLKIEN.


Je vais consacrer ces quelques lignes à présenter un peu le ring0.
Comme vous le savez peut être déjà tous, les processeurs mettent à disposition 4 niveaux de privilèges appelés rings (ring0 , .. , ring3).
Le système windows en utilise que deux d'entre eux à savoir :

- L'userland ou le ring3 (abrégé r3).
- Et le kerneland ou le ring0 (abrégé r0).

Le ring0 va permettre la gestion de la mémoire virtuelle par exemple, ou encore la gestion d'un matériel connecté à votre ordinateur ; c'est enfaite le coeur du système.
Comme la citation le laisse entrevoir, dans le ring0 c'est nous le maître :).
En revanche le ring3 est ce qui est le plus classique, les exécutables classiques, notre bon vieux client irc, ou notre player de musique préférée ; ceci dit cette espace est restreint à des règles.




On retrouve souvent le fonctionnement suivant : une application est exécutée depuis l'userland, celle-ci va envoyer des informations à un driver qui lui va pouvoir agir en conséquence, en lui renvoyant si nécessaire des informations de retours.

If faut savoir aussi que la taille des registres de nos processeurs s'élève à 32bits (architecture x86), nous avons donc accès a 2^32 adresses mémoire, soit 4go : 2 pour l'userland (de 0x00000000 à 0xBFFFFFFF) et 2 pour le kerneland (de 0xC0000000 à 0xFFFFFFFF).

A présent notre but va être de coder des programmes capables de survivre dans ce monde où il n'est question que de BSOD (mais nan :)).
On appellera ces programmes des drivers.

Et pourquoi pas arriver vers un rootkit de base commandé de l'userland ? :).
Place au coding à présent.


Message venu du nouveau monde.


Après cette brève introduction au ring0, nous allons pouvoir aborder la programmation de driver.
Le point d'entré d'un driver est celui-ci :

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegistryPath)
{
}

Avec pDriverObject qui est un pointeur sur une structure du type DRIVER_OBJECT.
Celle-ci représente le driver chargé, et le second argument pRegistryPath est une chaine de caractères UNICODE de la forme suivante :

\Registry\Machine\System\CurrentControlSet\Services\NomDuDriver

Ensuite si vous voulez déchargez un driver, il faut spécifier une fonction d'unload par le biais du membre DriverUnload de la structure DRIVER_OBJECT.

pDriverObject->DriverUnload = VotreFonction;

Et enfin, on utilise l'équivalent de printf() mais au niveau kerneland à savoir : DbgPrint().
Les messages seront bien sur visible grâce à un outil utilisé dans des articles précédents : DebugView.
Ceci nous amène donc à la compilation!

Euh..On compile cela comment?

J'y viens.:)
Tout d'abord j'utiliserais le compilateur disponible avec le wdk, cela évitera de se casser la tête.
Deux fichiers sont nécéssaires à la compilation :

- le makefile.
- et un fichier "sources" (c'est enfaite le nom des fichiers de projets sous le wdk).

Le fichier makefile est composé d'une seule ligne :

!INCLUDE $(NTMAKEENV)\makefile.def

Ensuite le fichier sources est décomposé de la façon suivante :

TARGETNAME = LeNomDuDriver
TARGETPATH = obj
TARGETTYPE = DRIVER

INCLUDES = %BUILD%\inc
LIBS = %BUILD%\lib

SOURCES = VotreSource.c

Nous sommes donc prêt à compiler notre premier driver, émotion au rendez vous !
Nous ouvrons le build environment xp.
On se déplace dans notre dossier contenant les trois fichiers, et on lance la commande build.
Oh..un .sys :), il s'agit de notre driver.

Mais comment le lance t-on?

Patience, nous y voilà.
Dans les premières lignes de ce modeste article, je vous proposais plusieurs outils, dont DriverLoader.
DriverLoader va nous permettre d'enregistrer notre driver, et de pouvoir le lancer.
Nous demarrons DebugView, on lance DriverLoader, et on lance notre driver.



Et voilà, notre helloWorld fonctionne :).
A présent, just for phun, nous allons provoquer un BSOD, histoire d'en réver pendant une semaine.
On va aller écrire n'importe quoi à n'importe qu'elle adresse enfaite :).
Resultat en image :



Enfin bon, a présent passons aux choses sérieuses.


E.T téléphone kernel.


Maintenant notre but va être de faire communiquer une application lancée en ring3 et un driver en ring0.
Nous commencerons par le driver.
Pour mener à bien notre quête, nous allons utiliser les IOCTLs codes et les IRPs.
Mais nous en parlerons un peu plus bas.
Afin de pouvoir communiquer avec l'exterieur, nous avons besoin de creer un "device" une sorte d'interface.

NTSTATUS
IoCreateDevice(
IN PDRIVER_OBJECT DriverObject,
IN ULONG DeviceExtensionSize,
IN PUNICODE_STRING DeviceName OPTIONAL,
IN DEVICE_TYPE DeviceType,
IN ULONG DeviceCharacteristics,
IN BOOLEAN Exclusive,
OUT PDEVICE_OBJECT *DeviceObject
);

N'oublions pas que les chaines mis en jeux sont des chaines unicodes.
Ensuite il est nécéssaire de creer un symlink entre le nom de notre interface, et le nom visible de l'userland.
Ce symlink permettra d'avoir accès à notre device depuis le r3.

NTSTATUS
IoCreateSymbolicLink(
IN PUNICODE_STRING SymbolicLinkName,
IN PUNICODE_STRING DeviceName
);

Après ces étapes, nous allons "handler" des fonctions à déclencher selon la réception des différentes IRP.
Je m'explique, une IRP est enfaite un paquet d'information envoyé à un driver, il existe plusieurs type d'IRP (voir documentation).

A l'intérieur de la structure DRIVER_OBJECT il existe un membre nommé MajorFunction qui est tableau de pointeur.

kd> dt nt!_DRIVER_OBJECT
+0x000 Type : Int2B
+0x002 Size : Int2B
+0x004 DeviceObject : Ptr32 _DEVICE_OBJECT
+0x008 Flags : Uint4B
+0x00c DriverStart : Ptr32 Void
+0x010 DriverSize : Uint4B
+0x014 DriverSection : Ptr32 Void
+0x018 DriverExtension : Ptr32 _DRIVER_EXTENSION
+0x01c DriverName : _UNICODE_STRING
+0x024 HardwareDatabase : Ptr32 _UNICODE_STRING
+0x028 FastIoDispatch : Ptr32 _FAST_IO_DISPATCH
+0x02c DriverInit : Ptr32 long
+0x030 DriverStartIo : Ptr32 void
+0x034 DriverUnload : Ptr32 void
+0x038 MajorFunction : [28] Ptr32 long

Ce tableau nous permet alors d'handler des fonctions qui vont réagir selon les différentes IRPs reçus.

Par exemple, lorsque l'on va ouvrir un handle sur notre device (dans notre application ring3) par le biais de la fonction CreateFile(), le driver va recevoir
une IRP_MJ_CREATE, et quand on va fermer le handle, il va recevoir une IRP_MJ_CLOSE.

C'est ici que les IOCTLs rentrent en jeux.
En effet pour pouvoir déclencher tel ou tel action, nous avons besoin d'une sorte de "code" qui serait recuperé par le driver, et qui agirait en conséquence.
Nous allons donc forger des IOCTLs, par le biais de la macro CTL_CODE().
On va donc creer notre propre "code" qui sera reconnus par le driver.

#define IOCTL_LOL\
CTL_CODE( SIOCTL_TYPE, 0x800, METHOD_BUFFERED, FILE_READ_DATA|FILE_WRITE_DATA)

par exemple.
Il faut savoir qu'il existe plusieurs type de transfert pour nos données, en ce qui nous concerne nous utiliserons la METHOD_BUFFERED.

Bon à présent lors de l'envoi de l'IOCTL par notre appli r3, le driver va alors recevoir une IRP_MJ_DEVICE_CONTROL.
La fonction qui sera "handler" à cette irp va alors s'occuper de récuperer des informations sur le type d'IOCTL reçus.
Pour cela nous utiliserons la fonction suivante :

PIO_STACK_LOCATION
IoGetCurrentIrpStackLocation(
IN PIRP Irp
);

Cette fonction va permettre de récupérer tous ce dont on aura besoin sur l'action demandée.
Ensuite nous allons lire le membre Parameters.DeviceIoControl.IoControlCode de la structure IO_STACK_LOCATION.
Ce membre nous indique le "code" envoyé : celui forgé ; notre IOCTLs.
Il nous reste plus qu'a mettre en place un switch sur ce membre, et agir en conséquence :).
Il est aussi possible de passer des arguments, il suffit de lire le membre AssociatedIrp.SystemBuffer de la structure IRP et d'y écrire dedans.
Ce buffer fait office de buffer d'entré et de sortie, mais ceci est propre à la METHOD_BUFFERED.


Screenshot pour la route :



On peut aussi à ce moment là, utiliser l'outil WinObj pour constater l'existence de notre device avec un symlink.



Ouf, vous pouvez soufler un peu, nous arrivons à la fin.
Comme vous vous en doutez surrement, ces IOCTLs vont donc être massivement employer dans les rootkits par exemple, afin de faire communiquer le driver et l'application userland.

Pas d'exemple concret?:(

Mais si!


How to hide a fucking process with DKOM (Direct Kernel Object Manipulation).


Dans cette partie nous allons nous amusez à cacher un processus au système :).
Je vous explique un peu notre plan :

- Notre application userland, va recuperer le nom du processus que l'on veut cacher.
- L'appli va envoyer une IOCTL au driver, avec un argument : le nom du processus.

- Le driver va donc recuperer le nom du processus. (c'est là que ça devient intéréssant)
- Nous allons récupérer un pointeur sur une structure EPROCESS grâce à la fonction IoGetCurrentProcess().
- Une fois récupérer notre pointeur, nous allons parcourir les structures grâce au membre ActiveProcessLinks qui est enfaite une double liste chainée.
- Nous allons comparer le nom du processus récupéré avec le membre ImageFileName.
- Si il n'y a aucune différence nous nous trouvons dans la structure EPROCESS concernant le processus à cacher.
- A présent il nous reste juste à modifier la structure précédente et suivante afin que les membres Flink et Blink des listes chainées ne pointent plus sur la structure du processus à caché.
On va en quelques sortes "sauter" la structure à caché.

Voilà à présent je vous file 2 structures qui vont être utile dans la compréhension du code :

kd> dt nt!_EPROCESS
+0x000 Pcb : _KPROCESS
+0x06c ProcessLock : _EX_PUSH_LOCK
+0x070 CreateTime : _LARGE_INTEGER
+0x078 ExitTime : _LARGE_INTEGER
+0x080 RundownProtect : _EX_RUNDOWN_REF
+0x084 UniqueProcessId : Ptr32 Void //PID du processus, à l'offset 0x084.
+0x088 ActiveProcessLinks : _LIST_ENTRY //ce qui nous interesse :)) à l'offset 0x088.
+0x090 QuotaUsage : [3] Uint4B
+0x09c QuotaPeak : [3] Uint4B
+0x0a8 CommitCharge : Uint4B
+0x0ac PeakVirtualSize : Uint4B
+0x0b0 VirtualSize : Uint4B
+0x0b4 SessionProcessLinks : _LIST_ENTRY
+0x0bc DebugPort : Ptr32 Void
+0x0c0 ExceptionPort : Ptr32 Void
+0x0c4 ObjectTable : Ptr32 _HANDLE_TABLE
+0x0c8 Token : _EX_FAST_REF
+0x0cc WorkingSetLock : _FAST_MUTEX
+0x0ec WorkingSetPage : Uint4B
+0x0f0 AddressCreationLock : _FAST_MUTEX
+0x110 HyperSpaceLock : Uint4B
+0x114 ForkInProgress : Ptr32 _ETHREAD
+0x118 HardwareTrigger : Uint4B
+0x11c VadRoot : Ptr32 Void
+0x120 VadHint : Ptr32 Void
+0x124 CloneRoot : Ptr32 Void
+0x128 NumberOfPrivatePages : Uint4B
+0x12c NumberOfLockedPages : Uint4B
+0x130 Win32Process : Ptr32 Void
+0x134 Job : Ptr32 _EJOB
+0x138 SectionObject : Ptr32 Void
+0x13c SectionBaseAddress : Ptr32 Void
+0x140 QuotaBlock : Ptr32 _EPROCESS_QUOTA_BLOCK
+0x144 WorkingSetWatch : Ptr32 _PAGEFAULT_HISTORY
+0x148 Win32WindowStation : Ptr32 Void
+0x14c InheritedFromUniqueProcessId : Ptr32 Void
+0x150 LdtInformation : Ptr32 Void
+0x154 VadFreeHint : Ptr32 Void
+0x158 VdmObjects : Ptr32 Void
+0x15c DeviceMap : Ptr32 Void
+0x160 PhysicalVadList : _LIST_ENTRY
+0x168 PageDirectoryPte : _HARDWARE_PTE
+0x168 Filler : Uint8B
+0x170 Session : Ptr32 Void
+0x174 ImageFileName : [16] UChar //Nom du process
+0x184 JobLinks : _LIST_ENTRY
+0x18c LockedPagesList : Ptr32 Void
+0x190 ThreadListHead : _LIST_ENTRY
+0x198 SecurityPort : Ptr32 Void
+0x19c PaeTop : Ptr32 Void
+0x1a0 ActiveThreads : Uint4B
+0x1a4 GrantedAccess : Uint4B
+0x1a8 DefaultHardErrorProcessing : Uint4B
+0x1ac LastThreadExitStatus : Int4B
+0x1b0 Peb : Ptr32 _PEB
+0x1b4 PrefetchTrace : _EX_FAST_REF
+0x1b8 ReadOperationCount : _LARGE_INTEGER
+0x1c0 WriteOperationCount : _LARGE_INTEGER
+0x1c8 OtherOperationCount : _LARGE_INTEGER
+0x1d0 ReadTransferCount : _LARGE_INTEGER
+0x1d8 WriteTransferCount : _LARGE_INTEGER
+0x1e0 OtherTransferCount : _LARGE_INTEGER
+0x1e8 CommitChargeLimit : Uint4B
+0x1ec CommitChargePeak : Uint4B
+0x1f0 AweInfo : Ptr32 Void
+0x1f4 SeAuditProcessCreationInfo : _SE_AUDIT_PROCESS_CREATION_INFO
+0x1f8 Vm : _MMSUPPORT
+0x238 LastFaultCount : Uint4B
+0x23c ModifiedPageCount : Uint4B
+0x240 NumberOfVads : Uint4B
+0x244 JobStatus : Uint4B
+0x248 Flags : Uint4B
+0x248 CreateReported : Pos 0, 1 Bit
+0x248 NoDebugInherit : Pos 1, 1 Bit
+0x248 ProcessExiting : Pos 2, 1 Bit
+0x248 ProcessDelete : Pos 3, 1 Bit
+0x248 Wow64SplitPages : Pos 4, 1 Bit
+0x248 VmDeleted : Pos 5, 1 Bit
+0x248 OutswapEnabled : Pos 6, 1 Bit
+0x248 Outswapped : Pos 7, 1 Bit
+0x248 ForkFailed : Pos 8, 1 Bit
+0x248 HasPhysicalVad : Pos 9, 1 Bit
+0x248 AddressSpaceInitialized : Pos 10, 2 Bits
+0x248 SetTimerResolution : Pos 12, 1 Bit
+0x248 BreakOnTermination : Pos 13, 1 Bit
+0x248 SessionCreationUnderway : Pos 14, 1 Bit
+0x248 WriteWatch : Pos 15, 1 Bit
+0x248 ProcessInSession : Pos 16, 1 Bit
+0x248 OverrideAddressSpace : Pos 17, 1 Bit
+0x248 HasAddressSpace : Pos 18, 1 Bit
+0x248 LaunchPrefetched : Pos 19, 1 Bit
+0x248 InjectInpageErrors : Pos 20, 1 Bit
+0x248 VmTopDown : Pos 21, 1 Bit
+0x248 Unused3 : Pos 22, 1 Bit
+0x248 Unused4 : Pos 23, 1 Bit
+0x248 VdmAllowed : Pos 24, 1 Bit
+0x248 Unused : Pos 25, 5 Bits
+0x248 Unused1 : Pos 30, 1 Bit
+0x248 Unused2 : Pos 31, 1 Bit
+0x24c ExitStatus : Int4B
+0x250 NextPageColor : Uint2B
+0x252 SubSystemMinorVersion : UChar
+0x253 SubSystemMajorVersion : UChar
+0x252 SubSystemVersion : Uint2B
+0x254 PriorityClass : UChar
+0x255 WorkingSetAcquiredUnsafe : UChar
+0x258 Cookie : Uint4B

kd> dt nt!_LIST_ENTRY
+0x000 Flink : Ptr32 _LIST_ENTRY //Pointe sur la struct suivante.
+0x004 Blink : Ptr32 _LIST_ENTRY //Pointe sur la struct precedente.

Je pense que vous êtes apte à comprendre le code fournis :).

Un petit screenshot pour la route :



A présent il nous reste à aborder l'application ring3.
Celle-ci est extremement simple à comprendre/coder.
En effet, on ouvre un handle sur notre device avec CreateFile(), nous envoyons nos IOCTLs grâce à la fonction DeviceIoControl().
Voilà tout!

Et je compile ça comment?

J'ai utilisé le compilateur disponible dans le wdk.
Seul le fichier "sources" diffère, je vous propose le mien :


TARGETNAME=votreAppli
TARGETTYPE=PROGRAM

INCLUDES=

SOURCES=VotreAppli.c

UMTYPE=console
UMBASE=0x04000000

USE_MSVCRT=1


Vous pouvez dorénavant compiler l'application utilisé pour communiquer avec notre driver !

Mais..cette technique n'a pas de "point" faible?

Hum, à mon grand regret après avoir lus un article disponible sur le blog d'un amis (lilxam), celui-ci nous montre comment "bypasser" ce hide de process :).
Enfin bon, je ne m'avous pas vaincus, je reviendrais avec une meilleure technique :))).

Il est venus le temps de filer les codes :

- HelloWorld.c
- BSOD.c

- HideFuckingProcessR3.c
- HideFuckingProcessR0.c

Et voilà c'est finit pour aujourd'hui !
Encore merci aux personnes qui m'auraient filer un coup de main et toussa :).
cya.

PS : Achetez vous "Subverting kernel windows" écrit par le créateur rootkit.com, un superbe livre de chevet :).