Archive for août 14th, 2009

Debugging with LEDs

Dans la série ‘j’touche le fond et je creuse encore ! ‘ je vous propose une méthode sympa pour debugger vos codes critiques. Récemment j’ai été amené à dev du code noyau tournant dans un contexte critique par rapport à l’OS. Comprendre par là que je tournait à des IRQL >= DIRQL, comme si j’étais dans une Interrupt Service Routine (ISR) déclénché par une interruption extérieur. Dans ces cas lorsqu’on veut débugger ces routines on ne peut pas forcément utiliser des fonctions comme DbgPrint ou KdPrint, même si la doc dit que c’est possible on perd beaucoup en performances et si comme moi vous debuggez votre machine depuis la liaison série l’OS se retrouve vite à genoux.

Alors après on peut très bien me dire de mettre des message de debug en queue et de les envoyer dans un worker thread qui balancera des DbgPrint à un IRQL de PASSIVE_LEVEL, ce n’est pas difficile à implémenter c’est juste que je n’avais pas envie de faire. de la même manière, mettre des breakpoints dans le code ou bien à l’aide du kernel-debugger n’est pas forcément très pratique non plus vu que l’OS notifiera à chaque fois le debugger dès qu’il en verra un.

De plus j’avais juste besoin de savoir si un codepath particulier était prit donc un simple signal me disant « oui ou non » me suffisait. Je me suis dit entre 2 trolls sur IRC concernant l’OS des barbus (qui ne marche pas très bien apparemment) qu’utiliser les LEDs du clavier comme signal pourrait être une solution, certes bizarre, mais efficace.

L’idée est simple, il s’agit juste de demander au code de faire clignoter une LED à un moment précis. Dans un premier temps je me suis donc documenté rapidement sur le contrôleur clavier i8042 pour savoir que 2 I/Os port sont utilisés :

  • Le Read-input buffer sur 1 byte. Port 0×60
  • Le Write-ouput buffer, 1 byte. Port 0×60
  • Le Status-register, 1 byte uniquement accessible en lecture. Port 0×64
  • Le Control-register, 1 byte en lecture/écriture.

Pour le controleur i8042 le Read-input et Write-ouput sont en fait confondus. Le Control-register quand à lui est uniquement accessible en envoyant une commande sur le Status-register qui sert alors de byte de commande lorsqu’on l’écrit. Attention il s’agit alors d’une commande pour le contrôleur clavier et non le clavier lui même !

Justement, la commande qui m’intéresse est celle qui permet de définir les LEDS clavier. Après quelques recherches sur le net je tombe sur The PS/2 Keyboard Interface et The AT Keyboard Controler. La commande qui m’intéresse est donc ’0xED (Set/Reset LEDs)’, comme il s’agit du clavier nous devons écrire cette commande dans le Write-ouput buffer

  • Si 1, SROLL_LOCK est allumée. Éteinte sinon.
  • Si 1, NUM_LOCK est allumée. Éteinte sinon.
  • Si 1, CAPS_LOCK est allumée. Éteinte sinon.
  • Maintenant il ne reste plus qu’a envoyer la commande puis les données. Ce qui se traduit en asm par :

    #define KBD_DATA        0x60    // I/O port for keyboard data
    #define KBD_STATUS      0x64    // I/O port for keyboard status (read)
    
    #define KBD_CMD_SET_LEDS        0xED    // Set keyboard leds
    
    #define SCROLL_LOCK 1
    #define NUM_LOCK 2
    #define CAPS_LOCK 4
    
    xor eax, eax
    mov al, KBD_CMD_SET_LEDS
    out KBD_DATA , al
    mov al, Leds
    out KBD_DATA, al
    

    Oulà, pas trop vite, on oublie que pour écrire dans le Write-ouput buffer il faut d’abord attendre que le controleur nous dise que nous pouvons le faire. Pour cela il faut que le bit 1 du Status-register soit à 0, de plus pour une lecture il faut que le bit 0 soit à 1. On doit donc poller le Status-register afin de savoir quand on peut lire ou écrire le port 0×60. La routine est donc simplement :

    kbd_wait:
    in al, KBD_STATUS
    test al, 2
    jne kbd_wait
    ret
    

    Pour tester au lieu de me faire chier directement avec un driver, j’ai demandé à ce que l’IOPL de mon process soit modifié, pour Windows il faut que le token du process possède le privilège SeTcbPrivilege. Celui-ci peut être attribuer en allant dans Panneau de configuration -> Outils d’administration -> Stratégie de sécurité locale -> Stratégies locales -> Attribution des droits utilisateurs et en ajoutant votre utilisateur dans la stratégie « Agir en tant que partie du système d’exploitation » (après avoir ajouter votre user il faut vous que relanciez votre session).

    Je vous laisse les sources maintenant à vous de vous amuser avec, en tout cas cela m’a bien servit dans mon driver pour tracer mon code.

    Vous trouverez les sources ici :

    http://ivanlef0u.fr/repo/kbd-leds.rar

    Sinon quelques liens à lire :

    Updates: Autoruns v9.53, ProcDump v1.3, Process Monitor v2.6 | New Mark’s Blog post: The Case of the Temporary Registry Profiles | Download Windows Internals 5 sample chapter

    VMWare Cloudburst

    VMware ring3 detection (RF handling)

    Preventing the exploitation of user mode heap corruption vulnerabilities

    11 comments août 14th, 2009


    Calendar

    août 2009
    L Ma Me J V S D
    « juin   sept »
     12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31  

    Posts by Month

    Posts by Category