Appareils à interface humaine : HID sur I2C

Dans les deux articles HID précédents, nous avons parlé du vol de descripteurs HID, découvert un certain nombre d'outils intéressants que vous pouvez utiliser pour le piratage HID sous Linux et créé un périphérique à écran tactile. Cette fois, parlons d'une norme HID sous-estimée, mais que vous utilisez peut-être en ce moment même en lisant cet article : I2C-HID, ou HID sur I2C.

HID en tant que protocole peut être tunnelisé sur de nombreux canaux différents. Si vous avez utilisé un clavier Bluetooth, par exemple, vous avez utilisé un HID tunnelisé. Depuis une dizaine d'années maintenant, I2C-HID est très présent dans l'espace des ordinateurs portables, il a d'abord été utilisé dans les pavés tactiles, plus tard dans les écrans tactiles, et maintenant aussi dans les hubs de capteurs. Oui, vous pouvez exposer les données du capteur via HID, et si vous disposez d'un ordinateur portable à clapet (pliable), c'est ainsi que l'accéléromètre déterminant la rotation expose ses données à votre système d'exploitation.

Ce contrôleur à écran tactile capacitif n'est pas I2C-HID, même s'il est I2C. Par [Raymond Spekking]CC-BY-SA 4.0

Tous les périphériques d'entrée connectés en I2C ne sont pas I2C-HID. Par exemple, si vous avez vu des tablettes plus anciennes avec des écrans tactiles connectés en I2C, n'espérez pas, car elles n'utilisent probablement pas HID – il s'agit simplement d'un appareil I2C complexe, avec suffisamment de registres et de commandes propriétaires à piloter. vous êtes fou même si vos compétences en analyse logique sont au top. I2C-HID est loin de cela, et il est également bien meilleur que le PS/2 que nous utilisions auparavant – une interface uniquement x86 avec des capacités limitées, déjà presque éteinte même sur les cartes x86, et encore plus menacée dans ce monde de plus en plus RISCy. I2C-HID est à faible consommation, en particulier par rapport à l'USB, aussi performant que HID, compatible avec les logiciels HID existants et suffisamment omniprésent pour que vous ayez sûrement déjà un port I2C disponible sur votre SBC.

Dans le monde moderne des périphériques d'entrée, I2C-HID se répand, et le plus cool, c'est qu'il est standardisé. La standardisation signifie beaucoup de bonnes choses pour nous, les hackers. D’une part, contrairement à tous ces contrôleurs à écran tactile I2C, les appareils HID-I2C sont plus faciles à réutiliser ; Même si les informations à leur sujet font peut-être défaut à l'heure actuelle, c'est contre cela que nous combattons en ce moment même ! Si vous utilisez un ordinateur portable récent, le pavé tactile est très probablement I2C-HID. Aujourd'hui, examinons la conversion de l'un de ces pavés tactiles en USB HID.

Une plateforme piratable

Il y a deux ans, j'ai développé une carte contrôleur de couverture d'entrée pour ordinateur portable Framework. À l’époque, je connaissais certaines choses sur I2C-HID, mais pas trop, et cela m’intimidait un peu. Pourtant, j'ai connecté les broches I2C à un port I2C sur un RP2040, j'ai connecté la broche INT à un GPIO, j'ai réussi à détecter un périphérique I2C sur ces broches I2C avec une seule ligne de code MicroPython et je suis resté assis sur mon bureau hors de J'ai peur de convertir les données du pavé tactile en événements de souris – il s'avère que c'était beaucoup plus simple que je ne le pensais.

Il existe une spécification de Microsoft, et cela pourrait être votre premier point de départ. J'ai essayé de lire la spécification, mais je ne comprenais pas non plus HID à l'époque, donc cela n'a pas beaucoup aidé. Avec le recul, la spécification est malgré tout assez difficile à lire. Voici l'affaire dans le monde réel.

Si vous souhaitez obtenir le descripteur HID d'un appareil I2C-HID, il vous suffit de lire un bloc de données à partir de ses registres. La réception de rapports (paquets d'événements HID) est également simple. Lorsque la broche INT devient faible, lisez un bloc de données de l'appareil – vous recevrez un rapport HID. S'il existe une broche RST, vous souhaiterez la désactiver au démarrage pendant quelques centaines de millisecondes pour réinitialiser l'appareil, et vous pourrez également l'utiliser en cas de dysfonctionnement de votre appareil I2C-HID.

Maintenant, il y a des dysfonctionnements, et il y aura certainement des bizarreries. Le HID étant omniprésent, les fabricants disposent d’une multitude de moyens pour en abuser. Par exemple, les pavés tactiles sont si omniprésents que Chrome OS comporte des couches entières traitant de leurs bizarreries. Mais nous y sommes, et j'ai un appareil I2C connecté à un RP2040, un précédent travail MicroPython I2C en main, quelques captures LA entre le pavé tactile et le système d'origine cachées, et je suis prêt à lui envoyer toutes les commandes dont il a besoin.

