2016-03-27
La semaine dernière je me suis acheté (un peu sur un coup de tête, je l'avoue) une nouvelle souris : la SteelSeries Rival 100. Cette souris propose de nombreuses options de personnalisation, telles que la couleur du rétro-éclairage, ou la configuration de la sensibilité du capteur… le seul hic, c'est que ces options ne sont accessibles que via un petit logiciel, le SteelSeries Engine 3, qui est disponible uniquement sous Windows et Mac OS X.
Étant donné que mon PC tourne exclusivement sous Ubuntu et que je n'ai pas la moindre envie de démarrer une machine sous Windows à chaque fois que je souhaite configurer ma souris, je me suis lancé dans le reverse engineering de la souris afin de pouvoir développer un petit utilitaire pour la configurer directement sous Linux.
Pour réaliser le reverse engineering de la souris, je vais avoir besoin :
Je vais me servir de la machine virtuelle afin d'y faire tourner l'utilitaire de configuration, et pendant que je jouerai avec les réglages, je capturerai le trafic sur le bus USB à l'aide de Wireshark afin, je l'espère, de pouvoir déterminer le protocole utilisé entre le SteelSeries Engine 3 et la souris.
La première étape est de recueillir quelques informations sur la souris. La commande lsusb devrait fournir un certain nombre de renseignements utiles :
$ lsusb ... Bus 001 Device 022: ID 1038:1702 SteelSeries ApS
Ici, on apprend :
Ça fait déjà pas mal d'informations, mais on devrait pouvoir en dénicher quelques-unes supplémentaires dans les journaux du noyau Linux :
$ dmesg ... [23803.145407] usb 1-1: new full-speed USB device number 22 using xhci_hcd [23803.382869] usb 1-1: New USB device found, idVendor=1038, idProduct=1702 [23803.382871] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0 [23803.382873] usb 1-1: Product: SteelSeries Rival 100 Gaming Mouse [23803.382874] usb 1-1: Manufacturer: SteelSeries [23803.385604] hid-generic 0003:1038:1702.000D: hiddev0,hidraw6: USB HID v1.11 Device [SteelSeries SteelSeries Rival 100 Gaming Mouse] on usb-0000:00:14.0-1/input0 [23803.387969] input: SteelSeries SteelSeries Rival 100 Gaming Mouse as /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.1/0003:1038:1702.000E/input/input22 [23803.388128] hid-generic 0003:1038:1702.000E: input,hidraw7: USB HID v1.11 Mouse [SteelSeries SteelSeries Rival 100 Gaming Mouse] on usb-0000:00:14.0-1/input1
On retrouve ici la plupart des informations vues précédemment, mais les lignes "hid-generic" nous informent que la souris fournit deux interfaces implémentant la classe HID (Human Interface Device), ce qui est une très bonne nouvelle.
Les interfaces qui implémentent cette classe sont très simples à contrôler, car le noyau Linux nous fournit pour chacune d'entre elles un fichier dans /dev afin de communiquer avec ces interfaces sans avoir à se soucier des détails du protocole.
Ces deux lignes nous renseignent également sur le fait que ces deux interfaces sont liées aux fichiers hidraw6 et hidraw7 (dans /dev), ce que l'on peut facilement vérifier :
$ ls /dev/hidraw* /dev/hidraw0 /dev/hidraw2 /dev/hidraw4 /dev/hidraw6 /dev/hidraw1 /dev/hidraw3 /dev/hidraw5 /dev/hidraw7
Maintenant que nous sommes en possession de toutes les informations utiles pour identifier le périphérique, il est temps de passer à la préparation de la machine virtuelle. Dans mon cas je vais utiliser VirtualBox avec une machine virtuelle sous Windows 8.1 qui traîne sur mon disque.
--------------------------------------------------------------------------------
📝️ Note:
--------------------------------------------------------------------------------
NOTE : Pour ceux qui ne possèdent pas de machine virtuelle sous Window, il est possible de s'en procurer une très facilement. Dans le cadre du projet Modern IE, Microsoft fournit gratuitement des machines virtuelles sous Windows, prêtes à l'emploi.
--------------------------------------------------------------------------------
La préparation de la VM est très simple, il suffit :
Une fois ceci fait, il ne reste plus qu'à vérifier que tout fonctionne :
On peut même tester quelques réglages, normalement tout devrait être fonctionnel.
--------------------------------------------------------------------------------
📝️ Note:
--------------------------------------------------------------------------------
NOTE : c'est à ce moment-là que la seconde souris devient nécessaire. La Rival 100 n'est en effet plus utilisable dès lors qu'elle se retrouve connectée à la machine virtuelle.
--------------------------------------------------------------------------------
Connexion de la souris à la VM Windows
Pour commencer il faut s'assurer que le module usbmon du noyau est bien chargé, c'est lui qui va permettre à Wireshark de récupérer les trames qui passent sur le bus USB. On peut vérifier que le module est chargé avec la commande suivante :
$ lsmod | grep usbmon
Si une ligne similaire à celle-ci apparait, c'est que le module est chargé :
usbmon 28672 0
sinon, il faut le charger en utilisant la commande modprobe (en root) :
# modprobe usbmon
Une fois que le module usbmon est chargé, il ne reste plus qu'à lancer Wireshark (en root) :
# wireshark
--------------------------------------------------------------------------------
📝️ Note:
--------------------------------------------------------------------------------
NOTE : Il n'est pas recommandé de lancer Wireshark en root. Vous vous ferez d'ailleurs enguirlander lors du démarrage de celui-ci s'il détecte qu'il a été lancé en root… Ceci dit, je n'ai pas envie de régler ses permissions correctement pour l'instant, donc je vais le faire quand même.
--------------------------------------------------------------------------------
Maintenant que Wireshark est lancé, on va pouvoir commencer à travailler.
Pour commencer, il faut sélectionner l'interface à espionner. Dans le cas présent il s'agit de "usbmonX", où "X" est le numéro du bus USB sur lequel la souris est connectée. Dans mon cas elle est connectée au bus numéro 1, je vais donc sélectionner l'interface "usbmon1".
Il ne reste plus qu'à lancer la capture en cliquant sur le bouton "Start" (oui celui avec une icône verte en forme d'aileron de requin…).
Wireshark : sélection de l'interface
Une fois la capture lancée, la fenêtre de Wireshark va très vite se remplir de plein de lignes : il s'agit de l'ensemble du trafic circulant sur le bus USB de la machine. Seule une infime partie de tout ce trafic nous intéresse, il va donc falloir filtrer un peu tout ça. Pour ce faire on va entrer le filtre suivant dans le champ "Filter" qui se trouve en haut de la fenêtre :
usb.device_address == XXX
où "XXX" est le numéro qui a été attribué au périphérique (dans mon cas il s'agit du numéro 22).
Il devrait à présent y avoir beaucoup moins de lignes affichées (sauf si vous avez fait bouger la souris depuis le début de la capture, auquel cas vous aurez déjà plein de lignes).
Wireshark : filtré par usb.device\_address
Maintenant que tout est prêt, l'analyse va pouvoir débuter. Pour commencer on va jouer avec un réglage qui devrait être facile à interpréter : la couleur du rétro-éclairage de la souris.
Dans l'interface du SteelSeries Engine 3, sélectionnons une couleur dont le code hexadécimal soit facile à repérer, par exemple "#112233" ou "#AABBCC"… Dans mon cas je choisis "#FF4411" par ce que c'est un orange que j'aime bien (no comment)…
Une fois le réglage validé (en cliquant sur le bouton "Fermer" de la fenêtre), la souris change instantanément de couleur, et deux nouvelles lignes apparaissent dans Wireshask :
--------------------------------------------------------------------------------
📝️ Note:
--------------------------------------------------------------------------------
NOTE : Normalement, dans la colonne Protocol du premier paquet, le protocole indiqué devrait être USBHID. Si ce n'est pas le cas, il faut déconnecter puis reconnecter la souris à la Machine virtuelle. Cela permettra à Wireshark de capturer les trames qui lui indiqueront qu'il a à faire à un périphérique de classe HID.
--------------------------------------------------------------------------------
À priori celle qui devrait nous intéresser est la première, et en fouillant un peu dans les données de la trame, on finit par tomber sur la ligne suivante :
Data Fragment: 0500FF44110000000000000000000000...
On y retrouve très clairement la couleur que nous avions sélectionnée précédemment. Pour s'assurer qu'il ne s'agit pas là d'une coïncidence, il est possible de réessayer avec une autre couleur, par exemple "#00FFFF".
Cette fois encore, la souris change de couleur (elle vire au bleu) et deux nouvelles trames apparaissent dans Wireshark. Dans la première d'entre elles, on retrouve une fois de plus notre couleur :
Data Fragment: 050000FFFF0000000000000000000000...
À ce stade, on peut conclure qu'il existe une commande 0x0500 qui prend en paramètre les trois canaux (rouge, vert et bleu) de la couleur souhaitée.
À présent essayons de changer la couleur à la main. Vous vous souvenez des fichiers que nous avions trouvés dans /dev au tout début de nos investigations ? Et bah c'est maintenant qu'ils vont nous être utiles.
echo -en "\x05\x00\xFF\x00\x00" > /dev/hidraw6"
--------------------------------------------------------------------------------
📝️ Note:
--------------------------------------------------------------------------------
NOTE : Il est possible que dans certains cas il faille répéter la commande précédente deux fois pour que cela fonctionne car pour une raison que j'ignore, les octets peuvent ne pas être directement écrits dans le fichier (ils restent dans le buffer d'écriture en attendant d'être effectivement écrits).
--------------------------------------------------------------------------------
Et là, la souris devrait s'allumer en rouge. Si ce n'est pas le cas, essayez d'écrire dans un autre fichier (voire dans /dev/hidraw0 dans certains cas…).
Il ne reste plus qu'à répéter les opérations pour chacun des réglages présents dans l'utilitaire de configuration de SteelSeries pour trouver toutes les commandes existantes.
Reverse engineering de la souris SteelSeries Rival 100
Ci-dessous, un tableau récapitulatif des commandes que j'ai été en mesure de découvrir :
+--------------------+----------+----------------------+--------------------------------+ | Nom | Commande | Paramètres | Descriptions | +====================+==========+======================+================================+ | set\_sensitiviry | ``0x03`` | ``<preset> <value>`` | Définit la sensibilité du | | | | | capteur | +--------------------+----------+----------------------+--------------------------------+ | set\_polling\_rate | ``0x04`` | ``0x00 <rate>`` | Définit la fréquence | | | | | d'interrogation | +--------------------+----------+----------------------+--------------------------------+ | set\_color | ``0x05`` | ``0x00 <red> <green> | Change la couleur de la souris | | | | <blue>`` | | +--------------------+----------+----------------------+--------------------------------+ | set\_light\_effect | ``0x07`` | ``0x00 <effect>`` | Définit les effets lumineux | | | | | (pulsation…) | +--------------------+----------+----------------------+--------------------------------+ | save | ``0x09`` | \- | Sauvegarde les paramètres dans | | | | | la souris | +--------------------+----------+----------------------+--------------------------------+ | set\_btn6\_action | ``0x0B`` | ``<action>`` | Définit l'action du bouton | | | | | sous la molette | +--------------------+----------+----------------------+--------------------------------+ | ??? | ``0x16`` | ??? | Envoyée à la connexion de la | | | | | souris, action indéterminée |
La souris est capable de contenir deux pré-réglages de sensibilité que l'on peut alterner via le bouton situé sous la molette de la souris.
0x03 <preset> <value>
Paramètres :
Définit la fréquence à laquelle la position de la souris sera lue par l'ordinateur. Plus cette valeur est élevée, plus la précision sera grande. Cependant, une valeur élevée signifie également plus de trafic sur le bus USB et une plus grande utilisation du CPU.
0x04 0x00 <rate>
Paramètres :
Définit la couleur du rétro-éclairage de la souris.
0x05 0x00 <red> <green> <blue>
Paramètres :
Configure un effet de lumière.
0x07 0x00 <effect>
Paramètres :
Sauvegarde les réglages actuels dans la mémoire interne de la souris. Si cette commande n'est pas appelée après avoir modifié les paramètres de la souris, celle-ci retournera à sa précédente configuration la prochaine fois qu'elle sera reconnectée à la machine.
0x09
Définit l'action que le bouton numéro 6 (numéroté comme tel dans SteelSeries Engine 3) doit effectuer.
0x0B <action>
Paramètres :
Au final, le reverse engineering de cette souris s'est avéré beaucoup plus simple que je ne l'aurais pensé. Et maintenant que je suis en possession de toutes les informations nécessaires, je devrais être en mesure de développer assez rapidement un petit utilitaire en ligne de commande pour configurer ma souris (je le placerais sur Github lorsque je l'aurai terminé).
--------------------------------------------------------------------------------
📝️ Note:
--------------------------------------------------------------------------------
EDIT 16/04/2016 : J'ai écrit le petit utilitaire en python, et comme promis il est disponible sur Github : github.com/flozz/rivalcfg. Si vous souhaitez étudier le code du logiciel, je vous recommande de jeter un coup d'œil à la version 1.0.1 qui est la plus simple à comprendre.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------