Sommaire
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 "JFIF\0", 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 !
# Bravo
Posté par Pinaraf . Évalué à 10.
Super journal…
[^] # Re: Bravo
Posté par BAud (site web personnel) . Évalué à 4.
moi je n'ai pas compris la formulation « d'où les guillemets à utile » et il reste quelques pavés (mais je travaille à les remettre en forme).
[^] # Re: Bravo
Posté par Sébastien B. . Évalué à 7.
Ah, ce que je voulais dire, c'est que théoriquement, ça ne pouvait pas vraiment exister (en tous cas avec les modèles qu'on a à l'école) un vidéo projecteur qui a plusieurs noms. Après c'est peut être prévu par le protocole.
En tous cas merci beaucoup pour le travail de remise en forme, je suis pas très doué pour ça.
[^] # Re: Bravo
Posté par BAud (site web personnel) . Évalué à 10. Dernière modification le 13 juillet 2012 à 00:46.
oh bah je dois être un des rares modérateurs qui y passe beaucoup de temps, ça doit être parce que je ne suis pas très doué pour créer du contenu :-) (et que vu que je peux modifier, je n'ai pas besoin de me limiter à critiquer l'orthographe dans les commentaires :p)
edit : bon j'ai fini la remise en forme et l'ortho, vous pouvez reprendre une activité normale et ajouter des commentaires sur les autres threads pertinents :-)
[^] # Re: Bravo
Posté par François Chaix (site web personnel) . Évalué à 10. Dernière modification le 12 juillet 2012 à 23:04.
Ouais, même chose : Bravo.
Je m’étais toujours demandé ce qui se cachait derrière ce terme ésotérique de « rétro ingénierie », me voilà renseigné avec un exemple bien détaillé. Merci.
Une ’tite dépêche ?
La lumière pense voyager plus vite que quoi que ce soit d'autre, mais c'est faux. Peu importe à quelle vitesse voyage la lumière, l'obscurité arrive toujours la première, et elle l'attend.
# C'est bien simple...
Posté par ナイコ (site web personnel) . Évalué à 9.
…tu me fais rêver.
# Bien !
Posté par insert_coincoin . Évalué à 9.
Un peu pavé, mais très intéressant à lire !
# Tu t'ennuies encore?
Posté par ʭ ☯ . Évalué à 8. Dernière modification le 12 juillet 2012 à 23:20.
Si jamais tu t'ennuies à nouveau, j'ai plein de matos à la … qui utilise des protocoles non documentés (SMILEY compatible)
Et sinon, tout ça est super, mais qu'est devenu ton travail, à part un journal linuxfr (ce qui est le top du top)? As-tu pu aller plus loin?
⚓ À g'Auch TOUTE! http://afdgauch.online.fr
[^] # Re: Tu t'ennuies encore?
Posté par Sébastien B. . Évalué à 8.
Pour l'instant, l'essentiel de mon travail, c'était la prise de notes. À coté de ça, j'ai une petite documentation personnelle du protocole (que j'aimerais publier mais avant, je voudrais trouver un outil simple qui permet de décrire un protocole réseau efficacement mais je n'ai pas l'impression que ça existe). J'ai aussi des morceaux de code (écrits en Python) : une application qui implémente un vidéo projecteur auquel les clients EPSON Projector peuvent se connecter et une autre qui implémente un client qui peut se connecter à un vidéo projecteur. Par contre, dans les deux cas, le lien avec VNC n'est pas fait, ce qui fait que le client n'envoie qu'une séquence VNC pré enregistrée pour afficher des éléments et le serveur reçoit des directives VNC sans rien en faire. Du coup les logiciels ne sont pas encore utilisable (et pas forcément bien codé, comme l'explique le commentaire en bas, c'est très compliqué d'avoir un code cohérent quand ta vision du protocole change en permanence. Je vais essayer de mettre mes codes au propre et de faire un dépot gitorious.
Ensuite, je suis en train de rédiger un rapport d'activité pour mon école, dedans j'y explique ce que j'ai fait de manière plus générale et le plus adapté possible à un public non averti. J'essaierais de faire un journal une fois qu'il sera rendu.
Enfin, j'avais fait une petite conférence à mon école pour expliquer un peu ce qu'était la rétro ingénierie, j'essaierai de reprendre les slides, les améliorer et les publier.
Mais du coup, d'un point de vu fonctionnel, je n'ai pas été assez loin pour avoir quelque chose d'utilisable.
# Bienvenue au club
Posté par Batchyx . Évalué à 10.
Ah, je me souviens avoir fait la même chose il n'y a pas si longtemps. Mais bon, ça fait longtemps, et j'ai pu d'accès à un videoprojecteur EPSON, du coup mon code pourri à l'air libre.
Par contre, j'avais été un peu plus loin : certains des vidéoprojecteurs ont du code en GPL, et donc il y a du code source disponible sur le site d'EPSON. Le code ne compile pas (il en manque la moitié), mais fourni quelques informations intéressantes. Sinon je crois que j'avais cherché des chaînes de caractères dans les binaires officiels, et j'avais eu quelques informations.
Mais bon, le fait qu'il y ai un client VNC et un vieuw ffmpeg m'avais pas mal aidé, j'ai pas eu à découvrir qu'il y avais du VNC en dessous.
Faudrai peut-être que je te sorte le code crade que j'avais fait, peu importe dans quel état déplorable c'est. J'avais même écrit un petit analyseur pour wireshark pour m'aider un peu.
Mais bon, de ce que je souviens :
Si je me souviens bien, y en a un qui s'appelle 'easysearch' (le 0x01, celui en broadcast) et l'autre qui s'apelle 'ipsearch' (le 0x02). T'a peut-être du remarquer que si dans l'interface tu lui demande de choisir une IP à la main, il utilise le 0x02.
Dans ce message, je me souviens avoir reconnu un morceau de protocole RFB, la partie qui permet au serveur d'indiquer au client quel est sa résolution, son nombre de bit par pixel, d'indiquer que la valeur max du rouge c'est 0xff avec un décalage de 16 bit pour y accéder …
Ce qui est encore plus bizarre, c'est que dans les sources, c'est plus présenté comme une modification de la configuration IP qu'autre chose, sauf que si j'essaye de mettre d'autres adresses, ça marchai pas, ça modifiait pas la conf du vidéoproj…
Moi ce qui m'avais aussi surpris, c'est que dans le code source, il y avais du code pour chercher "EPRD0600" arbitrairement dans le flux … mais bon comme il en manquait la moitié du code …
Non, il sert pas à grand chose … Pour la télécommande, c'est le proto ESC/VP.net sur le port 3629. Y a une doc trouvable facilement qui spécifie les échanges, mais pas l'initialization, mais bon, c'est pas compliqué, juste un échange UDP et une ouverture de session TCP ou tu fait un échange similaire. J'ai pas les détails en tête, mais mon vieux code, si.
Avec ça, tu peut simuler un appui sur toutes les touches de la télécommande infrarouge.
oui, le 0x0a est un keepalive. j'ai cru un moment que c'était un "displayrefresh", sauf que ça correspondait à rien.
Je n'ai pas recherché de ce coté là (si tu parle de la case "crypter les communications", mais je vais te décevoir (ou te faire rire) : EPSON utilise du DES, ou alors de l'AES64. Qu'est ce que l'AES64 ? C'est de l'AES128, sauf que la clef de départ n'a que 64bit, et tu la répète deux fois pour avoir une clef de 128bit. C'est pratique AES64, c'est la même taille de clef que DES…
Ah, et il y a (peut-être) un champ dans le message 0x04 qui s'apelle 'encryption_key'. Et j'ai pas envie de vérifier si la clef est effectivement envoyée en clair.
Fin bon, moi mon but, c'était surtout d'envoyer de la vidéo au videoproj. Mais le meilleur truc que j'ai eu, ça n'était que du son… et j'ai jamais réussi à reproduire.
[^] # Re: Bienvenue au club
Posté par gnumdk (site web personnel) . Évalué à 2.
Pareil, ce n'était pas du réseau, mais j'ai du y'a quelques années écrire un module python capable d'écrire des GPO Windows depuis des clés/user/machine stocker dans une base MySQL…
Le plus dur, c'est pas de comprendre le protocole, ni de le retranscrire, c'est d'écrire du code qui ressemble à quelque chose, en gros, revenir le plus proche du code original plutot que recracher le protocole à l'arrache… Heureusement, j'avais trouvé un mec sur le net qui m'avait filé un bon coup de main.
https://svn.ac-grenoble.fr/websvn/filedetails.php?repname=se3&path=%2Ftrunk%2Fse3-logonpy%2Fusr%2Fshare%2Fse3%2Flogonpy%2Fse3GPO.py
Bon, depuis, je travaille avec des serveurs Windows comme controleur, donc la partie GPO, je leur laisse… Parce que bon, se3 c'était quand meme du hack avec envoie de GPO machine et utilisateur à la connexion de l'utilisateur en tant que GPO local…
[^] # Re: Bienvenue au club
Posté par Sébastien B. . Évalué à 7.
Ah, tu me fais très plaisir là, en plus de m'être amusé à faire un jeu sur une boite de céréales, j'ai la solution en bas du paquet !
Et du coup, je n'avais même pas vu qu'il y avait du code sous GPL qui traînait, en effet ça m'aurait facilité la tâche.
Ah, intéressant, ça je ne l'avais pas trouvé et je me suis longtemps demandé ce que ça pouvait être !
D'accord, je pensais que c'était juste un hack bizarre pour être savoir si le client et le vidéo projecteur était sur le même sous réseau (sans trop savoir ce que ça pouvait lui faire). Après, j'ai vu qu'entre plusieurs vidéoprojecteurs, le protocole peut différer un peu me semble il, du coup il y a peut être des vidéo projecteurs "de luxe" où tu peux modifier la configuration réseau à distance … Ou alors la fonctionnalité n'a jamais été implémenté …. Mais en tous cas c'est intéressant, je n'avais pas pensé à cet aspect de configuration.
Ah, en fait, c'était une conclusion pour généraliser, je ne savais même pas que les échanges avec le vidéo projecteur pouvaient être chiffrés, mais bon après, apparemment autant laisser en clair, c'est vrai que c'est vraiment risible :p.
Merci encore pour ces précisions !
[^] # Re: Bienvenue au club
Posté par Batchyx . Évalué à 2.
Bon, c'est triste, mais je retrouve pas la moitié de mes sources… il me reste plus qu'une appli crade en C++ qui essayait de regrouper un peu tout (sauf vnc)
J'avais certainement du les virer parce que j'avais plus de place et que je me disais que ça resservirai jamais …
# Rétro ingénierie
Posté par hitmanu . Évalué à 9.
un GRAND MERCI,
pour ce travail qui éclaire nos lanterne concernant la rétro ingénierie,
maintenant je saurai comment faire grasse a tes précieuse explication ;)
Merci aux personnes qui mon aidé a trouvé des solutions pour essayer d’écrire sans faute d’orthographe.
[^] # Re: Rétro ingénierie
Posté par liberforce (site web personnel) . Évalué à 6.
Je ne suis pas sûr qu'avoir les doigts enduits de beurre ou d'huile t'aide dans la pratique de rétro-ingéniérie.
[^] # Re: Rétro ingénierie
Posté par Sébastien B. . Évalué à 6.
Détrompe toi ! Regarde ce super site de rétro ingénierie : http://www.lasupersuperette.com/ !
Ils prennent des produits vendus dans le commerce et proposent une recette que l'on peut faire chez nous. J'adore ce site.
# Encore!
Posté par Denis BRAUSSEN . Évalué à 5.
Merci pour cet excellent journal!
# Well done
Posté par lordblackfox . Évalué à 5.
Bravo pour ce travail et le partage :)
BTW, si t'es intéressé, j'avais bossé un peu sur un autre rétroprojecteur, l'acer c110, en me basant sur le boulot de rétro-ingénierie d'autres types (tant qu'à faire sa pub):
https://github.com/lordblackfox/acerc110
https://github.com/rettichschnidi/acerc11xdrv
http://git.ao2.it/libam7xxx.git
# Tout n'est pas perdu
Posté par Nicolas Dumoulin (site web personnel) . Évalué à 8.
Apparemment, tu es encore étudiant (voire au lycée). Ça fait plaisir de voir un jeune qui se jette sur un tel projet et le fait aussi bien. Tu feras certainement un très bon stagiaire, et je te souhaite de trouver ensuite un boulot dans lequel ton enthousiasme soit conservé et apprécié !
[^] # Re: Tout n'est pas perdu
Posté par Sébastien B. . Évalué à 7.
Merci !
Du coup, je suis en études supérieures et pour la petite anecdote j'ai eu à réaliser un peu de rétro ingénierie durant mon dernier stage. En effet, on voulait faire du chaînage de Proxy avec un ISA server de chez Microsoft qui utiliserait lui même un proxy pour accéder aux sites web. Cette fonctionnalité existe dans ISA server, mais elle est faite pour se chaîner à d'autres ISA, avec un squid par exemple, ça marche jusqu'à ce qu'il y ait une coupure entre l'ISA et le Squid. À ce moment là, le ISA considérera que le Squid est tombé de manière permanente même si le problème de communication a été résolu (le cable a été rebranché quoi).
Il y a un petit protocole de communication entre les ISA et je n'ai pas trouvé de doc. Bon, après avoir regardé un peu, c'est tout bête, le ISA envoie régulièrement des requêtes GET /array.dll et il faut lui répondre (même une réponse vide, ça va). Le problème était que notre proxy ignorait ce problème.
# Un jour ...
Posté par Allan Simon (site web personnel) . Évalué à 5.
… On pourra se connecter aux projo de supinfo et donner cours linux sans passer par windows \o/ Ça fait plaisir de voir que tu avais pas abandonné le projet
# adresse MAC, t'es sur ?
Posté par Tonton Th (Mastodon) . Évalué à 5.
Chez moi, les adresses MAC font 6 octets.
[^] # Re: adresse MAC, t'es sur ?
Posté par Sébastien B. . Évalué à 4.
Chez moi aussi, mais elle est précédée de deux octets nuls, que ça soit dans son adresse ou dans le paquet. Je me suis mal exprimé, disons que je lisais cette suite comme étant une information de 4 octets sans vraiment m'occuper des octets nuls qui la précédait. Donc plutôt, "cette suite inconnue de 4 octets est un fragment de l'adresse mac du vidéo projecteur" !
[^] # Re: adresse MAC, t'es sur ?
Posté par kowalsky . Évalué à 2.
Peut être que toute la mac n'est pas envoyé car le constructeur "connait" son range de mac ?
http://standards.ieee.org/develop/regauth/oui/oui.txt
[^] # Re: adresse MAC, t'es sur ?
Posté par Batchyx . Évalué à 3. Dernière modification le 17 juillet 2012 à 22:46.
Non, c'est juste que les deux premiers octets de l'adresse mac sont 00:00 (l'OUI, si tu veux savoir, est celle de Seiko/Epsonn, soit 00:00:48), du coup, quand t'a un paquet avec plein de 0 partout, tu te dit que 4 valeurs non-nulles en plein millieu d'octets nuls forment un champ de 4 octets. Sauf que le champ faisait 6 octets, avec les deux premiers nuls.
Le fait que le protocole utilise plein de champs de taille fixe pour stocker des chaînes de caractères aide pas mal à avoir plein d'octets nuls dans des paquets.
# vncrec
Posté par cyberic99 (site web personnel) . Évalué à 1.
Beau boulot!
D'après ce que je comprends, à part la phase de discovery, c'est du RFB pur et simple qui est utilisé?
Crois tu qu'il serait possible de capturer le flux et de le rejouer, par exemple grâce à http://www.sodan.org/~penny/vncrec/ ?
http://theotherdays.net
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.