Dies ist eine alte Version des Dokuments!


Jawbone Up Move

Jawbone Up Move ist ein Fitness-Tracker von der 2017 pleite gegangenen Firma Jawbone. Es enthält Bewegungssensoren und hat einen Knopf auf der Vorderseite, hinter dem sich 14 LEDs befinden. Damit lassen sich lustige Animationen anzeigen.

Da die Dinger an einen Onlinedienst gebunden sind den Jawbone natürlich nicht mehr weiterbetreibt, sind sie jetzt quasi Elektroschrott. Wir haben ein paar davon und wollen mal schauen, was man damit noch so machen kann.

Es gibt noch ein HedgeDoc mit weiteren interessanten (low-level-) Infos. [von wem?]

Anmerkung der Redaktion: Leider macht Dokuwiki Doppelstriche zu langen Einzelstrichen, was die Kommandos kaputtmacht. Sorry!

Ziele

  • Bluetooth-Kommunikationsprotokoll verstehen und sprechen lernen
  • Firmware-Update mit eigener Firmware

Zwischenbaustellen

  • App auseinandernehmen
  • App wieder in Betrieb nehmen (patchen oder API nachbauen)
  • Protokoll zwischen App und NRF8001 verstehen (App beobachten)
  • Protokoll zwischen MSP430 und NRF8001 verstehen (wie tut man den MSP in den DFU-Modus? App beobachten)
  • MSP430 programmieren lernen (inkl. Peripherie)

Mögliche neue Verwendung

  • Fitness-Tracker :- ) - Vielleicht kann man sie einfach mit ihrem Originalzweck weiter benutzen.
  • Irgendeine andere Art von Bewegungstracker (Türsensor, Alarmanlage)
  • Fernsteuerknopf (dafür besonders cool: Es gibt die Dinger in verschiedenen Farben und Mustern, man kann also mehrere auseinanderhalten. Außerdem lassen sich durch die LEDs besonders komplexe Interaktionen realisieren)
  • Airtag-Klon (z.B. mit )
  • Bluetooth LE-Experimentierplattform
  • Irgendein Akteur: Man hat schließlich 14 Ausgänge auch UART, USB und mehr
  • Irgendeine Anzeige (die LEDs blinken doch nett)

Hardware

Das Move Up hat den Modellnamen V3J-JL06, details gibt es dazu bei fccid.io.

Es kommuniziert mit dem Handy des Nutzers per Bluetooth Low Energy (LE) 4.0. Die App und das FCC-Filing deuten darauf hin, dass das Gerät einen Firmware-Update-Modus hat.

Unter der schwarzen Klebefolie befinden sich ganz schön viele Testpunkte. Die zu identifizieren könnte viel bringen: Vielleicht befinden sich darunter UART-Schnittstelle & Co.

Die Hauptkomponenten des Up Move sind, wie auf den FCC-Bildern zu erkennen, ein Nordic Semiconductor NRF8001D und ein Texas Instruments M430F5528/MSP430F5528 („MSP430“).

MSP430
NRF8001

Herstellerseite Datenblatt

Ganz interessant ist an dem Gerät, dass es nicht umprogrammierbar ist.

Offizielle App

Man kann die offizielle App untersuchen, um das Kommunikationsprotokoll zu verstehen. Einerseits durch eine statische Analyse (z.B. Dekompilation per jadx), andererseits durch eine Dynamische: Sie einfach mal benutzen und schauen, was sie tut.

Leider funktioniert die offizielle App (com.jawbone.up, nicht die neue com.jawbone.upopen!) nicht über die Kopplung hinaus, sie will immer, dass man einen Account erstellt. Geht natürlich nicht. Man müsste sie also patchen. Das hätte den Vorteil, dass man sie vielleicht auch einfach mit ihrem Originalzweck nutzen könnte.

Vielleicht kann man ihr gegenüber per mitmproxy Jawbone-Server spielen und ihr ein valides Benutzerkonto vortäuschen. Dieses könnte man dann vielleicht auch auf anderen Apps benutzen. Funktioniert nur (gut), wenn die App nicht ständig versucht, sich mit dem Server zu verbinden (könnte man in Erfahrung bringen: Können Leute, die sich irgendwann mal eingeloggt haben, die App noch benutzen?).

