Freedelity  - Derniers blogs actifs  - Liste des blogs  -
Utilisateur   Mot de passe  
Webmaster
Suivez l'actualité de Freedelity en direct. Abonnez vous dès maintenant à notre flux RSS, à notre page facebook et à notre feed Twitter!
Hacking the Lighning cable, let's talk tech!
Publié le 10/05/2015 @ 19:00:00 dans la catégorie Chroniques

For one of our project, we needed to send and receive data from the iPad to an external device, an Android tablet. We first decided to rely on WiFi, but sadly the production environment is highly perturbated and we had to find a more reliable solution, ... a cable! We could have used the audio port, but for practical reason it was impossible for us, so we decided to take a closer look at the lighning port.

In our environement, we already have an accessory plugged into the lighning port, so we decided to open everything up and see if it was possible to hijack the connexion opened by the accessory and add our own data into it... and, it is! Sadly, we are highly limited by the speed of the solution, and our production team decided to go forward with another solution, getting rid of this problem.

We are still happy to share our work, hoping it will help someone else understanding how to use lightning in a professionnal environment. Enjoy the technical read and feel free to share your improvements on github or by email at info@freedelity.be

Let's talk dirty now!

How Lightning works

The Lightning cable

The lightning cable is a cable with 8 wires:
  1. GND
  2. HOST PWR to power the iDevice
  3. ACC_PWR to power the accessory
  4. ACC_ID, used to determine the kind of accessory
  5. two data pairs.


The connector has two rows of 8 pins connected to each wire:
https://blog.freedelity.be/images/stories/lightning/lightning_connector.jpg

As all wires are connected to both sides of the connector and that its shape is symmetrical, the connector can be inserted in both orientation.
But we can see that the way the wires are connected to pins aren't the same on both rows:
https://blog.freedelity.be/images/stories/lightning/lightning_connector_pinout.jpg

Connector configuration process

When plugging a lightning connector, the wires are not directly connected to the corresponding wires on the iDevice, there is a configuration process first (at least to detect the orientation of the cable). That is why you cannot just put voltage on the HOST PWR pin to power up your iDevice, you need to use a genuine charger cable.

Thanks to these articles: http://www.chipworks.com/en/technical-competitive-analysis/resources/blog/systems-analysis-of-the-apple-lightning-to-usb-cable/ and http://ramtin-amin.fr/#tristar, we know that the process is initiated by the iDevice by sending some commands on the ACC_ID pin with a protocol that looks like 1-wire.

In this protocol, the bus has a high voltage by default and any device connected can pull the voltage low (thanks to an open drain or open collector circuit, look at this article to have further info about this kind of connection).
When wanting to send a bit, we announce it by pulling the line low, then all the other devices prepare to sample the line to read the bit value. The sender either keep the line low to send a zero, or let it go high to send a one.
There are timings requirements to let all devices detect the falling edge, let the sender change the line to the good value, and then let each devices the time to read that value. The line is then released by letting the line go high.

The timings used in Lightning ACC_ID pin are:
  1. the complete bit time is: 10.2 μs (micro seconds)
  2. to send a zero, the line is low for 6.9 μs
  3. to send a one, the line is low for 1.6 μs

So when detecting a falling edge, we can sample the line after about 4 μs to read the bit value.

We wrote a little program (acc_id_sniff) to sniff the bytes exchanged in this pin using an Arduino and the exchanged bytes look like this:

iDevice: 74 00 01 FD
Accessory: 75 02 C0 00 00 00 00 50
iDevice: 70 00 00 3D
Accessory: 71 93
iDevice: 76 10
Accessory: 77 01 25 01 00 AC F5 57 29 F6 8A AF
iDevice: 78 0F
Accessory: 79 44 57 48 33 32 36 34 34 37 35 41 46 39 34 4E 31 4A 00 2E 88 AF
iDevice: 7A B3
Accessory: 7B 44 57 48 33 32 36 34 34 37 35 41 46 39 34 4E 31 4A 00 16 08 B5
iDevice: 72 71
Accessory: 73 00 00 C0 00 5E 84 00 00 05 46 46 34 33 32 E8


