[Archive] Reverse engineering and removing Pokémon GO’s certificate pinning in IDA Pro
This is very old tutorial written by eaton-works, I just re-post it to make it known. It is still useful to learn reverse engineering and modding
Original source:
https://eaton-works.com/2016/07/31/reverse-engineering-and-removing-pokemon-gos-certificate-pinning/
--------------------------------------------------------------------------------------------------------------------------
Original source:
https://eaton-works.com/2016/07/31/reverse-engineering-and-removing-pokemon-gos-certificate-pinning/
--------------------------------------------------------------------------------------------------------------------------
Update: Due to new security improvements in new versions of Pokémon GO, this method may no longer work.
What is
certificate pinning?
Put simply,
it is Pokémon GO performing additional validation against the certificate
provided by the server. Pokémon GO expects the Niantic Labs certificate, but
when you MITM with Fiddler, Pokémon GO sees Fiddler’s certificate. Pokémon
GO detects this and aborts the connection before any data is sent to the
server.
Has Pokémon
GO always had certificate pinning?
On July
30th, 2016, version 0.31.0 of Pokémon GO was released. This is the
second update for the game. The base game and the first update did not have
certificate pinning. I was a little surprised that certificate pinning was
not implemented from the beginning. However, once it was added, it was easily
noticeable in Fiddler with all the failed CONNECTs.
And an
error in Pokémon GO itself, even though the network and account are both fine.
Based on
those observations, coupled with the fact that Fiddler worked fine on the
previous version of Pokémon GO, there is a very high chance certificate
pinning is now implemented in version 0.31.0.
Do I
need root access?
You
do not need root access! This method works on both rooted and
non-rooted devices.
Will I
be banned if I do this?
No bans
were encountered during testing on version 0.31.0, but this can easily change
in a future version. It is recommended you use a throwaway account when you
need to MITM, just in case there are any custom/secret APK modification checks.
If you
log in using Google…
Due to an
Android security feature, you may be unable to log in to Pokémon GO using
your Google account with a patched APK.
Reverse
engineering the certificate pinning
Note:
These steps are only valid for Pokémon GO version 0.31.0.
If you
aren’t interested in learning how this was done and just want to patch your
APK, scroll down to “Patching the APK”.
Pokémon
GO obviously must have the entire leaf, intermediate, or
root certificate or at least the public key to validate against
somewhere in the APK, likely in a file that contains code. The first thing I
tried was searching for the leaf certificate’s public key. To get that, I went
to the Niantic Labs website and examined its leaf certificate using Chrome.
Let’s
extract the APK and use a hex editor to do a byte sequence search in the files
that contain code to find the public key.
classes.dex?
Nope.
lib\armeabi-v7a\libmain.so? Nope.
lib\armeabi-v7a\libNianticLabsPlugin.so? DING!
lib\armeabi-v7a\libmain.so? Nope.
lib\armeabi-v7a\libNianticLabsPlugin.so? DING!
One
instance found for the public key. This definitely looks like a copy of the
Niantic Labs leaf certificate.
This is an
so (shared object) file which is full of native code. This is where things get
more complicated. I’m going to be using IDA Pro version 6.9 to dig into this
file. There are other disassemblers out there that can do the job, but IDA
Pro is my tool of choice.
The fun begins.
Let’s
search for that same sequence of public key bytes.
There is
one instance, as expected. Scrolling up a bit eventually reveals a function
that references the entire leaf certificate.
Let’s go
into sub_A9BE4. Conveniently, the compiler has left a string at the top that
identifies this function.
After a
little research on Google, I discovered that NianticTrustManager is
basically Niantic’s customized X509TrustManager, and they have chosen to
override the default GetAcceptedIssuers method. By overriding it, they,
according to Java documentation, have the option to “Return an array of
certificate authority certificates which are trusted for authenticating peers.”
Let’s see
if there is anything interesting in this function.
I’ve spent
enough time reverse engineering to know that a memcmp (compare two blocks of
memory) and a “Rejected” string appearing in the same function is definitely
something worth investigating. unk_1E2584 is the embedded Niantic Labs
leaf certificate, so this function must be comparing it against another
certificate. In this case, the other certificate is the Fiddler
certificate. Looking at the flow of the assembly, we can NOP (no-operation)
that branch below the memcmp and it will eliminate the possibility of getting
to that “Rejected” block because of a memcmp failure. A NOP opcode in
ARM is 0x00BF, so let’s patch that in and see what the function looks
like.
As you can
see, our NOP is in place and there is no chance of getting to that
“Rejected” block anymore.
One more
patch is needed. Before the memcmp, the function is checking the
server certificate’s length. It is making sure the server certificate
is 0x5FF in length. The Niantic Labs leaf certificate is that long, but
Fiddler’s is not. Unfortunately, the flow of the assembly does not allow
us to NOP this branch. Right now, it is a BEQ, which, in this context, means
“branch if the server certificate’s length is equal to 0x5FF.” Let’s change
that to just a B, which is an unconditional branch, meaning it will always
branch to a specified location. This will eliminate the possibility of getting
to that “Rejected” block because of a length mismatch. To change this BEQ to a
B, all we need to do is to update the opcode from 0x14D0 to 0x14E0.
Looks good!
There are a few more possibilities of getting to that “Rejected” block, but
let’s test this out before we worry about them.
Patching
the APK
Note:
These steps are only valid for Pokémon GO version 0.31.0.
Open libNianticLabsPlugin.so
using a hex editor, or use IDA Pro’s Edit->Patch program menu functions to
do the following:
- Go to offset 0xA9C76 and
change 14 D0 to 14 E0. If you do not see 14
D0, you might be looking at the wrong file, or are looking at the wrong
version of Pokémon GO.
- Go to offset 0xA9CB0 and
change E2 D1 to 00 BF. If you do not see
E2 D1, you might be looking at the wrong file, or are looking at the wrong
version of Pokémon GO.
- Save the changes and close the
hex editor.
- Replace the
old libNianticLabsPlugin.so file in the APK with the patched one. You
can do this using any program that can open zip files – an APK is
basically a zip file.
- Sign the APK using your tool of
choice or ZipSigner in the Google Play
store.
- Uninstall Pokémon GO on your
device if it is installed and then install the patched APK, ignoring the
unknown sources warnings.
If
everything was done correctly, you will be able to see the HTTPS
requests in Fiddler, and Pokémon GO will function without displaying any error
messages.
Does
this work on iPhone?
You need a
jailbroken iPhone to modify apps. Thanks to reddit user Mila432, we know that the function is very
similar and can be patched the same way.
Important Note: Please do not abuse the Pokémon GO API. Putting additional load on the already-stressed servers could degrade the experience of millions of players around the world and encourage Niantic Labs to implement further API restrictions. Develop responsibly.
Comments
Post a Comment