Clients that run on machines have an interesting problem: we control the client. How do we know that the device is not being tampered with? How do we know that the application is not being reversed? Because developers do not want their IP stolen, there is a constant arms race on exploitation and protection.
Pokemon Go is mobile phone game meant to bring Pokemon to real life. The authors of the game, understandably, do not want people cheating at this game. People can cheat by spawning arbitrary Pokemon at will or teleports to foreign countries without actually traveling.
To make cheating harder, they have added anti-cheat protections. To start with, whenever the app is loaded when a Jailbroken phone, the game simply crashes. But why? The crashes are intentional!
The main Pokemon Go application is just a stub around the Unity implementation, which has the main logic. Among the things loaded is the NianticLabsPlugin plugin. This contains the myriad of protections put into the game to stop reversing, cheating and other things. This library is where the crash happens at.
Analyzing constructors gets us a long ways. On iOS and Android, we can hook the function call_array from the ELF loader. Within this, all constructor addresses are checked beforehand, making this a wonderful place to debug the code.
By hooking at this location, we can get control before the execution of constructors. This allows for the ability to trace them, replace/disable them and detect to hook other constructors as well. From this, NianticLabsPlugin has 120 constructors with various detection methods.
First, it checks for debuggers by seeing if PTrace is attached to the binary. If so, it kills itself. Straight syscalls are used instead of the normal wrapper function around PTrace.
In the same area, this is a kill to the PID of the binary with a signal of 0. According to the man page "[…] A value of 0, however, will cause error checking to be performed (with no signal being sent). This can be used to check the validity of pid." If the PID is not valid, we crash the program.
Pokemon Go opens a socket on the same port that Frida uses and tests the Frida handshake. If this is the case, then simply crash the program.
There is also simply Jailbreak detection that is done by checks if specific files exist. If so, the device is likely jailbroken and should crash. At some point, signature validation is done as well.
The ant-debugging techniques on this are pretty serious! The author goes into how to decode obfuscated strings in the binary as well. The new feature of the post (for Frida) is undo all relocations of symbols with an ELF. Overall, interesting post on anti-debugging techniques!