We didn't decode the exact meaning of these bytes but their purpose is for the iDevice to know the kind of the accessory.
There are four types of accessories (USB Host, USB accessory, Power and Serial) and they need to be connected to different buses. So, following the bytes received, the iDevice will connect one data pair to a serial RX/TX pair, or to an USB differential pair.
The interesting thing here is that the bytes exchanged are always the same for a given iDevice/accessory couple ! There is no authentication process whatsoever. So if you manage to sniff the bytes sent by a genuine charger, you could build your own.

For the orientation detection, in fact, it first tries in one possible orientation, if it has not got any response, it then tries on pin for the other orientation. If the accessory responds, the orientation is correct.

After the identification is made, the ACC_ID pin is let high as no one is communicating and it can serve as a power line for the accessory instead of the ACC_PWR. Some accessories use that to save a wire. In that case, the accessory chip is asleep when plugging the connector to the iDevice. The connector identifies itself so that we connect to the correct internal bus. And then, the accessory chip is awake by the fact that ACC_ID is kept high and it can freely communicate over its data pairs.

Serial communication

It seems that to be able to communicate directly to an iOS app, the connector needs to be of "Serial" type. The only USB device we found is the Apple USB adapter that only serves to connect standard USB devices like keyboards.

When plugging a Serial lightning connector, the Data1/Data2 pair is connected to a UART port (Data1 is matched against the TX line of iDevice, Data2 is matched against the RX line).
The UART uses 8 bits, no parity and one stop bit and its baudrate is 57600.

We wrote another program to sniff the serial communication (serial_sniff) and we manage to figure out some parts of the protocol used.

The communication is divided in blocks of bytes. The frame of the block is as follows:

FF 55 LL 00 XX XX XX XX XX YY


  1. The block starts with the two bytes: 0xFF 0x55
  2. The following bytes encode the length of data. The number of bytes for this field can vary:
    1. for length <= 255: the length is encoded in one byte
    2. for length > 255: the first byte is set to zero, then the length is encoded in the two following bytes in big endian
  3. After length, there is always a null byte (maybe reserved for future usage)
  4. The following bytes are the data to transmit
  5. The last byte is a checksum and is computed so that the sum (truncated to one byte) of all the bytes is equal to 0x54

Note: The length encodes the number of data bytes plus the checksum byte.

The first byte of data defines the type of the packet:
  1. 0x42: data from accessory to iOS app
  2. 0x43: data from iOS app
  3. 0x02: ack from iDevice when receiving a 0x42 packet
  4. 0x41: ack from accessory when receiving a 0x43 packet
  5. there are other types that we could not define and that are used during the authentication process


For 0x42 and 0x43 messages, it seems that the following two bytes encode the frame number (big-endian), and the two following are kind of a session id. That "session" bytes must be the same as the ones the iOS app is using to communicate with the accessory. Then the following bytes are the payload from or to the iOS app.

Here is a packet that send "hello world" to the iOS app:

FF 55 11 00 42 01 00 00 01 'h' 'e' 'l' 'l' 'o' ' ' 'w' 'o' 'r' 'l' 'd' CRC


ACK messages follows this format:

02 XX XX 00 42
or 41 XX XX 00 43

where XX XX is the frame number of the frame to ack.
We can see that the last byte is the type of the frame to ack.

It should be possible to change the baudrate that is used, as this accessory claims to be able to go up to 115200 bps but we did not figure out how yet.

Application

Knowing all this, we then can open a serial bus between an iOS app and any other UART interface without the need to register it to the MFI program.

The only requirement is to have a MFI accessory with a lightning connector of type Serial that will authenticate himself to the iOS system. Until we find a way to crack the way the authentication is done on the serial bus, we cannot bypass this requirement.

We wrote a program (serial_mitm) that runs on an Arduino and allows to make a Man-In-The-Middle attack on the serial bus. It let the authentified accessory speaks freely to the iDevice, but once there are data from an iOS app, it redirects them to the unauthentified device. When this third device responds, the arduino packs it in a correct frame for the iDevice to accept it and forward it to the app.

There are another program (acc_id_spoof) that let the Arduino speaks over the ACC_ID pin and identifies himself as a genuine Serial connector. For now, as we are forced to used and MFI accessory, we can let the accessory's connector do this job but later it could serve to build an all-in-one accessory that does not need MFI to speaks to an iDevice.

How it is built

Materials:
  1. a CableJive dockXtender
  2. an MFI accessory
  3. an Arduino Mega (as we need at least 3 UART)


