Skip to content
KitploitKITPLOIT
OutilsBlog
Log in
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
CMF-Watch-Pro-2-BLE-Protocol — Protocole BLE rétro-conçu pour la CMF Watch Pro 2, documentant la disposition GATT, les trames de commande chiffrées en AES-128-CBC, l'échange d'authentification et la synchronisation des données de santé pour le développement d'une application compagne alternative. | Kitploit
Outils/GitHubGitHub/joshuapassos/cmf-watch-pro-2-ble-protocol
Sécurité des Systèmes EmbarquésSécurité BluetoothSécurité IoTRétro-ingénierieSécurité Sans FilCryptographieSécurité MobileSécurité Matériel et IoTAnalyse de Micrologiciel

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager
GitHubjoshuapassos/cmf-watch-pro-2-ble-protocol

CMF-Watch-Pro-2-BLE-Protocol

Protocole BLE rétro-conçu pour la CMF Watch Pro 2, documentant la disposition GATT, les trames de commande chiffrées en AES-128-CBC, l'échange d'authentification et la synchronisation des données de santé pour le développement d'une application compagne alternative.

Voir le dépôtSite web
342il y a 2 moisPas encore vérifié

CMF Watch Pro 2 — Protocole BLE (rétro-ingénierie)

Non officiel. Ce document décrit le protocole Bluetooth Low Energy (BLE) de la CMF Watch Pro 2 (CMF by Nothing), reconstruit par rétro-ingénierie pour une application compagnon alternative. Il n'est ni affilié à, ni approuvé par Nothing/CMF. À utiliser à vos propres risques.