Spätestens dann müsste man über richtiges Patching nachdenken, z.B. per Xposed-Modul (was sich auch mithilfe verschiedener Werkzeuge anwenden ließe, ohne dass man Xposed/LSPosed installiert haben muss).

Dekompilieren

Mit jadx up.apk –export-gradle –deobf -d up-decompiled. –deobf sorgt dafür, dass gekürzte Bezeichner (wie gz.a) durch zwar genau so kryptische, aber wenigstens einfacher Suchbare ersetzt werden. –export-gradle sorgt dafür, dass ein Gradle-Projekt erstellt wird. Noch ist das nicht besonders nützlich, da es sowieso nicht kompiliert, aber vielleicht lässt sich das irgendwann mal schaffen.

Ein Codename des Up Move ist wohl „Pele“ (weitere: UP: Armstrong, UP24: Pottier, UP2: Spitz, UP3: Thorpe, UP4: Phelps/Sky, UPX: Deion).

Die interessantesten Sachen für die BLE-Kommunikation scheinen in com.jawbone.ble.common und com.jawbone.ble.sparta zu sein. Potenziell interessante Klassen sind: OtaService (ganz viele magische Werte), DeviceInfo, JawboneDevice, SpartaDevice, C2994gs, C3223mz (enthalten characteristic und service-UUIDs), C2988gn (fpabl.AndroidWirelessBandManager, macht grundlegende BLE-Sachen).

Die interessanteste Klasse für's Login ist wohl ''com.jawbone.p006up.oobe.SignInActivity''. Dort wird in der Methode ''mo6922b'' die Antwort auf einen Loginversuch verarbeitet. Gibt es keine Fehler, wird der Benutzer in die lokale Datenbank eingetragen. Interessant ist die Fehlerbehandlung. Hier wird bei einem generischen Fehler "Email or Password cannot be validated. Please try again" (bzw. "E-Mail-Adresse oder Passwort konnten nicht bestätigt werden. Bitte versuche es noch einmal.") ausgegeben - allerdings auch, wenn tatsächlich vom Server eine Verweigerung kommt. Das sind unterschiedliche Codepfade, die sich darin unterscheiden, dass der Dialog im ersten Fall mit ''materialAlertDialogBuilder.setNeutralButton'' und im zweiten Fall mit ''materialAlertDialogBuilder.setPositiveButton'' gebaut wird. Kann man da einen Unterschied erkennen?

Die Klasse ''com.jawbone.p006up.datamodel.Login'' enthält die Daten für einen Loginversuch: Eine ID für die Session (''session_uid'') und einen User, sowie Konstanten für Fehlerzustände (''AUTH_FAIL'', ''INVALID_EMAIL'', ''INVALID_PASSWORD''). Außerdem hat die Klasse einen Builder.

Die Klasse ''com.jawbone.p006up.datamodel.User'' ist deutlich weniger überschaubar, da hier wohl so gut wie alle Nutzerdaten gespeichert sind. Die Klasse enthält scheinbar auch Methoden für die Nutzerverwaltung (''saveUser'', ''getCurrentUser'', ''setCurrentUser'').

Mitm

Da die App als targetSdkVersion 22 hat, haben wir noch nicht das Problem, dass sie nutzerinstallierten Zertifikaten nicht vertraut. Ab API Version 24 wäre das so, dann müssten wir die App dafür patchen.

Für's Login sendet die App einen POST-request an https://api-android.jawbone.com/nudge/api/v.1.59/users/login.

Mit mitmproxy https://github.com/mitmproxy/mitmproxy/ und einem einfachen Skript lassen sich hoffentlich die API-Antworten spoofen, die richtige Antwort ist allerdings noch unklar. Ein Beispielskript dafür sieht so aus:

up-api.py
from mitmproxy import http, ctx
 
def request(flow: http.HTTPFlow) -> None:
    if flow.request.pretty_host == "api-android.jawbone.com":
        res = b"""
{}
        """
 
        flow.response = http.Response.make(
            200,
            res,
            {"Content-Type": "application/json"}
        )

Das lässt sich ausführen mit mitmdump –set connection_strategy=lazy -s up-api.py. 1)

Die von Eric Blue dokumentierte API-Antwort funktioniert scheinbar nicht; ist wohl einfach veraltet. Schade.

Testpunkte

