Now that I've examined the GATT for the bulb and hit a dead end, I'll capture packets from the light bulb's control application to understand how it controls the bulb. This is possible using a BLE sniffer like the Bluefruit LE sniffer that's based on a Nordic nRF51822 chip. Using a special firmware and tools from Nordic I can watch the BLE commands sent to the bulb to change its color. Nordic's sniffing tool even allows the use of Wireshark, a powerful and popular packet analysis tool, to examine the traffic.
If you're doing your own BLE device sniffing with the Bluefruit LE sniffer, make sure to read the guide on its usage first as it explains how to install and setup the software. In my case I'll be using Nordic's tool on Windows as it lets me directly see the data in Wireshark.
One thing to note, after you've finished examining the GATT for a device be sure to disconnect or turn off any applications which were connected to the light bulb. BLE only allows one connection to a device at a time, and if you leave a GATT control app running then you won't be able to run the sniffer or other things that talk to the bulb!
First I begin by plugging in the Bluefruit LE sniffer and running's Nordics's sniffer application. After a few moments the tools scans and lists all available BLE devices. Notice the device it finds has the same address for the light bulb that I saw earlier while exploring its GATT--this helps me know I'm looking at the correct device:
Then I press 0 to select device zero in the list and then press w to start Wireshark with the packet capture.
One thing to note before you sniff BLE traffic with the Bluefruit LE sniffer is that it can be sensitive to noise from other BLE devices. Try to turn off all the other nearby BLE devices like tablets, phones, etc. Also be sure as few programs as possible are running on your PC becuase the tool needs to grab data from the Bluefruit sniffer as quickly as possible to prevent dropping packets.
Once Wireshark loads I quickly see a flood of advertising packets like:
If you haven't used Wireshark before the interface can be a little daunting. I recommend reading the official documentation and watching videos on using it to get a quick overview of the tool. At a very high level Wireshark's main window shows you three things:
- The top third is the list of packets that have been captured. When wire shark is capturing packets this list will quickly grow. You can scroll up and down to see packets as they've been received, and you can click a packet to see more information about it.
- The middle third is information that's been decoded from the packet. You can drill in to specific frames inside the packet to see what it's doing. Think of a network packet kind of like an onion, where you have layers of information that get more detailed as you peel them back and look deeper into the packet.
- The bottom third is the raw hexadecimal and ASCII representation of the packet data. It's interesting to note that as you click around information in the middle pane you can see highlighted the raw representation in the bottom pane.
In the picture above I've selected a BLE advertising packet and highlighted a few interesting details in the middle pane. You can see this packet is coming from the light bulb since it has the same address for the bulb that I learned earlier from exploring its GATT. You can also see the advertisement packet includes a few of the services I saw earlier that the bulb exposes.
Now it's time to load the bulb's control application and see what happens when I change the bulb's color. I loaded up the control app on an iOS device (note: for some reason I couldn't capture packets from the Colorific! Android application--my suspicion is the app might be generating packets that are malformed or confusing the nRF sniffer), found the bulb, and changed the bulb's color a few times. As I did this I saw small bursts of interesting packets scroll by in Wireshark. Unfortunately the continuous stream of other BLE communication packets added a lot of noise that made it difficult to focus on just the bulb control packets. However Wireshark has a great capability for filtering packets that I can use to help focus on on just the control packets.
To filter the packets I first stopped the capture of packets by pressing the red square stop button in Wireshark's toolbar. This is also a good point to save the capture file so it can be examined again without having to sniff device traffic.
Once the capture stopped I scrolled through the packet list and found some interesting packets under the ATT protocol. These are packets which contain commands for reading and writing BLE characteristics and are what I need to examine in more detail. To filter out all the other packets I entered the expression 'btl2cap.cid == 0x0004' (without quotes) in the filter box below the toolbar, then pressed enter. Wireshark immediately hid all the other packets and just showed me the ATT packets:
Another way to filter to just the ATT packets is to select an ATT packet and drill into the Bluetooth L2CAP Protocol in the middle pane. Click the CID: Attribute Protocol (0x0004) line to select that part of the packet which identifies it as an ATT packet, then right click and choose the Apply as Filter -> Selected menu item. This will set the filter expression to only show packets with that exact attribute protocol value.
I can now restart packet capture with the filter applied and see only the ATT packets and none of the other BLE packet noise. This is great because it removes the packets I don't care about and lets me easily see the packets that matter.
As I changed the color of the bulb in the app I saw BLE characteristic write commands like the picture above shows. Notice the parts of the packet I've highlighted which show the handle that identifies the characteristic being updated, and the value which are the bytes to use as the new value of the characteristic.
Now that I can see the packets associated with a color change I can try to reverse engineer what the bytes inside the packet mean. Reverse engineering can be more of an art than a science as it helps to have intuition and experience with what you're trying to reverse engineer. Unfortunately there is no fool-proof process for reverse engineering any device!
In this case I know the application is probably sending the bulb a new color, and colors are typically represented in a few common ways like as a 24-bit value (with 1 byte/8 bits for each red, green, and blue component), a floating point value for each color component, or perhaps even a string or ID that identifies the color inside a palette or lookup table. If I'm really unlucky the color information might be encoded or even encrypted in some way that I can't decipher--there is no guarantee I will be able to figure out the protocol!
I started by comparing the value of multiple color change packets to see how they differed. These are the values I saw (in hexadecimal):
Do you see a pattern? The first few bytes are exactly the same and only the last 3 bytes are changing. I know a 24-bit representation of color with a byte for each red, green, and blue component is quite common so could these last three bytes be the color of the bulb? Let's look at the colors if I assume the first changing byte is red, the second is green, and the third is blue:
Aha! I can see these color values are the red, green, blue, and orange colors that I had sent to the bulb with its control application! By just looking at a few packets it's trivially easy to reverse engineer this bulb's protocol. It appears that sending a write to the characteristic with handle 0x0028 and providing a value that starts with 0x58010301FF00 and ends with a byte for the red color, green color, and blue color will change the bulb's color.
Before I get too excited about this discovery I need to replicate it myself to confirm the protocol works as I suspect. What the 6 bytes in front of the color represent are a complete mystery and might complicate understanding how the protocol works. Are they a static value that uniquely identifies this write as a color update, could they be a magic value like a session ID the bulb told the app to send ahead of time, or perhaps something else entirely? Trying to replay one of the captured packets myself will help me confirm if I've really figured out the protocol.
Continue on to learn how to use the bluez Bluetooth stack to send BLE packets to the bulb.