The Paragon 2000 command set (more commonly referred to as P2K) is the most common method for accessing the file system and binary settings of Motorola phones. However, it is not an open protocol, so all the information obtained has been a result of reverse engineering. Despite some very successful reverse engineering attempts (p2kman, p2k-core, libp2kmoto), it has been very difficult to find documentation on the protocol itself. The introduction of Paragon 2005 further complicated matters with a different packet structure despite supporting mostly the same commands. While I was writing libparagon, I decided I would document the structures to save others endless hours of running usb sniffers and searching through mostly-uncommented source code.
All groups of bytes that are treated as a single value are, unless noted otherwise, in big endian format. In case you are not familiar with big endian format, here are several examples comparing the differences between it and little endian format:
Byte Sequence (Hexadecimal) | Little Endian Value (Hexadecimal) | Big Endian Value (Hexadecimal) |
12 | 0x12 | 0x12 |
12 34 | 0x3412 | 0x1234 |
12 34 56 78 | 0x78563412 | 0x12345678 |
fe ff | 0xfffe | 0xfeff |
If this is still unclear, the Wikipedia article on Endianness is far more comprehensive.
The Paragon 2005 Header consists of a 12-byte structure laid out in the following manner:
0000:0000 xx yy zz zz 00 uu 00 00 ww ww ww ww [end of header]
xx | A Status Byte; the bits mean the following:
|
yy | An 8-bit integer containing the packet ID (a counter starting at 0 and incrementing for every packet sent). The response header contains the packet ID it is responding to. |
zz zz | A 16-bit integer containing the command. The command set is mostly the same between p2k and p2k05 phones, although there are a few differences. |
00 | Zero padding; don't know if it has another function. |
uu | The reponse code for a completed command (only needed for responses). I don't know most of them, but 0x06 is Generic Success and 0x07 is Generic Failure. |
ww ww ww ww | A 32-bit integer containing the length of data in bytes. |
The layout of the Data Section depends greatly on the command being used. As far as I can tell, the Data Section is invariant with respect to the version of the Paragon command set used as long as the command is in the set. Here is a list of the contents of the data section for various commands (corresponding command value in square brackets, all commands on both Paragon 2000 and Paragon 2005 phones):
0000:0000 xx xx yy yy zz zz ww ww [end of packet]
xx xx: A 16-bit integer containing the seem number.
yy yy: A 16-bit integer containing the seem record.
zz zz: A 16-bit integer containing the offset (in bytes).
ww ww: A 16-bit integer containing the seem length in bytes. A length of 0 will get the entire seem.
0000:0000 00 * [seem data] 0000:xxxx [end of packet]
00: This is a zero byte before the actual seem data.
[seem data]: The actual seem data. This continues to the end of the packet.
0000:0000 xx xx yy yy zz zz ww ww * [seem data] 0000:xxxx [end of packet]
xx xx: A 16-bit integer containing the seem number.
yy yy: A 16-bit integer containing the seem record.
zz zz: A 16-bit integer containing the offset (in bytes). An offset of 0 will get the entire seem.
ww ww: A 16-bit integer containing the seem length.
[seem data]: The actual seem data. This continues to the end of the packet.
0000:0000 00 [end of packet]
00: As far as I can tell, a successful Seem Write command will always return a single 0 byte in the data section.
The Paragon FSAC Packet is actually transmitted in the Data Section of the Paragon 2000 or Paragon 2005 packet. That is, we set the 'command' in the p2k or p2k05 packet to be the FSAC command (0x004A) and set this structure as the Data Section. We can think of the FSAC protocol as riding on top of the Paragon 2000 and Paragon 2005 protocols. An interesting thing to note is that the FSAC packet does not carry its own size; rather, it relies on the Paragon 2000 or Paragon 2005 packet to hold its size (under the length of the data, which includes the 4 bytes from the FSAC command itself). With that in mind, here is the structure of an FSAC Packet:
0000:0000 xx xx xx xx * [FSAC data section] 0000:xxxx [end of packet]
xx xx xx xx: A 32-bit integer containing the FSAC command to send.
[FSAC data section]: This is the data section of the FSAC packet. Its length should be the length set in the Paragon 2000 or Paragon 2005 packet minus 4 (for the FSAC command itself).
This section describes the FSAC Data section of various FSAC commands:
0000:0000 [end of packet]
The Get Volumes FSAC command does not take any parameters.
0000:0000 xx xx xx xx FF FE yy yy yy yy FF FE * [pattern above repeats] 0000:xxxx zz zz zz zz 00 00 [end of packet]
xx xx xx xx: The first full volume path in UCS-2; this will usually be 00 2F 00 61 ("/a").
FF FE: This value serves as a separator between the volume paths.
yy yy yy yy: The second full volume path in UCS-2.
zz zz zz zz: The last full volume path in UCS-2.
00 00: This is the NULL-terminator in UCS-2; it denotes no more volumes after this point.
0000:0000 00 00 xx xx xx xx 00 00 [end of packet]
xx xx xx xx: The full volume path to check in UCS-2; this will usually be (00 2F 00 yy), where yy is the ascii encoding of the volume we are checking (it corresponds to "/v", where v is the volume character).
00 00: This is the NULL-terminator in UCS-2; it denotes the end of the path string.
0000:0000 xx xx xx xx [end of packet]
xx xx xx xx: A 32-bit integer containing the remaining space on the volume in bytes.
0000:0000 xx xx xx xx xx xx FF FE * [filter] 0000:xxxx 00 00 [end of packet]
xx xx xx xx xx xx: The full volume path with trailing slash in UCS-2; this will usually be (00 2F 00 yy 00 2F), where yy is the ascii encoding of the volume we are checking (it corresponds to "/v/", where v is the volume character).
FF FE: This value serves as a separator between the path and the filter.
[filter]: This is the UCS-2 encoded filter string; at a minimum, it should be "*" (00 2A) to select all files in the volume. However, we can also do strings like "*.mp3" to select all mp3 files, for example.
00 00: This is the NULL-terminator in UCS-2; it denotes the end of the filter string.
0000:0000 xx xx [end of packet]
xx xx: A 16-bit integer containing the number of files on the volume matching the filter.
0000:0000 xx [end of packet]
xx: The number of file records returned by this function; I honestly don't see how any more than 3 would be a 'safe' value (since the maximum packet size is limited to 0x400 bytes = 1024 bytes, and the return structure is pretty large at 4 + 268 * xx bytes). Libparagon exclusively uses a value of 1 here (to get the 'next' file record in the list).
0000:0000 xx xx 00 00 yy yy yy yy yy yy yy yy yy yy yy yy 0000:0010 yy yy yy yy yy yy yy yy yy yy yy yy yy yy yy yy 0000:0020 yy yy yy yy yy yy yy yy yy yy yy yy yy yy yy yy 0000:0030 yy yy yy yy yy yy yy yy yy yy yy yy yy yy yy yy 0000:0040 yy yy yy yy yy yy yy yy yy yy yy yy yy yy yy yy 0000:0050 yy yy yy yy yy yy yy yy yy yy yy yy yy yy yy yy 0000:0060 yy yy yy yy yy yy yy yy yy yy yy yy yy yy yy yy 0000:0070 yy yy yy yy yy yy yy yy yy yy yy yy yy yy yy yy 0000:0080 yy yy yy yy yy yy yy yy yy yy yy yy yy yy yy yy 0000:0090 yy yy yy yy yy yy yy yy yy yy yy yy yy yy yy yy 0000:00A0 yy yy yy yy yy yy yy yy yy yy yy yy yy yy yy yy 0000:00B0 yy yy yy yy yy yy yy yy yy yy yy yy yy yy yy yy 0000:00C0 yy yy yy yy yy yy yy yy yy yy yy yy yy yy yy yy 0000:00D0 yy yy yy yy yy yy yy yy yy yy yy yy yy yy yy yy 0000:00E0 yy yy yy yy yy yy yy yy yy yy yy yy yy yy yy yy 0000:00F0 yy yy yy yy yy yy yy yy yy yy yy yy yy yy yy yy 0000:0100 yy yy yy yy yy yy yy yy zz zz uu uu ww ww ww ww
xx xx: The number of file records in the returned data section. I don't know why this is a 16-bit integer here, but only an 8-bit integer when we transmit the command, but I didn't write the protocol.
yy yy yy yy yy yy yy yy yy yy yy yy yy yy yy yy ...: The ascii-encoded absolute path of the file described by this record. The size of this section is 260 bytes. This needs more testing to determine if the max path is actually 256 bytes and there is a 32-bit zero padding integer between it and the attributes.
zz zz: The attributes of the file pointed to by this record. Not sure what a lot of the attributes mean, but if ((zz zz) & 00 10 == 00 10), this is a directory.
uu uu: The owner of the file pointed to by this record. Again I have very little idea of what exactly this means, but '7' seems to be the generic phone user (i.e. not a super user).
ww ww ww ww: The size of the file pointed to by this record (in bytes).