Man kann vielleicht über die Testpunkte das Kommunikationsprotokoll zwischen NRF-und TI-Modul in Erfahrung bringen.

Kommunikation zwischen Handy und Up Move

Man kann, z.B. per HCI Snoop Log mitlesen, was die Android-App macht. Man kann auch, z.B. mit Btlejack, eine bestehende Verbindung für sich übernehmen (das könnte für's Testen momentan am Einfachsten sein, da das Koppeln mit dem Handy ja funktioniert). Für's Mitlesen müsste man leider die App zum Laufen bringen.

Analyse mit nRF connect

Man kann das Gerät ganz gut untersuchen, indem man es erst in den Koppelmodus versetzt (Batterie raus, Knopf drücken), sich per nRF connect damit verbindet und es dann mit der App koppelt.

photo_2022-05-25_18.47.45.jpeg

Das Up Move bietet 4 Bluetooth-Dienste an: 0x1800 (Generic Access mit Device Name = „Up Move“), 0x1801 (Generic Attribute, leer), f7c9ba7e-6658-4390-b53c-1de5e1453654 (Unbekannt), 0x180A (Device Information, Manufacturer Name String = „Jawbone“, Firmware Revision String = „4.0.27“, Model Number String = „UP Move“). Besonders interessant dürfte der unbekannte Dienst sein. Dieser scheint auch beim Up 24 präsent zu sein.

Der Großteil der Kommunikation findet wohl über die erste Characteristic mit der UUID f7c9b162-6658-4390-b53c-1de5e1453654 statt. Dort schreibt das Gerät immer mal wieder Dinge hinein.

Die zweite Charakteristic sieht weniger häufig Kommunikation, auffällig ist, dass sie bei einem langen Druck auf den Knopf (Wechsel zwischen Tag- und Nachtmodus) zwischen (0x) 20-0D-01-02 respektive (0x) 20-0C-01-02 wechselt (bei der Kopplung stand dort allerdings ein anderer Wert).

Bei einem Bonding-Versucht terminiert das Up Move die Verbindung, schickt hinterher aber weiter Daten. Generell schickt das Gerät nach einem langen Knopfdruck viele Nachrichten, ungerfähr 30 Sekunden lang. Nach einem einfachen oder doppelten (oder mehr) kurzen Knopfdruck kommt nichts. Das Gerät reagiert auf den Bonding-Versuch auch, während es scheinbar schläft (Versuch 1). Das scheint allerdings auch nicht immer zu funktionieren (Versuch 2). Nach einigen Versuchen kann es zu Error 8 (0x8): GATT CONN TIMEOUT kommen.

Verbindung ohne Pairing

Wenn man sich mit der nRF Connect app mit dem Gerät verbindet bevor es mit der UP-App gekoppelt ist, lässt sich zwar über die bekannten (Standard BLE-)Charakteristiken darauf zugreifen, das Gerät bricht die Verbindung aber nach 10-15 Sekunden ab. Auf eine neue Verbindungsanfrage reagiert es erst, wenn man auf den Knopf drückt.

Kommunikation zwischen Bluetooth-Modul und CPU

Man kann davon ausgehen, dass der TI-Chip die stromsparende Datensammlung übernimmt, während der NRF-Chip hin und wieder für die Bluetooth-Kommunikation aufgeweckt wird.

Die beiden kommunizieren über das von Nordic Semiconductor erfundene „Application Controller Interface“ (ACI), welches auf einer höheren Schicht arbeitet als das Host Controller Interface (HCI), dafür aber nicht standardisiert ist. Allerdings gibt es dafür Bibliotheken.

Man kann es sich wohl so vorstellen, dass die Kommunikation mit dem NRF8001 zum größten Teil einfach direkt an den TI-Chip durchgeschleift wird. Die große Ausnahme dürfte das Firmware-Update sein, der TI-Chip muss ja irgendwie in den Update-Modus versetzt werden (wobei das theoretisch auch per roher Kommuniation möglich wäre).

1)
connection_strategy=lazy ist wichtig, da mitmproxy sonst versucht, sich mit dem Originalserver zu verbinden und einen Verbindungsfehler wirft. Das sieht dann so aus:
client connect
error establishing server connection: [Errno 8] nodename nor servname provided, or not known
CONNECT api-android.jawbone.com:443
<< 502 Bad Gateway 101b
client disconnect