De ATAG One app (voor iPhone en Android) benadert rechtstreeks via het locale netwerk de ATAG One thermostaat. Atag stelt helaas geen technische documentatie online beschikbaar hoe de thermostaat aan te sturen is. De enige manier om uit te vissen hoe de app “praat” met de thermostaat, is door de app te hacken 🙂
De Android app ontleden
Het installatie pakket voor Android is een Android PacKage bestand, kortweg APK. Dit is een ge-zipt archief en daarom eenvoudig uit te pakken met unzip:
$ mv io\ cordova\ AtagUser_apkpure.com.apk io\ cordova\ AtagUser_apkpure.com.apk.zip $ unzip io\ cordova\ AtagUser_apkpure.com.apk.zip Archive: io cordova AtagUser_apkpure.com.apk.zip inflating: META-INF/MANIFEST.MF inflating: META-INF/ATAG_TES.SF inflating: META-INF/ATAG_TES.RSA inflating: AndroidManifest.xml inflating: assets/_where-is-www.txt inflating: assets/www/AnalyticsEvents.js inflating: assets/www/Controllers/ActivateScheduleC.js inflating: assets/www/Controllers/AddDeviceC.js inflating: assets/www/Controllers/AdjustDayScheduleC.js etc...
De App maakt gebruik van Apache Cordova. Apache Cordova is een populair framework voor het maken van mobiele applicaties. De applicatie is ontwikkeld in de talen JavaScript, HTML en CSS. Voor het uitlezen van UDP netwerk berichten, is de applicatie aangevuld met plugins die geschreven zijn in Java en rechtstreeks met het Android besturingssysteem praten.
Zoek thermostaat in netwerk
/assets/www/index.html
lijkt een belangrijk bestand. Na wat gebladerd te hebben in dit bestand kom ik de volgende JavaScript voor het zoeken naar de thermostaat tegen:
cordova.exec(null, null, "UdpReceive", "close", ["close"]); $controller('searchForOneDiv')._fire();
Het belangrijkste deel wordt blijkbaar uitgevoerd door een externe plugin met de naam UdpReceive
.
Helaas bevat het Android PacKage alleen de gecompileerde Dalvik bytecode. De code is samengevoegd in het bestand classes.dex
. Gelukkig zijn er tools om deze gecompileerde code weer om te zetten in enigszins leesbare code.
Eén zo’n tool is dexdump. Een andere handige tool is dex2jar. Beide tools heb ik gebruikt om de werking van de plugin te achterhalen.
$ dexdump -d classes.dex > dump.txt $ d2j-dex2jar.sh classes.dex
dexdump
geeft de volgende output:
0d51ac: |[0d51ac] io.cordova.AtagUser.UdpReceive.startListening:(Lorg/apache/cordova/CallbackContext;Ljava/lang/String;)V 0d51bc: 1a16 4503 |0000: const-string v22, "AtagUser" // string@0345 0d51c0: 1a17 f00e |0002: const-string v23, "Listening" // string@0ef0 0d51c4: 7702 7412 1600 |0004: invoke-static/range {v22, v23}, Landroid/util/Log;.d:(Ljava/lang/String;Ljava/lang/String;)I // method@1274 0d51ca: 2213 7405 |0007: new-instance v19, Ljava/net/DatagramSocket; // class@0574 0d51ce: 1316 f82a |0009: const/16 v22, #int 11000 // #2af8 0d51d2: 0800 1300 |000b: move-object/from16 v0, v19 0d51d6: 0201 1600 |000d: move/from16 v1, v22 0d51da: 7020 a024 1000 |000f: invoke-direct {v0, v1}, Ljava/net/DatagramSocket;.<init>:(I)V // method@24a0 0d51e0: 1316 0100 |0012: const/16 v22, #int 1 // #1 0d51e4: 0800 1300 |0014: move-object/from16 v0, v19 0d51e8: 0201 1600 |0016: move/from16 v1, v22 0d51ec: 6e20 a324 1000 |0018: invoke-virtual {v0, v1}, Ljava/net/DatagramSocket;.setBroadcast:(Z)V // method@24a3 0d51f2: 1316 3075 |001b: const/16 v22, #int 30000 // #7530 0d51f6: 0800 1300 |001d: move-object/from16 v0, v19 0d51fa: 0201 1600 |001f: move/from16 v1, v22 0d51fe: 6e20 a424 1000 |0021: invoke-virtual {v0, v1}, Ljava/net/DatagramSocket;.setSoTimeout:(I)V // method@24a4 0d5204: 1316
Bovenstaande code maakt een DatagramSocket
aan om naar UDP
berichten op poort 11.000 te luisteren. Blijkbaar verstuurt de ATAG One berichten naar het lokale netwerk. Een andere tool met de naam Wireshark luistert naar alle berichten op het lokale netwerk. Dit gebruik ik om te zien wat voor soort berichten de thermostaat verstuurt en wat de inhoud van dit bericht is.
De thermostaat heeft IP 10.0.1.45 binnen het locale netwerk. Onderstaande Wireshark screenshot toont verkeer van en naar IP 10.0.1.45. Elke 10 seconden stuurt de thermostaat een bericht van 37 tekens, met daarin het unieke device id van de thermostaat:
Vind thermostaat in netwerk
De code voor het zoeken naar de thermostaat in het locale netwerk ziet er dan vervolgens in Java als volgt uit:
datagramSocket = new DatagramSocket(11000, InetAddress.getByName("0.0.0.0")); datagramSocket.setBroadcast(true); datagramSocket.setSoTimeout(30000); byte[] receiveData = new byte[37]; final DatagramPacket datagramPacket = new DatagramPacket(receiveData, receiveData.length); datagramSocket.receive(datagramPacket); final InetAddress oneInetAddress = datagramPacket.getAddress(); final String receivedMessage = new String(datagramPacket.getData(), "UTF-8"); if (receivedMessage.startsWith("ONE ")) { String deviceId = receivedMessage.split(" ")[1]; System.out.println("Found at IP: " + oneInetAddress + " device id: " + deviceId); }
Bovenstaande code toont bij uitvoer na maximaal 10 seconden het volgende:
Found at IP: 10.0.1.45 device id: 6808-1401-3109_15-30-001-544
Conclusie
De werking van de ATAG One thermostaat is via de Android App en met de hulp van een aantal tools eenvoudig via reverse engineering technieken te achterhalen.
Een volgende stap is onderzoeken hoe de app rechtstreeks de temperatuur van de thermostaat uitleest en instelt.
One thought on “Hack de ATAG One Android App”