During normal operations, iTunes communicates with the iPhone using something called “usbmux” – this is a system for multiplexing several “connections” over one USB pipe. Conceptually, it provides a TCP-like system – processes on the host machine open up connections to specific, numbered ports on the mobile device. (This resemblance is more than superficial – on the mobile device, usbmuxd actually makes TCP connections to localhost using the port number you give it.)
On the Mac, this is handled by /System/Library/PrivateFrameworks/MobileDevice.framework/Resources/usbmuxd, a daemon that is started by launchd (see /System/Library/LaunchDaemons/ com.apple.usbmuxd.plist). It creates a listening UNIX Domain Socket at /var/run/usbmuxd. usbmuxd then watches for iPhone connections via USB; when it detects an iPhone running in normal user mode (as opposed to recovery mode), it will connect to it and then start relaying requests that it receives via /var/run/usbmuxd – this is to say, usbmuxd is the only thing that actually speaks USB to the iPhone. This means that third-party applications which wish to talk to the iPhone must either do so through usbmuxd, or usbmuxd must be replaced.
Communications between the host (generally, iTunes running on a Mac or Windows machine) and the device (an iPhone or iPod Touch) take place using a complicated scheme of nested layers. From lowest level to highest, they are:
When a process on the host machine wants to talk to the iPhone, it opens up a connection to /var/run/usbmuxd. It then performs an initial handshake; after this handshake, the data in the socket is transparently tunneled to the specified TCP port on the phone.
Data structures: (all are little-endian)
struct usbmux_header { u32 length; // length of message, including header u32 reserved; // always zero u32 type; // message type u32 tag; // responses to this query will echo back this tag }; struct usbmux_result { struct usbmux_header header; u32 result; }; struct usbmux_connect_request { struct usbmux_header header; u32 device_id; u16 port; // TCP port number }; enum { usbmux_result = 1, usbmux_connect = 2, usbmux_hello = 3, };
An easy way to watch this happen is to use socat, like so:
sudo mv /var/run/usbmuxd /var/run/usbmuxx sudo socat -t100 -x -v UNIX-LISTEN:/var/run/usbmuxd,mode=777,reuseaddr,fork UNIX-CONNECT:/var/run/usbmuxx
Sequence of events:
1. Client opens connection to /var/run/usbmuxd 2. Client sends "Hello" packet: 10000000 00000000 03000000 02000000 (length = 0x10, reserved = 0, type = 3, tag = 2) 3. Client receives "Hello" response: 14000000 00000000 01000000 02000000 00000000 (length = 0x14, type = 1, tag = 2, result = 0) 4. Client receives device ID 1c 01 00 00 00 00 00 00 04 00 00 00 00 00 00 00 ................ 19 00 00 00 91 12 31 33 31 34 64 66 34 61 30 30 ......1314df4a00 65 37 31 37 35 35 62 31 32 30 31 66 64 36 34 34 e71755b1201fd644 35 34 63 63 35 38 36 39 39 63 30 31 66 64 00 00 54cc58699c01fd.. 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ [...] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00 00 00 00 00 00 00 00 00 00 10 fd ............ (length=0x1c1, type = 4, tag = 0, device_id = 0x19, usb_product_id = 0x1291, serial number string = "1314.....01fd".... ?) 5. Client sends TCP connect request 18000000 00000000 02000000 03000000 19000000 00160000 (length = 0x18, type = 2, tag = 3, device_id = 0x19, port = 0x0016 (big-endian) = 22) 6a. Client receives ack -- connection refused 14000000 00000000 01000000 03000000 03000000 (length = 0x14, type = 1, tag = 3, result = 3 -- connection refused?) or 6b. Client receives ack -- connection established 14000000 00000000 01000000 03000000 00000000 (length = 0x14, type = 1, tag = 3, result = 0 -- no error) From this point on, data is piped directly between the unix socket on the host and the TCP port on the device.
lockdownd uses port 62078. It uses a simple packet format - each packet is a 32-bit big-endian word indicating the size of the payload of the packet. Packets are in XML plist format, unless otherwise stated; the first two packets are shown in full, and the rest are abbreviated for the sake of readability.
Example: plug iTouch into iTunes
1. request: {Label=iTunesHelper, Request=QueryType} 0000011d (length of request, now in big-endian!) Ascii payload:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key> <string>iTunesHelper</string> <key>Request</key> <string>QueryType</string> </dict> </plist>
2. response: {Request=QueryType, Result=Success, Type=com.apple.mobile.lockdown} 00000156 (length)
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Request</key> <string>QueryType</string> <key>Result</key> <string>Success</string> <key>Type</key> <string>com.apple.mobile.lockdown</string> </dict> </plist>
3. request: {Label=iTunesHelper, PairRecord={DeviceCertificate=xxxx,HostCertificate=xxxx,HostID=xxxx,RootCertificate=xxxx}, Request=ValidatePair}
<dict> <key>Label</key> <string>iTunesHelper</string> <key>PairRecord</key> <dict> <key>DeviceCertificate</key> <data> LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNOVENDQVIyZ0F3SUJB [...] RVJUSUZJQ0FURS0tLS0tCg== </data> <key>HostCertificate</key> <data> LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN1akNDQWFLZ0F3SUJB [...] UlRJRklDQVRFLS0tLS0K </data> <key>HostID</key> <string>D7......-....-....-....-........4EFE</string> <key>RootCertificate</key> <data> LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNyVENDQVpXZ0F3SUJB [...] NUVPRitjZVFNcUovZHBFdz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo= </data> </dict> <key>Request</key> <string>ValidatePair</string> </dict>
4. response: {Request=ValidatePair, Result=Success}
<dict> <key>Request</key> <string>ValidatePair</string> <key>Result</key> <string>Success</string> </dict>
5. request: {HostID=xxx, Label=iTunesHelper, Request=StartSession}
<dict> <key>HostID</key> <string>D7......-....-....-....-........4EFE</string> <key>Label</key> <string>iTunesHelper</string> <key>Request</key> <string>StartSession</string> </dict>
6. response: {EnableSessionSSL=true, Request=StartSession, Result=Success, SessionID=xxx}
<dict> <key>EnableSessionSSL</key> <true/> <key>Request</key> <string>StartSession</string> <key>Result</key> <string>Success</string> <key>SessionID</key> <string>DE622607-91A9-4DA7-A38C-F6DC1F8EF24F</string> </dict>
(TBD …)