URL: https://linuxfr.org/users/sebastienb/journaux/retro-ingenierie-epson Title: Rétro ingénierie Epson Authors: Sébastien B. Date: 2012年07月12日T22:14:35+02:00 License: CC By-SA Tags: epson, vidéoprojecteur, rétro-ingénierie et firefox Score: 121 Bonjour à tous ! Cette année je me suis amusé à faire de la rétro ingénierie, comme je ne savais pas comment on faisait ,je me suis dit que ça serait une occasion de découvrir. Du coup, j'ai noté pas mal de trucs et je fais partager mes notes. J'espère que ça pourra intéresser des gens. Le sujet d'étude : un vidéo projecteur EPSON, il utilise un protocole réseau spécial pour déporter l'affichage (comme ça pas besoin de câble VGA). Le protocole de déport d'affichage en lui même, c'est du RFB, mais tout le protocole de découverte et de connexion est propre à EPSON. Voilà, bonne lecture pour ceux qui sont intéressés. (note, je n'ai fait aucune modifications sur ce que j'ai écrit il y a pas mal de temps, pour garder un peu l'esprit du truc, mais maintenant, le début me paraît un peu stupide maintenant, mais j'en savais moins que maintenant sur le protocole). C'est pas très structuré du coup, désolé. # Reverse Engineering Bon, demain je commence le travail sur un projecteur Epson afin d'essayer d'analyser le protocole utilisé et ainsi, pouvoir créer un logiciel permettant de s'y connecter. # Jour 0 Bon, on commence ! Installation d'une machine virtuelle Windows XP. Elle accueillera le Epson NSC qui permet de se connecter au vidéo projecteur. Après cela, installation des VirtualBox tools, de Firefox et surtout de Wireshark, qui risque de grandement m'aider pour analyser les paquets qui passent. Préparons un peu le terrain. Je lance le logiciel Epson et sélectionne configuration avancée. Là, il me dit qu'il recherche d'éventuels vidéoprojecteurs sur le réseau. Pas de bol pour lui, il n'y en a pas. Par contre, on peut voir grâce à Wireshark qu'il a bien essayé de contacter un vidéoprojecteur. Le résultat : 21 segments UDP vers 255.255.255.255 sur le port 3620 (après vérification, l'IANA confirme qu'il s'agit du port utilisé par EPSON pour leurs vidéoprojecteur). Le port source change à chaque fois en s'incrémentant. Tous les segments contiennent le même contenu : la chaîne EEMP0100 suivie de l'adresse IP du client et enfin un SOH (0x01) suivi d'une suite de caractères nuls (surement des caractères de bourrage). Lorsqu'on lance une recherche manuelle sur un vidéoprojecteur, avec l'IP de ma machine, des segments UDP sont envoyés alternativement en broadcast et en unicast (vers l'IP que j'ai donnée). Les segments envoyés en unicast diffèrent des segments envoyés en broadcast puisque le dernier caractère avant la suite de caractères nuls est un STX (0x02). Ce mot permet certainement au vidéoprojecteur de savoir si le segment reçu lui est destiné ou si il a été envoyé en broadcast. En plus des segments UDP, des requêtes de connexion TCP sont envoyées (SYN) sur l'IP de ma machine, port 3620. En gros, un vidéoprojecteur, ça écoute en TCP et en UDP sur le port 3620. Par contre, en utilisant NETSTAT, je remarque que le logiciel de connexion semble n'écouter aucun port ... Soit je ne sais pas me servir de netstat sous Windows, soit il y a quelque chose qui m'échappe : comment un vidéoprojecteur peut il répondre pour signaler sa présence ? Ah, tiens, en y regardant d'un peu plus près, le logiciel de connexion écoute le port 3620 en UDP lorsque l'on effectue une recherche de vidéoprojecteur. C'est par ce biais qu'un vidéoprojecteur peut signaler sa présence. L'écoute s'arrête en même temps que la recherche, c'est pour cela que je n'ai pas vu ce comportement plus tôt. Petit mémo : netstat sous windows : -a pour connaître les écoutes, -b pour savoir à quel binaire elles sont associées et -n pour avoir les ports en nombre (donc sans avoir le nom du service associé) (netstat -n -b -a). Maintenant, on va essayer de le rendre un peu plus bavard ce logiciel : créons un petit script Python qui va accepter les connexions TCP. Voilà, la connexion TCP s'effectue sans encombre, ensuite, c'est le client qui commence à parler, il envoie les mêmes données que tout à l'heure, sauf que cette fois ci c'est dans une connexion TCP. Je suppose que l'UDP ne sert donc qu'à effectuer des broadcasts et qu'on peut l'ignorer pour se concentrer sur cette connexion TCP. Bon, voilà, je ne vois pas ce que je pourrais faire de plus en n'analysant que le trafic réseau (en touchant un peu au binaire, je pourrais essayer de déclencher certaines fonctions et voir à ce à quoi je pourrais m'attendre (ex : quel message est envoyé lorsque je clique sur se connecter (bouton grisé lorsqu'il n'y a pas de vidéo projecteur), je n'ai pas les compétences pour ça et je préfère me cantonner aux analyses réseaux). Allez, une dernière chose : à tout hasard, j'essaie de renvoyer le segment de découverte envoyé par le client ... Bon, ok, il coupe la connexion (et ce même si je modifie l'IP), ça rigole pas. Ah, enfin, détail important : c'est du little endian. Allez, je vais m'arrêter là en commençant à écrire le client en insérant la gestion du segment de découverte. Petite note pour Epson afin de finir : dans votre protocole, vous envoyez l'adresse IP du client au serveur... Vous avez déjà entendu parler du modèle OSI ? ;-) Heureusement que j'ai trouvé cette information par hasard tout à l'heure sur le forum d'Ubuntu-fr, sinon je serais encore à plancher dessus ! [...] Youpee, j'ai enfin accès à un vidéo projecteur ! Bon, ne traînons pas, voyons immédiatement ce qu'il répond à notre cher programme. Ok, alors déja ça commence pareil, mais avec un 3. Ça doit être le code de réponse. Ah, et aussi, après, il y a beaucoup plus de données. Déja, il y a 3 caractères nuls, suivis d'un nombre : c'est certainement un entier codé sur 32bits : 74, c'est peut être un numéro de version du protocole, je ne sais pas. Plus loin, on voit une chaîne correspondant au nom du vidéoprojecteur. Tiens, du coup, le 74, c'est peut être simplement une longueur ! Après le 74, il y a 77 octets dans le message ... Maintenant, je vais faire une hypothèse. le "type" du message (ici à 3) trouble l'alignement des bits. On y ajoute donc 3 octets vides de bourrage. Après quoi on met la taille du segment (74) puis encore 3 octets de bourrage, et là, après ces 3 octets, on retrouve bien une taille de 74 octets ! Attention, il ne s'agit bien sûr que d'une hypothèse. Mais ça parait crédible. De plus, lorsque le client envoie un message au vidéoprojecteur, il envoie le code, suivi de 3 \x00 (bits de bourrage pour être aligné sur 32bits) puis une suite de 4 \x00. Donc une longueur de message de 0, ce qui est vrai puisqu'après cet entête, il n'y a plus rien. En fait, je crois que j'ai découvert non pas un type de segment, mais je pense que j'ai plutôt percé le secret de l'entête des segments. Le plus dur maintenant : savoir à quoi correspondent les codes. Bon, j'espère que je ne me trompe pas. Du coup, le code et la taille sont codés sur 32bits (mais c'est du little endian). Bon, maintenant, réfléchissons un peu. Qu'est ce que le vidéo projecteur pourrait envoyer au client ? Bon, déjà, l'état : en veille, actif, locké... Ensuite, son nom, mais on l'a déjà vu. Après, dans pleins de protocoles, on envoie la version du protocole pour que les entités se mettent d'accord entre elles. Mais je serais bien tenté, après réflexion, de dire qu'ici, cette vérification n'est pas faite. En effet, lorsque l'on utilise une trop vieille version du logiciel, on apprend que la version est trop vieille seulement à la connexion. Bon, il y a une suite de nombres pas très clair, ils n'ont aucune signification pour moi ... On verra plus tard ! Là, on va essayer de se connecter pour voir le changement d'état sur un autre ordinateur : on verra ainsi qu'est ce qui change. Bon, mon autre VM ne fonctionne pas, tant pis, on reviendra là-dessus plus tard. Essayons de voir un peu ce qu'il passe lors de la connexion au vidéoprojecteur. Le client envoie un segment UDP au vidéo projecteur : le code c'est 4. Plein de nombres dans ce message de 74 octets, je ne reconnais rien, il y a une suite de nombre (ascii), mais je ne vois pas ce que cela peut représenter (ni même si ça a bel et bien un sens). Par contre, je vois une adresse IP un peu après. Pas la mienne, ni celle du vidéo projecteur. Par contre, c'est l'IP du routeur de ma route par défaut. Je me demande bien pourquoi le vidéo projecteur a besoin de ça ... et de toute façon, il la connaît déjà puisqu'il obtient son IP via le DHCP. Peut être que c'est une manière de vérifier que l'on soit bien sur le même réseau ? Bon, bah du coup, il m'a suffit de relire le segment pour voir que juste avant la passerelle par défaut, j'envoie le netmask du réseau ! Merci au réseau de l'école, sans le netmask un peu bizarre (255.255.252.0), je crois que j'aurais vraiment eu du mal à le trouver, même si il était facile à deviner. On continue la lecture et on voit que le message se termine par l'IP du vidéoprojecteur. Ah, encore dans le message, je retrouve une suite de 4 nombres qui m'avaient intrigué. Je ne sais toujours pas ce que c'est, peut être un identifiant du vidéo projecteur ? En tous cas, ça ne doit pas coder d'information dans les messages de code 3 (ça aurait pu être par exemple l'état du vidéo projecteur). Après l'envoi de ce segment de code 4, surprise : le vidéoprojecteur se connecte en TCP sur le port 3620 du client. Le vidéoprojecteur commence à parler avec un segment de code 5. On y trouve beaucoup de \x00, le nom du vidéoprojecteur et surtout encore la même suite de nombre. Réponse ensuite du client, code 0A et message vide. Là, le client se connecte en TCP sur le port 3621 et il envoie un message à l'entête EPRD0600. Tiens, une nouvelle entête ? Elle est suivie de l'IP du client (bon, on commence à avoir l'habitude) et de plusieurs 0. Est-ce le code 0 ou est-ce que la notion de code a disparu ? Bon, en tous cas, le message se termine par une séquence de 3 nombres que je n'ai pas croisé auparavant. Après cela, le client envoie des segments contenant une tonne de données. Certainement l'image à afficher. J'avais entendu dire il y a quelques temps que le protocole utilisé, c'est du VNC. J'espère que c'est vrai ! Je vais m'arrêter là pour aujourd'hui, j'analyserai plus en détail cette conversation puisqu'elle est la plus intéressante. Le but, ça va être d'essayer de me raccrocher au protocole VNC, dès que j'aurais réussi, la suite sera beaucoup plus simple. Par contre, je remarque quand même que les deux connexion subsistent ! Celle sur le port 3620 et celle sur le 3621. Sur la connexion du 3620, le même segment est envoyé régulièrement (0A). Je suppose que cette connexion sert à commander la session. Par exemple, lorsque je déconnecte le client, un segment code 6 est envoyé, et un code 7 est répondu. Mon hypothèse est que l'image est transférée sur la connexion du port 3621, et le reste sur le 3620, enfin bon, on verra bien. En attendant, je ramène chez moi de belles captures réseau. [...] Bon, aujourd'hui, deux points : j'essaie de me documenter sur le protocole RFB (VNC) pour essayer de me raccrocher à la communication du vidéoprojecteur, bon, ça, je suis pas sûr d'y arriver, il faut que j'en sache plus. Je vais donc essayer de programmer mon propre vidéo projecteur. Avec les informations que j'ai, je devrais pouvoir faire croire au programme qu'il communique au vidéoprojecteur. Avec ça, je pourrais travailler même sans être en présence d'un vidéoprojecteur. Ça serait bien puisque c'est le dernier jour où j'ai accès au vidéo projecteur avant la semaine prochaine. Première étape, décortiquer le header. Bon, en regardant de plus près le segment de réponse à la découverte, j'ai enfin vu la différence entre vidéo projecteur libre et vidéo projecteur pris. J'essaierais plus tard de changer ce nombre pour voir un peu toutes les possibilités. Ah, sinon la chaîne qui code le nom du vidéo projecteur fait 32 octets. En gros, le nom puis du bourrage à \x00. Après le nombre qui code l'état, un nombre dont je ne connais pas la signification (pareil, je vais essayer différentes valeurs) et une suite de 0 avec un code bizarre au milieu (celui dont on parlait hier, qui se retrouvait plusieurs fois). Bon, autant je pensais être plutôt bien avancé, autant lorsque je réponds au client comme un vidéo projecteur, il ignore mes messages. Pourtant, le contenu est identique. Les seuls différences vont être au niveau des IPs. Et si la chaîne bizarre était une forme de hash ? Ça me paraît vraiment bizarre sachant que cette chaine est présente dans plusieurs messages différents, mais c'est une hypothèse à étudier. Bon, j'ai comparé plus en détail la différence entre les paquets. Le message transmis est identique, par contre, je remarque que le vidéoprojecteur ne renvoie que des segment UDP qui ont pour port source 1024. On va essayer ça, après tout on a rien à perdre. Je viens d'essayer. Soit c'est pas ça, soit c'est pas que ça. J'avance toujours pas, j'ai juste fait un petit script qui fait une découverte sur l'IP du vidéoprojecteur, il me répond exactement la même chose qu'au logiciel. C'est bon signe, là mon problème se situe au niveau de l'émulation d'un vidéoprojecteur, ce n'est pas mon but, mais si j'y arrivais, ça serait un outil très puissant pour continuer l'analyse du protocole. Je patauge... Mmmh, bon, regardons un peu, en supposant que le code de statut soit codé sur un octet, suivi par un octet de bourrage, on a un nombre inconnu (qui est 4) juste après, suivi de 3 octets de bourrage, puis 8 octets de bourrage, la suite de 4 nombres inconnus, puis 16 octets vides. Au total, ça fait une chaine de 32 octets, c'est plutôt rond. Du coup, le nombre code certainement la longueur de cette suite. Dommage, ça ne me dit toujours pas ce que c'est ! Je vais aller jeter un oeil aux autres segments qui contiennent cette même chaîne. Bon, je m'arrête là pour aujourd'hui. La journée ne fut pas productive. [...] Ça y est, je n'ai plus de vidéoprojecteur et mon émulateur ne fonctionne pas. Déjà, je vais essayer d'utiliser un outil un peu plus sophistiqué que netstat pour savoir à quel moment il attend des messages. Le comportement est assez étrange, toutes les ~3 secondes, un socket UDP est créé et une connexion TCP (ou 2 ?) est envoyée. Bon je vais regarder d'un peu plus près les enregistrements effectués avec un vidéoprojecteur. En gros, une connexion TCP est envoyée (SYN), un refus est répondu (RST), après le message de découverte en UDP est envoyé par le logiciel, puis une réponse est reçue du vidéoprojecteur. Comme je ne vois toujours pas ce qui peut changer, on va changer de tactique, essayons d'initer cette communication en TCP ! Bon, il m'envoie un message de découverte mais n'accepte toujours pas ma réponse. Tiens, je vais essayer une approche très stupide : le brute force. Je ne sais pas ce qu'est ce nombre de 32 bits qui, me semble il, est indispensable pour se faire passer pour un vidéo projecteur. Je vais donc essayer d'envoyer des réponses en essayant n'importe quel nombre. Bon, un petit soucis : 2**32, ça fait quand même plus de 4 milliards de possibilités. Ah, par contre on peut pas envoyer mille requêtes par secondes sans faire freezer la VM, il faut donc y aller doucement. En plus, on ne peut pas envoyer les informations en permanence puisque le logiciel n'attend des réponses que de temps en temps. Ça va être long... Pendant ce temps là je vais passer à autre chose : étudions ce qu'il se passe sur une connexion établie avec un vidéo projecteur, je vais pouvoir ressortir mes anciennes captures. Dans une connexion faite sur le port 3621 (là où doivent passer les captures d'écran), je vois écrit "JFIF" ! Après une petite recherche sur google, il s'agit de l'acronyme pour Jpeg File Interchange Format, on a une belle piste là ! Il faut que je me renseigne sur ce format, mais avant, je me pose une question : ce message est-il une sorte de configuration de début de connexion, pour indiquer le format de fichier qu'on va utiliser durant tout l'entretien, ou est-ce que le logiciel envoie juste des images au format JFIF en permanence au vidéo projecteur pour qu'il les affiche ? Une petite recherche dans le fichier de capture m'indique que la chaîne de caractère "JFIF" se retrouve 17 fois, bon, là j'en suis à supposer que le logiciel envoie bel et bien des fichiers JFIF au vidéoprojecteur. Maintenant, on va chercher des informations sur ce format. Pendant ce temps là, je désespère à l'idée de réussir mon brute-force, donc je coupe tout ça. De toute façon, si je n'ai pas à travailler sur le format des images, je n'ai pas vraiment besoin d'émuler un vidéoprojecteur. Dommage, j'aurais bien aimé être assez exhaustif dans cette étude, mais n'oublions pas le but premier : réussir à afficher sur le vidéo projecteur, et pour ce faire, pour l'instant, rien n'indique que j'ai besoin de comprendre comment est généré ce nombre mystère. Je ne vais pas vous recopier la norme JFIF, sachez juste qu'elle tient sur 9 pages et qu'elle donne du baume au coeur : format très léger et simple et portable partout (donc parfait pour le vidéoprojecteur), ce format a une entête qui se termine par "JFIF0円", oh, quelle coïncidence :). Oui, je sais, je fanfaronne, mais c'est une super découverte qu'on a là : je connais le format d'échange d'image utilisé (la partie qui aurait pu être la plus complexe à comprendre). Un peu avant la petite chaine on voit un SOI : Start Of Image (c'est un nombre codé sur 16bits spécifique au format JPEG). Petite lecture de la spécification : la version de JFIF utilisée est la 1.01, la version actuelle est la 1.02. Même si les différences sont certainement minimes, dans le doute, je vais quand même récupérer les spécifications de l'ancienne version. Par contre, les deux premiers octets d'un fichier JPEG, c'est un SOI : Start Of Image (0xFFD8). Il y a 20 octets avant ce marqueur. Ceux ci sont certainement spécifiques au protocole du vidéoprojecteur. Première chose à faire : les comparer, eh oui, si ils sont avant chaque image, alors on en a plusieurs, comme ça, on verra si quelque chose change dans ce header, et on verra même quoi... sans forcément comprendre pourquoi. Tiens, on dirait que ça change, c'est pas très bon signe. En regardant un peu la conversation dans sa globalité, je remarque, de temps à autre, des messages "traditionnels" : un message de 8 octets (EPRD0600), suivie de l'IP source, le type du message est 0, et est suivi par un nombre de 32bits... Argh, que peut bien être ce nombre ? Mince, en plus il change à chaque fois et les valeurs semblent totalement aléatoires, j'espère que ce n'est pas une protection contre ce que j'essaie de faire : un nombre dont seul le logiciel et le vidéoprojecteur ont le secret pour le générer. En y regardant de plus près, ces nombres ne semble pas si aléatoires que ça. Leurs valeurs sont souvent plutôt basses (quelques centaines, milliers tout au plus). Du coup, j'émets l'hypothèse qu'il s'agit d'une taille : plus précisément la taille des données envoyées entre chaque messages "traditionnels" (j'aime ce terme). En gros, le logiciel envoie un message (type = 0) pour dire qu'il envoie X octets. Petit détail : et si on vérifiait ? ... Oui, c'est bien ça ! Ce nombre en hexadécimal correspond parfaitement à la taille en octet des données transporté par le segment TCP qui suit. Par curiosité, on va voir si ces fichiers sont bien des fichiers jpegs utilisable avec n'importe quel logiciel (donc certainement exportable avec n'importe quelle bibliothèque). J'ouvre donc un éditeur hexadécimal et récupère une image dans le flux. Une image JPEG commence par un SOI (Sart Of Image, FF D8) et fini par un EOI (End Of Image, FF D9), il me suffit donc de coller tout ce qui se trouve entre ces deux valeurs spécifiques dans un fichier. Mon lecteur d'image préféré ouvre le fichier fraîchement crée sans aucun problème. Bon, mes remarques sur l'image que j'ai en face de moi : elle a une résolution de 256x256 pixels, et une bonne partie de l'image est noire (le reste est bel et bien un morceau d'écran). Ça m'aurait simplifié la tâche si le logiciel envoyait simplement une image de l'écran dans sa globalité. Donc là, quand il a l'image, le vidéoprojecteur doit savoir où placer l'image, et quel morceau de l'image doit être utilisé (ça n'a pas de sens d'afficher la partie noire qui occuppe la moitié de la largeur de l'image). Ces informations sont elles incluses dans les messages échangés ou convenues en avance ? Exemple : toutes les images font 256x256, elles sont envoyées séquentiellement de gauche à droite et de haut en bas et la partie noire correspond à un remplissage superflu pour pallier au fait que la résolution de l'écran n'est pas un multiple de 256. Ça sera plus simple d'émettre des hypothèses en voyant les autres images qui sont envoyées. Hop, voilà, j'ai fait un petit script python pour enregistrer tout ce qui se trouve entre un SOI et un EOI dans un fichier, numéroté dans l'ordre d'envoi. Les premières images font 256 par 256 pixels et suivent séquentiellement l'écran de gauche à droite, ensuite, j'ai une suite d'images illisibles (étrange) et quelques petites images, très petites, avec pour beaucoup le curseur de ma souris dessus. Ah, on dirait que le logiciel peut seulement envoyer les morceaux d'écran qui ont changé. Il faut donc que je trouve comment préciser les coordonnées où l'on affiche l'image. Ah, du coup, c'est peut être là que se trouve la ressemblance avec le protocole VNC (parce que jusqu'à maintenant je n'ai pas vu le rapport, c'est certainement une fausse information, mais je vais regarder comment le protocole VNC se débrouille sur ce point) ... Tiens, je viens de voir qu'en fait, sur la connexion 3621, c'est du big Endian qui est utilisé ... C'est tellement naturel qu'on ne s'en aperçoit pas en fait. Mais du coup, ça peut servir ! C'est très certainement parce que le format JFIF est au format big Endian. Oh, ça c'est intéressant, on dirait qu'on ne m'avait pas menti ! Si je regarde l'instruction FrameBufferUpdate du protocole RFB, je peux percevoir une parfaite similitude entre ce qu'il y a avant le SOI et le protocole. Ça m'explique ce que signifie les premiers octets du message, je sais désormais comment sont affichées les images et comment ça marche (le logiciel envoie d'abord 4 octets pour indiquer, entre autre, le nombre de rectangles dans la liste, ensuite, pour chaque rectangle, il envoie sa position et sa taille, correspondant pour la première image à 0x0 et 256x256 ce qui est on ne peut plus cohérent. Ensuite, pour chaque rectangle, un type d'encodage est précisé, ici, c'est le n°7, son nom, c'est "tight". Il n'est pas abordé dans mon document, je vais donc faire quelques recherches sur cet encodage qui m'en dira certainement plus sur les 4 octets situés juste avant le SOI, eh oui, je ne sais toujours pas ce que c'est. Cet encodage permet la compression par Jpeg, c'est ce qu'indique le protocole d'après le premier octet inconnu, je suis sur la bonne voie. Les trois octets qui suivent représentent la taille du JPEG en octets. Voilà, la fonction permettant de convertir la taille du JPEG en "compact representation" est codée, il fallait que je le fasse tant que j'ai encore en tête la manière dont ça s'utilise. Maintenant, on va pouvoir tester si elle marche ! J'ai aussi fait la fonction inverse que je vais m'empresser de tester avec des valeurs prises dans le fichiers de captures. Dans le fichier de capture, je sélectionne le JPEG grâce à mon éditeur hexadécimal (du SOI au EOI), 354 octets ! Voyons ce que donne la longueur convertie avec ma petite fonction ... 852. Argh, bon, je vérifie la fonction... Non pourtant j'obtiens bien le bon résultat. Je vais donc regarder ce que ça donne si je lis 852 octets après le début de l'image et ... je m'aperçoit ainsi que mon éditeur hexadécimal m'a donné la longueur en hexadécimal, ce qui correspond bien à 852 en décimal, me voilà soulagé, ma fonction marche ! J'ai bien avancé, il faudrait que je me mette à écrire le protocole au propre. [...] Bon sang mais c'est bien sûr ! Je discutais un peu de ce que je faisais avec un mec de ma classe, et c'est au moment où je lui montrais un exemple de segment envoyé par le vidéoprojecteur lors de la phase de découverte, juste après lui avoir parlé de cette suite inconnue de 4 octets, que mes yeux se sont placés au bon endroit : l'adresse mac du vidéoprojecteur. Eh oui ! Le vidéoprojecteur envoie son adresse mac ! Alors si c'est ça, je vais pouvoir essayer de me faire passer pour un vidéoprojecteur ! Vous n'allez pas me croire, mais j'avais bien pensé à un moment qu'il pouvait s'agir de l'adresse mac, je vous assure, mais à ce moment là je ne devais pas avoir d'ordinateur sous la main pour vérifier et puis, avec du recul, je pensais qu'un logiciel ne devait pas avoir accès à cette information. J'avais tort ! Ma conclusion ? Ne jamais se dire qu'une idée est mauvaise : il faut toujours vérifier ! C'est pas parce que c'est mauvais que eux ne l'ont pas fait. Bref, il faut toujours explorer toutes les pistes, même les plus farfelues. Allez, c'est pas grave, maintenant que j'ai cette information, je vais dans un premier temps essayer mon logiciel permettant de se faire passer pour un vidéoprojecteur [...] Bon, ça avance, j'ai un petit script python qui fait une requête de connexion avec le vidéoprojecteur. Maintenant j'ai plus qu'à communiquer avec (cette fois ci tout se passe en TCP). Mais cette connexion ne me permet pas de faire grand chose. C'est juste une étape pour se connecter réellement. À ce niveau là, le vidéo projecteur cherche à se connecter au client (il faut donc binder sur le port 3620 en attendant la connexion). Le premier à parler, c'est le vidéoprojecteur. Mais il ne dit pas grand chose, juste quelques rappels : il précise son nom, etc ... J'ai pas vu d'information nouvelle. Ce canal a l'air d'être ouvert en permanence. Je ne sais pas à quoi il sert mais peut être qu'il est utile pour l'utilisation de la télécommande. On verra ça plus tard. Maintenant que ce canal est ouvert, je vais voir pour ouvrir le canal qui nous intéresse pour le moment : celui qui nous permet d'envoyer les images que le vidéo projecteur va afficher. Peut être que le canal coté projecteur (je vais l'appeler comme ça parce que c'est lui qui initialise la connexion) permet aussi de maintenir la connexion (avec un keep alive -like (type 0x0A ?). Dans le canal client, seul le client parle au vidéo projecteur, aucune réponse à traiter de la part du vidéoprojecteur. Ça, c'est cool. Bon, il faut que je fasse un proof of concept pour voir si je peux faire cette connexion et envoyer des ordres d'affichage. Voilà, c'est génial, j'ai affiché quelque chose au vidéo projecteur ! C'est un palier important qui vient d'être franchi ! Pour ça, j'ai juste envoyé une session que j'avais capturée, comme il n'y a aucune réponse à attendre du vidéo projecteur, c'était super simple à faire (ouvrir un socket et envoyer le contenu d'un fichier). Bon, maintenant une petite remarque : quand c'est fini j'ai une déconnexion. Il faut que j'essaie de creuser ça, j'ai peut être besoin de préciser en permanence que je suis encore en vie (keep alive). Bon, une remarque intéressante, si au lieu d'arrêter d'envoyer des directives (capturées précédemment), je les envoie en boucle, ça marche et en plus, je ne suis jamais déconnecté, donc il n'y a peut être pas de _time to live_, peut-être que le vidéoprojecteur exige juste qu'il y ait régulièrement un flux de données qui arrive. Du coup ça expliquerait peut être que lorsque j'ai fait mon petit script d'extraction des images à partir du flux, j'avais des images noires ou complètement inexploitables. # Conclusion Du coup, ça y est, j'ai enfin une bonne base. J'ai maintenant une connaissance minimale du protocole réseau du vidéo projecteur pour pouvoir afficher les images que je veux (à partir de maintenant, j'ai juste à suivre le protocole RFB). Bien sûr, le protocole, ça ne fait pas tout, un lourd développement m'attend pour réaliser une application complète, mais maintenant, plus aucun secret ne me barre la route. J'aurais bien aimé avoir un binôme pour réaliser cette application. Cela aurait permis de bien cloisonner la découverte du protocole et la réalisation de l'implémentation, on aurait ainsi pu voir si la documentation était bonne et suffisante pour bien comprendre le protocole. Maintenant, je vais tenter de faire cette application. Ensuite, je reviendrais sur l'analyse du protocole pour améliorer l'application (supporter les options de connexion, gérer la télécommande, ...). Mon petit débriefing : * Le plus important de tout : je pense que c'est de bien documenter tout ce qu'on fait et ce qu'on observe. Un détail insignifiant à un instant T peut tout à fait s'avérer être au final un élément important. De plus, sans cette documentation, je n'aurais jamais pu terminer ce projet. Eh oui, l'étude du protocole s'est faite sur une très longue période avec plusieurs mois de creux (c'est un projet qui marche à la motivation, et elle n'est pas toujours là). * Ne jamais affirmer. Là, le travail c'est de deviner. On ne peut rien affirmer. On doit toujours pouvoir douter de n'importe quelle certitude que l'on a pu émettre. * Ne jamais bloquer. Si on est bloqué sur quelque chose, il faut passer, si c'est possible, ou juste passer à autre chose. Une suite d'octet n'a pas plus de sens après avoir été fixée pendant trois heures. Voir autre chose avant de repasser à l'élément du blocage peut permettre d'aborder les choses sous un autre angle. * Essayer d'être logique. Se poser la question « Et si j'avais conçu le protocole, qu'est ce que j'aurais fait ? » est très pertinent. Si on a une idée de comment répondre à certaines problématiques, il est tout à fait possible que les concepteur du protocole ait eu la même idée. * Toujours essayer de se raccrocher à quelque chose d'autre. Tout le monde ne réinvente pas la roue chaque matin. Déjà, on peut supposer qu'un protocole réseau aura toujours une forme de header / data. Ça doit être le cas dans à peu près tous les protocoles connus, et ça marche. Il y a très peu de chances pour qu'un protocole cherche l'originalité à ce niveau là. Par extension, il est tout à fait possible que le protocole s'inspire d'un protocole connu. De plus, on peut supposer que si le protocole utilise un algorithme de chiffrement, celui-ci est connu et ouvert (AES, Serpent, 3DES...). Un protocole échange une image ? C'est sûrement du BMP, JPEG, GIF ou PNG, le protocole échange du son ? Pareil, c'est certainement du WAV, MP3, OGG... # Post étude En regardant un peu tout et une fois que j'ai bien compris comment faire pour créer un client alternatif, j'ai réessayé de me faire passer pour un vidéo projecteur et ça marche impeccablement bien ! Du coup, en modifiant les octets que je ne connais pas, je verrais le changement de comportement du logiciel. Voilà, j'ai une liste des codes et de leurs significations dans le logiciel : * 1 = vidéoprojecteur en veille, * 2 = quelqu'un l'a déjà pris, * 6 = plantage du logiciel ... * wait, what ? Ah oui, c'est étrange, quand le code de l'état du vidéo projecteur est à 6, le projecteur est grisé et le logiciel plante. En gros, un logiciel malicieux sur le réseau pourrait répondre à toutes les réponses de broadcast avec un segment UDP malicieux qui ferait planter le logiciel. J'essaierais de contacter Epson pour les prévenir. Bon, après vérification une nouvelle version du logiciel de projection est sortie et cette faille est corrigée. En continuant de regarder, j'ai noté d'une que l'IP qui est en permanence dans le header n'est pas l'IP source comme je le croyais, mais est en fait l'IP du client. Donc au final, pour simuler le comportement du client, ça ne change rien, mais du coup c'est pour ça que je n'arrivais pas à simuler un vidéoprojecteur. C'est évident, maintenant que je sais ! Deuxième chose, l'adresse mac envoyée semble être "utile" : elle permet de différencier plusieurs vidéo projecteurs qui ont la même IP et (ou ?) le même nom (ouais bon, d'où les guillemets à _utile_). -- That's all folks !

AltStyle によって変換されたページ (->オリジナル) /