URL: https://linuxfr.org/users/raphj/journaux/reception-d-un-mms-difficile Title: Réception d'un MMS difficile Authors: raphj Date: 2020年10月04日T17:10:48+02:00 License: CC By-SA Tags: mms, sms, overkill, sqlite, communication et téléphonie Score: 74 # Incipit Un alignement de planètes quelconques (ou un alignement quelconque de planètes, comme vous préférez) a rendu impossible une réception de MMS sur le téléphone que j'utilise, un vieil appareil bas de gamme sur Android 6 abandonné par la personne à qui il appartient (c'est pour donner le contexte, rendre les choses concrètes et augmenter le nombre de mots, mais ça n'a pas du tout d'intérêt pour la suite). En général ça fonctionne, mais là, non : je reçois un SMS curieux contenant deux émojis morts de rire. SMS auquel je réponds par un point d'interrogation, et la réponse ne se fait pas attendre : « Tu n'as pas reçu les images ? », suivie par « Je ne pensais pas que tu étais le type de personne à envoyer des points d'interrogation :-P ». Je finis par faire des incantations vaudoues du style redémarrer le téléphone, forcer l'arrêt de l'application SMS, vider son cache, etc. Et là, je vois apparaître un petit message proposant de télécharger le MMS, indiquant sa taille : autour de 400 Kio. Soit, je tape sur le bouton, ça mouline, ça mouline, et je pars dormir. Le lendemain matin, quelle ne fut pas mon absence de surprise quand c'était toujours marqué « téléchargement en cours ». En résumé : les deux applications SMS que j'utilise n'ont jamais réussi à télécharger le message. Mais je ne vais quand même pas rester impuissant devant cette situation ! Je demande à la personne qui m'a envoyé ce MMS de me le renvoyer. Elle me le renvoie, je le reçois correctement. Je me suis effectivement marré. Fin de l'histoire. Bon dimanche. Non, je déconne. Je n'ai pas choisi cette piste simple et évidente, sinon ce journal n'existerait pas. J'ai bien sûr tenté de récupérer le MMS manuellement. Mais est-ce que j'ai réussi ? C'est ce que nous allons voir dans ce journal. Vous devez tout lire et tout déchiffrer parce que je n'ai intentionnellement pas laissé une formulation claire et concise pour cette réponse dans ce journal, sinon vous allez la lire et partir faire autre chose. Ne partez pas maintenant, ça donne un « *read time* » moisi après. # Fonctionnement des MMS Vous allez me demander, comment récupérer un MMS manuellement ? C'est pas ultra compliqué ? Je suis content que vous me posiez la question, parce qu'il n'y aurait pas eu de journal sinon. Alors oui et non, ça dépend, peut-être... Nous allons faire un survol de tout ce qu'il faut savoir sur les MMS pour arriver à nos fins (parce que maintenant, récupérer mon MMS, c'est votre problème aussi en tant que lecteur. En principe, la rédaction est suffisamment fluide et agréable pour que vous vous identifiiez un peu et ayez envie de connaître la suite. Vous n'êtes pas ce type de personne qui quitte un journal et qui « zappe » dès que c'est un peu long, n'est-ce pas ?). Bien. Les SMS, *Short Message Service*, sont des messages courts passant par les canaux de signalisation du réseau GSM (le réseau 2G). Ils sont disponibles aussi sur les réseaux 3G et 4G, [si je lis bien](https://fr.wikipedia.org/wiki/Short_Message_Service), et peut-être aussi la 5G maintenant, mais ça, l'histoire ne le dit pas. Les MMS, ce n'est pas la même came. La réception, comment ça marche ? Votre opérateur vous envoie un SMS de notification disant à votre téléphone « Hey, t'a un MMS qui t'attend à cette adresse HTTP ! ». Et le téléphone accède à cette adresse HTTP via la 3G ou la 4G (et la 5G ? Ah bah non, les antennes sont vandalisées avant de toute façon ! ah ah). Avant il y avait WAP aussi, mais ça, depuis le début des années 2010, c'était avant. C'est pour ça d'ailleurs que vous pouvez avoir une notification de réception de MMS sans les données mobiles activées, mais que vous devez activer les données mobiles pour le récupérer et que dans certains endroits reculés du monde, cela peut engendrer des frais (souvent quand même, le téléchargement d'un MMS n'est pas décompté du forfait, mais bon ça dépend). Et si vous n'avez pas l'impression de devoir activer les données mobiles pour recevoir les MMS, c'est juste que votre téléphone vous ment et les active temporairement pour télécharger le MMS. Ce qui est plutôt pratique pour ne pas avoir à laisser les données activées en permanence (parce que, qui a besoin des données activées en permanence, HEIN ? HUUUM, pardon, j'ai un chat dans la gorge), mais ce fonctionnement est pour le moins aléatoire selon les modèles et les systèmes, et les applications. Sur Lineage 14.1 par exemple, il fallait [activer une option](https://github.com/FireLord/android_device_lenovo_kuntao/pull/3/files) sur chaque modèle de téléphone, à sa compilation. Option introduite par [ce patch](https://github.com/LineageOS/android_frameworks_opt_telephony/commit/33acc52d6740cbd21e656f6d7f6ba5f8c47b903a), [qui a été annulé dans Lineage 15](https://github.com/LineageOS/android_frameworks_opt_telephony/commit/3217e14a5557cbedfa315c836cb4de0979420fdd) et ça ne marchait plus très bien après. Mais de ma brève épopée sur Lineage 17.1, je crois me souvenir que ça remarche bien maintenant. Bref, la fête du slip... Le MMS est donc téléchargé par HTTP via les données mobiles. Et pourquoi pas par Wifi ? Certainement parce que l'opérateur vous identifie facilement via la connexion mobile. On reçoit donc un blob binaire contenant les métadonnées et les différentes parties du message : - Une description du contenu au [format SMIL](https://fr.wikipedia.org/wiki/Synchronized_Multimedia_Integration_Language) du W3C, basé sur XML. C'est grosso merdo la disposition du message (position et ordre des pièces jointes et du texte). Un exemple est donné plus tard, ne partez pas ; - Les pièces jointes, dont le texte s'il y en a un, et en général des images mais ça peut être autre chose (vous avez déjà reçu un MMS vocal ou une vidéo ?). Vous savez maintenant tout ce que je sais sur les MMS. # Récupérer un MMS bloqué Bon, du coup, comment on récupère ce MMS ? Facile, il suffit de connaitre l'adresse à laquelle il faut le télécharger. La difficulté c'est justement de trouver cette adresse. Et il faut faire vite, on a que 3-4 jours (plus ou moins) pour le récupérer, après quoi votre opérateur supprimera le message de son serveur et cela vous coûtera une interaction sociale pour demander qu'on vous le renvoie. Cette adresse est envoyée dans la notification SMS de réception d'un MMS et elle est stockée dans votre téléphone, et plus précisément, très certainement dans une base de donnée SQLite si vous utilisez Android ou iOS. Sur Android, si votre téléphone est « rooté », vous pouvez récupérer cette base de données sur votre ordinateur avec les outils de débogage. ``` $ adb shell su cp /data/user*/0/com.android.providers.telephony/databases/mmssms.db* /sdcard exit exit $ adb pull /sdcard/mmssms.db /sdcard/mmssms.db-journal ``` S'il n'est pas rooté... eh bien, je vous laisse construire une application qui utilise [l'API permettant de consulter cette base de données](https://developer.android.com/reference/android/provider/Telephony.MmsSms) sur votre système, et des implémentations libres utilisant cette API (sous Android) : - [l'application SMS/MMS par défaut d'Android](https://github.com/LineageOS/android_packages_apps_Messaging/tree/lineage-17.1/src/com/android/messaging/sms) - [l'application QKSMS](https://github.com/moezbhatti/qksms/) (je recommande, d'ailleurs) On va partir du principe qu'on a pu récupérer cette base de données sur l'ordinateur pour une consultation confortable. On peut l'ouvrir avec [DB Browser for SQLite - `sqlitebrowser`](https://sqlitebrowser.org/) par exemple, ou [`sqliteman`](https://sourceforge.net/projects/sqliteman/) : ``` sqlitebrowser mmssms.db ``` Et là, il y a plein de tables. Les SMS / MMS, c'est un peu compliqué, mine de rien, faut gérer les cas d'erreurs, les fils de conversations, les numéros de téléphones pas normalisés, les extraits de messages / conversations affichés par les applications, bref, ce qui nous intéresse c'est la table « PDU » (pour Protocol Data Unit – c'est un des deux types de SMS possibles, l'autre étant le texte simple, le premier étant utilisé pour les notifications MMS). Triez par `date` ou par `id_` pour trouver la notification qui correspond à notre MMS perdu (j'ai retiré plein de colonnes, le rendu était dégueu sinon) : | _id | thread_id | date | msg_box | m_id | |----- |----------- |------------ |--------- |------ | | 622 | 6 | 1601163785 | 1 | | | ct_l | exp | seen | text_only | |---------------------------------------------------- |----------- |------ |---------------- | `http://213.228.3.58/mms.php?BKhStABSEeuF3oSPaWggdg` | 1601422983 | 1 | 0 | Le voilà ! La notification ayant l'identifiant unique 622. On peut vérifier sa date : ``` $ date -d '1970-01-01 1601163785 sec UTC' dim. 27 sept. 2020 01:43:05 CEST ``` On est bon, ça correspond bien à l'heure de réception de la notification. On regarde la date d'expiration : ``` $ date -d '1970-01-01 1601422983 sec UTC' mer. 30 sept. 2020 01:43:03 CEST ``` On est ok. Enfin, on était ok au moment des faits. Il me restait deux jours pour expérimenter. On voit que le champ `m_id` est vide, donc il n'y a pas de message qui correspond à ce PDU dans la base de données. Et par contre, on a bien une adresse HTTP dans le champ... `ct_l`. Bon alors, on lance la commande suivante et c'est bon ? ``` wget http://213.228.3.58/mms.php?BKhStABSEeuF3oSPaWggdg ``` Spoiler : si vous lancez cette commande depuis votre ordinateur sur votre connexion fixe, ça ne va pas marcher. Ça va attendre et il ne se passera rien. Il faut passer par votre connexion mobile. Vous devez pouvoir partager votre connexion mobile à votre ordinateur et lancer la commande, sur le moment j'ai opté pour lancer la commande sur le téléphone dans Termux en désactivant le Wifi et en activant les données mobiles, comme ça ça passe par la 3G (et oui ! pas de 4G sur ce modèle). (alors oui, chez Free, à chaque fois que vous récupérez un MMS, quelque part un script PHP est exécuté. Amusant, non ?) Bref, je transfère ce fichier sur l'ordinateur pour... une manipulation confortable, hé hé, vous suivez bien. Alors qu'est-ce qu'on a récupéré ? ``` $ mv mms.php\?BKhStABSEeuF3oSPaWggdg mms $ ll mms -rw------- 1 raph raph 407K 4 oct. 12:31 mms ``` Bon, ok, 407K, la notification ne nous avait pas menti. ``` $ mimetype mms mms: application/smil+xml ``` Alors... pas du tout : ``` $ less mms "mms" may be a binary file. See it anyway? ``` Bien sûr que c'est un fichier binaire. Qui contient effectivement une partie en SMIL, mais ce n'est pas que ça. J'utilise un moteur de recherche pour chercher un programme, puis, résigné, trouver un bout de code pour extraire les parties de ce fichier, et je tombe sur [cette classe PHP](https://www.phpclasses.org/browse/file/6996.html). Bon soit, la classe a une bonne gueule (d'ailleurs, si vous vouliez un exemple de code PHP bien écrit, en voilà un). Je rajoute du code comme un sale en fin de fichier pour itérer sur les pièces jointes (`parts`) du MMS et les écrire dans des fichiers. Je me mange une erreur. L'histoire aurait malgré tout pu s'arrêter là, si j'avais remarqué que le code avait quand même fonctionné et qu'il avait correctement extrait les parties du MMS. Mais ce n'est pas le cas, alors je me dis bon, ok, ça ne doit pas être sorcier de récupérer les parties à la main, le format est probablement relativement simple. Je lance une nouvelle requête sur le moteur de recherche, cette fois pour trouver un bon lecteur / éditeur hexadécimal. J'ai en tête de copier coller les bouts de fichiers manuellement dans des fichiers à part, il me faut un outil graphique confortable. Je retiens Okteta, un éditeur hexadécimal basé sur les technos KDE (ça ne peut que être bien du coup (?)). Et je ne suis pas déçu, il fait le job. Je vous colle le début : ``` 0000:0000 | 8C 84 98 42 4B 68 53 74 41 42 53 45 65 75 46 33 | ...BKhStABSEeuF3 0000:0010 | 6F 53 50 61 57 67 67 64 67 00 8D 92 8B 42 4B 68 | oSPaWggdg....BKh 0000:0020 | 53 74 41 42 53 45 65 75 46 33 6F 53 50 61 57 67 | StABSEeuF3oSPaWg [... censuré, il y a des numéros de téléphones...] 0000:0060 | 37 2F 54 59 50 45 3D 50 4C 4D 4E 00 8A 80 8F 81 | 7/TYPE=PLMN..... 0000:0070 | 86 81 90 81 84 1B B3 89 61 70 70 6C 69 63 61 74 | ......3.applicat 0000:0080 | 69 6F 6E 2F 73 6D 69 6C 00 8A 3C 73 6D 69 6C 3E | ion/smil.. 0000:0090 | 00 04 2F 82 5D 1B 61 70 70 6C 69 63 61 74 69 6F | ../.].applicatio 0000:00A0 | 6E 2F 73 6D 69 6C 00 85 73 6D 69 6C 2E 78 6D 6C | n/smil..smil.xml 0000:00B0 | 00 C0 22 3C 73 6D 69 6C 3E 00 8E 73 6D 69 6C 2E | .À"..smil. 0000:00C0 | 78 6D 6C 00 3C 73 6D 69 6C 3E 3C 68 65 61 64 3E | xml. 0000:00D0 | 3C 6C 61 79 6F 75 74 3E 3C 72 6F 6F 74 2D 6C 61 |
< 0000:01D0 | 70 61 72 20 64 75 72 3D 22 35 30 30 30 6D 73 22 | par dur="5000ms" 0000:01E0 | 3E 3C 69 6D 67 20 73 72 63 3D 22 69 6D 61 67 65 |>

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

