Reverse Engineering PixMob LED Concert Bracelets Part One
Introduction
Firstly, I want to share a bit of background on how this project began. Before this, I had virtually no understanding of microcontrollers or low-level communication protocols like I²C and SPI. My unexpected dive into hardware hacking started at a Taylor Swift concert, which I was dragged to attend. Each attendee was handed a wristband upon entering the arena. Initially, these wristbands were dark; a plastic tag kept the coin cell battery from powering the device. Removing it proved anticlimactic—the show hadn’t even begun, so I realized I’d just have to wait.
The wristbands seemed simple at first: a pair of coin cell batteries, two LEDs, and an inert white plastic cover that had the word “PIXMOB” marked at the bottom. But as the concert began, they transformed into a stunning display of light, perfectly synchronized across thousands of people around the arena. My curiosity was sparked; what was the secret behind controlling these devices?
Was it sound? That seemed too unpredictable for the precise patterns I saw, since at one point they lit up in a perfect heart shape. Radio Frequency (RF) signals came to mind next, but how could RF manage such detailed control?
To test my theories, I hid my wristband under my seat. It didn’t light up with the others, which was my first clue. That’s when it hit me—the wristbands weren’t using RF; they were controlled by infrared signals. This realization set me off on a journey to explore the tech behind these devices.
Replay Attacks with a Flipper Zero
After the concert, the first thing I did was look up “PixMob”—the name printed on the back of the wristband—to learn more about these bracelets. During my search, I came across a GitHub repository by Dani and Sean. Their work showcased efforts to reverse engineer the IR communication used in PixMob bracelets, providing valuable insight into how these devices operate.
On the GitHub repository, I found some Flipper Zero .sub
files in the raw_wild_ir_captures folder. These were IR signal captures from similar live events where Pixmob bracelets were used. I downloaded some of these files and decided to test them on the bracelets I had from the concert. They actually worked to my surprise! 😁 I was able to cycle through the different captures and the wristband lit up with various patterns and colour effects, replicating the concert experience. This was a significant breakthrough, as it confirmed that the IR signals were indeed controlling the bracelets and that I could potentially replay these signals to create custom light shows.
The Teardown and Investigation
Cracking open the plastic case to uncover its inner workings, I found a compact printed circuit board (PCB) powered by two 3V CR1632 button cell batteries, a common choice for low-power devices. The board contained a few interesting components at first glance.
Notably, there were two RGB LEDs (labeled LED01 and LED02) that provide the vivid light effects you see from the outside. These LEDs are controlled via a microcontroller (MCU), which serves as the smarts of the bracelet. Unfortunately, the microcontroller on this board had no visible markings, making identification tricky.
In addition to the MCU, the PCB featured an infrared (IR) receiver, identified as IR1, which enables the bracelet to receive remote commands. There were also resistors and capacitors scattered across the board, likely for stabilizing and filtering power or signals.
A small 5-pin SMD component stood out. After examining its markings 24C02 and searching online for the numbers printed on the component, I identified it as an AT24C02 EEPROM, a 2K EEPROM chip that likely stores configuration data or settings for the bracelet.
The LEDs appeared to be driven by transistors or FETs, controlled by the MCU to create the dynamic lighting effects. This configuration allows for precise control over brightness and colour. The combination of these components illustrates a clever design optimized for low-cost production while delivering a captivating user experience.
To gain a better understanding of the bracelet’s operation, I decided to focus on the EEPROM. My investigation revealed interesting details about its connections and potential uses, which we will explore in the next section.
The EEPROM
In this first part of the blog series, we will focus solely on the EEPROM component, as it was the easiest to uncover and understand during my initial investigation. Using a multimeter and the AT24C02 EEPROM datasheet, I was able to trace several key connections on the PCB and determine how the microcontroller (MCU) communicates with the EEPROM.
The datasheet provided crucial information about the pinout of the EEPROM, helping me identify the purpose of each pin. With this guidance, I traced the paths for essential signals such as SCL
(clock) and SDA
(data), which connect the EEPROM to specific pins on the MCU, revealing the I²C communication protocol in use. This protocol is critical for exchanging data between the MCU and the EEPROM, likely including the configurations that determine how the bracelet responds to the IR signals I experimented with earlier.
I also traced the power (VCC
) and ground (GND
) connections supplying the EEPROM with its operating voltage. The WP
(write-protect) pin, as indicated in the datasheet, was tied to the power rail, showing that write protection was not enabled on this device. This suggests that the EEPROM is writable, opening up the possibility of altering the existing data on there to influence the bracelet’s behavior.
By understanding how the EEPROM connects to the MCU and its role in storing configuration data, it became clear that this component is vital to the bracelet’s functionality. Near the end of this blog series, we will explore writing to the EEPROM and modifying its structure to better understand how changing the values stored in it directly affects the behavior and patterns displayed by the LEDs.
Understanding Digital Signals
Before I talk about what I²C is and the role it plays in communication between components, it’s important to briefly understand how digital signals work. Digital signals represent information using discrete states—typically represented as 0
and 1
—which are fundamental to how microcontrollers and other digital systems operate.
You can think of digital signals as a series of on/off switches. For example, a 0
might represent an off state (no voltage), while a 1
represents an on state (voltage applied). These sequences of 0
s and 1
s are used to encode data, making it possible for devices like microcontrollers to process and exchange information.
My explanation here is a very simplified version so for a more detailed explanation, you can check out the Digital Signal Wikipedia page. This foundational concept will help make sense of the data exchange happening over the SDA
and SCL
lines in the I²C protocol.
Now that we have a basic understanding of digital signals, let’s dive into the I²C protocol and how it enables communication between peripherals on a microcontroller.
I2C Protocol
Naturally, I was curious about the data stored on this tiny component. According to the datasheet, communication with it required using a protocol called I²C. Before this project, I had never worked with serial communication protocols like I²C; my knowledge was limited to more common ones like USB or FireWire.
I²C (Inter-Integrated Circuit) is a serial communication protocol used to communicate with peripherals on a microcontroller. It was developed by Philips Semiconductors in the 1980s and has since become a widely adopted standard. I²C is a simple, two-wire protocol that uses a single data line SDA
and a single clock line SCL
to transmit data between devices.
The protocol is designed to be efficient and easy to implement, making it a popular choice for embedded systems. As I’ve been learning more about it, I’ve found that I²C devices are connected to the I²C bus using pull-up resistors, which ensure that the data lines are in a high state when no device is driving them. This allows multiple devices to share the same bus without interfering with each other.
The I²C bus can support multiple devices, each with a unique address. The MCU initiates communication with a device by sending a start condition on the SCL
line, followed by the device’s address and a read or write bit. I found it pretty cool that the addressed device then acknowledges by pulling the SDA
line low, creating a handshake of sorts between the master and the slave device.
Once this handshake is complete, the MCU can send or receive data on the SDA
line, with the SCL
line providing the clock signal to synchronize the communication. The process ends with a stop condition, defined as a high-to-low transition on the SCL
line while the SDA
line is high. Understanding these steps made me realize just how methodical and robust this protocol is.
I²C supports various speeds, including standard mode (100 kHz), fast mode (400 kHz), and fast mode plus (1 MHz). It also allows for different addressing modes, such as 7-bit and 10-bit addressing, as well as data transfer modes like byte and block transfer. These features make it adaptable to a wide range of use cases, from simple sensors to more complex peripherals.
It’s no surprise that I²C is commonly used to communicate with sensors, memory devices, and other peripherals in embedded systems. Its versatility and efficiency have made it a staple in the world of microcontrollers and embedded devices. As I dive deeper into this protocol, I’m starting to see why it’s so widely supported and valued.
The Bus Pirate
Now that you have a better understanding of I²C, we can move on to the next step in this journey: reading data from the EEPROM. To achieve this, I’ll need a tool capable of communicating with I²C devices. One such tool is the Bus Pirate, a versatile hardware device that can sniff, read, and write data across various communication protocols, including I²C and SPI. Additionally, it supports asynchronous serial communication through hardware interfaces like UART. I was fortunate enough to get my hands on the latest revision recently released by Ian, called the Bus Pirate 5, which features a vibrant, colorful display. I’ll be using this device to read the data from the EEPROM and see what information it contains.
Reading Data from the EEPROM
Before I had purchased proper IC clips from AliExpress, I had to make do with a sketchy solution of trying to solder wires to the pins of the EEPROM. I’m not going to lie, it was a bit of a mess, but it worked well enough for my needs.
Using this setup, I connected the Bus Pirate to the EEPROM’s SDA
and SCL
pins for data communication. Additionally, I connected the power output leads from the Bus Pirate to the VCC
and GND
pins to power the chip.
The Bus Pirate provides a variable power output ranging from 0.80V to 5.00V DC, which is sufficient to power our EEPROM. Referring to the datasheet, we can see the supported voltage levels and the transfer speed modes for I²C communication: Standard mode at 100 kHz, Fast mode at 400 kHz, and Fast Mode Plus (FM+) at 1 MHz. These modes are compatible with a voltage range of 1.7V to 5.5V, making our 5V power setting ideal.
I set the power output to the maximum available value of 5V and enabled the power supply. With the EEPROM now powered, we can proceed to read data from it.
To read data from the EEPROM, we need to send a command to the device telling it which address we want to read from. The EEPROM uses a 7-bit device address (plus a read/write bit, making it 8 bits in total for communication). Since our EEPROM is a 2Kbit device, it can store 256 bytes of data. To read data from a specific address, we need to send a command that includes the device’s I²C address and the memory address of the data we want to read.
Even though we have the datasheet, which explains exactly what device address values to use to communicate with the 24C02, we can still use the Bus Pirate to scan for I²C devices on the bus. This is a good practice to get familiar with the tool and to ensure that the device is properly connected and responding to commands. To do this, we can use the Bus Pirate’s I²C scanner function. This function will send a command to each possible I²C address on the bus and listen for a response. If a device responds to a command, it will display the device’s I²C address on the screen. In our case, we should see the address 0x50 (or 0xA1 when including the read bit) since that’s the address of the 24C02 device.
Great! Using the Bus Pirate’s I²C scanner, we can confirm that our EEPROM is properly connected and responding to commands. When the scanner detects the device, it should display the address 0x50. This is the 7-bit I²C device address for the 24C02 EEPROM.
If we factor in the read/write bit, the full 8-bit address becomes 0xA0 for write operations or 0xA1 for read operations. These addresses are used during communication to specify whether we’re reading data from or writing data to the EEPROM. Now let’s break down the addressing structure in 010Editor.
- Device Type Identifier: The most significant four bits (bits 7–4) of the address byte are set to
1010
(Ah
) for standard EEPROM operations. - Hardware Address Bits: Bits 3–1 (
A2
,A1
, andA0
) allow up to eight EEPROM devices on the same bus. These bits correspond to the voltage levels on the device’s address pins. For SOT23 packages, these pins are not accessible and default to0
, meaning the software bits forA2
,A1
, andA0
must always be set to logic0
. - Read/Write Select: The least significant bit (bit 0) determines the operation type:
0
initiates a write operation.1
initiates a read operation.
After sending the device address byte, the EEPROM will return an acknowledgment (ACK) if the address matches. Otherwise, it will send a non-acknowledgment (NACK).
Dump it
Let’s give this a go using the Bus Pirate syntax to read all the pages of the EEPROM. The syntax for this operation looks like this:
[0xA0 0x00] [0xA1 r:256]
The first command is a dummy write, we are setting the address pointer to 0x0
the very first byte of memory. The second part, [0xA1 r:256]
, performs the actual read operation. 0xA1
is the 8-bit I²C address for a read operation, and r:256 tells the Bus Pirate to read 256 bytes of data starting from the memory address specified in the dummy write (0x00).
There we have it! All the data currently stored in the EEPROM chip has been dumped out. Observing the output, it seems that around 0x58
bytes appear to contain meaningful data, while the remaining bytes are filled with 0xFF
, which likely indicates unused or uninitialized memory.
This initial dump provides us with a solid foundation for further analysis. By examining these bytes, we can begin to understand how the PixMob wristbands store and handle data, potentially uncovering configurations or sequences that control their lighting patterns.
With the data dump complete, our next step is to dive deeper into analyzing the data and exploring customizations—but that’s a story for the next part of this series!
Conclusion
In this first part of our exploration into the PixMob wristbands, we’ve delved into their synchronized light displays and internal components. By examining the EEPROM, we’ve learned how it manages data that influences wristband functionality and how to interact with it using tools like the Bus Pirate.
We successfully powered up the EEPROM, identified its address, and extracted its memory contents. This lays the groundwork for deeper analysis, where we’ll interpret the hex data and explore ways to modify it for custom light patterns.
In the upcoming post, I’ll guide you through reverse-engineering the data using tools like 010Editor. I’ll also discuss further experiments with wristbands from different sources. Additionally, I’ll demonstrate how I developed a GUI tool and firmware using the Raspberry Pi Pico, making it simpler to read and write to the EEPROM, allowing for exciting customizations like our own light sequences.
This is just the beginning—stay tuned for Part 2 as we delve deeper into the data and explore what we can do with it!