Journal Disséquer un APK pour trouver une API de météo

Posté par . Licence CC by-sa.
31
11
juin
2019

Intro

Si vous vous rendez sur le site de Météo France, il n'y a pas de moyen évident de récupérer les prévisions météorologiques par API pour les intégrer dans ses propres applications. Alors que, si j'en crois Wikipedia, Météo France est un "établissement public administratif", donc plus ou moins financé par nos impôts.

Pour commencer gentiment, j'ouvre les outils de développement de Firefox (F12) pour voir comment une page de prévisions est construite (onglet "network"). On peut constater que la page n'est pas construite par un appel d'API (xhr) mais directement rendu en HTML côté serveur. Doh !

FF F12

Pourtant il y a une application officielle sur le playstore de google/android. Et qui ne semble pas être un simple revamping du site web. Je parierai qu'elle utilise une API.

J'envisage quelques solutions pour en avoir le cœur net :

  • installer l'application sur mon ordiphone, lancer l'application en la faisant passer par un proxy et regarder le trafic quand je l'utilise.
  • faire de même dans un simulateur sur le PC avec l'android studio
  • faire une analyse statique de l'application : peut être un fichier de configuration me donnera un pointeur

Les deux premières me semblent compliquées et intrusives car mon ordiphone n'est pas relié à google. J'opte pour l'analyse statique.

Analyse d'un APK

Télécharger l'APK

S'assurer de l'identifiant de l'application. Notons au passage la taille de la bête - 51M - qui dépasse mon entendement.

Chercher un site qui permet de télécharger une application Android sur PC. Il y en a des centaines. On se demande ce qu'ils ont à y gagner : juste afficher de la pub ou installer une petite spécialité maison au passage … méfions nous des fichiers récupérés de cette manière.

Je prends le premier, j'entre l'ID de l'application et lance le téléchargement. J'obtiens un fichier APK sur mon PC.

Extraire l'APK

Un APK est grosso-modo une archive ZIP.

Mais dex2jar fournit un outil appelé "d2j-std-apk" qui prétend "clean up apk to standard zip". Alors pourquoi pas.

dex2jar-2.0/d2j-std-apk.sh -o apk.zip ~/Downloads/My\ Weather\ App_v6.2.1_apkpure.com.apk puis unzip apk.zip.

strings

Avant toute chose, je tente une méthode un peu brutale, en utilisant strings sur l'ensemble des fichiers.

find apk -type f -print0 | xargs -0 strings | less -p "meteofrance.com"

Je commence à trouver des trucs très sympa comme "webservice.meteofrance.com", "ws.meteofrance.com", "api.meteofrance.com". C'est bon signe mais cela ne me dit pas vraiment comment utiliser l'API ni où elle est exactement.

Déchiffrer les DEX

Le code de l'application se trouve dans les fichiers dex. Il faut tout d'abord recréer les fichiers class de java.

dex2jar propose l'outil dex2jar exactement pour ça.

dex2jar-2.0/d2j-dex2jar.sh classes.dex

à répéter avec classes2.dex et classes3.dex

strings, le retour

Maintenant que j'ai des jar avec des class. Je retente la méthode brutale, strings mais cette fois si sur le contenu des jars.

unzip -p apk/classes2-dex2jar.jar | strings | less -p "meteofrance.com", à répéter avec classes2.dex et classes3.dex.

Je ne trouve rien de plus que lors de la première passe.

décompiler

Java Decompiler permet de décompiler les fichiers class. Et propose une GUI en plus de la CLI.

java -jar ~/Downloads/jd-gui-1.5.1.jar apk/classes-dex2jar.jar

Dans le premier fichier je trouve un package "rest" avec une class "RestClient". On touche au but mais ce n'est pas suffisant.

Dans le second fichier, rien de bien folichon.

Dans le troisième, bingo, l'API est explicitée, avec l'hôte, les chemins et les paramètres.

Exploitation de l'API

curl et jq permettent de facilement comprendre comment fonctionnent l'API.

Il faut noter que Météo France travaille avec les identifiants INSEE des villes de France et pas avec les code postaux.

Un verbe de l'API permet de chercher une ville et d'obtenir cet identifiant.

curl -s -S 'http://ws.meteofrance.com/ws/getLieux/rennes.json' | jq -rc '.result.france[]|[.indicatif, .nom]|@csv'

"352380","Rennes"
"531890","Rennes-en-Grenouilles"
"113090","Rennes-le-Château"
"113100","Rennes-les-Bains"
"254880","Rennes-sur-Loue"

Un verbe permet d'avoir les prévisions :