=..Y.image/png. 0000:0230 | 85 69 6D 61 67 65 30 30 30 30 30 30 2E 70 6E 67 | .image000000.png 0000:0240 | 00 C0 22 3C 69 6D 61 67 65 30 30 30 30 30 30 3E | .À" 0000:0250 | 00 8E 69 6D 61 67 65 30 30 30 30 30 30 2E 70 6E | ..image000000.pn 0000:0260 | 67 00 89 50 4E 47 0D 0A 1A 0A 00 00 00 0D 49 48 | g..PNG........IH ``` Alors là, on voit clairement le document SMIL en début de fichier, annoncé par le type MIME `application/smil`. Je vous le remets en clair et indenté : ```xml ``` Ok, donc on voit bien qu'il y a trois images, au format PNG. Fait amusant, une durée est associée à chaque image, ici 5 secondes. Et parfois, certaines applications (anciennes ?), sont assez pénibles pour respecter ces directives à la lettre... mais ça ne correspond pas du tout à l'usage habituel des MMS. Deuxième remarque, on voit un truc qui ressemble à un marqueur de début de fichier PNG sur la dernière ligne que je vous ai collée. Un petit tour [sur la page Wikipédia](https://en.wikipedia.org/wiki/Portable_Network_Graphics#File_header) confirme qu'un fichier PNG doit commencer par ces caractères : ``` 89 50 4E 47 # PNG 0D 0A 1A 0A ``` Séquence qu'on retrouve clairement dans la ligne. Le fichier se finit par : ``` 0006:58F0 | 49 45 4E 44 AE 42 60 82 | IEND®B`. ``` Et vu qu'il est censé se finir par une image PNG et qu'on retrouve cette séquence 3 fois (et pas 4, donc ce n'est probablement pas un marqueur de fin de pièce jointe d'un MMS), il y a fort à parier que ce soit un marqueur de fin de fichier PNG. Je n'ai pas vérifié ça, en me disant que ça avait des chances de marcher même s'il y a des trucs en trop à la fin des images, et que sinon il suffirait de retirer des caractères. Je copie colle mes trois images de cette manière à l'aide d'Ockteta. Je les enregistre dans mon dossier de travail, et c'est d'ailleurs en ouvrant ce dernier avec le gestionnaire de fichiers pour retrouver les images ainsi extraites que je me suis rendu compte que le script PHP avait fonctionné... 🤦 mais bon, ça a marché : mes images s'ouvrent. # Conclusion TOUT ÇA POUR NE PAS DEMANDER À LA PERSONNE DE ME RENVOYER LES IMAGES ! (et aussi parce que c'est fun)> Mais est-ce que j'ai réussi ? C'est ce que nous allons voir dans ce journal, vous devez tout lire et tout déchiffrer parce que je n'ai intentionnellement pas laissé une formulation claire pour cette réponse dans ce journal, sinon vous allez la lire et partir faire autre chose. J'ai menti. « Oui ». Bonne fin de dimanche !