Aaron Ardiri
[Valid RSS] RSS/XML feed
198 entries available (show all)


Internet of Things (IoT)

RIoT Secure AB


"security through obscurity" - keeping things private/secret to go against the norm.

Sometimes; things are not always as they seem - take the above entry to the IOCCC in 1989. What on the surface looks like the mathematical symbol π, even containing the well known 3.1415 number sequence actually calculated the value of the e constant (2.718). In the realm of reverse engineering one of the most common approaches is to find known patterns that are put in place by the compiler, such as how parameters and return values are passed at assembler level.

In Pokémon GO; they made a simple mistake - standard calling methods making detection easy.

    uint8_t  buf[256] = { 0x61, 0x24, 0x7f, 0xbf, 0x00 };
    uint32_t len = 28;
    uint64_t hash;

For the same of demonstration, lets consider we have the above global variables and we want to calculate the LocationHash at lat=0, long=0 and altitude=0. This has been a standard test vector to verify the hash function; as the GPS can be spoofed/disabled to get a known response from the game servers to validate the hash function. The existing calling sequence was:

    uint64_t Hash(uint8_t *buf, uint32_t *len);
    hash = Hash(buf, len); // perform the hash

This is a standard calling sequence - when compiled to ARM assembly; the buffer pointer is passed in register r0, the length is passed in register r1 and the result is returned as a combination of registers r0 and r1. In fact; taking a quick look at the sources to the unicorn program doing the hashing - you can see this directly. So; in order to find the hash function, just need to find a similar signature and it will be considered a candidate.

So; what could Niantic do to mess with this pattern?

The following is a very simple modification, venturing away from standard practice; that could throw the reverse engineering team off guard when it comes to finding the hash function. A couple of small type declarations and the function signature needs to change:

    typedef struct
      uint8_t  *buf;
      uint32_t  len;
      uint64_t  hash;
    } HashPayload; 
    void Hash(HashPayload *payload);

The idea now would be to use a single parameter that references a chunk of memory that will contain the other parameters; this single parameter is then passed in using the register r0 and since there is no return value declared - the hash result can be obfuscated in the calling sequence. To hash a buffer, the following code would be required:

    HashPayload payload;
    payload.buf = buf;
    payload.len = len;
    Hash(&payload); // perform the hash
    hash = payload.hash; 

Depending on how the HashPayload structure is defined - this could be hell for the reverse engineering efforts. They would need to figure out how to reconstruct the result from whatever is being stored. A small tweak would be to mix up the structure and force some deconstruction after.

    typedef struct
      uint32_t  hash_lo;
      uint8_t  *buf;
      uint32_t  len;
      uint64_t  hash_hi;
    } HashPayload; 
    hash = ((uint64_t)payload.hash_hi << 32) | payload.hash_lo;

Even without employing code obfuscation to force a wild goose chase; such a simple modification would be far more effective - as it requires internal knowledge to know how to piece together the resulting information. Not as simple as following standard calling procedures.

In fact; it seems that something like this may have been implemented with the latest 0.47 release, finding the elusive hash function has been a lot more effort - and even when some candidates have been found, they haven't been using the registers the same way. A live update from discord:

    i can't see what parameters are being passed to the hash function
    it seems encrypted?
    its not buffer, size of buffer anymore
    source: discord #re-research chat room

It isn't however the end of the cat and mouse game; just another chapter in what will continue to be an ongoing saga between the game developer and those who want to capitalize on the API with bot engines or maps to either cheat or improve gameplay experience.

What about anti-emulation measures, what can be done here to make it harder?

It has been speculated that on Android; the SafetyNet engine has been integrated to prevent the use of emulation; more specifically, since Google can provide device integrity checks independent of the application this could be tied into the hashing process - an unknown only available when running on a non-tampered device. iOS doesn't offer such a service - at this point in time.

I am surprised that Niantic hasn't tried to integrate a dynamic element into the process - something that can only be generated when the application is running on the device itself. It could be as simple as hashing a couple of known resources in sequence between each API release. Injecting it using obscurity would make it almost impossible to track. Tie it into "forced-updates" periodically - it will be simply too much effort to reverse engineer for the rewards earned.


advertisement (self plug):
need assistance in an IoT project? contact us for a free consultation.


Pokémon GO - Revisiting the "hacking" scene (part 10)
Pokémon GO - Revisiting the "hacking" scene (part 8)

All content provided on this blog is for informational purposes only.
All comments are generated by users and moderated for inappropriateness periodically.
The owner will not be liable for any losses, injuries, or damages from the display or use of this information.