MTPZ: Handshake Packets
In the previous post, I presented a USB session between the Windows Zune software and my Zune 8GB device. As I noted, the entire USB session conformed to the MTP protocol, in that it could be neatly and correctly split into a list of MTP packets. Well, I wrote a little Python script that took the USB data being sent back and forth and formatted it neatly into the MTP packets seen below, which makes it easier to understand this handshake.
MTP packets exist in the following format:
- 32-bit length of the entire packet
- 16-bit type of the packet (i.e: Command, Data, Response, and Event)
- 16-bit opcode (e.g:
PTP_OC_OpenSession
) - 32-bit transaction number
- variable-size payload
The transaction number allows you to see the relationship between the inbound and outbound packets.
Outbound MTP packets:
Length | Type | Command | Transaction | Data |
0x10 | Command (1) | 0x1002: PTP_OC_OpenSession | 0 | View |
0x0C | Command (1) | 0x1001: PTP_OC_GetDeviceInfo | 1 | |
0x10 | Command (1) | 0x1016: PTP_OC_SetDevicePropValue | 2 | View |
0x63 | Data (2) | 0x1016: PTP_OC_SetDevicePropValue | 2 | View |
0x10 | Command (1) | 0x1014: PTP_OC_GetDevicePropDesc | 3 | View |
0x10 | Command (1) | 0x1014: PTP_OC_GetDevicePropDesc | 4 | View |
0x10 | Command (1) | 0x9801: PTP_OC_MTP_GetObjectPropsSupported | 5 | View |
0x14 | Command (1) | 0x9802: PTP_OC_MTP_GetObjectPropDesc | 6 | View |
0x0C | Command (1) | 0x1004: PTP_OC_GetStorageIDs | 7 | |
0x10 | Command (1) | 0x1005: PTP_OC_GetStorageInfo | 8 | View |
0x0C | Command (1) | 0x9216: PTP_OC_MTP_WMDRMPD_EndTrustedAppSession | 9 | |
0x0C | Command (1) | 0x9216: PTP_OC_MTP_WMDRMPD_EndTrustedAppSession | 10 | |
0x0C | Command (1) | 0x9216: PTP_OC_MTP_WMDRMPD_EndTrustedAppSession | 11 | |
0x0C | Command (1) | 0x9212: PTP_OC_MTP_WMDRMPD_SendWMDRMPDAppRequest | 12 | |
0x31D | Data (2) | 0x9212: PTP_OC_MTP_WMDRMPD_SendWMDRMPDAppRequest | 12 | View |
0x0C | Command (1) | 0x9213: PTP_OC_MTP_WMDRMPD_GetWMDRMPDAppResponse | 13 | |
0x0C | Command (1) | 0x9212: PTP_OC_MTP_WMDRMPD_SendWMDRMPDAppRequest | 14 | |
0x20 | Data (2) | 0x9212: PTP_OC_MTP_WMDRMPD_SendWMDRMPDAppRequest | 14 | View |
0x10 | Command (1) | 0x1005: PTP_OC_GetStorageInfo | 15 | View |
0x10 | Command (1) | 0x1014: PTP_OC_GetDevicePropDesc | 16 | View |
0x10 | Command (1) | 0x1015: PTP_OC_GetDevicePropValue | 17 | View |
0x10 | Command (1) | 0x1015: PTP_OC_GetDevicePropValue | 18 | View |
0x10 | Command (1) | 0x1014: PTP_OC_GetDevicePropDesc | 19 | View |
0x10 | Command (1) | 0x1015: PTP_OC_GetDevicePropValue | 20 | View |
0x1C | Command (1) | 0x9104: PTP_OC_MTP_WMDRMPD_GetSyncList | 21 | View |
0x10 | Command (1) | 0x1014: PTP_OC_GetDevicePropDesc | 22 | View |
0x10 | Command (1) | 0x1014: PTP_OC_GetDevicePropDesc | 23 | View |
0x10 | Command (1) | 0x1014: PTP_OC_GetDevicePropDesc | 24 | View |
0x10 | Command (1) | 0x1014: PTP_OC_GetDevicePropDesc | 25 | View |
Inbound MTP packets:
Length | Type | Command | Transaction | Data |
0x0C | Response (3) | 0x2001: PTP_RC_OK | 0 | |
0x345 | Data (2) | 0x1001: PTP_OC_GetDeviceInfo | 1 | View |
0x0C | Response (3) | 0x2001: PTP_RC_OK | 1 | |
0x0C | Response (3) | 0x2001: PTP_RC_OK | 2 | |
0x0C | Response (3) | 0x200A: PTP_RC_DevicePropNotSupported | 3 | |
0x1E | Data (2) | 0x1014: PTP_OC_GetDevicePropDesc | 4 | View |
0x0C | Response (3) | 0x2001: PTP_RC_OK | 4 | |
0x6A | Data (2) | 0x9801: PTP_OC_MTP_GetObjectPropsSupported | 5 | View |
0x0C | Response (3) | 0x2001: PTP_RC_OK | 5 | |
0x1E | Data (2) | 0x9802: PTP_OC_MTP_GetObjectPropDesc | 6 | View |
0x0C | Response (3) | 0x2001: PTP_RC_OK | 6 | |
0x14 | Data (2) | 0x1004: PTP_OC_GetStorageIDs | 7 | View |
0x0C | Response (3) | 0x2001: PTP_RC_OK | 7 | |
0x8C | Data (2) | 0x1005: PTP_OC_GetStorageInfo | 8 | View |
0x0C | Response (3) | 0x2001: PTP_RC_OK | 8 | |
0x0C | Response (3) | 0x2001: PTP_RC_OK | 9 | |
0x0C | Response (3) | 0x2001: PTP_RC_OK | 10 | |
0x0C | Response (3) | 0x2001: PTP_RC_OK | 11 | |
0x10 | Response (3) | 0x2001: PTP_RC_OK | 12 | View |
0x3D4 | Data (2) | 0x9213: PTP_OC_MTP_WMDRMPD_GetWMDRMPDAppResponse | 13 | View |
0x0C | Response (3) | 0x2001: PTP_RC_OK | 13 | |
0x10 | Response (3) | 0x2001: PTP_RC_OK | 14 | View |
0x18 | Event (4) | 0x400C: PTP_EC_StorageInfoChanged | 0 | View |
0x8C | Data (2) | 0x1005: PTP_OC_GetStorageInfo | 15 | View |
0x0C | Response (3) | 0x2001: PTP_RC_OK | 15 | |
0x1C | Data (2) | 0x1014: PTP_OC_GetDevicePropDesc | 16 | View |
0x0C | Response (3) | 0x2001: PTP_RC_OK | 16 | |
0x1604 | Data (2) | 0x1015: PTP_OC_GetDevicePropValue | 17 | View |
0x0C | Response (3) | 0x2001: PTP_RC_OK | 17 | |
0xCC | Data (2) | 0x1015: PTP_OC_GetDevicePropValue | 18 | View |
0x0C | Response (3) | 0x2001: PTP_RC_OK | 18 | |
0x1C | Data (2) | 0x1014: PTP_OC_GetDevicePropDesc | 19 | View |
0x0C | Response (3) | 0x2001: PTP_RC_OK | 19 | |
0xCC | Data (2) | 0x1015: PTP_OC_GetDevicePropValue | 20 | View |
0x0C | Response (3) | 0x2001: PTP_RC_OK | 20 | |
0x10 | Response (3) | 0xA101: PTP_RC_CANON_BATTERY_LOW | 21 | View |
0x14 | Data (2) | 0x1014: PTP_OC_GetDevicePropDesc | 22 | View |
0x0C | Response (3) | 0x2001: PTP_RC_OK | 22 | |
0x64 | Data (2) | 0x1014: PTP_OC_GetDevicePropDesc | 23 | View |
0x0C | Response (3) | 0x2001: PTP_RC_OK | 23 | |
0x1A | Data (2) | 0x1014: PTP_OC_GetDevicePropDesc | 24 | View |
0x0C | Response (3) | 0x2001: PTP_RC_OK | 24 | |
0x62 | Data (2) | 0x1014: PTP_OC_GetDevicePropDesc | 25 | View |
0x0C | Response (3) | 0x2001: PTP_RC_OK | 25 |
So where do we start?
Probably at the first packet. Quickly scanning through, you can see that the software first opens a session with the Zune which replies with PTP_RC_OK
(success).
Then, at transaction 2 (PTP_OC_SetDevicePropValue
), the software sends its driver string, +Windows/6.1.7600 MTPZClassDriver/4.7.965.0
, to which the Zune states that
it does not support that property. Somewhat bizarre.
Skipping over a bit, the interesting packets start at transaction 9, PTP_OC_MTP_WMDRMPD_EndTrustedAppSession
. This command is repeated two more times (I’m no doctor, but this seems like
Obsessive Compulsive Disorder). Then, at transaction 12, comes our PTP_OC_MTP_WMDRMPD_SendWMDRMPDAppRequest
which has a large data payload. As I mentioned in the previous post,
this seems to be the first step of the handshake, containing two constant certificates appended with some generated data.
As I also mentioned previously, the software waits until the Zune sends a handshake response before continuing. This is seen at transaction 13, PTP_OC_MTP_WMDRMPD_GetWMDRMPDAppResponse
,
to which the Zune generates a PTP_OC_MTP_WMDRMPD_GetWMDRMPDAppResponse
packet with a large data payload. This is the second step of the handshake. The software receives
this response and presumably does some sort of verification.
Next, the software sends another PTP_OC_MTP_WMDRMPD_SendWMDRMPDAppRequest
as transaction 14 with a relatively small payload. This is the last step of the handshake. I would
assume that the Zune verifies this response and unlocks itself for synchronization (perhaps the cause of the PTP_EC_StorageInfoChanged
event).
Cool beans, what now?
Now I have to figure out how these payloads are generated, which is clearly going to be the difficult part of this project.
Stay tuned.