kinnay / NintendoClients

Python package to communicate with Switch, Wii U and 3DS servers
MIT License
551 stars 67 forks source link

[Wiki]: PIA `Monitoring Data` protocol seems to have incorrect structure and payload sizes #139

Open jonbarrow opened 6 days ago

jonbarrow commented 6 days ago

We've been looking at the data sent by the Wii U in SendReport, and it seems like some parts of the wiki are incorrect with how this data is encoded?

Here are all the SendReport payloads we've been working with:

MK8

0700fcff00a0ffffffffffffffffffff25a5c41168df2549adeeab05a0664a1e07c6388576c7ef6429167879d79f3ffcad10aa376e184db7c9c1b9d3938c773c3f1f73f197a18869e8737fb81f439b765b62ad82f596eada7a57d8154b57021f7c765e03e66772af3382b68e9de23e417ec5848676126e0c3b76e6e49c6a1ee1b9ea5e6c90ed25b581ecf5ec9f1a7f079d59f4d872ca0e438caab90522de52d1539c7dfaa3283018bad2bd2a6c37924d053b96e44d7f194a7924ae1967a73ddd

In this sample you can see it's using version 7, data type 0. So the Monitoring data header decodes to:

Version: 7
Data type: 0
Flags: 0xFC
Constant: 0xFF
Payload size: 0x00A0 (160 bytes)
Padding

However the payload size seems to be wrong? Following the header there is actually 176 bytes, not 160. Though including them in the payload doesn't seem to actually change anything with the crypto/decompression, so it's not clear what those bytes are? Version 7 is PIA 3.10 so it shouldn't have the authentication tag like 5.7+ does, since it's using ECB and not GCM?

Splatoon

0b00fcff010dffffffffffffffffffff1b6a99fbb9d160ecc8fcf318df07bb5c8d47bab8e60a01b54f11ed20022662e7569d5dcdfb6a88744431ded0353a5ee17cf52fe0390865bd43947c0c1de2858f73297c371b8a0e1bd14875b63d19419d9c740f3334ecd3e7606c7ba33bc3fa256f1a4de649c2cc6bb08629d38e494b3d1211a994be51143c026a92c2268f4f61ac01c35b06955e892f02d1440269b017b35f00b66ae75f8f00b456d191b1fbb6ee9bf3d9e041d122fa28489bcdbfbfcf9adea9f1eea44ae4c2a7a0e101695491a0186369197cd5ec75e32ef69789fa339ccd922895d2fdacd7e5cf430645d555346b7bf8c01e126df11a86e02e0898eea61cf615fec05270671915b34acb551641e89dd2c1675cfa23a6b7d38986689d

In this sample you can see it's using version 11, data type 0. So the Monitoring data header decodes to:

Version: 11
Data type: 0
Flags: 0xFC
Constant: 0xFF
Payload size: 0x010D (269 bytes)
Padding

However the payload size seems to be wrong? Following the header there is actually 272 bytes, not 269. If these 3 bytes are not included in the payload, then the decryption fails, making the payload size in the header rather useless?

Minecraft

1200fcff00a445b037878b6ce783c1ff3a18b65d81b244713a7b922e1fda7cf427d7a7c6e4f3593364776fd5cf2f210f17f080c0b1d90dc4a845f0576c2694d55623dc2ae3525ae79d7a1d3d6741d78c27e8505cd91ebfe44afde2eec12dba2caa62922d9d0534ea27b7f040f39370f2e2488a98876eab2139eb6a2f641bd8928f73ccf499e2f5cc79965d6ec6de686d417c38f3a531db1f1ff23f29f33e70fd62b53ff87e5f76d2a7cc7158f962404fffa42e3d176e914cca06e919990303afde59661988891c9e744f83ad76233556

In this sample you can see it's using version 18, data type 0. So the Monitoring data header decodes to:

Version: 18
Data type: 0
Flags: 0xFC
Constant: 0xFF
Payload size: 0x00A4 (164 bytes)
GCM nonce start: 0x45B037878B6CE783
GCM key ID: 0xC1 (index 1)
Constant: 0xFF

However the payload size seems to be wrong? The payload is actually 176 bytes, not 164. The GCM authentication tag is always 16 bytes at the end of the data, but using 164 bytes leaves 28 bytes as the authentication tag. This doesn't work. Using 176 bytes as the payload and the final 16 bytes as the authentication tag does work, so the payload size is again wrong

All

Additionally there seems to be some issues with the way the internal payload is documented as well. For example take this Minecraft payload:

1200ffff07aeffffffffffffffffffff050900ff00005335030a00ff000303010200400000fffe7a41ffffffffffffffffffffffffffffffffffffff49c01055c0a8000e0102000307f4003b04d85c3e4974ee28bdbb00306e0e101d9d000200080000002000000040000000200000004000000020ffffffffffffffffffffffffffffffff2710000001f4000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0020df90df90ff8ebb72a3ffffffffffffffffffffffffffffffffff000000ae0000000fffffffffffffffffffffffffffffffffffffffffffffffff0008ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffffff00ffffffffffffffffffffffff0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5069614d

According to the wiki following the header there should be the PIA version stored as a uint32, but this isn't the case. The PIA version is stored as 3 (4?) separate bytes, each representing a different part of the version. In this case it's 0x050900FF which would translate to 5.9.0 (ignore FF?), but if this was treated as a uint32 the value would be 84476159 or 8447.61.59

The same is true for the NEX version, it is also stored as 3 (4?) individual bytes for each section. In this case that would be 0x030A00FF which would translate to 3.10.0 (ignore FF?), but if this was treated as a uint32 the value would be 50987263 or 5098.72.63

The SDK version is stored as a uint32 though. It's stored as 0x00005335, or 21301 which translates correctly to 2.13.1. So it seems like only some values are actually supposed to be treated as uint32's?

EDIT: I've just looked at the encoding functions for the data content in Minecraft, I do see now that it serializes these fields as uint32s despite their structure. I see where that comes from now. However it may be beneficial to change the wiki anyway to document how the data is actually stored in the uint32?

DaniElectra commented 6 days ago

About the payload size, that represents the size of the data after decrypting it and before decompressing it. The value is extracted from the zlib total_out value from the stream. The payload size is still 2 bytes smaller, so I'm guessing the total_out value represents the size without the zlib magic?

This is an example from Minecraft Wii U (The raw payload size removes the AES-GCM tag from the end):

imagen