Balise BLE : scanner et décoder le Bluetooth Low Energy
Balise BLE pour débutant : comprendre le Bluetooth Low Energy, lire une trame d'advertising, décoder iBeacon et Eddystone avec nRF Connect, Wireshark, Python.
Une balise BLE est un petit émetteur Bluetooth Low Energy qui répète en boucle un court message, une « trame d'advertising », que n'importe quel smartphone peut capter sans se connecter. Pour la décoder, il suffit d'un téléphone avec l'application nRF Connect, puis, pour aller plus loin, de Wireshark ou de quelques lignes de Python. Ce guide explique ce que contient une trame et comment lire les deux formats de balise les plus courants, iBeacon et Eddystone, sur votre propre matériel.
Une cible d'entraînement simple : une balise BLE du commerce, un ESP32 (une carte microcontrôleur à quelques euros avec Bluetooth intégré) programmé en balise, ou l'option d'émission de certaines applications Android.
BLE vs Bluetooth classique
Le Bluetooth Low Energy (BLE) est arrivé avec la version 4.0 de la norme Bluetooth. Il partage la même bande de fréquences que le Bluetooth classique, celle des 2,4 GHz, mais c'est un protocole différent, pensé pour des usages opposés.
| Bluetooth classique | Bluetooth Low Energy | |
|---|---|---|
| Usage typique | Casque audio, enceinte, voiture | Montre, capteur, tracker, balise |
| Canaux | 79 canaux de 1 MHz | 40 canaux de 2 MHz, dont 3 d'advertising |
| Débit | Continu, pour l'audio | Petits paquets, par intermittence |
| Consommation | Batterie rechargeable | Des mois, voire des années sur pile bouton |
| Découverte | Appairage | Annonces diffusées à tous (advertising) |
La notion clé du BLE est l'advertising : un appareil annonce régulièrement sa présence sur trois canaux réservés, numérotés 37, 38 et 39 (2402, 2426 et 2480 MHz). Un smartphone qui scanne écoute ces trois canaux. Une balise ne fait que ça : elle n'attend aucune connexion, elle diffuse.
Anatomie d'une trame d'advertising
Une trame d'advertising BLE « classique » (dite legacy) ressemble à ceci, simplifiée :
┌────────────┬────────────┬────────┬──────────────┬────────────────────┬─────┐
│ Préambule │ Adresse │ En-tête│ Adresse de │ Données d'annonce │ CRC │
│ 1 octet │ d'accès │ PDU │ l'appareil │ 0 à 31 octets │ │
│ │ 8E89BED6 │ │ 6 octets │ │ │
└────────────┴────────────┴────────┴──────────────┴────────────────────┴─────┘
Ce qui vous intéresse se trouve dans les 31 octets de données d'annonce. Ils sont découpés en blocs « AD structures », chacun au format longueur, type, valeur :
02 01 06 → longueur 2, type 0x01 (Flags), valeur 0x06
1A FF 4C 00 02 15 … → longueur 26, type 0xFF (données fabricant)…
Les types les plus courants :
| Type | Signification |
|---|---|
0x01 | Flags : mode de découverte de l'appareil |
0x09 | Nom complet de l'appareil |
0x03 | Liste de services (UUID 16 bits) |
0x16 | Données de service (UUID 16 bits suivi de données) |
0xFF | Données propres au fabricant (identifiant fabricant de 2 octets, puis données libres) |
Deux remarques utiles. D'abord, 31 octets, c'est peu : tous les formats de balise sont des exercices de compression. Ensuite, l'adresse de l'appareil n'est pas toujours fixe : les smartphones et beaucoup d'objets récents utilisent des adresses aléatoires qui changent régulièrement, précisément pour limiter le pistage. Une balise, au contraire, garde souvent la même adresse, puisqu'elle est faite pour être reconnue.
Les outils : nRF Connect, Wireshark, bleak
nRF Connect for Mobile
L'application gratuite de Nordic Semiconductor, un fabricant de puces BLE, existe sur Android et iOS. L'onglet Scanner liste les appareils à portée avec leur puissance reçue (RSSI, en dBm) et, en touchant une ligne, affiche les données d'annonce brutes et décodées. C'est l'outil idéal pour commencer.
Une limite à connaître : iOS ne transmet pas les trames iBeacon aux applications Bluetooth génériques. Pour étudier une balise iBeacon, utilisez Android ou un ordinateur.
Wireshark
Wireshark, l'analyseur de trafic réseau de référence, sait décoder le BLE. Deux façons de lui fournir des trames :
- Capturer l'interface Bluetooth de votre propre ordinateur sous Linux : vous voyez ce que votre adaptateur reçoit et envoie, ce qui suffit pour les annonces.
- Utiliser un renifleur dédié, comme le nRF Sniffer for Bluetooth LE de Nordic sur une clé nRF52840, pour capter les trames radio directement.
Pour un débutant, la première option suffit largement.
bleak (Python)
bleak est une bibliothèque Python open source qui fonctionne sous Linux, macOS et Windows. Elle permet d'écrire votre propre scanner en quelques lignes, et donc de comprendre chaque octet.
python -m pip install bleak
Décoder iBeacon et Eddystone sur votre propre balise
iBeacon
Le format iBeacon, défini par Apple, se loge dans les données fabricant (type 0xFF) avec l'identifiant fabricant d'Apple, 0x004C. Les octets qui suivent :
| Octets | Champ | Rôle |
|---|---|---|
| 1 | 0x02 | Type iBeacon |
| 1 | 0x15 | Longueur restante : 21 octets |
| 16 | UUID | Identifiant de l'organisation ou du déploiement |
| 2 | Major | Groupe (par exemple un bâtiment) |
| 2 | Minor | Balise précise (par exemple une salle) |
| 1 | Puissance mesurée | RSSI attendu à 1 mètre, en dBm signé |
Une balise iBeacon ne transmet donc que des identifiants. C'est l'application qui sait que « UUID X, major 3, minor 12 » correspond au rayon fromages d'un magasin.
Eddystone
Eddystone, le format ouvert lancé par Google, utilise les données de service (type 0x16) avec l'UUID de service 0xFEAA. Le premier octet indique le type de trame. Le projet est archivé depuis fin 2022, mais sa spécification reste en ligne et beaucoup de balises le parlent encore.
| Octet de type | Trame | Contenu |
|---|---|---|
0x00 | UID | Espace de noms de 10 octets et instance de 6 octets |
0x10 | URL | Une URL compressée |
0x20 | TLM | Télémétrie : tension de pile, température, compteurs |
0x30 | EID | Identifiant chiffré qui change périodiquement |
La trame URL est un joli exercice de décodage : un octet code le préfixe (0x00 pour http://www., 0x01 pour https://www., 0x02 pour http://, 0x03 pour https://) et certains octets remplacent des suffixes courants (0x00 pour .com/, 0x07 pour .com, etc.).
Un scanner en Python
Ce script écoute pendant 10 secondes et décode les trames iBeacon et Eddystone. Lancez-le à côté de votre balise.
import asyncio
import struct
from bleak import BleakScanner
APPLE_ID = 0x004C
EDDYSTONE_UUID = "0000feaa-0000-1000-8000-00805f9b34fb"
async def main():
found = await BleakScanner.discover(timeout=10.0, return_adv=True)
for address, (device, adv) in found.items():
apple = adv.manufacturer_data.get(APPLE_ID)
if apple and len(apple) >= 23 and apple[0] == 0x02 and apple[1] == 0x15:
uuid = apple[2:18].hex()
major, minor = struct.unpack(">HH", apple[18:22])
power = struct.unpack("b", apple[22:23])[0]
print(f"iBeacon {address} uuid={uuid} major={major} "
f"minor={minor} power@1m={power} dBm rssi={adv.rssi}")
eddy = adv.service_data.get(EDDYSTONE_UUID)
if eddy:
frame = {0x00: "UID", 0x10: "URL", 0x20: "TLM", 0x30: "EID"}.get(eddy[0], "?")
print(f"Eddystone-{frame} {address} data={eddy.hex()} rssi={adv.rssi}")
asyncio.run(main())
Quelques pistes pour progresser avec ce script :
- Comparez le RSSI reçu à la puissance mesurée annoncée en vous éloignant de la balise : vous obtenez une estimation grossière de la distance, et vous verrez vite pourquoi elle est si imprécise à l'intérieur.
- Écrivez la fonction qui reconstruit l'URL d'une trame Eddystone-URL.
- Changez le major et le minor de votre balise et vérifiez que votre décodeur suit.
Sous macOS, le système peut lui aussi masquer les trames iBeacon : si votre balise n'apparaît pas, testez sous Linux ou Windows.
Et les balises des autres ?
Votre scanner affichera aussi les appareils de vos voisins : montres, écouteurs, téléviseurs. Écouter ces annonces publiques est passif, c'est ce que fait en permanence votre téléphone. Mais l'exercice s'arrête là : ne vous connectez pas à un appareil qui n'est pas le vôtre, ne modifiez pas ses données, et ne cherchez pas à suivre une personne grâce aux annonces de son matériel. Pour vos expériences, votre propre balise suffit.
Pour aller plus loin : le défi BLE Beacon Decode
Une fois iBeacon et Eddystone maîtrisés, la suite logique est une balise dont le message n'est pas en clair. C'est le principe de notre puzzle BLE Beacon Decode Challenge : une balise de la taille d'une carte, alimentée par une pile CR2032, diffuse un message à décoder en trois niveaux honnêtement étiquetés. Un smartphone suffit pour le premier niveau, un ordinateur devient utile pour les suivants, rien n'est à souder, et la solution officielle est publiée 60 jours après la livraison.
Le puzzle est prévu pour l'été 2027 au prix de 32 € : inscrivez-vous sur la liste d'attente depuis sa page ou depuis notre page puzzles CTF. D'ici là, si le format « défi » vous plaît, notre guide C'est quoi un CTF en cybersécurité ? vous indique où vous entraîner, et notre article débuter le hacking matériel situe le BLE parmi les autres disciplines.
Questions fréquentes
Bluetooth Low Energy, c'est quoi ?
Une variante du Bluetooth apparue avec la version 4.0, conçue pour consommer très peu. Elle sert aux montres, capteurs, trackers et balises qui tiennent des mois sur une pile bouton. Elle partage la bande des 2,4 GHz avec le Bluetooth classique mais n'est pas compatible avec lui.
Pourquoi mon iPhone ne voit-il pas ma balise iBeacon dans nRF Connect ?
iOS ne transmet pas les trames iBeacon aux applications Bluetooth génériques. Pour observer une balise iBeacon, utilisez un téléphone Android ou un ordinateur sous Linux ou Windows.
Est-il légal de scanner les balises BLE autour de moi ?
Écouter les annonces publiques que diffusent les appareils est une opération passive, et c'est ce que font en permanence tous les smartphones. En revanche, se connecter à un appareil qui n'est pas le vôtre, modifier ses données ou suivre une personne grâce à son matériel n'est pas acceptable. Faites vos essais sur vos propres balises.