Piquer et sonder

Pour lire le descripteur, vous pouvez lire un bloc du registre 0x20, où les quatre premiers octets définissent la version du descripteur et la longueur du descripteur – en comptant ces quatre octets. Lorsque nous mettrons ce descripteur dans le décodeur, nous obtiendrons quelque chose comme ceci :

[...]
0x05, 0x0D, // Usage Page (Digitizer)
0x09, 0x05, // Usage (Touch Pad)
0xA1, 0x01, // Collection (Application)
0x85, 0x01, // Report ID (1)
0x05, 0x0D, // Usage Page (Digitizer)
0x09, 0x22, // Usage (Finger)
0xA1, 0x02, // Collection (Logical)
0x09, 0x47, // Usage (Confidence)
0x09, 0x42, // Usage (Tip Switch)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
[...]

C'est un descripteur HID pour un pavé tactile, d'accord ! Enregistrez ce descripteur quelque part – bien qu’il soit tentant de l’obtenir de manière dynamique, le coder en dur dans votre micrologiciel pourrait également être une décision viable, en fonction du type de micrologiciel dans lequel vous ajouterez la prise en charge I2C-HID, et vous voudrez vraiment avoir c'est pratique comme référence. Mettez ce descripteur sur notre site Web de décodeur préféré, et c'est parti ! Oh, et si vous ne pouvez pas extraire le descripteur du pavé tactile pour une raison quelconque, vous pouvez l'obtenir depuis un système d'exploitation en cours d'exécution, comme je l'ai fait dans le dernier article – c'est ce que j'ai fini par faire, parce que je ne pouvais pas le faire. MicroPython récupère correctement le descripteur.

Pour une raison quelconque, Microsoft a décidé de distribuer cette spécification sous forme de fichier .docx, ce dont j'ai immédiatement abusé pour réduire le stress.

Jetez un œil aux identifiants des rapports – ils peuvent être utiles plus tard. Tous les rapports provenant du pavé tactile auront leur identifiant de rapport joint, et il est bon de savoir à quels types d'événements vous pouvez réellement vous attendre. Voici également un défi : essayez de repérer les rapports utilisés pour la fonctionnalité « souris simple » du BIOS, la mise à jour du micrologiciel, l'étalonnage du pavé tactile et toute fonctionnalité propriétaire !

Il ne reste plus qu'à obtenir les rapports. C'est aussi simple : vous n'avez même pas besoin de lire un bloc à partir d'un registre, juste un bloc de données à partir du pavé tactile. Tout d’abord, vous lisez un seul octet, ce qui vous indique combien d’octets supplémentaires vous devez lire pour obtenir le paquet réel. Ensuite, vous lisez un octet une fois que INT est affirmé (défini sur un niveau bas). Cela signifie que le pavé tactile contient des données pour vous. Si votre INT ne fonctionne pas pour une raison quelconque, comme c'était le cas sur ma carte, vous pouvez plutôt interroger continuellement le pavé tactile en boucle, en lisant un seul octet à chaque fois et en lisant un paquet complet lorsque le premier octet n'est pas le cas. 0x00. Ensuite, c'est la situation habituelle : le premier octet est l'ID du rapport et tous les autres octets sont le contenu réel du rapport. Pour le code I2C du type utilisé par notre dernier article, la lecture d'un rapport fonctionne comme ceci :

while True:
    try:
    l = i2c.readfrom(0x2c, 1)[0]
    if l:
        d = i2c.readfrom(0x2c, l)
        if d[2] != 0x01:
            # only forward packets with a specific report ID, discard all others
            print("WARNING")
            print(l, d)
            print("WARNING")
        else:
            d = d[3:]
            print(l, len(d), d)
            usb_hid.report(usb_hid.MOUSE_ABS, d)
    except OSError:
    # touchpad unplugged? retry in a bit
    sleep(0.01)

Maintenant, touchez le pavé tactile et voyez. Vous avez un rapport ? Merveilleux! Vous n'avez encore rien reçu ? Il y a quelques choses à vérifier. Tout d'abord, votre pavé tactile peut nécessiter qu'une broche TP_EN soit affirmée basse ou haute. De plus, si votre pavé tactile possède une broche TP_RST, vous devrez peut-être la baisser au démarrage pendant quelques centaines de millisecondes. En dehors de cela, si votre pavé tactile provient d'un ordinateur portable assez populaire, vérifiez s'il existe des références à ses bizarreries dans le noyau Linux ou dans l'un des firmwares ouverts disponibles.

