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.

1 commentaire:

Sans a dit…

Bonjour,

A préciser quand même qu'il faut être équipé d'un clavier ps/2 et non usb.

Salutation