curl -s -S 'http://ws.meteofrance.com/ws/getDetail/france/352380.json' | jq -rc '.result.previsions48h|.[]|[.moment, .description]|@csv'

"20-23","Rares averses"
"23-02","Rares averses"
"02-05","Rares averses"
"05-08","Rares averses"
"08-11","Rares averses"
"11-14","Risque d'orages"
"14-17","Averses orageuses"
"17-20","Averses orageuses"
"20-23","Rares averses"
"23-02","Eclaircies"

Outro

Voilà, nous avons vu comment disséquer une application Android pour retrouver l'API qu'elle utilise. Y avait-il un autre moyen ?

Happy hacking !

  • # Syntax error

    Posté par . Évalué à 2 (+0/-0). Dernière modification le 11/06/19 à 20:54.

    Mais c'est très amusant tout ça !

    Par contre quand je tente de le refaire à la main jq n'a pas l'air très content :

    $ curl -s -S 'http://ws.meteofrance.com/ws/getLieux/rennes.json' | jq -rc '.result.france[]|[.indicatif, .nom]@csv'
    jq: error: syntax error, unexpected FORMAT, expecting $end (Unix shell quoting issues?) at <top-level>, line 1:
    .result.france[]|[.indicatif, .nom]@csv                                   
    jq: 1 compile error
    (23) Failed writing body
    

    Pour info, le curl lui-même a l'air de fonctionner, j'ai bien un JSON en sortie.

    Tu aurais une idée de l'erreur ?

    EDIT : en fait c'est la syntaxe du @csv qui semble poser problème
    EDIT2 : corrigé dans le journal, il manquait un '|' avant le @csv

    En théorie, la théorie et la pratique c'est pareil. En pratique c'est pas vrai.

  • # Ils ne doivent pas en voir assez, du budget public

    Posté par . Évalué à 3 (+1/-0).

    Alors que, si j'en crois Wikipedia, Météo France est un "établissement public administratif", donc plus ou moins financé par nos impôts.

    Parce que leur site ou leur application téléphone sont farcis de pub. Sans adblockers, point de salut, et des pubs à la mode old school avec des popups etc. Du coup je vais voir ailleurs :)

    Vont pas être content que tu tapes sur leur api à mon avis.

    Mais merci pour l'astuce, moi aussi je veux la météo rennaise :)

  • # proxy

    Posté par . Évalué à 2 (+1/-0).

    J'ai déja eu a faire ce genre de manip, pour voir les appels aux API du LeBonCoin il y'a quelques années. Finalement, c'etait plus simple d'installer un proxy sur le device, qui gérait même le HTTPS (ca installait en fait un genre de VPN, et on voyait ensuite passer les requetes HTTPS "en clair". Me souviens plus du nom).

    Sinon, pour les API météo, il vaut mieux ne pas se prendre la tête avec Meteo France. Personnellement, j'utilise https://www.wunderground.com/weather/api/ qui est bien mieux.

  • # Proxy?

    Posté par . Évalué à 3 (+1/-0).

    installer l'application sur mon ordiphone, lancer l'application en la faisant passer par un proxy et regarder le trafic quand je l'utilise.

    Comment réalises-tu cette opération? C'est un option de l'application ou bien de ton OS mobile?

    • [^] # Re: Proxy?

      Posté par (page perso) . Évalué à 1 (+0/-0).

      Sur android tu peux spécifier le proxy dans les paramètres avancés de ta connexion wifi.

      Après faut avoir un proxy traceur quelque-part :)

  • # Un autre moyen

    Posté par . Évalué à 2 (+2/-0).

    Y avait-il un autre moyen ?

    Je vois un moyen légal :

    • L'article L300-2 du code des relations entre le public et l'administration indique que les "codes sources […] produits ou reçus, dans le cadre de leur mission de service public […] par les autres personnes de droit public ou les personnes de droit privé chargées d'une telle mission" sont des documents administratifs.

    • L'article L311-1 du même code, indique que "les administrations mentionnées à l'article L. 300-2 sont tenues de publier en ligne ou de communiquer les documents administratifs qu'elles détiennent aux personnes qui en font la demande, dans les conditions prévues par le présent livre."

    La seule réserve que pourrait opposer météo-france est d'estimer que ces informations sont protégées par le secret des affaires (article L311-6). Dans ce cas, il faudrait saisir un tribunal administratif pour obtenir le code source.

    C'est sans doute plus long et fastidieux que des décompiler un APK. Mais pas forcément moins marrant.

  • # Pour apporter ma pierre (python) ... + les pictos

    Posté par (page perso) . Évalué à 3 (+2/-0).

    import requests,json,datetime
    
    r=requests.get("http://ws.meteofrance.com/ws/getDetail/france/750560.json").json()
    
    now=datetime.datetime.now()
    f=lambda nb: (now +datetime.timedelta(days=nb)).strftime("%d/%m/%Y")
    
    def liste(p):
        for k in sorted(p.keys()):
            yield "%s : %s - %s (pluie:%s%%) (%s - %s°C)  <img src='http://ws.meteofrance.com/img/pictos/70x56/%s.png' width='24'/><br>" % (
                f(p[k]["jour"]),
                p[k]["moment"] or "jour",
                p[k]["description"],
                p[k]["probaPluie"] or "0",
                p[k]["temperatureMin"],
                p[k]["temperatureMax"],
                p[k]["picto"],
            )
    
    yield "<h4>Prévisions 10j</h4>"
    yield "".join(liste(r["result"]["resumes"]))
    yield "<h4>Prévisions 5j</h4>"
    yield "".join(liste(r["result"]["previsions"]))
    yield "<h4>Prévisions 24h</h4>"
    yield "".join(liste(r["result"]["previsions48h"]))
    
  • # J'ai arrêté de lire là.

    Posté par . Évalué à 6 (+4/-0).

    On peut constater que la page n'est pas construite par un appel d'API (xhr) mais directement rendu en HTML côté serveur. Doh !

    Si j'avais eu le même problème que toi, je me serais arrêté à cette constatation, et j'aurais simplement bricolé un script un peu sale qui fait les requêtes pour toutes les données dont j'ai besoin, et qui extrait les données du HTML.

    Pour les raisons suivantes :

    S'ils sont assez bornés pour ne me donner que ça, je suis assez borné pour me contenter de ça. Je suis un pauvre glandu d'intérim de province, je vais pas jouer au plus malin avec les décideurs d'élite d'un machinchaipaquoi administratif public. Si y'a des "premiers de cordées", je veux bien être celui qui se laisse pendouiller les jambes dans le vide.

    Que ce soit pour des besoins personnels ou pro, si j'ai un problème comme le tien, je n'ai pas le temps ni l'énergie d'aller chercher "aussi loin". J'attrape le premier fil qui dépasse et je commence à tirer.

    Le Web c'est la guerre depuis quelques années.

    Il y a 10 ans je me serais souvent posé la question de savoir si je vais défoncer la connexion ou le CPU de la machine qui héberge, surtout quand un site Web c'était encore assez souvent un petit truc propre administré à la main, avec un CMS plus ou moins bien déployé et un hébergement mutualisé voire dédié. J'aurais des scrupules si je devais lancer des requêtes automatiques sur (par exemple) Linuxfr, et mon premier mouvement serait de contacter poliment les admin du site pour savoir comment accéder proprement aux données qui m'intéressent.

    Je n'ai aucun scrupule envers des sites Web qui me balancent des dizaines de connexions SSL vers des domaines différents dont le nom ne me dit absolument rien, dont les propriétaires sont anonymes, dans le but d'envoyer un maximum de mes données personnelles dans je ne sais quelles bases de données. Quoi que je fasse subir à (par exemple) www.meteofrance.com dans le but d'y récupérer des données, ce sera moins dégueulasse, moins infâme, moins glauque que le bordel de connexions réseaux qui défilent dans la console quand je me contente de REGARDER LE SITE WEB SANS MÊME BOUGER LA SOURIS o_O

    Je n'ai aucune raison de ménager la charge réseau ou CPU d'un site Web totalement inutilisable en ADSL 2Mo ou avec un processeur de 2010. Il me ménage, lui ? Le site n'a pas commencé à s'afficher, que déjà plusieurs données destinées à m'identifier (de ma résolution d'écran, à mon user agent, en passant par des cookies google/facebook/etc) sont parties dans des BDD dont j'ignore l'existence, d'où elles sont revendues à des entreprises dont le nom m'est inconnu, et il faudrait que moi je m'inquiète de savoir si la BDD va pas crasher avec mes bêtises ?

    Du coup, quand je veux automatiser mes interactions avec un site Web, la console Firefox me suffit généralement. J'ai juste à automatiser des requêtes HTTP d'un côté, et de l'autre côté j'ai du HTML à parser. Ce n'est pas moi qui ai mis autant d'emballage autour du colis.

    Ils ont voulu me faire bouffer du Web, je vais en bouffer, du Web. Avec appétit.

    THIS IS JUST A PLACEHOLDER. YOU SHOULD NEVER SEE THIS STRING.

Envoyer un commentaire

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n'en sommes pas responsables.