Intégration plus poussée

Théoriquement, vous pourriez écrire très facilement un convertisseur I2C-HID vers USB-HID assez universel – ce qui permettrait des choses comme des pavés tactiles connectés par USB à bon marché, tout comme certaines personnes l'ont fait avec PS/2 au bon vieux temps. Pour moi, il y a une question intéressante : comment intégrer cela dans le firmware d'un clavier ? Il existe quelques options. Par exemple, vous pouvez écrire un module QMK pour gérer tout type de périphérique I2C-HID, qui transmettrait les rapports du pavé tactile et générerait ses propres rapports pour les rapports du clavier. C'est une option viable pour la plupart d'entre vous ; pour moi, le C++ n'est pas mon ami autant que je le souhaiterais.

Il existe l'option MicroPython que nous avons explorée dans l'article précédent, et c'est ce que j'utilise actuellement pour le transfert. Cette option nécessite la traduction du descripteur en macros TUSB, ce qui a pris un peu de temps, mais j'ai pu le faire fonctionner. Bientôt, la prise en charge des périphériques USB sera ajoutée à la nouvelle version de MicroPython, ce qui rendra mon travail de traduction obsolète de toutes les meilleures manières, mais il n'est pas encore fusionné. Plus important encore, cependant, je n'ai pas pu trouver de code de clavier d'origine compatible avec ce firmware, et même si cela pourrait être éducatif, je ne cherche pas à écrire mon propre code de numérisation de clavier.

Actuellement, j'étudie une troisième option, KMK. Un micrologiciel de clavier basé sur CircuitPython, il devrait permettre des choses telles que des définitions de descripteurs dynamiques, ce qui nous permet de gagner pas mal de temps lors des itérations sur le piratage de descripteurs, en particulier par rapport au fork de MicroPython.

Toutes ces options nécessitent que vous fusionniez les descripteurs du clavier et du pavé tactile en un seul, ce qui est logique. La seule mise en garde concerne la question des ID de rapport contradictoires entre le descripteur de clavier du micrologiciel d'origine et le descripteur du pavé tactile d'origine. Pour résoudre ce problème, vous voudriez réécrire les ID de rapport à la volée – non pas que ce soit compliqué, juste une substitution d'un seul octet, mais c'est une bonne mise en garde à garder à l'esprit ! Le code de mon pavé tactile le fait déjà car la bibliothèque effectue une insertion automatique des identifiants de rapport, mais si ce n'est pas le cas, assurez-vous qu'ils sont modifiés.

Une réutilisation encore plus facile

Maintenant, tout cela concernait le tunneling des événements HID obtenus par I2C-HID vers USB. Utilisez-vous quelque chose comme un Raspberry Pi ? Bonnes nouvelles! Il existe un support i2c-hid dans le noyau Linux, qui ne veut vraiment que l'IRQ GPIO et l'adresse I2C de votre périphérique I2C. Fondamentalement, tout ce que vous avez à faire est d’ajouter un fragment d’arborescence des périphériques et quelques données très minimes. Je n'ai pas de tutoriel pour cela, mais il y a une documentation initiale dans l'arborescence du noyau, et récupérer le répertoire de l'arborescence des périphériques pour le nom de la superposition seul devrait vous donner un bon départ.

Cet article n'est pas long, et cela est dû à la facilité d'utilisation d'I2C-HID. Bien sûr, il y a des bizarreries – il suffit de consulter ce fichier pour quelques exemples. Pourtant, il n’y a rien que vous ne puissiez comprendre avec un analyseur logique, et vous pouvez maintenant voir à quel point c’est facile. J'espère que cela pourra vous aider dans vos incursions en matière de piratage informatique. Ainsi, chaque fois que vous verrez un pavé tactile d'ordinateur portable, vous saurez à quel point il peut être facile de le câbler, que vous utilisiez un microcontrôleur ou un Raspberry Pi.

François Zipponi
Je suis François Zipponi, éditorialiste pour le site 10-raisons.fr. J'ai commencé ma carrière de journaliste en 2004, et j'ai travaillé pour plusieurs médias français, dont le Monde et Libération. En 2016, j'ai rejoint 10-raisons.fr, un site innovant proposant des articles sous la forme « 10 raisons de... ». En tant qu'éditorialiste, je me suis engagé à fournir un contenu original et pertinent, abordant des sujets variés tels que la politique, l'économie, les sciences, l'histoire, etc. Je m'efforce de toujours traiter les sujets de façon objective et impartiale. Mes articles sont régulièrement partagés sur les réseaux sociaux et j'interviens dans des conférences et des tables rondes autour des thèmes abordés sur 10-raisons.fr.