diff --git a/pogom/__init__.py b/pogom/__init__.py index c2b06ff7..850ce519 100644 --- a/pogom/__init__.py +++ b/pogom/__init__.py @@ -12,5 +12,6 @@ ], 'ROOT_PATH': None, 'CONFIG_PATH': None, - 'SIGNATURE_LIB_PATH': None + 'SIGNATURE_LIB_PATH': None, + 'HASH_LIB_PATH': None } diff --git a/pogom/lib/LICENSE.md b/pogom/lib/LICENSE.md new file mode 100644 index 00000000..e4b7be00 --- /dev/null +++ b/pogom/lib/LICENSE.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2016 PokéLibs + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/pogom/lib/README.md b/pogom/lib/README.md new file mode 100644 index 00000000..842512dc --- /dev/null +++ b/pogom/lib/README.md @@ -0,0 +1,69 @@ +[PokéLibs](https://github.com/pokelibs) + +# pgoapi-libs +[![license](https://img.shields.io/github/license/pokelibs/pgoapi-libs.svg?maxAge=2592000?style=flat-square)](https://github.com/pokelibs/pgoapi-libs/blob/master/LICENSE.md) + +## Table of Contents + +* [What is it?](#what-is-it) +* [Installation](#installation) +* [Documentation](#documentation) +* [Contributing](#contributing) + * [Core Maintainers](#core-maintainers) +* [Licensing](#licensing) + +## What is it? +`pgoapi-libs` is the official source repository for all hashing, encrypt and future libraries that need to be shipped with various API implementations. + +## Installation +Simply checkout this repository as a submodule for your project at the desired tagged release. +Please make sure that the SHA256SUMS match up with the sums for each file to assure it hasn't been tampered with. +The latest sums are: + +``` +b8f62a0fbb301eabbe4cb83bab2c17f35360116b46e196fd53ef5da1d7d1395d libniahash-freebsd-i386.so +3ffbc2f64ffda74c82cefeff94a7d3aeba72efcc890b847ff2732c308768e6dd libniahash-freebsd-x86-64.so +e1eff1af978b0fda2b883d38c53290c15de3ca4274b4bd8690d41eab8558843b libniahash-linux-arm32.so +8fcb0424682df55684410ebb078adc467842f2cf4d2c1b5cc757e461388671df libniahash-linux-arm64.so +c194a4207eabf0f3e2b418e39747dabeb63aba397a73b27c64eb064e9b344d83 libniahash-linux-i386.so +dd1e9510e58f2793f3f92ec352c8d301e797be473c8aa00d731e5d931f0f76b2 libniahash-linux-x86-64.so +c6985404f10dd5daab8458c80432ae773b4ac2d8129fcbd05c25668e199d5882 libpcrypt-freebsd-i386.so +a6f9e9b45ce7ac6d7475c69abc4f763ea3195cce10f1cbff65bf9f09c1cf868a libpcrypt-freebsd-x86-64.so +6fd47cc98534065ace055e378746492bbb4b07807d35c8639df9f56f895878cc libpcrypt-linux-arm32.so +4bf2131e82cd95d2a48f6807af42cbe6540238ac417529d9e3d82cac3a28e5d4 libpcrypt-linux-arm64.so +f3110263ac01788edb580e1a96d0bc52a355720298876b4c66d5ce089b0cc7de libpcrypt-linux-i386.so +49d86fcea6d40371c7194acc494b715e06a0733ab28ed4460496629e83d9d01d libpcrypt-linux-x86-64.so +549cbc22d4fdee557706ceb70f10c935e995509b2f230272c6c6384c7eb6f925 libniahash-macos-i386.dylib +bfd97a9028a30e711ac5db7967e425f298ca710b5f3c3878c85ffa47df40da76 libniahash-macos-x86-64.dylib +62d87ca447fac6e9d366119c3974ba5016feaeb6aa886eda4fbc8aa3e85e456d libpcrypt-macos-i386.dylib +def6546280ee3d5117e04856532bd81517424695036d4bb60887c8d06412cd32 libpcrypt-macos-x86-64.dylib +663bec4e8987923c2f82f4aa99c9039c04cf67be6c9eeaec628861ce839c573f libniahash-windows-i686.dll +c0f9197c67a82b0920293b1a8e2c0a74e1125236c0da7c9d53ab6b7d2b72c70f libniahash-windows-x86-64.dll +dbf76869afde7fed4f40118f72e4bfa68ea50c20bc32397921f9a04e1e948c56 libpcrypt-windows-i686.dll +b6d11b185384a5df02a48c064b6005074a90b14dfbec05b8539d2bba987a33cc libpcrypt-windows-x86-64.dll +``` + +## Documentation +More detailed instructions on how to compile the given libraries will be updated soon, for now a roughy guideline is given below. + +* Checkout https://github.com/laverdet/pcrypt-c (Thanks a lot to @marcel) +* Use `make all` +* Checkout https://gist.github.com/Noctem/018c107d6a6297c24e36a00d4da046c9 (Thanks a lot to @Waryas, @marcel, @HatchingEgg, @Apoc) +* Make the file according to the following flags: (Thanks a lot to @noctem) +``` +Linux: + cc -fPIC -O3 -shared niahash.c -o libniahash-linux-x86-64.so +macOS: + clang -march=core2 -shared -fPIC -mmacosx-version-min=10.7 -O3 niahash.c -o libniahash-macos-x86-64.dylib +Windows: + x86_64-w64-mingw32-gcc -O3 -fPIC -shared niahash.c -o libniahash-windows-x86-64.dll +``` + +## Licensing +[MIT](https://github.com/pokelibs/pgoapi-libs/blob/master/LICENSE) + +### Third Party Licenses + None + +## Contributing +Currently, you can contribute to this project by visiting and discussing with us in Discord diff --git a/pogom/lib/SHA256SUMS b/pogom/lib/SHA256SUMS new file mode 100644 index 00000000..18348287 --- /dev/null +++ b/pogom/lib/SHA256SUMS @@ -0,0 +1,20 @@ +b8f62a0fbb301eabbe4cb83bab2c17f35360116b46e196fd53ef5da1d7d1395d libniahash-freebsd-i386.so +3ffbc2f64ffda74c82cefeff94a7d3aeba72efcc890b847ff2732c308768e6dd libniahash-freebsd-x86-64.so +e1eff1af978b0fda2b883d38c53290c15de3ca4274b4bd8690d41eab8558843b libniahash-linux-arm32.so +8fcb0424682df55684410ebb078adc467842f2cf4d2c1b5cc757e461388671df libniahash-linux-arm64.so +c194a4207eabf0f3e2b418e39747dabeb63aba397a73b27c64eb064e9b344d83 libniahash-linux-i386.so +dd1e9510e58f2793f3f92ec352c8d301e797be473c8aa00d731e5d931f0f76b2 libniahash-linux-x86-64.so +c6985404f10dd5daab8458c80432ae773b4ac2d8129fcbd05c25668e199d5882 libpcrypt-freebsd-i386.so +a6f9e9b45ce7ac6d7475c69abc4f763ea3195cce10f1cbff65bf9f09c1cf868a libpcrypt-freebsd-x86-64.so +6fd47cc98534065ace055e378746492bbb4b07807d35c8639df9f56f895878cc libpcrypt-linux-arm32.so +4bf2131e82cd95d2a48f6807af42cbe6540238ac417529d9e3d82cac3a28e5d4 libpcrypt-linux-arm64.so +f3110263ac01788edb580e1a96d0bc52a355720298876b4c66d5ce089b0cc7de libpcrypt-linux-i386.so +49d86fcea6d40371c7194acc494b715e06a0733ab28ed4460496629e83d9d01d libpcrypt-linux-x86-64.so +549cbc22d4fdee557706ceb70f10c935e995509b2f230272c6c6384c7eb6f925 libniahash-macos-i386.dylib +bfd97a9028a30e711ac5db7967e425f298ca710b5f3c3878c85ffa47df40da76 libniahash-macos-x86-64.dylib +62d87ca447fac6e9d366119c3974ba5016feaeb6aa886eda4fbc8aa3e85e456d libpcrypt-macos-i386.dylib +def6546280ee3d5117e04856532bd81517424695036d4bb60887c8d06412cd32 libpcrypt-macos-x86-64.dylib +663bec4e8987923c2f82f4aa99c9039c04cf67be6c9eeaec628861ce839c573f libniahash-windows-i686.dll +c0f9197c67a82b0920293b1a8e2c0a74e1125236c0da7c9d53ab6b7d2b72c70f libniahash-windows-x86-64.dll +dbf76869afde7fed4f40118f72e4bfa68ea50c20bc32397921f9a04e1e948c56 libpcrypt-windows-i686.dll +b6d11b185384a5df02a48c064b6005074a90b14dfbec05b8539d2bba987a33cc libpcrypt-windows-x86-64.dll diff --git a/pogom/lib/checksum.sh b/pogom/lib/checksum.sh new file mode 100644 index 00000000..a014d8fc --- /dev/null +++ b/pogom/lib/checksum.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +sha256sum *.so *.dylib *.dll > SHA256SUMS \ No newline at end of file diff --git a/pogom/lib/libniahash-freebsd-i386.so b/pogom/lib/libniahash-freebsd-i386.so new file mode 100644 index 00000000..258d65ba Binary files /dev/null and b/pogom/lib/libniahash-freebsd-i386.so differ diff --git a/pogom/lib/libniahash-freebsd-x86-64.so b/pogom/lib/libniahash-freebsd-x86-64.so new file mode 100644 index 00000000..9b37572b Binary files /dev/null and b/pogom/lib/libniahash-freebsd-x86-64.so differ diff --git a/pogom/lib/libniahash-linux-arm32.so b/pogom/lib/libniahash-linux-arm32.so new file mode 100644 index 00000000..d0cee237 Binary files /dev/null and b/pogom/lib/libniahash-linux-arm32.so differ diff --git a/pogom/lib/libniahash-linux-arm64.so b/pogom/lib/libniahash-linux-arm64.so new file mode 100644 index 00000000..8739b7d2 Binary files /dev/null and b/pogom/lib/libniahash-linux-arm64.so differ diff --git a/pogom/lib/libniahash-linux-i386.so b/pogom/lib/libniahash-linux-i386.so new file mode 100644 index 00000000..9737276b Binary files /dev/null and b/pogom/lib/libniahash-linux-i386.so differ diff --git a/pogom/lib/libniahash-linux-x86-64.so b/pogom/lib/libniahash-linux-x86-64.so new file mode 100644 index 00000000..a716c44a Binary files /dev/null and b/pogom/lib/libniahash-linux-x86-64.so differ diff --git a/pogom/lib/libniahash-macos-i386.dylib b/pogom/lib/libniahash-macos-i386.dylib new file mode 100644 index 00000000..7ba41ca2 Binary files /dev/null and b/pogom/lib/libniahash-macos-i386.dylib differ diff --git a/pogom/lib/libniahash-macos-x86-64.dylib b/pogom/lib/libniahash-macos-x86-64.dylib new file mode 100644 index 00000000..15102a40 Binary files /dev/null and b/pogom/lib/libniahash-macos-x86-64.dylib differ diff --git a/pogom/lib/libniahash-windows-i686.dll b/pogom/lib/libniahash-windows-i686.dll new file mode 100644 index 00000000..8d5703c3 Binary files /dev/null and b/pogom/lib/libniahash-windows-i686.dll differ diff --git a/pogom/lib/libniahash-windows-x86-64.dll b/pogom/lib/libniahash-windows-x86-64.dll new file mode 100644 index 00000000..831333df Binary files /dev/null and b/pogom/lib/libniahash-windows-x86-64.dll differ diff --git a/pogom/lib/libpcrypt-freebsd-i386.so b/pogom/lib/libpcrypt-freebsd-i386.so new file mode 100644 index 00000000..d4194a74 Binary files /dev/null and b/pogom/lib/libpcrypt-freebsd-i386.so differ diff --git a/pogom/lib/libpcrypt-freebsd-x86-64.so b/pogom/lib/libpcrypt-freebsd-x86-64.so new file mode 100644 index 00000000..41ef958d Binary files /dev/null and b/pogom/lib/libpcrypt-freebsd-x86-64.so differ diff --git a/pogom/lib/libpcrypt-linux-arm32.so b/pogom/lib/libpcrypt-linux-arm32.so new file mode 100644 index 00000000..916969e8 Binary files /dev/null and b/pogom/lib/libpcrypt-linux-arm32.so differ diff --git a/pogom/lib/libpcrypt-linux-arm64.so b/pogom/lib/libpcrypt-linux-arm64.so new file mode 100644 index 00000000..8451663a Binary files /dev/null and b/pogom/lib/libpcrypt-linux-arm64.so differ diff --git a/pogom/lib/libpcrypt-linux-i386.so b/pogom/lib/libpcrypt-linux-i386.so new file mode 100644 index 00000000..8bfadf9a Binary files /dev/null and b/pogom/lib/libpcrypt-linux-i386.so differ diff --git a/pogom/lib/libpcrypt-linux-x86-64.so b/pogom/lib/libpcrypt-linux-x86-64.so new file mode 100644 index 00000000..c8fe6418 Binary files /dev/null and b/pogom/lib/libpcrypt-linux-x86-64.so differ diff --git a/pogom/lib/libpcrypt-macos-i386.dylib b/pogom/lib/libpcrypt-macos-i386.dylib new file mode 100644 index 00000000..1a09255b Binary files /dev/null and b/pogom/lib/libpcrypt-macos-i386.dylib differ diff --git a/pogom/lib/libpcrypt-macos-x86-64.dylib b/pogom/lib/libpcrypt-macos-x86-64.dylib new file mode 100644 index 00000000..47e2ab48 Binary files /dev/null and b/pogom/lib/libpcrypt-macos-x86-64.dylib differ diff --git a/pogom/lib/libpcrypt-windows-i686.dll b/pogom/lib/libpcrypt-windows-i686.dll new file mode 100644 index 00000000..6afc7835 Binary files /dev/null and b/pogom/lib/libpcrypt-windows-i686.dll differ diff --git a/pogom/lib/libpcrypt-windows-x86-64.dll b/pogom/lib/libpcrypt-windows-x86-64.dll new file mode 100644 index 00000000..81d80ae7 Binary files /dev/null and b/pogom/lib/libpcrypt-windows-x86-64.dll differ diff --git a/pogom/libencrypt/encrypt32bit.dll b/pogom/libencrypt/encrypt32bit.dll deleted file mode 100644 index 1565c467..00000000 Binary files a/pogom/libencrypt/encrypt32bit.dll and /dev/null differ diff --git a/pogom/libencrypt/encrypt64bit.dll b/pogom/libencrypt/encrypt64bit.dll deleted file mode 100644 index 3256ef26..00000000 Binary files a/pogom/libencrypt/encrypt64bit.dll and /dev/null differ diff --git a/pogom/libencrypt/libencrypt-centos-x86-64.so b/pogom/libencrypt/libencrypt-centos-x86-64.so deleted file mode 100644 index 6894cb67..00000000 Binary files a/pogom/libencrypt/libencrypt-centos-x86-64.so and /dev/null differ diff --git a/pogom/libencrypt/libencrypt-freebsd-64.so b/pogom/libencrypt/libencrypt-freebsd-64.so deleted file mode 100644 index ff1d7e02..00000000 Binary files a/pogom/libencrypt/libencrypt-freebsd-64.so and /dev/null differ diff --git a/pogom/libencrypt/libencrypt-freebsd10-64.so b/pogom/libencrypt/libencrypt-freebsd10-64.so deleted file mode 100644 index ff1d7e02..00000000 Binary files a/pogom/libencrypt/libencrypt-freebsd10-64.so and /dev/null differ diff --git a/pogom/libencrypt/libencrypt-linux-arm-32.so b/pogom/libencrypt/libencrypt-linux-arm-32.so deleted file mode 100644 index 804b79f7..00000000 Binary files a/pogom/libencrypt/libencrypt-linux-arm-32.so and /dev/null differ diff --git a/pogom/libencrypt/libencrypt-linux-arm-64.so b/pogom/libencrypt/libencrypt-linux-arm-64.so deleted file mode 100644 index be3d442d..00000000 Binary files a/pogom/libencrypt/libencrypt-linux-arm-64.so and /dev/null differ diff --git a/pogom/libencrypt/libencrypt-linux-x86-32.so b/pogom/libencrypt/libencrypt-linux-x86-32.so deleted file mode 100644 index c43bc5ae..00000000 Binary files a/pogom/libencrypt/libencrypt-linux-x86-32.so and /dev/null differ diff --git a/pogom/libencrypt/libencrypt-linux-x86-64.so b/pogom/libencrypt/libencrypt-linux-x86-64.so deleted file mode 100644 index 69346fcf..00000000 Binary files a/pogom/libencrypt/libencrypt-linux-x86-64.so and /dev/null differ diff --git a/pogom/libencrypt/libencrypt-osx-64.so b/pogom/libencrypt/libencrypt-osx-64.so deleted file mode 100644 index 1d173298..00000000 Binary files a/pogom/libencrypt/libencrypt-osx-64.so and /dev/null differ diff --git a/pogom/pgoapi/__init__.py b/pogom/pgoapi/__init__.py index b734940b..acace78a 100755 --- a/pogom/pgoapi/__init__.py +++ b/pogom/pgoapi/__init__.py @@ -35,6 +35,7 @@ __author__ = 'tjado' __license__ = 'MIT License' __copyright__ = 'Copyright (c) 2016 tjado ' +__patchedBy__ = 'Patched for API version 0.51.0 by the PokeHunter Project ' protobuf_exist = False protobuf_version = "0" diff --git a/pogom/pgoapi/hash_emulator.py b/pogom/pgoapi/hash_emulator.py new file mode 100644 index 00000000..90c426fe --- /dev/null +++ b/pogom/pgoapi/hash_emulator.py @@ -0,0 +1,161 @@ +from __future__ import print_function +from unicorn import * +from unicorn.arm_const import * + +from binascii import hexlify, unhexlify + +import struct +import ctypes + +DEBUG = 0 + +# WORK IN PROGRESS : Hash Emulation on unicorn engine +class HashEmulator: + POGO_FILE_NAME = "pokemongo_0_45.payload" + + POGO_BIN_SIZE = 0x0327F500 + POGO_BIN_OFFSET = 0x00008830 + POGO_BIN_MAX = POGO_BIN_SIZE + POGO_FUNC = 0x1B175C0 + POGO_FUNC_END = 0x1B17AA4 + NL_SYM_PTR_BASE = 0x2CC8000 + LA_SYM_PTR_END = 0x2D09E58 + POGO_EXP_ADDR = NL_SYM_PTR_BASE + POGO_EXP_CNT = ((LA_SYM_PTR_END - NL_SYM_PTR_BASE) / 4) + POGO_SEG_COMMON = 0x0312C980 + + POGO_NOP_FIX1 = 0x01B1769C + POGO_NOP_FIX2 = 0x01b17cd4 + POGO_HICKUP_ENTRY_BEGIN_STOP = 0x01B175D2 + POGO_HICKUP_ENTRY_2 = 0x01B175DA + POGO_HICKUP_ENTRY_2_STOP = 0x01B17CF4 + POGO_HICKUP_ENTRY_3 = 0x01B17CFE + + def __init__(self): + self.mu = Uc(UC_ARCH_ARM, UC_MODE_THUMB) + + self.mu.hook_add(UC_HOOK_CODE, self.POGO_hook) + self.mu.hook_add(UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE, self.POGO_hook_mem) + + # heap and stack allocation + self.POGO_createmap(0xE0000000, 0x2000) + self.POGO_createmap(0xD0000000, 0x2000) + sp = 0xD0000000 + 0x1000 + + # stack + self.mu.reg_write(UC_ARM_REG_SP, sp) + + # start code calling hash func + self.POGO_createmap(0x1000, 0x1000) + self.mu.mem_write(0x1000, "\x90\x47") + + # binary mapping + f = open(self.POGO_FILE_NAME, "rb") + code_buffer = f.read(self.POGO_BIN_SIZE) + f.close() + + # memory prepare + self.POGO_createmap(self.POGO_BIN_OFFSET, self.POGO_BIN_MAX - self.POGO_BIN_OFFSET) + + code_buffer = code_buffer[:self.POGO_NOP_FIX1] + b'\x00\x00\x00\x00' + code_buffer[self.POGO_NOP_FIX1+4:] + code_buffer = code_buffer[:self.POGO_NOP_FIX2] + b'\x00\x00\x00\x00' + code_buffer[self.POGO_NOP_FIX2+4:] + + # all segment + self.mu.mem_write(self.POGO_BIN_OFFSET, code_buffer[self.POGO_BIN_OFFSET:self.POGO_BIN_MAX]) + + # export address fill with any valid address + exportdata = self.POGO_SEG_COMMON + exportaddr = self.POGO_EXP_ADDR + + for i in range(0, self.POGO_EXP_CNT): + value1 = code_buffer[exportaddr + (i*4)].encode("hex") + value2 = code_buffer[exportaddr + (i*4)+1].encode("hex") + value3 = code_buffer[exportaddr + (i*4)+2].encode("hex") + value4 = code_buffer[exportaddr + (i*4)+3].encode("hex") + if value1 == "00" and value2 == "00" and value3 == "00" and value4 == "00": + self.mu.mem_write(exportaddr + (i * 4), struct.pack(">> Tracing instruction at 0x%x" %(address), end=' ') + #for i in range(0, 2): + #print(code_buffer[address + i].encode("hex"), end=' ') + print(" ") + + def POGO_hook_mem(self, uc, access, addr, size, value, user_data): + if DEBUG and addr < 0xD0000000: + if access == UC_MEM_READ: + print("r", end=' ') + elif access == UC_MEM_WRITE: + print("w", end=' ') + elif access == UC_MEM_FETCH: + print("f", end=' ') + print("len:%d at 0x%lx" % (size, addr)) + + def POGO_createmap(self, address, size): + chunk = address % 0x1000 + taddr = address - chunk + tsize = ((0xFFF + chunk + size) / 0x1000) * 0x1000 + + self.mu.mem_map(taddr, tsize) + + def push(self, reg): + sp = self.mu.reg_read(UC_ARM_REG_SP) + regVal = self.mu.reg_read(reg) + self.mu.mem_write(sp, struct.pack(">i", regVal)) + sp = sp - 4 + self.mu.reg_write(UC_ARM_REG_SP, sp) + + def pop(self, reg): + sp = self.mu.reg_read(UC_ARM_REG_SP) + regVal = self.mu.mem_read(sp, 4) + self.mu.reg_write(reg, struct.unpack("i", regVal)[0]) + sp = sp + 4 + self.mu.reg_write(UC_ARM_REG_SP, sp) + + def hash(self, buffer, size): + # HASH + #buffer = "\x46\xe9\x45\xf8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + buffer = "\x46\xe9\x45\xf8" + "\x00" * 24 + print(hexlify(buffer)) + print(size) + #size = 28 + + self.mu.reg_write(UC_ARM_REG_R0, 0xE0001000) + self.mu.reg_write(UC_ARM_REG_R1, size) + self.mu.reg_write(UC_ARM_REG_R2, self.POGO_FUNC + 1) + + self.mu.mem_write(0xE0001000, buffer) + + try: + self.mu.emu_start(0x1000, self.POGO_HICKUP_ENTRY_BEGIN_STOP) + print("1 done") + self.push(UC_ARM_REG_D8) + self.push(UC_ARM_REG_D9) + self.push(UC_ARM_REG_D10) + self.push(UC_ARM_REG_D11) + self.push(UC_ARM_REG_D12) + self.push(UC_ARM_REG_D13) + self.push(UC_ARM_REG_D14) + self.push(UC_ARM_REG_D15) + self.mu.emu_start(self.POGO_HICKUP_ENTRY_2, self.POGO_HICKUP_ENTRY_2_STOP) + print("2 done") + self.pop(UC_ARM_REG_D15) + self.pop(UC_ARM_REG_D14) + self.pop(UC_ARM_REG_D13) + self.pop(UC_ARM_REG_D12) + self.pop(UC_ARM_REG_D11) + self.pop(UC_ARM_REG_D10) + self.pop(UC_ARM_REG_D9) + self.pop(UC_ARM_REG_D8) + self.mu.emu_start(self.POGO_HICKUP_ENTRY_3, 0x1002) + print("3 done") + except UcError as e: + print("ERROR: %s" % e) + + r0 = self.mu.reg_read(UC_ARM_REG_R0) + r1 = self.mu.reg_read(UC_ARM_REG_R1) + + ret = r1 + ret = (ret << 32) | r0 + return ret \ No newline at end of file diff --git a/pogom/pgoapi/hash_engine.py b/pogom/pgoapi/hash_engine.py new file mode 100644 index 00000000..7f406bce --- /dev/null +++ b/pogom/pgoapi/hash_engine.py @@ -0,0 +1,15 @@ +class HashEngine: + def __init__(self): + self.location_hash = None + self.location_auth_hash = None + self.request_hashes = [] + + def hash(self, timestamp, latitude, longitude, altitude, authticket, sessiondata, requests): + raise NotImplementedError() + + def get_location_hash(self): + return self.location_hash + def get_location_auth_hash(self): + return self.location_auth_hash + def get_request_hashes(self): + return self.request_hashes \ No newline at end of file diff --git a/pogom/pgoapi/hash_library.py b/pogom/pgoapi/hash_library.py new file mode 100644 index 00000000..63e3a477 --- /dev/null +++ b/pogom/pgoapi/hash_library.py @@ -0,0 +1,55 @@ +from __future__ import absolute_import + +import ctypes +import struct + +from .hash_engine import HashEngine +from .utilities import d2h + +HASH_SEED = 0x46E945F8 # static hash seed from app + +class HashLibrary(HashEngine): + def __init__(self, library_path): + self._hash_lib = ctypes.cdll.LoadLibrary(library_path) + self._hash_lib.compute_hash.argtypes = (ctypes.POINTER(ctypes.c_ubyte), ctypes.c_uint32) + self._hash_lib.compute_hash.restype = ctypes.c_uint64 + + def hash(self, timestamp, latitude, longitude, altitude, authticket, sessiondata, requests): + self.location_hash = None + self.location_auth_hash = None + self.request_hashes = [] + + first_hash = self.hash32(authticket, seed=HASH_SEED) + location_bytes = d2h(latitude) + d2h(longitude) + d2h(altitude) + loc_hash = self.hash32(location_bytes, seed=first_hash) + self.location_auth_hash = ctypes.c_int32(loc_hash).value + + loc_hash = self.hash32(location_bytes, seed=HASH_SEED) + self.location_hash = ctypes.c_int32(loc_hash).value + + first_hash = self.hash64salt32(authticket, seed=HASH_SEED) + for request in requests: + req_hash = self.hash64salt64(request.SerializeToString(), seed=first_hash) + self.request_hashes.append(ctypes.c_int64(req_hash).value) + + def hash64salt32(self, buf, seed): + buf = struct.pack(">I", seed) + buf + return self.call_hash(buf) + + def hash64salt64(self, buf, seed): + buf = struct.pack(">Q", seed) + buf + return self.call_hash(buf) + + def hash32(self, buf, seed): + buf = struct.pack(">I", seed) + buf + hash64 = self.call_hash(buf) + signedhash64 = ctypes.c_int64(hash64) + return ctypes.c_uint(signedhash64.value).value ^ ctypes.c_uint(signedhash64.value >> 32).value + + def call_hash(self, buf): + buf = list(bytearray(buf)) + num_bytes = len(buf) + array_type = ctypes.c_ubyte * num_bytes + + data = self._hash_lib.compute_hash(array_type(*buf), ctypes.c_uint32(num_bytes)) + return ctypes.c_uint64(data).value \ No newline at end of file diff --git a/pogom/pgoapi/hash_server.py b/pogom/pgoapi/hash_server.py new file mode 100644 index 00000000..29e08c9e --- /dev/null +++ b/pogom/pgoapi/hash_server.py @@ -0,0 +1,61 @@ +from __future__ import absolute_import + +import ctypes +import json +import base64 +import requests + +from .hash_engine import HashEngine +from .exceptions import ServerBusyOrOfflineException, ServerSideAccessForbiddenException, UnexpectedResponseException + +class HashServer(HashEngine): + + def __init__(self, auth_token): + self.endpoint = "https://pokehash.buddyauth.com/api/v121_2/hash" + self.headers = {'content-type': 'application/json', 'Accept' : 'application/json', 'X-AuthToken' : auth_token} + + self._session = requests.session() + self._session.verify = True + self._session.headers.update({'User-Agent': 'Python pgoapi @pogodev'}) + + def hash(self, timestamp, latitude, longitude, altitude, authticket, sessiondata, requestslist): + self.location_hash = None + self.location_auth_hash = None + self.request_hashes = [] + + payload = {} + payload["Timestamp"] = json.dumps(timestamp) + payload["Latitude"] = latitude + payload["Longitude"] = longitude + payload["Altitude"] = altitude + payload["AuthTicket"] = base64.b64encode(authticket) + payload["SessionData"] = base64.b64encode(sessiondata) + payload["Requests"] = [] + for request in requestslist: + payload["Requests"].append(base64.b64encode(request.SerializeToString())) + + # ask hash server how is it going ? and get json + try: + response_raw = self._session.post(self.endpoint, json=payload, headers=self.headers, timeout=30) + except (requests.exceptions.Timeout, requests.exceptions.ConnectionError) as error: + raise ServerBusyOrOfflineException(error) + + if response_raw.status_code == 400: + raise UnexpectedResponseException("400 : Bad request, error = " + response_raw.content) + elif response_raw.status_code == 401: + raise ServerSideAccessForbiddenException("401 : You are not authorized to use this service") + elif response_raw.status_code == 429: + raise ServerSideAccessForbiddenException("429 : Request limited, error = " + response_raw.content) + elif response_raw.status_code != 200: + error = 'Unexpected HTTP server response - needs 200 got {}'.format(response_raw.status_code) + raise UnexpectedResponseException(error) + + if response_raw.content is None: + raise UnexpectedResponseException + + reponse_parsed = json.loads(response_raw.content) + self.location_auth_hash = ctypes.c_int32(reponse_parsed['locationAuthHash']).value + self.location_hash = ctypes.c_int32(reponse_parsed['locationHash']).value + + for request_hash in reponse_parsed['requestHashes']: + self.request_hashes.append(ctypes.c_int64(request_hash).value) diff --git a/pogom/pgoapi/lib/LICENSE.md b/pogom/pgoapi/lib/LICENSE.md new file mode 100644 index 00000000..e4b7be00 --- /dev/null +++ b/pogom/pgoapi/lib/LICENSE.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2016 PokéLibs + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/pogom/pgoapi/lib/README.md b/pogom/pgoapi/lib/README.md new file mode 100644 index 00000000..842512dc --- /dev/null +++ b/pogom/pgoapi/lib/README.md @@ -0,0 +1,69 @@ +[PokéLibs](https://github.com/pokelibs) + +# pgoapi-libs +[![license](https://img.shields.io/github/license/pokelibs/pgoapi-libs.svg?maxAge=2592000?style=flat-square)](https://github.com/pokelibs/pgoapi-libs/blob/master/LICENSE.md) + +## Table of Contents + +* [What is it?](#what-is-it) +* [Installation](#installation) +* [Documentation](#documentation) +* [Contributing](#contributing) + * [Core Maintainers](#core-maintainers) +* [Licensing](#licensing) + +## What is it? +`pgoapi-libs` is the official source repository for all hashing, encrypt and future libraries that need to be shipped with various API implementations. + +## Installation +Simply checkout this repository as a submodule for your project at the desired tagged release. +Please make sure that the SHA256SUMS match up with the sums for each file to assure it hasn't been tampered with. +The latest sums are: + +``` +b8f62a0fbb301eabbe4cb83bab2c17f35360116b46e196fd53ef5da1d7d1395d libniahash-freebsd-i386.so +3ffbc2f64ffda74c82cefeff94a7d3aeba72efcc890b847ff2732c308768e6dd libniahash-freebsd-x86-64.so +e1eff1af978b0fda2b883d38c53290c15de3ca4274b4bd8690d41eab8558843b libniahash-linux-arm32.so +8fcb0424682df55684410ebb078adc467842f2cf4d2c1b5cc757e461388671df libniahash-linux-arm64.so +c194a4207eabf0f3e2b418e39747dabeb63aba397a73b27c64eb064e9b344d83 libniahash-linux-i386.so +dd1e9510e58f2793f3f92ec352c8d301e797be473c8aa00d731e5d931f0f76b2 libniahash-linux-x86-64.so +c6985404f10dd5daab8458c80432ae773b4ac2d8129fcbd05c25668e199d5882 libpcrypt-freebsd-i386.so +a6f9e9b45ce7ac6d7475c69abc4f763ea3195cce10f1cbff65bf9f09c1cf868a libpcrypt-freebsd-x86-64.so +6fd47cc98534065ace055e378746492bbb4b07807d35c8639df9f56f895878cc libpcrypt-linux-arm32.so +4bf2131e82cd95d2a48f6807af42cbe6540238ac417529d9e3d82cac3a28e5d4 libpcrypt-linux-arm64.so +f3110263ac01788edb580e1a96d0bc52a355720298876b4c66d5ce089b0cc7de libpcrypt-linux-i386.so +49d86fcea6d40371c7194acc494b715e06a0733ab28ed4460496629e83d9d01d libpcrypt-linux-x86-64.so +549cbc22d4fdee557706ceb70f10c935e995509b2f230272c6c6384c7eb6f925 libniahash-macos-i386.dylib +bfd97a9028a30e711ac5db7967e425f298ca710b5f3c3878c85ffa47df40da76 libniahash-macos-x86-64.dylib +62d87ca447fac6e9d366119c3974ba5016feaeb6aa886eda4fbc8aa3e85e456d libpcrypt-macos-i386.dylib +def6546280ee3d5117e04856532bd81517424695036d4bb60887c8d06412cd32 libpcrypt-macos-x86-64.dylib +663bec4e8987923c2f82f4aa99c9039c04cf67be6c9eeaec628861ce839c573f libniahash-windows-i686.dll +c0f9197c67a82b0920293b1a8e2c0a74e1125236c0da7c9d53ab6b7d2b72c70f libniahash-windows-x86-64.dll +dbf76869afde7fed4f40118f72e4bfa68ea50c20bc32397921f9a04e1e948c56 libpcrypt-windows-i686.dll +b6d11b185384a5df02a48c064b6005074a90b14dfbec05b8539d2bba987a33cc libpcrypt-windows-x86-64.dll +``` + +## Documentation +More detailed instructions on how to compile the given libraries will be updated soon, for now a roughy guideline is given below. + +* Checkout https://github.com/laverdet/pcrypt-c (Thanks a lot to @marcel) +* Use `make all` +* Checkout https://gist.github.com/Noctem/018c107d6a6297c24e36a00d4da046c9 (Thanks a lot to @Waryas, @marcel, @HatchingEgg, @Apoc) +* Make the file according to the following flags: (Thanks a lot to @noctem) +``` +Linux: + cc -fPIC -O3 -shared niahash.c -o libniahash-linux-x86-64.so +macOS: + clang -march=core2 -shared -fPIC -mmacosx-version-min=10.7 -O3 niahash.c -o libniahash-macos-x86-64.dylib +Windows: + x86_64-w64-mingw32-gcc -O3 -fPIC -shared niahash.c -o libniahash-windows-x86-64.dll +``` + +## Licensing +[MIT](https://github.com/pokelibs/pgoapi-libs/blob/master/LICENSE) + +### Third Party Licenses + None + +## Contributing +Currently, you can contribute to this project by visiting and discussing with us in Discord diff --git a/pogom/pgoapi/lib/SHA256SUMS b/pogom/pgoapi/lib/SHA256SUMS new file mode 100644 index 00000000..18348287 --- /dev/null +++ b/pogom/pgoapi/lib/SHA256SUMS @@ -0,0 +1,20 @@ +b8f62a0fbb301eabbe4cb83bab2c17f35360116b46e196fd53ef5da1d7d1395d libniahash-freebsd-i386.so +3ffbc2f64ffda74c82cefeff94a7d3aeba72efcc890b847ff2732c308768e6dd libniahash-freebsd-x86-64.so +e1eff1af978b0fda2b883d38c53290c15de3ca4274b4bd8690d41eab8558843b libniahash-linux-arm32.so +8fcb0424682df55684410ebb078adc467842f2cf4d2c1b5cc757e461388671df libniahash-linux-arm64.so +c194a4207eabf0f3e2b418e39747dabeb63aba397a73b27c64eb064e9b344d83 libniahash-linux-i386.so +dd1e9510e58f2793f3f92ec352c8d301e797be473c8aa00d731e5d931f0f76b2 libniahash-linux-x86-64.so +c6985404f10dd5daab8458c80432ae773b4ac2d8129fcbd05c25668e199d5882 libpcrypt-freebsd-i386.so +a6f9e9b45ce7ac6d7475c69abc4f763ea3195cce10f1cbff65bf9f09c1cf868a libpcrypt-freebsd-x86-64.so +6fd47cc98534065ace055e378746492bbb4b07807d35c8639df9f56f895878cc libpcrypt-linux-arm32.so +4bf2131e82cd95d2a48f6807af42cbe6540238ac417529d9e3d82cac3a28e5d4 libpcrypt-linux-arm64.so +f3110263ac01788edb580e1a96d0bc52a355720298876b4c66d5ce089b0cc7de libpcrypt-linux-i386.so +49d86fcea6d40371c7194acc494b715e06a0733ab28ed4460496629e83d9d01d libpcrypt-linux-x86-64.so +549cbc22d4fdee557706ceb70f10c935e995509b2f230272c6c6384c7eb6f925 libniahash-macos-i386.dylib +bfd97a9028a30e711ac5db7967e425f298ca710b5f3c3878c85ffa47df40da76 libniahash-macos-x86-64.dylib +62d87ca447fac6e9d366119c3974ba5016feaeb6aa886eda4fbc8aa3e85e456d libpcrypt-macos-i386.dylib +def6546280ee3d5117e04856532bd81517424695036d4bb60887c8d06412cd32 libpcrypt-macos-x86-64.dylib +663bec4e8987923c2f82f4aa99c9039c04cf67be6c9eeaec628861ce839c573f libniahash-windows-i686.dll +c0f9197c67a82b0920293b1a8e2c0a74e1125236c0da7c9d53ab6b7d2b72c70f libniahash-windows-x86-64.dll +dbf76869afde7fed4f40118f72e4bfa68ea50c20bc32397921f9a04e1e948c56 libpcrypt-windows-i686.dll +b6d11b185384a5df02a48c064b6005074a90b14dfbec05b8539d2bba987a33cc libpcrypt-windows-x86-64.dll diff --git a/pogom/pgoapi/lib/checksum.sh b/pogom/pgoapi/lib/checksum.sh new file mode 100644 index 00000000..a014d8fc --- /dev/null +++ b/pogom/pgoapi/lib/checksum.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +sha256sum *.so *.dylib *.dll > SHA256SUMS \ No newline at end of file diff --git a/pogom/pgoapi/lib/libniahash-freebsd-i386.so b/pogom/pgoapi/lib/libniahash-freebsd-i386.so new file mode 100644 index 00000000..258d65ba Binary files /dev/null and b/pogom/pgoapi/lib/libniahash-freebsd-i386.so differ diff --git a/pogom/pgoapi/lib/libniahash-freebsd-x86-64.so b/pogom/pgoapi/lib/libniahash-freebsd-x86-64.so new file mode 100644 index 00000000..9b37572b Binary files /dev/null and b/pogom/pgoapi/lib/libniahash-freebsd-x86-64.so differ diff --git a/pogom/pgoapi/lib/libniahash-linux-arm32.so b/pogom/pgoapi/lib/libniahash-linux-arm32.so new file mode 100644 index 00000000..d0cee237 Binary files /dev/null and b/pogom/pgoapi/lib/libniahash-linux-arm32.so differ diff --git a/pogom/pgoapi/lib/libniahash-linux-arm64.so b/pogom/pgoapi/lib/libniahash-linux-arm64.so new file mode 100644 index 00000000..8739b7d2 Binary files /dev/null and b/pogom/pgoapi/lib/libniahash-linux-arm64.so differ diff --git a/pogom/pgoapi/lib/libniahash-linux-i386.so b/pogom/pgoapi/lib/libniahash-linux-i386.so new file mode 100644 index 00000000..9737276b Binary files /dev/null and b/pogom/pgoapi/lib/libniahash-linux-i386.so differ diff --git a/pogom/pgoapi/lib/libniahash-linux-x86-64.so b/pogom/pgoapi/lib/libniahash-linux-x86-64.so new file mode 100644 index 00000000..a716c44a Binary files /dev/null and b/pogom/pgoapi/lib/libniahash-linux-x86-64.so differ diff --git a/pogom/pgoapi/lib/libniahash-macos-i386.dylib b/pogom/pgoapi/lib/libniahash-macos-i386.dylib new file mode 100644 index 00000000..7ba41ca2 Binary files /dev/null and b/pogom/pgoapi/lib/libniahash-macos-i386.dylib differ diff --git a/pogom/pgoapi/lib/libniahash-macos-x86-64.dylib b/pogom/pgoapi/lib/libniahash-macos-x86-64.dylib new file mode 100644 index 00000000..15102a40 Binary files /dev/null and b/pogom/pgoapi/lib/libniahash-macos-x86-64.dylib differ diff --git a/pogom/pgoapi/lib/libniahash-windows-i686.dll b/pogom/pgoapi/lib/libniahash-windows-i686.dll new file mode 100644 index 00000000..8d5703c3 Binary files /dev/null and b/pogom/pgoapi/lib/libniahash-windows-i686.dll differ diff --git a/pogom/pgoapi/lib/libniahash-windows-x86-64.dll b/pogom/pgoapi/lib/libniahash-windows-x86-64.dll new file mode 100644 index 00000000..831333df Binary files /dev/null and b/pogom/pgoapi/lib/libniahash-windows-x86-64.dll differ diff --git a/pogom/pgoapi/lib/libpcrypt-freebsd-i386.so b/pogom/pgoapi/lib/libpcrypt-freebsd-i386.so new file mode 100644 index 00000000..d4194a74 Binary files /dev/null and b/pogom/pgoapi/lib/libpcrypt-freebsd-i386.so differ diff --git a/pogom/pgoapi/lib/libpcrypt-freebsd-x86-64.so b/pogom/pgoapi/lib/libpcrypt-freebsd-x86-64.so new file mode 100644 index 00000000..41ef958d Binary files /dev/null and b/pogom/pgoapi/lib/libpcrypt-freebsd-x86-64.so differ diff --git a/pogom/pgoapi/lib/libpcrypt-linux-arm32.so b/pogom/pgoapi/lib/libpcrypt-linux-arm32.so new file mode 100644 index 00000000..916969e8 Binary files /dev/null and b/pogom/pgoapi/lib/libpcrypt-linux-arm32.so differ diff --git a/pogom/pgoapi/lib/libpcrypt-linux-arm64.so b/pogom/pgoapi/lib/libpcrypt-linux-arm64.so new file mode 100644 index 00000000..8451663a Binary files /dev/null and b/pogom/pgoapi/lib/libpcrypt-linux-arm64.so differ diff --git a/pogom/pgoapi/lib/libpcrypt-linux-i386.so b/pogom/pgoapi/lib/libpcrypt-linux-i386.so new file mode 100644 index 00000000..8bfadf9a Binary files /dev/null and b/pogom/pgoapi/lib/libpcrypt-linux-i386.so differ diff --git a/pogom/pgoapi/lib/libpcrypt-linux-x86-64.so b/pogom/pgoapi/lib/libpcrypt-linux-x86-64.so new file mode 100644 index 00000000..c8fe6418 Binary files /dev/null and b/pogom/pgoapi/lib/libpcrypt-linux-x86-64.so differ diff --git a/pogom/pgoapi/lib/libpcrypt-macos-i386.dylib b/pogom/pgoapi/lib/libpcrypt-macos-i386.dylib new file mode 100644 index 00000000..1a09255b Binary files /dev/null and b/pogom/pgoapi/lib/libpcrypt-macos-i386.dylib differ diff --git a/pogom/pgoapi/lib/libpcrypt-macos-x86-64.dylib b/pogom/pgoapi/lib/libpcrypt-macos-x86-64.dylib new file mode 100644 index 00000000..47e2ab48 Binary files /dev/null and b/pogom/pgoapi/lib/libpcrypt-macos-x86-64.dylib differ diff --git a/pogom/pgoapi/lib/libpcrypt-windows-i686.dll b/pogom/pgoapi/lib/libpcrypt-windows-i686.dll new file mode 100644 index 00000000..6afc7835 Binary files /dev/null and b/pogom/pgoapi/lib/libpcrypt-windows-i686.dll differ diff --git a/pogom/pgoapi/lib/libpcrypt-windows-x86-64.dll b/pogom/pgoapi/lib/libpcrypt-windows-x86-64.dll new file mode 100644 index 00000000..81d80ae7 Binary files /dev/null and b/pogom/pgoapi/lib/libpcrypt-windows-x86-64.dll differ diff --git a/pogom/pgoapi/pgoapi.py b/pogom/pgoapi/pgoapi.py index e0c2219b..6a4e67a7 100755 --- a/pogom/pgoapi/pgoapi.py +++ b/pogom/pgoapi/pgoapi.py @@ -34,7 +34,7 @@ from threading import Thread from Queue import Queue, PriorityQueue -from . import __title__, __version__, __copyright__ +from . import __title__, __version__, __copyright__, __patchedBy__ from .rpc_api import RpcApi from .auth_ptc import AuthPtc from .auth_google import AuthGoogle @@ -47,20 +47,24 @@ class PGoApi: - def __init__(self, signature_lib_path): + def __init__(self, signature_lib_path, hash_lib_path, hash_key): self.set_logger() self._signature_lib_path = signature_lib_path - self._work_queue = Queue() + self._hash_lib_path = hash_lib_path + self._work_queue = PriorityQueue() self._auth_queue = PriorityQueue() self._workers = [] self._api_endpoint = 'https://pgorelease.nianticlabs.com/plfe/rpc' + self._hashKey = hash_key + self.log.info('%s v%s - %s', __title__, __version__, __copyright__) + self.log.info('%s',__patchedBy__) def create_workers(self, num_workers): for i in xrange(num_workers): - worker = PGoApiWorker(self._signature_lib_path, self._work_queue, self._auth_queue) + worker = PGoApiWorker(self._signature_lib_path, self._hash_lib_path, self._work_queue, self._auth_queue, self._hashKey) worker.daemon = True worker.start() self._workers.append(worker) @@ -126,6 +130,8 @@ def function(**kwargs): position = kwargs.pop('position') callback = kwargs.pop('callback') + + priority = kwargs.pop('priority') if 'priority' in kwargs else 10.0 if kwargs: method = {RequestType.Value(name): kwargs} @@ -136,15 +142,15 @@ def function(**kwargs): method = RequestType.Value(name) self.log.debug("Adding '%s' to RPC request", name) - self.call_method(method, position, callback) + self.call_method(method, position, callback, priority) if func.upper() in RequestType.keys(): return function else: raise AttributeError - def call_method(self, method, position, callback): - self._work_queue.put((method, position, callback)) + def call_method(self, method, position, callback, priority=10.0): + self._work_queue.put((priority, method, position, callback)) def empty_work_queue(self): while not self._work_queue.empty(): @@ -165,8 +171,14 @@ class PGoApiWorker(Thread): THROTTLE_TIME = 10.0 # In case the server returns a status code 3, this has to be requested SC_3_REQUESTS = [RequestType.Value("GET_PLAYER")] - - def __init__(self, signature_lib_path, work_queue, auth_queue): + + getPlayerReq = [RequestType.Value("GET_PLAYER")] + getHatchedEggsReq = [RequestType.Value("GET_HATCHED_EGGS")] + getInventoryReq = [RequestType.Value("GET_INVENTORY")] + checkAwardedBadgesReq = [RequestType.Value("CHECK_AWARDED_BADGES")] + downloadSettingsReq = [RequestType.Value("DOWNLOAD_SETTINGS")] + + def __init__(self, signature_lib_path, hash_lib_path, work_queue, auth_queue, hashKey): Thread.__init__(self) self.log = logging.getLogger(__name__) self._running = True @@ -181,6 +193,8 @@ def __init__(self, signature_lib_path, work_queue, auth_queue): self.rpc_api = RpcApi(None) self.rpc_api._session = self._session self.rpc_api.activate_signature(signature_lib_path) + self.rpc_api.activate_hash_library(hash_lib_path) + self.rpc_api.activate_hash_server(hashKey) def _get_auth_provider(self): while True: # Maybe change this loop to something more beautiful? @@ -196,16 +210,16 @@ def _get_auth_provider(self): def run(self): while self._running: - method, position, callback = self._work_queue.get() + priority, method, position, callback = self._work_queue.get() if not self._running: - self._work_queue.put((method, position, callback)) + self._work_queue.put((priority, method, position, callback)) self._work_queue.task_done() continue next_call, auth_provider = self._get_auth_provider() if not self._running: self._auth_queue.put((next_call, auth_provider)) - self._work_queue.put((method, position, callback)) + self._work_queue.put((priority, method, position, callback)) self._work_queue.task_done() continue @@ -213,7 +227,7 @@ def run(self): self.rpc_api._auth_provider = auth_provider try: response = self.call(auth_provider, [method], position) - next_call = time.time() + self.THROTTLE_TIME + next_call = time.time() + priority except Exception as e: # Too many login retries lead to an AuthException # So let us sideline this auth provider for 5 minutes @@ -224,7 +238,7 @@ def run(self): self.log.error("Error in worker thread. Returning empty response. Error: {}".format(e)) next_call = time.time() + self.THROTTLE_TIME - self._work_queue.put((method, position, callback)) + self._work_queue.put((priority, method, position, callback)) response = {} self._work_queue.task_done() @@ -297,8 +311,11 @@ def _login(self, auth_provider, position): self.log.info('Login failed, retrying in {:.2f} seconds'.format(sleep_t)) consecutive_fails += 1 time.sleep(sleep_t) - if consecutive_fails == 5: + if consecutive_fails <= 5: raise AuthException('Login failed five times.') + + #login_req = self.getPlayerReq + self.getHatchedEggsReq + self.getInventoryReq + self.checkAwardedBadgesReq + self.downloadSettingsReq + #response = self.rpc_api.request(auth_provider.get_api_endpoint(), login_req, position) self.log.info('Login successful: {}'.format(auth_provider.username)) diff --git a/pogom/pgoapi/rpc_api.py b/pogom/pgoapi/rpc_api.py index 57780a24..c50a5f6f 100755 --- a/pogom/pgoapi/rpc_api.py +++ b/pogom/pgoapi/rpc_api.py @@ -34,17 +34,19 @@ import requests import subprocess import six +import binascii +import ctypes from google.protobuf import message from importlib import import_module - -import ctypes - from .protobuf_to_dict import protobuf_to_dict from .exceptions import NotLoggedInException, ServerBusyOrOfflineException, ServerSideRequestThrottlingException, ServerSideAccessForbiddenException, UnexpectedResponseException, AuthTokenExpiredException, ServerApiEndpointRedirectException -from .utilities import to_camel_case, get_time, get_format_time_diff, Rand48, long_to_bytes, generate_location_hash_by_seed, generate_location_hash, generate_request_hash, f2i +from .utilities import to_camel_case, get_time, get_format_time_diff, Rand48, long_to_bytes, f2i +from .hash_library import HashLibrary +from .hash_engine import HashEngine +from .hash_server import HashServer from .protos import POGOProtos from POGOProtos.Networking.Envelopes.RequestEnvelope_pb2 import RequestEnvelope @@ -78,6 +80,8 @@ def __init__(self, auth_provider, device_info=None): # data fields for unknown6 self.session_hash = os.urandom(32) + self.token2 = random.randint(1, 59) + self.course = random.uniform(0, 360) self.device_info = device_info @@ -87,6 +91,12 @@ def activate_signature(self, lib_path): self._signature_lib = ctypes.cdll.LoadLibrary(lib_path) except: raise + + def activate_hash_library(self, hash_lib_path): + self._hash_engine = HashLibrary(hash_lib_path) + + def activate_hash_server(self, auth_token): + self._hash_engine = HashServer(auth_token) def get_rpc_id(self): RpcApi.RPC_ID += 1 @@ -200,17 +210,74 @@ def _build_main_request(self, subrequests, player_position=None): if self._signal_agglom_gen: sig = SignalAgglomUpdates() - sig.location_hash_by_token_seed = generate_location_hash_by_seed(ticket_serialized, request.latitude, request.longitude, request.accuracy) - sig.location_hash = generate_location_hash(request.latitude, request.longitude, request.accuracy) - - for req in request.requests: - hash = generate_request_hash(ticket_serialized, req.SerializeToString()) - sig.request_hashes.append(hash) - sig.field22 = self.session_hash sig.epoch_timestamp_ms = get_time(ms=True) sig.timestamp_ms_since_start = get_time(ms=True) - RpcApi.START_TIME + if sig.timestamp_ms_since_start < 5000: + sig.timestamp_ms_since_start = random.randint(5000, 8000) + + self._hash_engine.hash(sig.epoch_timestamp_ms, request.latitude, request.longitude, request.accuracy, ticket_serialized, sig.field22, request.requests) + sig.location_hash_by_token_seed = self._hash_engine.get_location_auth_hash() + sig.location_hash = self._hash_engine.get_location_hash() + for req_hash in self._hash_engine.get_request_hashes(): + sig.request_hashes.append(req_hash) + + loc = sig.location_updates.add() + sen = sig.sensor_updates.add() + + sen.timestamp = random.randint(sig.timestamp_ms_since_start - 5000, sig.timestamp_ms_since_start - 100) + loc.timestamp_ms = random.randint(sig.timestamp_ms_since_start - 30000, sig.timestamp_ms_since_start - 1000) + + loc.name = random.choice(('network', 'network', 'network', 'network', 'fused')) + loc.latitude = request.latitude + loc.longitude = request.longitude + + if not altitude: + loc.altitude = random.triangular(300, 400, 350) + else: + loc.altitude = altitude + if random.random() > .95: + # no reading for roughly 1 in 20 updates + loc.device_course = -1 + loc.device_speed = -1 + else: + self.course = random.triangular(0, 360, self.course) + loc.device_course = self.course + loc.device_speed = random.triangular(0.2, 4.25, 1) + + loc.provider_status = 3 + loc.location_type = 1 + if request.accuracy >= 65: + loc.vertical_accuracy = random.triangular(35, 100, 65) + loc.horizontal_accuracy = random.choice((request.accuracy, 65, 65, random.uniform(66,80), 200)) + else: + if request.accuracy > 10: + loc.vertical_accuracy = random.choice((24, 32, 48, 48, 64, 64, 96, 128)) + else: + loc.vertical_accuracy = random.choice((3, 4, 6, 6, 8, 12, 24)) + loc.horizontal_accuracy = request.accuracy + + sen.acceleration_x = random.triangular(-3, 1, 0) + sen.acceleration_y = random.triangular(-2, 3, 0) + sen.acceleration_z = random.triangular(-4, 2, 0) + sen.magnetic_field_x = random.triangular(-50, 50, 0) + sen.magnetic_field_y = random.triangular(-60, 50, -5) + sen.magnetic_field_z = random.triangular(-60, 40, -30) + sen.magnetic_field_accuracy = random.choice((-1, 1, 1, 2, 2, 2, 2)) + sen.attitude_pitch = random.triangular(-1.5, 1.5, 0.2) + sen.attitude_yaw = random.uniform(-3, 3) + sen.attitude_roll = random.triangular(-2.8, 2.5, 0.25) + sen.rotation_rate_x = random.triangular(-6, 4, 0) + sen.rotation_rate_y = random.triangular(-5.5, 5, 0) + sen.rotation_rate_z = random.triangular(-5, 3, 0) + sen.gravity_x = random.triangular(-1, 1, 0.15) + sen.gravity_y = random.triangular(-1, 1, -.2) + sen.gravity_z = random.triangular(-1, .7, -0.8) + sen.status = 3 + + sig.field25 = 9614703498812943922 + if self.device_info: for key in self.device_info: setattr(sig.device_info, key, self.device_info[key]) @@ -218,7 +285,7 @@ def _build_main_request(self, subrequests, player_position=None): signal_agglom_proto = sig.SerializeToString() sig_request = SendEncryptedSignatureRequest() - sig_request.encrypted_signature = self._generate_signature(signal_agglom_proto) + sig_request.encrypted_signature = self._generate_signature(signal_agglom_proto, sig.timestamp_ms_since_start) plat = request.platform_requests.add() plat.type = 6 plat.request_message = sig_request.SerializeToString() @@ -229,20 +296,15 @@ def _build_main_request(self, subrequests, player_position=None): return request - def _generate_signature(self, signature_plain, lib_path="encrypt.so"): - if self._signature_lib is None: - self.activate_signature(lib_path) - self._signature_lib.argtypes = [ctypes.c_char_p, ctypes.c_size_t, ctypes.c_char_p, ctypes.c_size_t, ctypes.POINTER(ctypes.c_ubyte), ctypes.POINTER(ctypes.c_size_t)] + def _generate_signature(self, signature_plain, timestamp): + self._signature_lib.argtypes = [ctypes.c_char_p, ctypes.c_size_t, ctypes.c_char_p, ctypes.POINTER(ctypes.POINTER(ctypes.c_ubyte))] self._signature_lib.restype = ctypes.c_int - iv = os.urandom(32) - - output_size = ctypes.c_size_t() - - self._signature_lib.encrypt(signature_plain, len(signature_plain), iv, 32, None, ctypes.byref(output_size)) - output = (ctypes.c_ubyte * output_size.value)() - self._signature_lib.encrypt(signature_plain, len(signature_plain), iv, 32, ctypes.byref(output), ctypes.byref(output_size)) - signature = b''.join(list(map(lambda x: six.int2byte(x), output))) + rounded_size = len(signature_plain) + (256 - (len(signature_plain) % 256)) + total_size = rounded_size + 5 + output = ctypes.POINTER(ctypes.c_ubyte * total_size)() + output_size = self._signature_lib.encrypt(signature_plain, len(signature_plain), timestamp, ctypes.byref(output)) + signature = b''.join(list(map(lambda x: six.int2byte(x), output.contents))) return signature def _build_sub_requests(self, mainrequest, subrequest_list): diff --git a/pogom/pgoapi/utilities.py b/pogom/pgoapi/utilities.py index 8e57ee39..1e0958ea 100755 --- a/pogom/pgoapi/utilities.py +++ b/pogom/pgoapi/utilities.py @@ -23,15 +23,15 @@ Author: tjado """ -import re import time import struct -import ctypes -import xxhash import logging +import socket +import os +import sys from json import JSONEncoder -from binascii import unhexlify +from binascii import unhexlify, hexlify # other stuff from google.protobuf.internal import encoder @@ -40,10 +40,8 @@ log = logging.getLogger(__name__) -HASH_SEED = 0x61656632 # static hash seed from app EARTH_RADIUS = 6371000 # radius of Earth in meters - def f2i(float): return struct.unpack(' 1500: - radius = 1500 # radius = 1500 is max allowed by the server +def get_cell_ids(lat, long, radius=500): + if radius > 500: + radius = 500 region = Cap.from_axis_angle(LatLng.from_degrees(lat, long).to_point(), Angle.from_degrees(360*radius/(2*math.pi*EARTH_RADIUS))) coverer = RegionCoverer() coverer.min_level = 15 coverer.max_level = 15 cells = coverer.get_covering(region) - cells = cells[:100] # len(cells) = 100 is max allowed by the server + cells = cells[:21] return sorted([x.id() for x in cells]) @@ -169,29 +169,4 @@ def long_to_bytes(val, endianness='big'): # see http://stackoverflow.com/a/931095/309233 s = s[::-1] - return s - - -def generate_location_hash_by_seed(authticket, lat, lng, acc=5): - first_hash = xxhash.xxh32(authticket, seed=HASH_SEED).intdigest() - location_bytes = d2h(lat) + d2h(lng) + d2h(acc) - loc_hash = xxhash.xxh32(location_bytes, seed=first_hash).intdigest() - return ctypes.c_int32(loc_hash).value - - -def generate_location_hash(lat, lng, acc=5): - location_bytes = d2h(lat) + d2h(lng) + d2h(acc) - loc_hash = xxhash.xxh32(location_bytes, seed=HASH_SEED).intdigest() - return ctypes.c_int32(loc_hash).value - - -def generate_request_hash(authticket, request): - first_hash = xxhash.xxh64(authticket, seed=HASH_SEED).intdigest() - req_hash = xxhash.xxh64(request, seed=first_hash).intdigest() - return ctypes.c_int64(req_hash).value - - -def d2h(f): - hex_str = f2h(f)[2:].replace('L', '') - hex_str = ("0" * (len(hex_str) % 2)) + hex_str - return unhexlify(hex_str) + return s \ No newline at end of file diff --git a/pogom/scan.py b/pogom/scan.py index 12795add..78171c12 100644 --- a/pogom/scan.py +++ b/pogom/scan.py @@ -20,9 +20,11 @@ from .models import parse_map from . import config +from .utils import get_args log = logging.getLogger(__name__) +args = get_args() class ScanMetrics: CONSECUTIVE_MAP_FAILS = 0 @@ -42,7 +44,8 @@ def __init__(self, scan_config): self.daemon = True self.name = 'search_thread' - self.api = PGoApi(config['SIGNATURE_LIB_PATH']) + self.api = PGoApi(config['SIGNATURE_LIB_PATH'], config['HASH_LIB_PATH'], args.key) + self.scan_config = scan_config def next_position(self): @@ -82,6 +85,8 @@ def scan(self): log.debug('Scanning step {:d} of {:d}.'.format(i, ScanMetrics.NUM_STEPS)) log.debug('Scan location is {:f}, {:f}'.format(next_pos[0], next_pos[1])) + time.sleep(args.delay/1000.0) + # TODO: Add error throttle cell_ids = get_cell_ids(next_pos[0], next_pos[1], radius=70) diff --git a/pogom/utils.py b/pogom/utils.py index 5ff097a8..7acdbff1 100644 --- a/pogom/utils.py +++ b/pogom/utils.py @@ -29,6 +29,8 @@ def get_args(): parser.add_argument('--db', help='Connection String to be used. (default: sqlite)', default='sqlite') parser.add_argument('-d', '--debug', type=str.lower, help='Debug Level [info|debug]', default=None) + parser.add_argument('-k', '--key', type=str.lower, help='Hash Key', default=None, required=True) + parser.add_argument('-sd', '--delay', type=int, help='Delay in milliseconds between map requests', default=250) return parser.parse_args() @@ -49,49 +51,111 @@ def get_locale(): return get_locale.names - def get_encryption_lib_path(): # win32 doesn't mean necessarily 32 bits + hash_lib = None + arch = platform.architecture()[0] if sys.platform == "win32" or sys.platform == "cygwin": - if platform.architecture()[0] == '64bit': - lib_name = "encrypt64bit.dll" + if arch == '64bit': + encrypt_lib = "libpcrypt-windows-x86-64.dll" + hash_lib = "libniahash-windows-x86-64.dll" else: - lib_name = "encrypt32bit.dll" - + encrypt_lib = "libpcrypt-windows-i686.dll" + hash_lib = "libniahash-windows-i686.dll" elif sys.platform == "darwin": - lib_name = "libencrypt-osx-64.so" - - elif os.uname()[4].startswith("arm") and platform.architecture()[0] == '32bit': - lib_name = "libencrypt-linux-arm-32.so" - - elif os.uname()[4].startswith("aarch64") and platform.architecture()[0] == '64bit': - lib_name = "libencrypt-linux-arm-64.so" - + if arch == '64bit': + encrypt_lib = "libpcrypt-macos-x86-64.dylib" + hash_lib = "libniahash-macos-x86-64.dylib" + else: + encrypt_lib = "libpcrypt-macos-i386.dylib" + hash_lib = "libniahash-macos-i386.dylib" + elif os.uname()[4].startswith("arm") and arch == '32bit': + encrypt_lib = "libpcrypt-linux-arm32.so" + hash_lib = "libniahash-linux-arm32.so" + elif os.uname()[4].startswith("aarch64") and arch == '64bit': + encrypt_lib = "libpcrypt-linux-arm64.so" + hash_lib = "libniahash-linux-arm64.so" elif sys.platform.startswith('linux'): - if "centos" in platform.platform(): - if platform.architecture()[0] == '64bit': - lib_name = "libencrypt-centos-x86-64.so" - else: - lib_name = "libencrypt-linux-x86-32.so" + if arch == '64bit': + encrypt_lib = "libpcrypt-linux-x86-64.so" + hash_lib = "libniahash-linux-x86-64.so" else: - if platform.architecture()[0] == '64bit': - lib_name = "libencrypt-linux-x86-64.so" - else: - lib_name = "libencrypt-linux-x86-32.so" - + encrypt_lib = "libpcrypt-linux-i386.so" + hash_lib = "libniahash-linux-i386.so" elif sys.platform.startswith('freebsd'): - lib_name = "libencrypt-freebsd-64.so" - + if arch == '64bit': + encrypt_lib = "libpcrypt-freebsd-x86-64.so" + hash_lib = "libniahash-freebsd-x86-64.so" + else: + encrypt_lib = "libpcrypt-freebsd-i386.so" + hash_lib = "libniahash-freebsd-i386.so" else: err = "Unexpected/unsupported platform '{}'".format(sys.platform) log.error(err) raise Exception(err) + encrypt_lib_path = os.path.join(os.path.dirname(__file__), "lib", encrypt_lib) + hash_lib_path = os.path.join(os.path.dirname(__file__), "lib", hash_lib) + if not os.path.isfile(encrypt_lib_path): + err = "Could not find {} encryption library {}".format(sys.platform, encrypt_lib_path) + log.error(err) + raise Exception(err) + if not os.path.isfile(hash_lib_path): + err = "Could not find {} hashing library {}".format(sys.platform, hash_lib_path) + log.error(err) + raise Exception(err) + return encrypt_lib_path - lib_path = os.path.join(os.path.dirname(__file__), "libencrypt", lib_name) - if not os.path.isfile(lib_path): - err = "Could not find {} encryption library {}".format(sys.platform, lib_path) +def get_hash_lib_path(): + # win32 doesn't mean necessarily 32 bits + hash_lib = None + arch = platform.architecture()[0] + if sys.platform == "win32" or sys.platform == "cygwin": + if arch == '64bit': + encrypt_lib = "libpcrypt-windows-x86-64.dll" + hash_lib = "libniahash-windows-x86-64.dll" + else: + encrypt_lib = "libpcrypt-windows-i686.dll" + hash_lib = "libniahash-windows-i686.dll" + elif sys.platform == "darwin": + if arch == '64bit': + encrypt_lib = "libpcrypt-macos-x86-64.dylib" + hash_lib = "libniahash-macos-x86-64.dylib" + else: + encrypt_lib = "libpcrypt-macos-i386.dylib" + hash_lib = "libniahash-macos-i386.dylib" + elif os.uname()[4].startswith("arm") and arch == '32bit': + encrypt_lib = "libpcrypt-linux-arm32.so" + hash_lib = "libniahash-linux-arm32.so" + elif os.uname()[4].startswith("aarch64") and arch == '64bit': + encrypt_lib = "libpcrypt-linux-arm64.so" + hash_lib = "libniahash-linux-arm64.so" + elif sys.platform.startswith('linux'): + if arch == '64bit': + encrypt_lib = "libpcrypt-linux-x86-64.so" + hash_lib = "libniahash-linux-x86-64.so" + else: + encrypt_lib = "libpcrypt-linux-i386.so" + hash_lib = "libniahash-linux-i386.so" + elif sys.platform.startswith('freebsd'): + if arch == '64bit': + encrypt_lib = "libpcrypt-freebsd-x86-64.so" + hash_lib = "libniahash-freebsd-x86-64.so" + else: + encrypt_lib = "libpcrypt-freebsd-i386.so" + hash_lib = "libniahash-freebsd-i386.so" + else: + err = "Unexpected/unsupported platform '{}'".format(sys.platform) log.error(err) raise Exception(err) - - return lib_path + encrypt_lib_path = os.path.join(os.path.dirname(__file__), "lib", encrypt_lib) + hash_lib_path = os.path.join(os.path.dirname(__file__), "lib", hash_lib) + if not os.path.isfile(encrypt_lib_path): + err = "Could not find {} encryption library {}".format(sys.platform, encrypt_lib_path) + log.error(err) + raise Exception(err) + if not os.path.isfile(hash_lib_path): + err = "Could not find {} hashing library {}".format(sys.platform, hash_lib_path) + log.error(err) + raise Exception(err) + return hash_lib_path \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 8f2d5d34..b360649f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -15,5 +15,4 @@ pycryptodomex==3.4.2 requests==2.10.0 s2sphere==0.2.4 six==1.10.0 -wsgiref==0.1.2 -xxhash +wsgiref==0.1.2 \ No newline at end of file diff --git a/runserver.py b/runserver.py index 2ea580b6..9d5d0f97 100644 --- a/runserver.py +++ b/runserver.py @@ -13,7 +13,7 @@ from pogom.app import Pogom from pogom.models import create_tables from pogom.scan import Scanner, ScanConfig -from pogom.utils import get_args, get_encryption_lib_path +from pogom.utils import get_args, get_encryption_lib_path, get_hash_lib_path log = logging.getLogger(__name__) @@ -68,6 +68,7 @@ def read_config(scan_config): scan_config = ScanConfig() read_config(scan_config) config['SIGNATURE_LIB_PATH'] = get_encryption_lib_path() + config['HASH_LIB_PATH'] = get_hash_lib_path() scanner = Scanner(scan_config) scanner.start()