AeonLucid / POGOProtos

A central repository for all proto files of PokémonGO.
MIT License
726 stars 279 forks source link

Signature decryption issues #223

Closed marceloueda closed 8 years ago

marceloueda commented 8 years ago

I've been debugging signature fields by decrypting them with code from https://github.com/laverdet/pcrypt. However I've just noticed that when I deserialize data (after decryption) to signature proto and serialize it back in binary format it doesn't match the initial data. I don't know much about protobuf, but I'd say it could be an issue with the decryption method (generating invalid information during decryption) or with the signature proto (missing fields). Does someone have any idea how could I sort this out?

trisk commented 8 years ago

Write out the decrypted buffer to a file with and use protoc --decode_raw on it, to look for extra fields.

marceloueda commented 8 years ago

It seems commit 6a7a0021e9c1c18e402668d6c4c0ccdb9a56edf1 broke things for me. Changing locationhash back to uint64 fixed the problem. Thank you!

marceloueda commented 8 years ago

Oh, there was also a field 9 in SensorInfo proto with value 18446744073709551615. Can anyone point me out if and how could I convert this to proto2 and compile to C# code?

trisk commented 8 years ago

compile.py etc. takes a -l csharp to generate the bindings. proto3 is required for the serialised format afaik. What device is this?

trisk commented 8 years ago

Field 9 has been identified as int32 magnetic_field_accuracy in https://github.com/pogodevorg/POGOProtos/blob/pogodev-develop/src/POGOProtos/Networking/Envelopes/SignalAgglomUpdates.proto

trisk commented 8 years ago

Thanks to @elfinlazz for discovering the cause of the failure. It seems the 32-bit location hashes can actually be 10 bytes on the wire, which when decoded looks like a uint64 with the high 32 bits set to 1. Even though the hash doesn't have a meaningful sign bit, this is the result of the protobuf encoding of a negative int32 or int64 which uses sign extension (both have the same encoding). Using either of those types on the proto spec will produce the correct results, though int32 may be nicer for applications to deal with since only the lower 32 bits are relevant.

marceloueda commented 8 years ago

Got it. But won't discarding these bytes result in a different encrypted signature?

marceloueda commented 8 years ago

I'm already using compile.py to generate .cs files. But this whole thing is setup for using proto3 which discards unknown fields. Would it be possible to use proto2 so these fields are kept when mitm manipulating these requests?

trisk commented 8 years ago

The sign extension happens during encoding so as long as you convert the hash to a signed value, the encoded int32 will have the correct form.

It doesn't look like the spec uses any proto3 specific features except for default values for missing fields so in theory they are valid if you declare them as proto2. I believe proto2 requires you to specify which fields are optional whereas they're all considered optional in proto3; that might be a problem if you encounter any missing fields.

marceloueda commented 8 years ago

Right, it worked great with both int32 and uint64, but failed with uint32 which is the current vaue in the proto. Is this an issue?

I've managed to convert everything to proto2 setting all fields as optional and replacing oneof and map types (they're supported by proto2 but not by the C# pre compiler). Couldn't test further to see if everything is working ok, but I gave up on this as I decided to keep up with proto3 and throw exceptions whenever unknown fields are found.

trisk commented 8 years ago

uint32 and uint64 will only produce correct encodings for hash values < 2^31 since the high bit needs to be treated as a sign bit when present and extended to the high 32 bits. uint32 cannot correctly decode the output for those values while uint64 will decode them as very large numbers which preserves the information if you pass it back as uint64 but is the wrong value internally and cannot construct encodings of new hashes because of the previous problem. Only int32 and int64 will produce consistently correct results.

marceloueda commented 8 years ago

Got it, thanks!