Tous les entiers multi-octets dans l'en-tête de trame et les opcodes sont en big-endian. Les entiers à l'intérieur des charges utiles de commande sont en little-endian sauf indication contraire (cela reflète le firmware de l'appareil) — attention aux exceptions (GOALS_SET, GPS_PUSH, décalage/longueur du transfert en masse sont en big-endian).

Marqueurs de confiance

Chaque affirmation non évidente ci-dessous est étiquetée selon la manière dont elle a été établie :

  • ✅ validé sur l'appareil — observé dans une capture en direct déchiffrée ou testé contre une montre réelle.
  • 🔎 issu du firmware / RE de l'APK — extrait par décompilation du firmware (1.0.0.73) ou de l'APK officielle (3.5.7) ; cohérent avec le code mais non testé en conditions réelles.
  • 🟡 partiellement prouvé — établi structurellement (hors ligne, à l'échelle du corpus, ou par RE) mais l'étape restante nécessite la montre et n'a pas été exécutée.
  • ⚠️ [incertain] — déduit, non confirmé ; peut être erroné.

Lorsqu'une section ultérieure corrige une section antérieure, le texte antérieur est conservé avec un renvoi plutôt que supprimé — savoir quelles lectures ont été essayées et réfutées évite à la personne suivante le même détour.

Appareil de test pour toutes les captures : CMF Watch Pro 2-5485, firmware 1.0.0.73, numéro de série CI04102520008192, MCU Actions ATS3089C (Cortex-M4), écran 466×360.


1. Disposition GATT

Le téléphone est le client GATT ; la montre est le périphérique, diffusant sous le nom CMF Watch Pro 2-XXXX (4 caractères hexadécimaux).

ObjectifServiceCaractéristiquePropriétés
Écriture de commande0000fff0-0000-1000-8000-00805f9b34fb0000fff2-…Write
Notification de commande0000fff0-…0000fff1-…Notify
Écriture shell (AT)—77d4ff01-2fe2-2334-0d35-9ccd078f529cWrite
Notification shell (AT)—77d4ff02-…Notify
Écriture de données en masse—02f00000-0000-0000-0000-00000000ffe1Write
Notification de données en masse—02f00000-…ffe2Notify

Activez les notifications en écrivant 01 00 sur chaque CCCD (00002902-…). Le canal de commande (fff1/fff2) transporte le protocole tramé ci-dessous. Le canal shell (77d4…) transporte du texte brut de type AT (par ex. AT GETSECRET ; voir §14). Le canal de données (02f0…) transporte de gros blobs binaires (cadran de montre, firmware, AGPS), coordonnés par des opcodes de contrôle sur le canal de commande.

UUID de services — la montre diffuse ~10 services principaux. Énumérés sur une unité réelle : 0xfff0 (commande), 0x180f (batterie), 0x180a (informations sur l'appareil), 0xefe7, 0xffd0, 02f00000-…ffe0 et 02f00000-…fe00 (données), 77d4e67c-2fe2-2334-0d35-9ccd078f529c (shell / appairage), e49a3001-f69a-11e8-8eb2-f2801f1b9fd1, f48a23c0-f69a-11e8-8eb2-f2801f1b9fd1.

⚠️ L'UUID du service shell est 77d4e67c-…, et non 77d4ff00-…. Les révisions antérieures de ce document supposaient que le service partageait le préfixe ff00 de ses caractéristiques (77d4ff01/77d4ff02, §14) — ce n'est pas le cas, du moins sur l'unité sur laquelle cela a été vérifié (constat issu de freethinkel/fmc, voir §Sources). Les UUID de caractéristiques sont inchangés. Non vérifié si 77d4e67c est stable entre les unités — énumérez plutôt que de coder en dur.

🌐 Remarque Web Bluetooth. Chromium ne découvre jamais que les services que la page a répertoriés dans optionalServices, même pour un appel getPrimaryServices() non filtré — une page répertoriant 3 services en voit 3, tandis que chrome://bluetooth-internals (la couche C++ propre de Chrome, non scopée) affiche les 10. Si vous écrivez un client navigateur, listez chaque UUID ci-dessus à l'avance ou l'appairage échouera avec des services qui existent pourtant clairement. Pas de Web Bluetooth dans Firefox/Safari ; nécessite un geste utilisateur + HTTPS/localhost.

✅ Une session réelle complète s'est déroulée sur le seul canal de commande — lors d'une capture de 160 s en usage intensif, il n'y a eu aucun trafic sur les canaux de données/firmware ou shell, sauf lors d'un transfert explicite OTA/cadran de montre.


2. Format de trame (0xF5)

Chaque message du canal de commande est encapsulé dans une ou plusieurs trames à en-tête de 11 octets :``` +------+-----------+--------+-------------+-------------+--------+-------------------+ | 0xF5 | chunkLen | cmd1 | chunkCount | chunkIndex | cmd2 | chunk bytes … | | 1 B | 2 B (BE) | 2 B BE | 2 B BE | 2 B BE | 2 B BE | chunkLen bytes | +------+-----------+--------+-------------+-------------+--------+-------------------+ __________________________ 11-byte header ____________________________/

- `cmd1`/`cmd2` forment ensemble l'**opcode** (voir §6). 🔎 confirmé par rapport au constructeur de trames
  de l'application officielle (`C6117b.m30831g`).
- `chunkCount` = nombre total de morceaux pour cette commande ; `chunkIndex` est **basé sur 1**.
- `chunkLen` = nombre d'octets de `chunk` dans cette trame.
- Une seule écriture BLE peut être fragmentée par le MTU de la liaison ; le récepteur met en mémoire
  tampon les octets bruts et ré-extrait les trames complètes. Les grandes charges utiles sont divisées
  en plusieurs morceaux (même `cmd1/cmd2`, `chunkIndex` croissant) et réassemblées dans l'ordre.

### Convention d'opcode (✅ confirmé sur le fil)

- `cmd1 = 0xFFFF` : `cmd2` dans `0x80xx`/`0x90xx` = téléphone→montre (requête/définition) ; `0x00xx`/`0xa0xx` =
  montre→téléphone (réponse). Les paires correspondent par l'octet de poids faible (`0x9055`↔`0xa055`, `0x8051`↔`0x0051`).
- `cmd1` spécifique à une fonctionnalité : suffixe `cmd2` = `0x0001` **SET**, `0x0002` **GET**, `0x0003` **ACK**.

### Corps du morceau

Pour chaque morceau, le corps est `payloadPiece ‖ CRC32_LE(payloadPiece)` (CRC 4 octets, petit-boutiste,
zlib/IEEE). Si la commande est **chiffrée** (voir §3), l'ensemble `payloadPiece ‖ CRC` est ensuite
chiffré en AES-128-CBC/PKCS7 et ce texte chiffré devient le `chunk` de la trame.

**Particularité du texte clair :** pour les opcodes en texte clair, la montre *compte* le CRC de 4 octets
dans `chunkLen` mais ne le **transmet** pas. Ainsi, lors du décodage d'une trame en texte clair, la longueur
réelle des données est `chunkLen − 4`. (Les trames chiffrées transportent le CRC à l'intérieur du texte
chiffré comme d'habitude.)

Dimensionnement des morceaux (pour que les morceaux chiffrés tombent sur les limites de blocs AES), avec
`maxWrite = mtu − 3` :
- chiffré : `floor((maxWrite − 11) / 16) * 16 − 4 − 1`
- texte clair : `maxWrite − 11 − 4 − 1`

✅ Toutes les valeurs `chunkLen` observées pour les trames chiffrées étaient des multiples de 16
(l'alignement des blocs est respecté).

---

## 3. Primitives cryptographiques

- **AES-128-CBC** avec remplissage **PKCS7** et un **IV fixe** (issu du firmware
  `CmfCharacteristic.AES_IV`) :
  `50 51 52 53 54 55 56 57 60 61 62 63 64 65 66 5A`.
- **CRC32** (zlib/IEEE), émis sous forme de 4 octets petit-boutistes.
- **SHA-256** sur la concaténation des parties.
Télécharger l’outil