The CableJive cable is an extension cable for the Lightning connector (so it has a male connector at one end, and a female one at the other end):
https://blog.freedelity.be/images/stories/lightning/cablejive.jpg

It will help us to hijack the wires between an accessory and an iDevice by opening it and directly connect us to its wires.
https://blog.freedelity.be/images/stories/lightning/cablejive_unwrapped.jpg
You could also directly cut off the wires to plug them where you want. But doing like in the picture allowed us to let an accessory communicate with the Apple device and sniff the communication.

Here is one mapping between the CableJive wires and the Lightning pins (remember, there are two possible mappings, and that's the iDevice that will determine the one you're using):
  1. black wire connects to the GND pin
  2. red wire connects to the Host Power pin
  3. shiny orange wire connects to the ACC_ID pin
  4. shiny blue wire connects to the ACC_PWR pin
  5. green wire connects to the Data 1 pin
  6. white wire connects to the Data 2 pin
  7. blue wire connects to the Data 3 pin
  8. brown wire connects to the Data 4 pin


We then unmount an MFI accessory to get its Lightning connector and access the pins it uses to communicate. In our case, it uses four pins: Power (ACC_ID actually, but used for power), GND, Data 1 and Data 2. But it should be quite the same for other accessories, just determine the mapping before removing the lightning connector :wink:

https://blog.freedelity.be/images/stories/lightning/accessory_unmounted.jpg

We then connect the data pair of the accessory to one UART of the Arduino, and the data pair of the Lightning cable to another UART (in our code we connect UART1 to the iDevice, and UART2 to the accessory).
Beware that the UART channels on the Arduino use 5V for the high voltage while the serial channel on the Lightning use 3.3V, we have to downscale the voltage of TX1 and TX2 pins of the Arduino (RX pins can be left as is as 3.3V is high enough to be detected as a logic one). You can use a level shifter circuit for that, but a simple resistor divider will do the trick for the prototype :wink:

Connect also ground to your accessory and 3.3V through a push-button to power it up when it is necessary.

https://blog.freedelity.be/images/stories/lightning/breadboard_serial_mitm.png

We then plug the Lightning connector of the accessory to the female end of the CableJive, and then after (this order is important) plug the other end to the iDevice:
https://blog.freedelity.be/images/stories/lightning/connector_in_cablejive.jpg
It's this connector that will set the lightning orientation, so plug it in a way that matches the wires you are using. To determine if it is correctly inserted, cut off the useless ACC_PWR wire (if you follow our orientation, it is the shiny blue wire), and then unplug/replug the CableJive on the iDevice port. If the connector is not correctly inserted, you will see an alert dialog after about ten seconds telling that the cable or accessory is bad.

Now, we can compile and upload the program to the Arduino (instructions are on the code repository).
Then we have to power up the accessory to let it authenticate itself to the system. You can power it off just after as it will not take part in the communication anymore.

In the computer connected to the Arduino through USB, you can listen and send bytes to the Arduino by reading or writing the file /dev/ttyACM0 (change it to the one your system has assigned to the Arduino).

First you need to tell that the serial bus is 56700-8-N-1, for that you can type:
stty -F /dev/ttyACM0 57600 cs8 raw

You can then read bytes that would have been sent to the accessory by doing:
cat /dev/ttyACM0

And to send bytes to the Arduino, you can type:
echo "Some text" > /dev/ttyACM0


You can use our simple iOS app to send bytes from the iDevice.

Demo



Conclusion
We managed to find a way to open a serial communication bus between an iOS app and a device that does not have to comply with the MFI program.

It still needs a MFI accessory to initiate the communication but it can certainly be useful for hobbyists that want to build custom accessories for iPhones and iPads or for companies that cannot afford to enter the MFI program for low batches of devices.

There are still plenty things to improve :
  1. How can we change the baudrate to have better throughput ?
  2. What is the process of authentication done in the serial bus and how could it be hacked so that we can build standalone custom accessories ?
  3. Would it be possible to take advantage of USB-type Lightning connectors for any kind of device or is it restricted to some USB classes as speaker or keyboards ?
  4. Would it be possible to multiplex two Lightning connectors of different types in order to use them simultaneously ? It will let us finally debug our apps while an accessory use the lightning port.
  5. ...


We are sharing our work in hope it will be useful for anyone and that some enthusiats will take the project further :smile:
All the code is available on github, and we are open to any modification request !
Copyright © Freedelity SA, tous droits réservés