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

 

Internet of Things (IoT)
   

PLEASE TAKE A MOMENT TO FOLLOW MY NEW VENTURE:
 
RIoT Secure AB
 
ALL SECURITY RELATED TOPICS ON IoT wILL BE POSTED THERE


2016-10-26
>> Pokémon GO - REVISITING THE "HACKING" SCENE (PART 2)

Seems fitting with the haloween promotion there is a shady creature sitting in the shadows.

In our previous entry we covered the history behind the reverse engineering effort on the Pokémon GO application that has now turned into a cat and mouse game between the developers Niantic and the hacking community. While the current method may be questionable; it is actually in fact quite ingenious - utilizing disassembly tools like Hex-Rays IDA and a CPU emulator known as Unicorn. While I wont post working code; I will explain the concept and show the hash generation.

The typical process of reverse engineering requires deconstructing the package files, isolating the executable code and using debugging tools to trace the execution flow of the application. In the initial versions of Pokémon GO where no counter measures in place to prevent the decompilation of the application - in fact, it was so easy, developers could modify the code and introduce neat hacks quite easily. Not anymore however - the code is now heavily obfuscated.

As updates rolled out, additional counter measures were implemented. One of the first was to deal with "cheaters", was the Unknown6 signature to the elusive hash function that has yet to be reverse engineered. While the hash function location was found quite easily - the frustration of dealing with the anti-tamper mechanisms forced exploring alternative solutions; CPU emulation.

While the documentation is sparse; the tutorial for Unicorn explains usage well.

The idea floating around was to utilize the pokemongo executable from the iOS application directly to calculate the hash required while communicating with the servers. After isolating the "root" check (basically, ignore the detection) and patching some of the dynamically loaded function references such as stack checking guards - the code was ready to run through the emulator.

In order to do this; the calling parameters of the hash function had to be determined. In typical ARM calling sequences, this was that r0 contains the pointer to the buffer and r1 contains the length of the buffer to be hashed detailing the calling sequence as:

    uint64_t Hash(unsigned char* buffer, int size)

While it would be possible to call the function directly in the emulation engine, to make things easier - a small stub was created to know when to stop emulation. This stub essentially executes a blx r2 which means call the function at the address stored in r2. On completion; the hash is stored within the r0 and r1 registers and an uint64_t hash can be constructed.

An overview of the assembler looks like:

    0x00001000: blx    r2      0x1be8290: push   {r4, r5, r6, r7, lr}
                               0x1be8292: add    r7, sp, #0xc
      ---> call 0x1be8290      0x1be8294: push.w {r8, r10, r11}
                               0x1be8298: sub    sp, #0x118
                               0x1be829a: mov    r4, sp
                               0x1be829c: bfc    r4, #0, #3
                               0x1be82a0: mov    sp, r4
    
                                                   ....
    
                               0x1be95aa: moveq  sp, r4
                               0x1be95ac: popeq.w {r8, r10, r11}
                               0x1be95b0: popeq  {r4, r5, r6, r7, pc} 

The exact calling sequence looks like:

    uint64_t Hash(unsigned char* buffer, int size)
    {
      uint64_t ret;
      uint32_t r0 = 0xE0001000;            // buffer (our emu heap)
      uint32_t r1 = size;                  // buffer length
      uint32_t r2 = HashFunctionAddr + 1;  // iOS hash function address
    
      // copy our buffer to the emulation heap
      uc_mem_write(uc, r0, buffer, size);
    
      // put the appropriate values in the right registers
      uc_reg_write(uc, UC_ARM_REG_R0, &r0);
      uc_reg_write(uc, UC_ARM_REG_R1, &r1);
      uc_reg_write(uc, UC_ARM_REG_R2, &r2);
    
      // execute code
      uc_err err = uc_emu_start(uc, 0x1000, 0x1002, 0, 0);
    
      // re-construct the return value from r0 and r1
      uc_reg_read(uc, UC_ARM_REG_R0, &r0);
      uc_reg_read(uc, UC_ARM_REG_R1, &r1);
    
      ret = (unsigned int)r1;
      ret = (ret << 32) | (unsigned int)r0;
      return ret;
    }

Looks pretty basic right? Let's see how it performs.

    $ ./pogohash
    :: Hash(buffer, sizeof(buffer) [iOS code]
    61 24 7f bf 00 00 00 00 00 00 00 00 00 00 00 00 
    00 00 00 00 00 00 00 00 00 00 00 00 len=28
    hash: 0xddef1097a35c4ed8
    done

The return value was validated and then integrated into the other known efforts for reverse engineering the API and a successful request was made. The most difficult effort was then to integrate the CPU emulation into the existing third party service and deal with the issue of performance. So; how does the Unicorn CPU emulator actually perform?

    $ time ./pogohash
    
    real	0m3.573s
    user	0m3.320s
    sys	0m0.280s

No; that wasn't for a single hash. In fact, the Unicorn CPU emulator has a JIT (Just In Time) compilation engine that actually gives it near native performance - it is only the initial execution that is slower. The above timing was performed on a Linux machine with a Intel® Xeon® CPU running at 3.20GHz with 8GB of RAM - for 10,000 hashes - thats 2,798 hashes per second!

While the reverse engineering team is continuing to deconstruct the algorithm to avoid utilizing the application binaries itself - it just goes to show that regardless how much you try to protect your application from hackers, you will always lose the battle. In fact; having a CPU emulator do all the work for you also gives it a little bit of future proofing as well.

The source code (updated to 43.3) for the cpu emulation and socket server for hashing is available:

UPDATE: 2016-11-05
A version of the hash function has been produced after hours of work tracing the raw assembler of the hash function and translating it to C. It has been released to the public on github - I have taken the liberty of integrating it into pogohash-server and a new, separate download is available below.


 

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

 



Arduino powered solar tracker turret
 
Pokémon GO - Revisiting the "hacking" scene (part 1)

DISCLAIMER:
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.