├── requirements.txt ├── requirements-gui.txt ├── fp3_post_data.gz ├── .gitignore ├── utils └── functions.py ├── config.yml ├── README.md ├── checkin ├── android_checkin_pb2.py ├── checkin_pb2.py └── checkin_generator_pb2.py ├── .github └── workflows │ └── workflow.yml ├── proto ├── android_checkin.proto ├── checkin-generator.proto └── checkin.proto ├── gui.py ├── probe.py └── output.txt /requirements.txt: -------------------------------------------------------------------------------- 1 | pyyaml 2 | requests 3 | protobuf 4 | -------------------------------------------------------------------------------- /requirements-gui.txt: -------------------------------------------------------------------------------- 1 | flet 2 | pyperclip 3 | markdownify -------------------------------------------------------------------------------- /fp3_post_data.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangalbert919/google-ota-prober/HEAD/fp3_post_data.gz -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | debug.txt 2 | test_data.txt 3 | fingerprints.txt 4 | *.gz 5 | *.zip 6 | __pycache__ 7 | 8 | # non-python output 9 | build/ 10 | .venv/ -------------------------------------------------------------------------------- /utils/functions.py: -------------------------------------------------------------------------------- 1 | import binascii, os, random 2 | 3 | def generateImei(): 4 | imei = [random.randint(0,9) for _ in range(15)] 5 | return ''.join(map(str, imei)) 6 | 7 | def generateMac(): 8 | return binascii.b2a_hex(os.urandom(6)) 9 | 10 | def generateSerial(): 11 | serial = [random.choice('0123456789abcdef') for _ in range(8)] 12 | return ''.join(serial) 13 | 14 | def generateDigest(): 15 | digest = [random.choice('0123456789abcdef') for _ in range(40)] 16 | return '1-' + ''.join(digest) 17 | -------------------------------------------------------------------------------- /config.yml: -------------------------------------------------------------------------------- 1 | # Configure this correctly. Otherwise, the prober will not succeed in getting OTA URLs! 2 | # All Android fingerprints follow the following format: 3 | # //://:user/release-keys 4 | 5 | build_tag: "" # Example: RKQ1.211119.001 6 | incremental: "" # Example: 2206131341 7 | android_version: "" # Only put in the major version number. 8 | oem: "" # The company that made your device (e.g. Samsung) 9 | device: "" # The device code. May be same as model code. 10 | model: "" # The model code. (e.g. SM-T380) 11 | product: "" # The product code. May be same as device code or model code. 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Google OTA prober 2 | 3 | This program is designed to obtain URLs to over-the-air (OTA) update packages from Google's servers for a specified device. 4 | 5 | ## Requirements 6 | * Python 3 7 | * Build fingerprint of your stock ROM 8 | 9 | ## How to use 10 | 11 | You must install dependencies before using the tool: `python -m pip install -r requirements.txt` 12 | 13 | ### Option 1: Using a terminal 14 | There are three ways to get the URL, which are listed here: 15 | ``` 16 | python probe.py --fingerprint # Skips reading config.yml entirely. 17 | python probe.py --config # Reads a custom YML file (same format as config.yml) 18 | python probe.py # Reads config.yml 19 | ``` 20 | 21 | If you wish to download the OTA file, pass `--download` as an argument on your terminal. 22 | 23 | ### Option 2: Using a graphical interface 24 | This option requires installing all needed modules in `requirements-gui.txt`. You must have the fingerprint for your device. The model code is optional, but encouraged. 25 | 26 | You can run the GUI with `python gui.py`. 27 | 28 | ## Limitations 29 | * This only works for devices that use Google's OTA update servers. 30 | * The prober can only get the latest OTA update package that works on the build specified in `config.yml`. 31 | * Unless it is a major Android upgrade (11 -> 12), the prober will only get links for incremental OTA packages. 32 | 33 | ## References 34 | 1. https://github.com/MCMrARM/Google-Play-API/blob/master/proto/gsf.proto 35 | 2. https://github.com/microg/GmsCore/blob/master/play-services-core-proto/src/main/proto/checkin.proto 36 | 3. https://chromium.googlesource.com/chromium/chromium/+/trunk/google_apis/gcm/protocol/android_checkin.proto 37 | 4. https://github.com/p1gp1g/fp3_get_ota_url 38 | -------------------------------------------------------------------------------- /checkin/android_checkin_pb2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by the protocol buffer compiler. DO NOT EDIT! 3 | # source: android_checkin.proto 4 | """Generated protocol buffer code.""" 5 | from google.protobuf.internal import builder as _builder 6 | from google.protobuf import descriptor as _descriptor 7 | from google.protobuf import descriptor_pool as _descriptor_pool 8 | from google.protobuf import symbol_database as _symbol_database 9 | # @@protoc_insertion_point(imports) 10 | 11 | _sym_db = _symbol_database.Default() 12 | 13 | 14 | 15 | 16 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x15\x61ndroid_checkin.proto\x12\rcheckin_proto\"\x8a\x03\n\x10\x43hromeBuildProto\x12:\n\x08platform\x18\x01 \x01(\x0e\x32(.checkin_proto.ChromeBuildProto.Platform\x12\x16\n\x0e\x63hrome_version\x18\x02 \x01(\t\x12\x38\n\x07\x63hannel\x18\x03 \x01(\x0e\x32\'.checkin_proto.ChromeBuildProto.Channel\"}\n\x08Platform\x12\x10\n\x0cPLATFORM_WIN\x10\x01\x12\x10\n\x0cPLATFORM_MAC\x10\x02\x12\x12\n\x0ePLATFORM_LINUX\x10\x03\x12\x11\n\rPLATFORM_CROS\x10\x04\x12\x10\n\x0cPLATFORM_IOS\x10\x05\x12\x14\n\x10PLATFORM_ANDROID\x10\x06\"i\n\x07\x43hannel\x12\x12\n\x0e\x43HANNEL_STABLE\x10\x01\x12\x10\n\x0c\x43HANNEL_BETA\x10\x02\x12\x0f\n\x0b\x43HANNEL_DEV\x10\x03\x12\x12\n\x0e\x43HANNEL_CANARY\x10\x04\x12\x13\n\x0f\x43HANNEL_UNKNOWN\x10\x05\"\xf6\x01\n\x13\x41ndroidCheckinProto\x12\x19\n\x11last_checkin_msec\x18\x02 \x01(\x03\x12\x15\n\rcell_operator\x18\x06 \x01(\t\x12\x14\n\x0csim_operator\x18\x07 \x01(\t\x12\x0f\n\x07roaming\x18\x08 \x01(\t\x12\x13\n\x0buser_number\x18\t \x01(\x05\x12:\n\x04type\x18\x0c \x01(\x0e\x32\x19.checkin_proto.DeviceType:\x11\x44\x45VICE_ANDROID_OS\x12\x35\n\x0c\x63hrome_build\x18\r \x01(\x0b\x32\x1f.checkin_proto.ChromeBuildProto*g\n\nDeviceType\x12\x15\n\x11\x44\x45VICE_ANDROID_OS\x10\x01\x12\x11\n\rDEVICE_IOS_OS\x10\x02\x12\x19\n\x15\x44\x45VICE_CHROME_BROWSER\x10\x03\x12\x14\n\x10\x44\x45VICE_CHROME_OS\x10\x04\x42\x02H\x03') 17 | 18 | _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) 19 | _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'android_checkin_pb2', globals()) 20 | if _descriptor._USE_C_DESCRIPTORS == False: 21 | 22 | DESCRIPTOR._options = None 23 | DESCRIPTOR._serialized_options = b'H\003' 24 | _DEVICETYPE._serialized_start=686 25 | _DEVICETYPE._serialized_end=789 26 | _CHROMEBUILDPROTO._serialized_start=41 27 | _CHROMEBUILDPROTO._serialized_end=435 28 | _CHROMEBUILDPROTO_PLATFORM._serialized_start=203 29 | _CHROMEBUILDPROTO_PLATFORM._serialized_end=328 30 | _CHROMEBUILDPROTO_CHANNEL._serialized_start=330 31 | _CHROMEBUILDPROTO_CHANNEL._serialized_end=435 32 | _ANDROIDCHECKINPROTO._serialized_start=438 33 | _ANDROIDCHECKINPROTO._serialized_end=684 34 | # @@protoc_insertion_point(module_scope) 35 | -------------------------------------------------------------------------------- /checkin/checkin_pb2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by the protocol buffer compiler. DO NOT EDIT! 3 | # source: checkin.proto 4 | """Generated protocol buffer code.""" 5 | from google.protobuf.internal import builder as _builder 6 | from google.protobuf import descriptor as _descriptor 7 | from google.protobuf import descriptor_pool as _descriptor_pool 8 | from google.protobuf import symbol_database as _symbol_database 9 | # @@protoc_insertion_point(imports) 10 | 11 | _sym_db = _symbol_database.Default() 12 | 13 | 14 | import android_checkin_pb2 as android__checkin__pb2 15 | 16 | 17 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\rcheckin.proto\x12\rcheckin_proto\x1a\x15\x61ndroid_checkin.proto\"/\n\x10GservicesSetting\x12\x0c\n\x04name\x18\x01 \x02(\x0c\x12\r\n\x05value\x18\x02 \x02(\x0c\"\xcb\x03\n\x15\x41ndroidCheckinRequest\x12\x0c\n\x04imei\x18\x01 \x01(\t\x12\x0c\n\x04meid\x18\n \x01(\t\x12\x10\n\x08mac_addr\x18\t \x03(\t\x12\x15\n\rmac_addr_type\x18\x13 \x03(\t\x12\x15\n\rserial_number\x18\x10 \x01(\t\x12\x0b\n\x03\x65sn\x18\x11 \x01(\t\x12\n\n\x02id\x18\x02 \x01(\x03\x12\x12\n\nlogging_id\x18\x07 \x01(\x03\x12\x0e\n\x06\x64igest\x18\x03 \x01(\t\x12\x0e\n\x06locale\x18\x06 \x01(\t\x12\x33\n\x07\x63heckin\x18\x04 \x02(\x0b\x32\".checkin_proto.AndroidCheckinProto\x12\x15\n\rdesired_build\x18\x05 \x01(\t\x12\x16\n\x0emarket_checkin\x18\x08 \x01(\t\x12\x16\n\x0e\x61\x63\x63ount_cookie\x18\x0b \x03(\t\x12\x11\n\ttime_zone\x18\x0c \x01(\t\x12\x16\n\x0esecurity_token\x18\r \x01(\x06\x12\x0f\n\x07version\x18\x0e \x01(\x05\x12\x10\n\x08ota_cert\x18\x0f \x03(\t\x12\x10\n\x08\x66ragment\x18\x14 \x01(\x05\x12\x11\n\tuser_name\x18\x15 \x01(\t\x12\x1a\n\x12user_serial_number\x18\x16 \x01(\x05\"\x83\x02\n\x16\x41ndroidCheckinResponse\x12\x10\n\x08stats_ok\x18\x01 \x02(\x08\x12\x11\n\ttime_msec\x18\x03 \x01(\x03\x12\x0e\n\x06\x64igest\x18\x04 \x01(\t\x12\x15\n\rsettings_diff\x18\t \x01(\x08\x12\x16\n\x0e\x64\x65lete_setting\x18\n \x03(\t\x12\x30\n\x07setting\x18\x05 \x03(\x0b\x32\x1f.checkin_proto.GservicesSetting\x12\x11\n\tmarket_ok\x18\x06 \x01(\x08\x12\x12\n\nandroid_id\x18\x07 \x01(\x06\x12\x16\n\x0esecurity_token\x18\x08 \x01(\x06\x12\x14\n\x0cversion_info\x18\x0b \x01(\tB\x02H\x03') 18 | 19 | _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) 20 | _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'checkin_pb2', globals()) 21 | if _descriptor._USE_C_DESCRIPTORS == False: 22 | 23 | DESCRIPTOR._options = None 24 | DESCRIPTOR._serialized_options = b'H\003' 25 | _GSERVICESSETTING._serialized_start=55 26 | _GSERVICESSETTING._serialized_end=102 27 | _ANDROIDCHECKINREQUEST._serialized_start=105 28 | _ANDROIDCHECKINREQUEST._serialized_end=564 29 | _ANDROIDCHECKINRESPONSE._serialized_start=567 30 | _ANDROIDCHECKINRESPONSE._serialized_end=826 31 | # @@protoc_insertion_point(module_scope) 32 | -------------------------------------------------------------------------------- /.github/workflows/workflow.yml: -------------------------------------------------------------------------------- 1 | name: "Build application" 2 | on: [push] 3 | jobs: 4 | build-linux: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - name: Checkout 8 | uses: actions/checkout@v4 9 | 10 | - name: Setup Flutter 11 | uses: subosito/flutter-action@v2 12 | with: 13 | channel: 'stable' 14 | flutter-version: 3.24.4 15 | 16 | - name: Install dependencies 17 | run: | 18 | echo flet >> requirements.txt 19 | echo markdownify >> requirements.txt 20 | python -m pip install --upgrade pip 21 | pip install -r requirements.txt 22 | 23 | - name: Patch for Linux build 24 | run: | 25 | flutter doctor 26 | sudo apt-get update -y 27 | sudo apt-get install -y ninja-build libgtk-3-dev 28 | flutter doctor 29 | 30 | - name: Flet build linux 31 | run: | 32 | flutter config --no-analytics 33 | flet build linux --verbose --no-rich-output --module-name gui 34 | 35 | - name: Upload artifact 36 | uses: actions/upload-artifact@v4 37 | with: 38 | name: linux-build-artifact 39 | path: build/linux 40 | if-no-files-found: warn 41 | overwrite: false 42 | 43 | build-windows: 44 | runs-on: windows-latest 45 | steps: 46 | - name: Checkout 47 | uses: actions/checkout@v4 48 | 49 | - name: Setup Flutter 50 | uses: subosito/flutter-action@v2 51 | with: 52 | channel: 'stable' 53 | flutter-version: 3.24.4 54 | 55 | - name: Install dependencies 56 | run: | 57 | echo flet >> requirements.txt 58 | echo markdownify >> requirements.txt 59 | python -m pip install --upgrade pip 60 | pip install -r requirements.txt 61 | 62 | - name: Fix encoding issues 63 | shell: bash 64 | run: | 65 | echo "PYTHONIOENCODING=utf-8" >> $GITHUB_ENV 66 | echo "PYTHONUTF8=1" >> $GITHUB_ENV 67 | echo "LANG=en_US.UTF-8" >> $GITHUB_ENV 68 | 69 | - name: Flet build windows 70 | run: | 71 | flutter config --no-analytics 72 | pip install flet markdownify 73 | python --version 74 | python -c "import flet; print(flet.__version__)" 75 | python -X utf8 -m pip show flet 76 | python -X utf8 -m flet.cli build windows --verbose --no-rich-output --module-name gui 77 | 78 | - name: Upload artifact 79 | uses: actions/upload-artifact@v4 80 | with: 81 | name: windows-build-artifact 82 | path: build/windows 83 | if-no-files-found: warn 84 | overwrite: false -------------------------------------------------------------------------------- /proto/android_checkin.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Chromium Authors 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | // 5 | // Logging information for Android "checkin" events (automatic, periodic 6 | // requests made by Android devices to the server). 7 | 8 | syntax = "proto2"; 9 | 10 | option optimize_for = LITE_RUNTIME; 11 | package checkin_proto; 12 | 13 | // Build characteristics unique to the Chrome browser, and Chrome OS 14 | message ChromeBuildProto { 15 | enum Platform { 16 | PLATFORM_WIN = 1; 17 | PLATFORM_MAC = 2; 18 | PLATFORM_LINUX = 3; 19 | PLATFORM_CROS = 4; 20 | PLATFORM_IOS = 5; 21 | // Just a placeholder. Likely don't need it due to the presence of the 22 | // Android GCM on phone/tablet devices. 23 | PLATFORM_ANDROID = 6; 24 | } 25 | 26 | enum Channel { 27 | CHANNEL_STABLE = 1; 28 | CHANNEL_BETA = 2; 29 | CHANNEL_DEV = 3; 30 | CHANNEL_CANARY = 4; 31 | CHANNEL_UNKNOWN = 5; // for tip of tree or custom builds 32 | } 33 | 34 | // The platform of the device. 35 | optional Platform platform = 1; 36 | 37 | // The Chrome instance's version. 38 | optional string chrome_version = 2; 39 | 40 | // The Channel (build type) of Chrome. 41 | optional Channel channel = 3; 42 | } 43 | 44 | // Information sent by the device in a "checkin" request. 45 | message AndroidCheckinProto { 46 | // Miliseconds since the Unix epoch of the device's last successful checkin. 47 | optional int64 last_checkin_msec = 2; 48 | 49 | // The current MCC+MNC of the mobile device's current cell. 50 | optional string cell_operator = 6; 51 | 52 | // The MCC+MNC of the SIM card (different from operator if the 53 | // device is roaming, for instance). 54 | optional string sim_operator = 7; 55 | 56 | // The device's current roaming state (reported starting in eclair builds). 57 | // Currently one of "{,not}mobile-{,not}roaming", if it is present at all. 58 | optional string roaming = 8; 59 | 60 | // For devices supporting multiple user profiles (which may be 61 | // supported starting in jellybean), the ordinal number of the 62 | // profile that is checking in. This is 0 for the primary profile 63 | // (which can't be changed without wiping the device), and 1,2,3,... 64 | // for additional profiles (which can be added and deleted freely). 65 | optional int32 user_number = 9; 66 | 67 | // Class of device. Indicates the type of build proto 68 | // (IosBuildProto/ChromeBuildProto/AndroidBuildProto) 69 | // That is included in this proto 70 | optional DeviceType type = 12 [default = DEVICE_ANDROID_OS]; 71 | 72 | // For devices running MCS on Chrome, build-specific characteristics 73 | // of the browser. There are no hardware aspects (except for ChromeOS). 74 | // This will only be populated for Chrome builds/ChromeOS devices 75 | optional checkin_proto.ChromeBuildProto chrome_build = 13; 76 | 77 | // Note: Some of the Android specific optional fields were skipped to limit 78 | // the protobuf definition. 79 | // Next 14 80 | } 81 | 82 | // enum values correspond to the type of device. 83 | // Used in the AndroidCheckinProto and Device proto. 84 | enum DeviceType { 85 | // Android Device 86 | DEVICE_ANDROID_OS = 1; 87 | 88 | // Apple IOS device 89 | DEVICE_IOS_OS = 2; 90 | 91 | // Chrome browser - Not Chrome OS. No hardware records. 92 | DEVICE_CHROME_BROWSER = 3; 93 | 94 | // Chrome OS 95 | DEVICE_CHROME_OS = 4; 96 | } 97 | -------------------------------------------------------------------------------- /proto/checkin-generator.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto2"; 2 | 3 | package tutorial; 4 | 5 | message AndroidBuildProto { 6 | message ClientGroups { 7 | optional int32 version = 1; 8 | optional string name = 2; 9 | } 10 | optional string id = 1; 11 | optional string hardware = 2; 12 | optional string brand = 3; 13 | optional string radio = 4; 14 | optional string bootloader = 5; 15 | optional string clientId = 6; 16 | optional int64 timestamp = 7; 17 | optional int32 googleServices = 8; 18 | optional string device = 9; 19 | optional int32 sdkVersion = 10; 20 | optional string model = 11; 21 | optional string manufacturer = 12; 22 | optional string product = 13; 23 | optional bool otaInstalled = 14; 24 | repeated ClientGroups groups = 15; 25 | optional string securityPatch = 19; 26 | } 27 | 28 | message AndroidCheckinReasonProto { 29 | optional int32 reasonType = 1; 30 | optional int32 attemptCount = 2; 31 | optional string sourcePackage = 3; 32 | optional string sourceClass = 4; 33 | optional bool sourceForce = 5; 34 | } 35 | 36 | message AndroidCheckinProto { 37 | optional AndroidBuildProto build = 1; 38 | optional int64 lastCheckinMsec = 2; 39 | repeated AndroidEventProto event = 3; 40 | repeated AndroidStatisticProto stat = 4; 41 | repeated string requestedGroup = 5; // unused 42 | optional string cellOperator = 6; 43 | optional string simOperator = 7; 44 | optional string roaming = 8; 45 | optional int32 userNumber = 9; 46 | optional int32 deviceType = 14 [default = 1]; 47 | optional AndroidCheckinReasonProto reason = 15; 48 | optional bool voiceCapable = 18; 49 | optional string unknown19 = 19; // unclear what this is for, but exists 50 | } 51 | 52 | message AndroidEventProto { 53 | optional string tag = 1; 54 | optional string value = 2; 55 | optional int64 timeMsec = 3; 56 | } 57 | 58 | message AndroidStatisticProto { 59 | optional string tag = 1; 60 | optional int32 count = 2; 61 | optional float sum = 3; 62 | } 63 | 64 | message DeviceConfigurationProto { 65 | optional int32 touchScreen = 1; 66 | optional int32 keyboard = 2; 67 | optional int32 navigation = 3; 68 | optional int32 screenLayout = 4; 69 | optional bool hasHardKeyboard = 5; 70 | optional bool hasFiveWayNavigation = 6; 71 | optional int32 screenDensity = 7; 72 | optional int32 glEsVersion = 8; 73 | repeated string systemSharedLibrary = 9; 74 | repeated string systemAvailableFeature = 10; 75 | repeated string nativePlatform = 11; 76 | optional int32 screenWidth = 12; 77 | optional int32 screenHeight = 13; 78 | repeated string systemSupportedLocale = 14; 79 | repeated string glExtension = 15; 80 | optional int32 deviceClass = 16; 81 | optional int32 maxApkDownloadSizeMb = 17[default = 50]; 82 | optional int32 smallestScreenWidthDP = 18; 83 | optional int32 lowRamDevice = 19[default=0]; 84 | optional int64 totalMemoryBytes = 20[default=8354971648]; 85 | optional int32 maxNumOf_CPUCores = 21[default=8]; 86 | repeated DeviceFeature deviceFeature = 26; 87 | optional bool keyGuardDeviceSecure = 28[default=true]; 88 | optional int32 unknown30 = 30[default=4]; 89 | } 90 | 91 | message DeviceFeature { 92 | optional string name = 1; 93 | optional int32 value = 2; 94 | } 95 | 96 | message AndroidCheckinRequest { 97 | optional string imei = 1; // used by GSM phones 98 | optional int64 id = 2[default=0]; 99 | optional string digest = 3; 100 | optional AndroidCheckinProto checkin = 4; 101 | optional string desiredBuild = 5; // DEPRECATED: Use AndroidCheckinProto.requestedGroup 102 | optional string locale = 6; 103 | optional int64 loggingId = 7; 104 | optional string marketCheckin = 8; // unused 105 | repeated string macAddr = 9; 106 | optional string meid = 10; // used by CDMA phones 107 | repeated string accountCookie = 11; 108 | optional string timeZone = 12; 109 | optional fixed64 securityToken = 13; 110 | optional int32 version = 14; 111 | repeated string otaCert = 15; 112 | optional string serialNumber = 16; 113 | optional string esn = 17; // used in CDMA networks 114 | optional DeviceConfigurationProto deviceConfiguration = 18; 115 | repeated string macAddrType = 19; 116 | optional int32 fragment = 20; 117 | optional string userName = 21; 118 | optional int32 userSerialNumber = 22; 119 | optional string droidguardResult = 24; 120 | optional int32 fetchSystemUpdates = 29; 121 | optional int32 unknown30 = 30; 122 | } 123 | 124 | message AndroidCheckinResponse { 125 | optional bool statsOk = 1; 126 | repeated AndroidIntentProto intent = 2; 127 | optional int64 timeMsec = 3; 128 | optional string digest = 4; 129 | repeated GservicesSetting setting = 5; 130 | optional bool marketOk = 6; 131 | optional fixed64 androidId = 7; 132 | optional fixed64 securityToken = 8; 133 | optional bool settingsDiff = 9; 134 | repeated string deleteSetting = 10; 135 | optional string deviceDataVersionInfo = 12; 136 | } 137 | 138 | message AndroidIntentProto { 139 | optional string action = 1; 140 | optional string dataUri = 2; 141 | optional string mimeType = 3; 142 | optional string javaClass = 4; 143 | repeated group Extra = 5 { 144 | optional string name = 6; 145 | optional string value = 7; 146 | } 147 | } 148 | 149 | message GservicesSetting { 150 | optional bytes name = 1; 151 | optional bytes value = 2; 152 | } 153 | -------------------------------------------------------------------------------- /gui.py: -------------------------------------------------------------------------------- 1 | import flet as ft 2 | import probe 3 | import time 4 | from markdownify import markdownify as md 5 | import sys 6 | import pyperclip 7 | 8 | # Ensure stdout and stderr use UTF-8 9 | sys.stdout.reconfigure(encoding='utf-8') 10 | sys.stderr.reconfigure(encoding='utf-8') 11 | 12 | def main(page: ft.Page): 13 | prober = probe.Prober() 14 | 15 | # Needed methods for buttons 16 | def start_probe(e): 17 | global url 18 | url = prober.checkin(fingerprint.value, model.value) 19 | if url is not None: 20 | update_info.value = "An update is available!" 21 | downloadBtn.disabled = False 22 | update_dlg_btn.disabled = False 23 | saveBtn.disabled = False 24 | update_dlg.content = ft.Markdown(md(prober.get_update_desc())) 25 | else: 26 | update_info.value = "No update is available." 27 | downloadBtn.disabled = True 28 | update_dlg_btn.disabled = True 29 | saveBtn.disabled = True 30 | page.update() 31 | 32 | def download(e): 33 | print("Download button clicked") 34 | global url 35 | prober.download(url, progress_bar=progress_bar, page=page) 36 | 37 | def validate_fingerprint(e): 38 | if fingerprint.value == "": 39 | probeBtn.disabled = True 40 | else: 41 | probeBtn.disabled = False 42 | page.update() 43 | 44 | def save_fingerprint(e): 45 | # Check if fingerprints.txt exists. 46 | try: 47 | fingerprint_file = open("fingerprints.txt", "r+") 48 | except: 49 | print("Fingerprints.txt does not exist. Creating one.") 50 | fingerprint_file = open("fingerprints.txt", "w+") 51 | # Check if the fingerprint is already in the file 52 | temp = update_info.value 53 | duplicate = False 54 | for line in fingerprint_file: 55 | if line == fingerprint.value: 56 | update_info.value = "Fingerprint already exists in the file." 57 | duplicate = True 58 | break 59 | if not duplicate: 60 | fingerprint_file.write(fingerprint.value + '\n') 61 | update_info.value = "Fingerprint saved." 62 | page.update() 63 | fingerprint_file.close() 64 | time.sleep(3) 65 | update_info.value = temp 66 | page.update() 67 | 68 | def load_saved_fp(): 69 | fp = [] 70 | try: 71 | fingerprint_file = open("fingerprints.txt", "r") 72 | except: 73 | fp.append(ft.Container(content=ft.Text("No saved fingerprints found."), alignment=ft.alignment.center)) 74 | return fp 75 | for line in fingerprint_file: 76 | fp.append(ft.Container(content=ft.Row( 77 | controls=[ 78 | ft.Text(line), 79 | ft.Container(expand=True), 80 | ft.IconButton(ft.Icons.COPY, on_click=lambda e: pyperclip.copy(line)) 81 | ]), alignment=ft.alignment.center)) 82 | fingerprint_file.close() 83 | return fp 84 | 85 | # Theme 86 | page.theme = ft.Theme(color_scheme_seed=ft.Colors.BLUE_GREY_900) 87 | page.dark_theme = ft.Theme(color_scheme_seed=ft.Colors.WHITE24) 88 | page.title = "Google OTA Prober" 89 | 90 | # GUI Components 91 | update_dlg = ft.AlertDialog( 92 | title=ft.Text("Update changelog", text_align=ft.TextAlign.CENTER), 93 | on_dismiss=lambda e: print("Dialog dismissed."), 94 | ) 95 | about_dlg = ft.AlertDialog( 96 | title=ft.Text("About", text_align=ft.TextAlign.CENTER), 97 | content=ft.Text("Google OTA Prober v1.0", text_align=ft.TextAlign.CENTER), 98 | on_dismiss=lambda e: print("Dialog dismissed."), 99 | ) 100 | saved_fp_dlg = ft.AlertDialog( 101 | title=ft.Text("Saved fingerprints", text_align=ft.TextAlign.CENTER), 102 | content=ft.Column(controls=load_saved_fp()), 103 | on_dismiss=lambda e: print("Dialog dismissed."), 104 | ) 105 | 106 | fingerprint = ft.TextField(label="Enter fingerprint here", on_change=validate_fingerprint) 107 | model = ft.TextField(label="Enter model here (optional)") 108 | serial = ft.TextField(label="Enter serial number here (optional)") 109 | probeBtn = ft.ElevatedButton("Start probe", bgcolor="#057A2C", color="#FFFFFF", on_click=start_probe, disabled=True) 110 | downloadBtn = ft.ElevatedButton("Download", on_click=download, disabled=True) 111 | saveBtn = ft.ElevatedButton("Save", on_click=save_fingerprint, disabled=True) 112 | update_info = ft.Text("Update info will be displayed here") 113 | update_dlg_btn = ft.ElevatedButton("Changelog", on_click=lambda e: page.open(update_dlg), disabled=True) 114 | progress_bar = ft.ProgressBar(width=300, value=0) 115 | 116 | page.bottom_appbar = ft.BottomAppBar( 117 | bgcolor="#057A2C", 118 | content=ft.Row( 119 | controls=[ 120 | ft.IconButton(ft.Icons.HOME, on_click=lambda e: page.go("/")), 121 | ft.IconButton(ft.Icons.SETTINGS, on_click=lambda e: page.go("/settings")), 122 | ft.Container(expand=True), 123 | ft.Column( 124 | controls=[progress_bar, update_info], alignment=ft.MainAxisAlignment.CENTER, horizontal_alignment=ft.CrossAxisAlignment.CENTER, expand=True 125 | ), 126 | ft.Container(expand=True), 127 | ft.IconButton(ft.Icons.FINGERPRINT, on_click=lambda e: page.open(saved_fp_dlg)), 128 | ft.IconButton(ft.Icons.INFO, on_click=lambda e: page.open(about_dlg)) 129 | ] 130 | ) 131 | ) 132 | 133 | # Generate the page 134 | content = ft.Column([ 135 | ft.Container(content=fingerprint, alignment=ft.alignment.center), 136 | ft.Container(content=model, alignment=ft.alignment.center), 137 | ft.Container(content=serial, alignment=ft.alignment.center), 138 | ft.Container(content=probeBtn, alignment=ft.alignment.center), 139 | ft.Container(content=ft.Row([downloadBtn, saveBtn], alignment=ft.MainAxisAlignment.CENTER, expand=True), alignment=ft.alignment.center), 140 | ft.Container(content=update_dlg_btn, alignment=ft.alignment.center) 141 | ], alignment=ft.MainAxisAlignment.CENTER, expand=True) 142 | 143 | page.add(content) 144 | page.update() 145 | 146 | ft.app(target=main) -------------------------------------------------------------------------------- /proto/checkin.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Chromium Authors 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | // 5 | // Request and reply to the "checkin server" devices poll every few hours. 6 | 7 | syntax = "proto2"; 8 | 9 | option optimize_for = LITE_RUNTIME; 10 | 11 | package checkin_proto; 12 | 13 | import "android_checkin.proto"; 14 | 15 | // A concrete name/value pair sent to the device's Gservices database. 16 | message GservicesSetting { 17 | required bytes name = 1; 18 | required bytes value = 2; 19 | } 20 | 21 | // Devices send this every few hours to tell us how they're doing. 22 | message AndroidCheckinRequest { 23 | // IMEI (used by GSM phones) is sent and stored as 15 decimal 24 | // digits; the 15th is a check digit. 25 | optional string imei = 1; // IMEI, reported but not logged. 26 | 27 | // MEID (used by CDMA phones) is sent and stored as 14 hexadecimal 28 | // digits (no check digit). 29 | optional string meid = 10; // MEID, reported but not logged. 30 | 31 | // MAC address (used by non-phone devices). 12 hexadecimal digits; 32 | // no separators (eg "0016E6513AC2", not "00:16:E6:51:3A:C2"). 33 | repeated string mac_addr = 9; // MAC address, reported but not logged. 34 | 35 | // An array parallel to mac_addr, describing the type of interface. 36 | // Currently accepted values: "wifi", "ethernet", "bluetooth". If 37 | // not present, "wifi" is assumed. 38 | repeated string mac_addr_type = 19; 39 | 40 | // Serial number (a manufacturer-defined unique hardware 41 | // identifier). Alphanumeric, case-insensitive. 42 | optional string serial_number = 16; 43 | 44 | // Older CDMA networks use an ESN (8 hex digits) instead of an MEID. 45 | optional string esn = 17; // ESN, reported but not logged 46 | 47 | optional int64 id = 2; // Android device ID, not logged 48 | optional int64 logging_id = 7; // Pseudonymous logging ID for Sawmill 49 | optional string digest = 3; // Digest of device provisioning, not logged. 50 | optional string locale = 6; // Current locale in standard (xx_XX) format 51 | required AndroidCheckinProto checkin = 4; 52 | 53 | // DEPRECATED, see AndroidCheckinProto.requested_group 54 | optional string desired_build = 5; 55 | 56 | // Blob of data from the Market app to be passed to Market API server 57 | optional string market_checkin = 8; 58 | 59 | // SID cookies of any google accounts stored on the phone. Not logged. 60 | repeated string account_cookie = 11; 61 | 62 | // Time zone. Not currently logged. 63 | optional string time_zone = 12; 64 | 65 | // Security token used to validate the checkin request. 66 | // Required for android IDs issued to Froyo+ devices, not for legacy IDs. 67 | optional fixed64 security_token = 13; 68 | 69 | // Version of checkin protocol. 70 | // 71 | // There are currently two versions: 72 | // 73 | // - version field missing: android IDs are assigned based on 74 | // hardware identifiers. unsecured in the sense that you can 75 | // "unregister" someone's phone by sending a registration request 76 | // with their IMEI/MEID/MAC. 77 | // 78 | // - version=2: android IDs are assigned randomly. The device is 79 | // sent a security token that must be included in all future 80 | // checkins for that android id. 81 | // 82 | // - version=3: same as version 2, but the 'fragment' field is 83 | // provided, and the device understands incremental updates to the 84 | // gservices table (ie, only returning the keys whose values have 85 | // changed.) 86 | // 87 | // (version=1 was skipped to avoid confusion with the "missing" 88 | // version field that is effectively version 1.) 89 | optional int32 version = 14; 90 | 91 | // OTA certs accepted by device (base-64 SHA-1 of cert files). Not 92 | // logged. 93 | repeated string ota_cert = 15; 94 | 95 | // Honeycomb and newer devices send configuration data with their checkin. 96 | // optional DeviceConfigurationProto device_configuration = 18; 97 | 98 | // A single CheckinTask on the device may lead to multiple checkin 99 | // requests if there is too much log data to upload in a single 100 | // request. For version 3 and up, this field will be filled in with 101 | // the number of the request, starting with 0. 102 | optional int32 fragment = 20; 103 | 104 | // For devices supporting multiple users, the name of the current 105 | // profile (they all check in independently, just as if they were 106 | // multiple physical devices). This may not be set, even if the 107 | // device is using multiuser. (checkin.user_number should be set to 108 | // the ordinal of the user.) 109 | optional string user_name = 21; 110 | 111 | // For devices supporting multiple user profiles, the serial number 112 | // for the user checking in. Not logged. May not be set, even if 113 | // the device supportes multiuser. checkin.user_number is the 114 | // ordinal of the user (0, 1, 2, ...), which may be reused if users 115 | // are deleted and re-created. user_serial_number is never reused 116 | // (unless the device is wiped). 117 | optional int32 user_serial_number = 22; 118 | 119 | // NEXT TAG: 23 120 | } 121 | 122 | // The response to the device. 123 | message AndroidCheckinResponse { 124 | required bool stats_ok = 1; // Whether statistics were recorded properly. 125 | optional int64 time_msec = 3; // Time of day from server (Java epoch). 126 | // repeated AndroidIntentProto intent = 2; 127 | 128 | // Provisioning is sent if the request included an obsolete digest. 129 | // 130 | // For version <= 2, 'digest' contains the digest that should be 131 | // sent back to the server on the next checkin, and 'setting' 132 | // contains the entire gservices table (which replaces the entire 133 | // current table on the device). 134 | // 135 | // for version >= 3, 'digest' will be absent. If 'settings_diff' 136 | // is false, then 'setting' contains the entire table, as in version 137 | // 2. If 'settings_diff' is true, then 'delete_setting' contains 138 | // the keys to delete, and 'setting' contains only keys to be added 139 | // or for which the value has changed. All other keys in the 140 | // current table should be left untouched. If 'settings_diff' is 141 | // absent, don't touch the existing gservices table. 142 | // 143 | optional string digest = 4; 144 | optional bool settings_diff = 9; 145 | repeated string delete_setting = 10; 146 | repeated GservicesSetting setting = 5; 147 | 148 | optional bool market_ok = 6; // If Market got the market_checkin data OK. 149 | 150 | optional fixed64 android_id = 7; // From the request, or newly assigned 151 | optional fixed64 security_token = 8; // The associated security token 152 | 153 | optional string version_info = 11; 154 | // NEXT TAG: 12 155 | } 156 | -------------------------------------------------------------------------------- /checkin/checkin_generator_pb2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by the protocol buffer compiler. DO NOT EDIT! 3 | # source: checkin-generator.proto 4 | """Generated protocol buffer code.""" 5 | from google.protobuf.internal import builder as _builder 6 | from google.protobuf import descriptor as _descriptor 7 | from google.protobuf import descriptor_pool as _descriptor_pool 8 | from google.protobuf import symbol_database as _symbol_database 9 | # @@protoc_insertion_point(imports) 10 | 11 | _sym_db = _symbol_database.Default() 12 | 13 | 14 | 15 | 16 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x17\x63heckin-generator.proto\x12\x08tutorial\"\x90\x03\n\x11\x41ndroidBuildProto\x12\n\n\x02id\x18\x01 \x01(\t\x12\x10\n\x08hardware\x18\x02 \x01(\t\x12\r\n\x05\x62rand\x18\x03 \x01(\t\x12\r\n\x05radio\x18\x04 \x01(\t\x12\x12\n\nbootloader\x18\x05 \x01(\t\x12\x10\n\x08\x63lientId\x18\x06 \x01(\t\x12\x11\n\ttimestamp\x18\x07 \x01(\x03\x12\x16\n\x0egoogleServices\x18\x08 \x01(\x05\x12\x0e\n\x06\x64\x65vice\x18\t \x01(\t\x12\x12\n\nsdkVersion\x18\n \x01(\x05\x12\r\n\x05model\x18\x0b \x01(\t\x12\x14\n\x0cmanufacturer\x18\x0c \x01(\t\x12\x0f\n\x07product\x18\r \x01(\t\x12\x14\n\x0cotaInstalled\x18\x0e \x01(\x08\x12\x38\n\x06groups\x18\x0f \x03(\x0b\x32(.tutorial.AndroidBuildProto.ClientGroups\x12\x15\n\rsecurityPatch\x18\x13 \x01(\t\x1a-\n\x0c\x43lientGroups\x12\x0f\n\x07version\x18\x01 \x01(\x05\x12\x0c\n\x04name\x18\x02 \x01(\t\"\x86\x01\n\x19\x41ndroidCheckinReasonProto\x12\x12\n\nreasonType\x18\x01 \x01(\x05\x12\x14\n\x0c\x61ttemptCount\x18\x02 \x01(\x05\x12\x15\n\rsourcePackage\x18\x03 \x01(\t\x12\x13\n\x0bsourceClass\x18\x04 \x01(\t\x12\x13\n\x0bsourceForce\x18\x05 \x01(\x08\"\x92\x03\n\x13\x41ndroidCheckinProto\x12*\n\x05\x62uild\x18\x01 \x01(\x0b\x32\x1b.tutorial.AndroidBuildProto\x12\x17\n\x0flastCheckinMsec\x18\x02 \x01(\x03\x12*\n\x05\x65vent\x18\x03 \x03(\x0b\x32\x1b.tutorial.AndroidEventProto\x12-\n\x04stat\x18\x04 \x03(\x0b\x32\x1f.tutorial.AndroidStatisticProto\x12\x16\n\x0erequestedGroup\x18\x05 \x03(\t\x12\x14\n\x0c\x63\x65llOperator\x18\x06 \x01(\t\x12\x13\n\x0bsimOperator\x18\x07 \x01(\t\x12\x0f\n\x07roaming\x18\x08 \x01(\t\x12\x12\n\nuserNumber\x18\t \x01(\x05\x12\x15\n\ndeviceType\x18\x0e \x01(\x05:\x01\x31\x12\x33\n\x06reason\x18\x0f \x01(\x0b\x32#.tutorial.AndroidCheckinReasonProto\x12\x14\n\x0cvoiceCapable\x18\x12 \x01(\x08\x12\x11\n\tunknown19\x18\x13 \x01(\t\"A\n\x11\x41ndroidEventProto\x12\x0b\n\x03tag\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t\x12\x10\n\x08timeMsec\x18\x03 \x01(\x03\"@\n\x15\x41ndroidStatisticProto\x12\x0b\n\x03tag\x18\x01 \x01(\t\x12\r\n\x05\x63ount\x18\x02 \x01(\x05\x12\x0b\n\x03sum\x18\x03 \x01(\x02\"\x9f\x05\n\x18\x44\x65viceConfigurationProto\x12\x13\n\x0btouchScreen\x18\x01 \x01(\x05\x12\x10\n\x08keyboard\x18\x02 \x01(\x05\x12\x12\n\nnavigation\x18\x03 \x01(\x05\x12\x14\n\x0cscreenLayout\x18\x04 \x01(\x05\x12\x17\n\x0fhasHardKeyboard\x18\x05 \x01(\x08\x12\x1c\n\x14hasFiveWayNavigation\x18\x06 \x01(\x08\x12\x15\n\rscreenDensity\x18\x07 \x01(\x05\x12\x13\n\x0bglEsVersion\x18\x08 \x01(\x05\x12\x1b\n\x13systemSharedLibrary\x18\t \x03(\t\x12\x1e\n\x16systemAvailableFeature\x18\n \x03(\t\x12\x16\n\x0enativePlatform\x18\x0b \x03(\t\x12\x13\n\x0bscreenWidth\x18\x0c \x01(\x05\x12\x14\n\x0cscreenHeight\x18\r \x01(\x05\x12\x1d\n\x15systemSupportedLocale\x18\x0e \x03(\t\x12\x13\n\x0bglExtension\x18\x0f \x03(\t\x12\x13\n\x0b\x64\x65viceClass\x18\x10 \x01(\x05\x12 \n\x14maxApkDownloadSizeMb\x18\x11 \x01(\x05:\x02\x35\x30\x12\x1d\n\x15smallestScreenWidthDP\x18\x12 \x01(\x05\x12\x17\n\x0clowRamDevice\x18\x13 \x01(\x05:\x01\x30\x12$\n\x10totalMemoryBytes\x18\x14 \x01(\x03:\n8354971648\x12\x1c\n\x11maxNumOf_CPUCores\x18\x15 \x01(\x05:\x01\x38\x12.\n\rdeviceFeature\x18\x1a \x03(\x0b\x32\x17.tutorial.DeviceFeature\x12\"\n\x14keyGuardDeviceSecure\x18\x1c \x01(\x08:\x04true\x12\x14\n\tunknown30\x18\x1e \x01(\x05:\x01\x34\",\n\rDeviceFeature\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05\"\xc5\x04\n\x15\x41ndroidCheckinRequest\x12\x0c\n\x04imei\x18\x01 \x01(\t\x12\r\n\x02id\x18\x02 \x01(\x03:\x01\x30\x12\x0e\n\x06\x64igest\x18\x03 \x01(\t\x12.\n\x07\x63heckin\x18\x04 \x01(\x0b\x32\x1d.tutorial.AndroidCheckinProto\x12\x14\n\x0c\x64\x65siredBuild\x18\x05 \x01(\t\x12\x0e\n\x06locale\x18\x06 \x01(\t\x12\x11\n\tloggingId\x18\x07 \x01(\x03\x12\x15\n\rmarketCheckin\x18\x08 \x01(\t\x12\x0f\n\x07macAddr\x18\t \x03(\t\x12\x0c\n\x04meid\x18\n \x01(\t\x12\x15\n\raccountCookie\x18\x0b \x03(\t\x12\x10\n\x08timeZone\x18\x0c \x01(\t\x12\x15\n\rsecurityToken\x18\r \x01(\x06\x12\x0f\n\x07version\x18\x0e \x01(\x05\x12\x0f\n\x07otaCert\x18\x0f \x03(\t\x12\x14\n\x0cserialNumber\x18\x10 \x01(\t\x12\x0b\n\x03\x65sn\x18\x11 \x01(\t\x12?\n\x13\x64\x65viceConfiguration\x18\x12 \x01(\x0b\x32\".tutorial.DeviceConfigurationProto\x12\x13\n\x0bmacAddrType\x18\x13 \x03(\t\x12\x10\n\x08\x66ragment\x18\x14 \x01(\x05\x12\x10\n\x08userName\x18\x15 \x01(\t\x12\x18\n\x10userSerialNumber\x18\x16 \x01(\x05\x12\x18\n\x10\x64roidguardResult\x18\x18 \x01(\t\x12\x1a\n\x12\x66\x65tchSystemUpdates\x18\x1d \x01(\x05\x12\x11\n\tunknown30\x18\x1e \x01(\x05\"\xae\x02\n\x16\x41ndroidCheckinResponse\x12\x0f\n\x07statsOk\x18\x01 \x01(\x08\x12,\n\x06intent\x18\x02 \x03(\x0b\x32\x1c.tutorial.AndroidIntentProto\x12\x10\n\x08timeMsec\x18\x03 \x01(\x03\x12\x0e\n\x06\x64igest\x18\x04 \x01(\t\x12+\n\x07setting\x18\x05 \x03(\x0b\x32\x1a.tutorial.GservicesSetting\x12\x10\n\x08marketOk\x18\x06 \x01(\x08\x12\x11\n\tandroidId\x18\x07 \x01(\x06\x12\x15\n\rsecurityToken\x18\x08 \x01(\x06\x12\x14\n\x0csettingsDiff\x18\t \x01(\x08\x12\x15\n\rdeleteSetting\x18\n \x03(\t\x12\x1d\n\x15\x64\x65viceDataVersionInfo\x18\x0c \x01(\t\"\xb3\x01\n\x12\x41ndroidIntentProto\x12\x0e\n\x06\x61\x63tion\x18\x01 \x01(\t\x12\x0f\n\x07\x64\x61taUri\x18\x02 \x01(\t\x12\x10\n\x08mimeType\x18\x03 \x01(\t\x12\x11\n\tjavaClass\x18\x04 \x01(\t\x12\x31\n\x05\x65xtra\x18\x05 \x03(\n2\".tutorial.AndroidIntentProto.Extra\x1a$\n\x05\x45xtra\x12\x0c\n\x04name\x18\x06 \x01(\t\x12\r\n\x05value\x18\x07 \x01(\t\"/\n\x10GservicesSetting\x12\x0c\n\x04name\x18\x01 \x01(\x0c\x12\r\n\x05value\x18\x02 \x01(\x0c') 17 | 18 | _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) 19 | _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'checkin_generator_pb2', globals()) 20 | if _descriptor._USE_C_DESCRIPTORS == False: 21 | 22 | DESCRIPTOR._options = None 23 | _ANDROIDBUILDPROTO._serialized_start=38 24 | _ANDROIDBUILDPROTO._serialized_end=438 25 | _ANDROIDBUILDPROTO_CLIENTGROUPS._serialized_start=393 26 | _ANDROIDBUILDPROTO_CLIENTGROUPS._serialized_end=438 27 | _ANDROIDCHECKINREASONPROTO._serialized_start=441 28 | _ANDROIDCHECKINREASONPROTO._serialized_end=575 29 | _ANDROIDCHECKINPROTO._serialized_start=578 30 | _ANDROIDCHECKINPROTO._serialized_end=980 31 | _ANDROIDEVENTPROTO._serialized_start=982 32 | _ANDROIDEVENTPROTO._serialized_end=1047 33 | _ANDROIDSTATISTICPROTO._serialized_start=1049 34 | _ANDROIDSTATISTICPROTO._serialized_end=1113 35 | _DEVICECONFIGURATIONPROTO._serialized_start=1116 36 | _DEVICECONFIGURATIONPROTO._serialized_end=1787 37 | _DEVICEFEATURE._serialized_start=1789 38 | _DEVICEFEATURE._serialized_end=1833 39 | _ANDROIDCHECKINREQUEST._serialized_start=1836 40 | _ANDROIDCHECKINREQUEST._serialized_end=2417 41 | _ANDROIDCHECKINRESPONSE._serialized_start=2420 42 | _ANDROIDCHECKINRESPONSE._serialized_end=2722 43 | _ANDROIDINTENTPROTO._serialized_start=2725 44 | _ANDROIDINTENTPROTO._serialized_end=2904 45 | _ANDROIDINTENTPROTO_EXTRA._serialized_start=2868 46 | _ANDROIDINTENTPROTO_EXTRA._serialized_end=2904 47 | _GSERVICESSETTING._serialized_start=2906 48 | _GSERVICESSETTING._serialized_end=2953 49 | # @@protoc_insertion_point(module_scope) 50 | -------------------------------------------------------------------------------- /probe.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | from checkin import checkin_generator_pb2 4 | from google.protobuf import text_format 5 | from utils import functions 6 | import argparse, requests, gzip, yaml 7 | 8 | parser = argparse.ArgumentParser() 9 | parser.add_argument('--debug', action='store_true', help='Print debug information to text file.') 10 | parser.add_argument('--download', action='store_true', help='Download the OTA file.') 11 | parser.add_argument('--fingerprint', help='Get the OTA using this fingerprint. Reading the config YML file is skipped.') 12 | parser.add_argument('--model', help='Specify the model of the device. If not specified, the device code will be used.') 13 | parser.add_argument('--config', help='Use this config file instead of the default one.', default='config.yml') 14 | parser.add_argument('--serial', help='Specify the serial number of the device.', default=functions.generateSerial()) 15 | parser.add_argument('--imei', help='Specify the IMEI of the device.', default=functions.generateImei()) 16 | args = parser.parse_args() 17 | 18 | class Prober: 19 | def __init__(self): 20 | self.checkinproto = checkin_generator_pb2.AndroidCheckinProto() 21 | self.payload = checkin_generator_pb2.AndroidCheckinRequest() 22 | self.build = checkin_generator_pb2.AndroidBuildProto() 23 | self.response = checkin_generator_pb2.AndroidCheckinResponse() 24 | 25 | def get_update_desc(self): 26 | setting = {entry.name: entry.value for entry in self.response.setting} 27 | update_desc = setting.get(b'update_description', b'').decode() 28 | return update_desc 29 | 30 | def checkin(self, fingerprint: str, model: str = None, debug: bool = False, 31 | serial = functions.generateSerial(), imei = functions.generateImei()) -> str: 32 | self.checkinproto.Clear() 33 | self.payload.Clear() 34 | self.build.Clear() 35 | self.response.Clear() 36 | 37 | try: 38 | config = fingerprint.split('/') 39 | # Split ": 40 | temp = config[2].split(':') 41 | # Drop, then reinsert as two separate entries 42 | config.pop(2) 43 | config.insert(2, temp[0]) 44 | config.insert(3, temp[1]) 45 | current_build = config[4] 46 | android_version = config[3] 47 | device = config[2] 48 | except: 49 | print("Invalid fingerprint.") 50 | return None 51 | if model is None or model == '': 52 | model = device 53 | self.headers = { 54 | 'accept-encoding': 'gzip, deflate', 55 | 'content-encoding': 'gzip', 56 | 'content-type': 'application/x-protobuffer', 57 | 'user-agent': f'Dalvik/2.1.0 (Linux; U; Android {android_version}; {model} Build/{current_build})' 58 | } 59 | 60 | # Add build properties 61 | self.build.id = fingerprint 62 | self.build.timestamp = 0 63 | self.build.device = device 64 | 65 | # Checkin proto 66 | self.checkinproto.build.CopyFrom(self.build) 67 | self.checkinproto.lastCheckinMsec = 0 68 | self.checkinproto.roaming = "WIFI::" 69 | self.checkinproto.userNumber = 0 70 | self.checkinproto.deviceType = 2 71 | self.checkinproto.voiceCapable = False 72 | self.checkinproto.unknown19 = "WIFI" 73 | 74 | # Generate the payload 75 | self.payload.imei = imei 76 | self.payload.id = 0 77 | self.payload.digest = functions.generateDigest() 78 | self.payload.checkin.CopyFrom(self.checkinproto) 79 | self.payload.locale = 'en-US' 80 | self.payload.macAddr.append(functions.generateMac()) 81 | self.payload.timeZone = 'America/New_York' 82 | self.payload.version = 3 83 | self.payload.serialNumber = serial 84 | self.payload.macAddrType.append('wifi') 85 | self.payload.fragment = 0 86 | self.payload.userSerialNumber = 0 87 | self.payload.fetchSystemUpdates = 1 88 | self.payload.unknown30 = 0 89 | 90 | with gzip.open('test_data.gz', 'wb') as f_out: 91 | f_out.write(self.payload.SerializeToString()) 92 | f_out.close() 93 | 94 | post_data = open('test_data.gz', 'rb') 95 | r = requests.post('https://android.googleapis.com/checkin', data=post_data, headers=self.headers) 96 | post_data.close() 97 | 98 | download_url = "" 99 | try: 100 | self.response.ParseFromString(r.content) 101 | if debug: 102 | with open('debug.txt', 'w') as f: 103 | f.write(text_format.MessageToString(self.response)) 104 | f.close() 105 | setting = {entry.name: entry.value for entry in self.response.setting} 106 | update_title = setting.get(b'update_title', b'').decode() 107 | if update_title: 108 | print("Update title: " + setting.get(b'update_title', b'').decode()) 109 | download_url = setting.get(b'update_url', b'').decode() 110 | if download_url: 111 | print("OTA URL obtained: " + download_url) 112 | return download_url 113 | else: 114 | print("No OTA URL found for your build. Either Google does not recognize your build fingerprint, or there are no new updates for your device.") 115 | return None 116 | except: 117 | print("Invalid fingerprint.") 118 | return None 119 | 120 | def checkin_cli(self) -> str: 121 | if args.fingerprint: 122 | return self.checkin(args.fingerprint, args.model, args.debug, args.serial, args.imei) 123 | else: 124 | try: 125 | with open(args.config, 'r') as file: 126 | config = yaml.safe_load(file) 127 | file.close() 128 | return self.checkin(f'{config["oem"]}/{config["product"]}/{config["device"]}:{config["android_version"]}/{config["build_tag"]}/{config["incremental"]}:user/release-keys', config['model'], args.debug) 129 | except: 130 | print("Invalid config file.") 131 | exit(1) 132 | 133 | def download(self, url: str, progress_bar = None, page = None) -> None: 134 | if url is None: 135 | return 136 | print("Downloading OTA file") 137 | with requests.get(url, stream=True) as resp: 138 | resp.raise_for_status() 139 | filename = url.split('/')[-1] 140 | 141 | total_size = int(resp.headers.get('content-length', 0)) 142 | chunk_size = 1024 143 | 144 | with open(filename, 'wb') as file: 145 | progress = 0 146 | 147 | for chunk in resp.iter_content(chunk_size=chunk_size): 148 | if chunk: 149 | file.write(chunk) 150 | progress += len(chunk) 151 | if progress_bar is not None and page is not None: 152 | progress_bar.value = float(progress / total_size) 153 | page.update() 154 | percentage = (progress / total_size) * 100 155 | print(f"Downloaded {progress} of {total_size} bytes ({percentage:.2f}%)", end="\r") 156 | print(f"File downloaded and saved as {filename}!") 157 | 158 | 159 | if __name__ == '__main__': 160 | prober = Prober() 161 | if args.download: 162 | prober.download(prober.checkin_cli()) 163 | else: 164 | prober.checkin_cli() -------------------------------------------------------------------------------- /output.txt: -------------------------------------------------------------------------------- 1 | 2: 0 2 | 3: {"1-da39a3ee5e6b4b0d3255bfef95601890afd80709"} 3 | 4: { 4 | 1: { 5 | 1: {"Fairphone/FP3/FP3:9/8901.2.A.0105.20191217/12171325:user/release-keys"} 6 | 2: {"qcom"} 7 | 3: {"Fairphone"} 8 | 4: {".TA.3.0.c1-00565-8953_GEN_PACK-1,.TA.3.0.c1-00565-8953_GEN_PACK-1"} 9 | 5: {"unknown"} 10 | 6: {"android-uniscope"} 11 | 7: 1576561122 12 | 8: 19275037 13 | 9: {"FP3"} 14 | 10: 28 15 | 11: {"FP3"} 16 | 12: {"Fairphone"} 17 | 13: {"FP3"} 18 | 14: 0 19 | 15: { 20 | 1: 2 21 | 2: {"ms-android-uniscope"} 22 | } 23 | 15: { 24 | 1: 5 25 | 2: {"mvapp-android-uniscope"} 26 | } 27 | 15: { 28 | 1: 9 29 | 2: {"ms-android-uniscope"} 30 | } 31 | 15: { 32 | 1: 4 33 | 2: {"gmm-android-uniscope"} 34 | } 35 | 15: { 36 | 1: 6 37 | 2: {"am-android-uniscope"} 38 | } 39 | 15: { 40 | 1: 1 41 | 2: {"android-uniscope"} 42 | } 43 | 19: {"2019-12-05"} 44 | } 45 | 2: 0 46 | 3: { 47 | 1: {"event_log_start"} 48 | 3: 1580413662631 49 | } 50 | 3: { 51 | 1: {"event_log_start"} 52 | 3: 1580413984544 53 | } 54 | 8: {"WIFI::"} 55 | 9: 0 56 | 14: 2 57 | 15: { 58 | 1: 1 59 | 2: 1 60 | 3: {"unspecified"} 61 | 4: {} 62 | 5: 0 63 | } 64 | 18: 1 65 | 19: {"WIFI"} 66 | } 67 | 6: {12: 9.155902e11i32} # 0x53552d6ei32 68 | 7: -1791219933935838326 69 | 9: {"84cfbf8f2bdf"} 70 | 10: {"357811090611905"} 71 | 11: {} 72 | 12: {"America/New_York"} 73 | 14: 3 74 | 15: {"+eBjakVbKgvqGgpzlIx35lE6iiM="} 75 | 16: {"A209F8CH0201"} 76 | 18: { 77 | 1: 3 78 | 2: 1 79 | 3: 1 80 | 4: 2 81 | 5: 0 82 | 6: 0 83 | 7: 480 84 | 8: 196610 85 | 9: {"android.ext.services"} 86 | 9: {"android.ext.shared"} 87 | 9: { 88 | 12: 6.9331381010284776e193 # 0x682e64696f72646ei64 89 | 12: 1.2791083649121865e213 # 0x6c2e657261776472i64 90 | 13: 1.3039158229230854e-76 # 0x302e32562d746867i64 91 | } 92 | 9: {"android.hidl.manager-V1.0-java"} 93 | 9: {"android.test.base"} 94 | 9: {"android.test.mock"} 95 | 9: { 96 | 12: 4.3520013205641373e251 # 0x742e64696f72646ei64 97 | 12: 3.455435e30i32 # 0x722e7473i32 98 | 14: 4.5443564e30i32 # 0x72656e6ei32 99 | } 100 | 9: {"com.android.future.usb.accessory"} 101 | 9: {"com.android.location.provider"} 102 | 9: {"com.android.media.remotedisplay"} 103 | 9: {"com.android.mediadrm.signer"} 104 | 9: {"com.android.nfc_extras"} 105 | 9: {"com.android.services"} 106 | 9: {"com.google.android.dialer.support"} 107 | 9: {"com.google.android.gms"} 108 | 9: {"com.google.android.maps"} 109 | 9: {"com.gsma.services.nfc"} 110 | 9: {"com.nxp.nfc.nq"} 111 | 9: {"com.qrd.wappush"} 112 | 9: {"com.qti.dpmapi"} 113 | 9: {"com.qti.dpmframework"} 114 | 9: {"com.qti.location.sdk"} 115 | 9: {"com.qti.snapdragon.sdk.display"} 116 | 9: {"com.qualcomm.embmslibrary"} 117 | 9: {"com.qualcomm.qcrilhook"} 118 | 9: {"com.qualcomm.qmapbridge"} 119 | 9: {"com.qualcomm.qti.QtiTelephonyServicelibrary"} 120 | 9: {"com.qualcomm.qti.audiosphere"} 121 | 9: {"com.qualcomm.qti.imscmservice-V2.0-java"} 122 | 9: {"com.qualcomm.qti.imscmservice-V2.1-java"} 123 | 9: {"com.qualcomm.qti.imscmservice@1.0-java"} 124 | 9: {"com.qualcomm.qti.lpa.uimlpalibrary"} 125 | 9: {"com.qualcomm.qti.ltedirectdiscoverylibrary"} 126 | 9: {"com.qualcomm.qti.remoteSimlock.manager.remotesimlockmanagerlibrary"} 127 | 9: {"com.qualcomm.qti.remoteSimlock.uimremotesimlocklibrary"} 128 | 9: {"com.qualcomm.qti.uim.uimservicelibrary"} 129 | 9: {"com.quicinc.cne"} 130 | 9: {"com.quicinc.cneapiclient"} 131 | 9: {"izat.xt.srv"} 132 | 9: {"javax.obex"} 133 | 9: {"org.apache.http.legacy"} 134 | 9: {"vendor.qti.hardware.data.connection-V1.0-java"} 135 | 9: {"vendor.qti.hardware.factory-V1.0"} 136 | 10: {"android.hardware.audio.output"} 137 | 10: {"android.hardware.bluetooth"} 138 | 10: {"android.hardware.bluetooth_le"} 139 | 10: {"android.hardware.camera"} 140 | 10: { 141 | 12: 6.9331381010284776e193 # 0x682e64696f72646ei64 142 | 12: 5.735720279860719e169 # 0x632e657261776472i64 143 | 12: 8.414499393736517e276 # 0x796e612e6172656di64 144 | } 145 | 10: {"android.hardware.camera.autofocus"} 146 | 10: {"android.hardware.camera.capability.manual_post_processing"} 147 | 10: {"android.hardware.camera.capability.manual_sensor"} 148 | 10: {"android.hardware.camera.capability.raw"} 149 | 10: {"android.hardware.camera.flash"} 150 | 10: {"android.hardware.camera.front"} 151 | 10: { 152 | 12: 6.9331381010284776e193 # 0x682e64696f72646ei64 153 | 12: 5.735720279860719e169 # 0x632e657261776472i64 154 | 12: 2.1080362219100268e262 # 0x76656c2e6172656di64 155 | 12: 2.917895e32i32 # 0x75662e6ci32 156 | 13:EGROUP 157 | 13:EGROUP 158 | } 159 | 10: {"android.hardware.faketouch"} 160 | 10: { 161 | 12: 6.9331381010284776e193 # 0x682e64696f72646ei64 162 | 12: 1.6144617321926332e184 # 0x662e657261776472i64 163 | 13: 7.358746945031531e223 # 0x6e6972707265676ei64 164 | 14:EGROUP 165 | } 166 | 10: {"android.hardware.location"} 167 | 10: {"android.hardware.location.gps"} 168 | 10: {"android.hardware.location.network"} 169 | 10: { 170 | 12: 6.9331381010284776e193 # 0x682e64696f72646ei64 171 | 12: 8.382764580288506e217 # 0x6d2e657261776472i64 172 | 13: 3.9466026192472086e180 # 0x656e6f68706f7263i64 173 | } 174 | 10: {"android.hardware.nfc"} 175 | 10: {"android.hardware.nfc.any"} 176 | 10: {"android.hardware.nfc.hce"} 177 | 10: {"android.hardware.nfc.hcef"} 178 | 10: {"android.hardware.opengles.aep"} 179 | 10: { 180 | 12: 6.9331381010284776e193 # 0x682e64696f72646ei64 181 | 12: 1.0134140540861765e242 # 0x722e657261776472i64 182 | 12: 1.1733908802423856e214 # 0x6c616d726f6e2e6di64 183 | } 184 | 10: {"android.hardware.screen.landscape"} 185 | 10: {"android.hardware.screen.portrait"} 186 | 10: {"android.hardware.sensor.accelerometer"} 187 | 10: {"android.hardware.sensor.compass"} 188 | 10: {"android.hardware.sensor.gyroscope"} 189 | 10: {"android.hardware.sensor.light"} 190 | 10: {"android.hardware.sensor.proximity"} 191 | 10: {"android.hardware.sensor.stepcounter"} 192 | 10: {"android.hardware.sensor.stepdetector"} 193 | 10: {"android.hardware.telephony"} 194 | 10: {"android.hardware.telephony.cdma"} 195 | 10: {"android.hardware.telephony.gsm"} 196 | 10: {"android.hardware.touchscreen"} 197 | 10: {"android.hardware.touchscreen.multitouch"} 198 | 10: {"android.hardware.touchscreen.multitouch.distinct"} 199 | 10: {"android.hardware.touchscreen.multitouch.jazzhand"} 200 | 10: {"android.hardware.usb.accessory"} 201 | 10: {"android.hardware.usb.host"} 202 | 10: {"android.hardware.vulkan.compute"} 203 | 10: {"android.hardware.vulkan.level"} 204 | 10: {"android.hardware.vulkan.version"} 205 | 10: {"android.hardware.wifi"} 206 | 10: { 207 | 12: 6.9331381010284776e193 # 0x682e64696f72646ei64 208 | 12: 1.225142415945115e266 # 0x772e657261776472i64 209 | 13: 6.4751898111237e170 # 0x63657269642e6966i64 210 | 14:EGROUP 211 | } 212 | 10: {"android.software.activities_on_secondary_displays"} 213 | 10: {"android.software.app_widgets"} 214 | 10: {"android.software.autofill"} 215 | 10: {"android.software.backup"} 216 | 10: {"android.software.cant_save_state"} 217 | 10: {"android.software.companion_device_setup"} 218 | 10: {"android.software.connectionservice"} 219 | 10: {"android.software.cts"} 220 | 10: {"android.software.device_admin"} 221 | 10: {"android.software.file_based_encryption"} 222 | 10: {"android.software.home_screen"} 223 | 10: {"android.software.input_methods"} 224 | 10: {"android.software.live_wallpaper"} 225 | 10: {"android.software.managed_users"} 226 | 10: {"android.software.midi"} 227 | 10: {"android.software.picture_in_picture"} 228 | 10: {"android.software.print"} 229 | 10: {"android.software.securely_removes_users"} 230 | 10: {"android.software.sip"} 231 | 10: {"android.software.sip.voip"} 232 | 10: {"android.software.verified_boot"} 233 | 10: {"android.software.voice_recognizers"} 234 | 10: {"android.software.webview"} 235 | 10: {"com.google.android.apps.dialer.SUPPORTED"} 236 | 10: {"com.google.android.feature.EEA_DEVICE"} 237 | 10: {"com.google.android.feature.WELLBEING"} 238 | 10: {"com.google.android.paid.chrome"} 239 | 10: {"com.google.android.paid.search"} 240 | 10: {"com.nxp.mifare"} 241 | 11: {12: 2.149428755982193e160} # 0x6138762d34366d72i64 242 | 11: {"armeabi-v7a"} 243 | 11: {"armeabi"} 244 | 12: 1080 245 | 13: 2160 246 | 14: {"af"} 247 | 14: {"af-ZA"} 248 | 14: {"am"} 249 | 14: {"am-ET"} 250 | 14: {"ar"} 251 | 14: {"ar-EG"} 252 | 14: {"ar-XB"} 253 | 14: {"as"} 254 | 14: {"az"} 255 | 14: {"be"} 256 | 14: {"bg"} 257 | 14: {"bg-BG"} 258 | 14: {"bn"} 259 | 14: {"bs"} 260 | 14: {"ca"} 261 | 14: {"ca-ES"} 262 | 14: { 263 | 12:SGROUP 264 | 14:SGROUP 265 | } 266 | 14: {"cs-CZ"} 267 | 14: {"da"} 268 | 14: {"da-DK"} 269 | 14: {"de"} 270 | 14: {"de-DE"} 271 | 14: {"el"} 272 | 14: {12: 2.1386514e11i32} # 0x52472d6ci32 273 | 14: {"en"} 274 | 14: {12: 1.3275054e13i32} # 0x55412d6ei32 275 | 14: {12: 12.198591i32} # 0x41432d6ei32 276 | 14: {12: 49.794365i32} # 0x42472d6ei32 277 | 14: {12: 8.437994e08i32} # 0x4e492d6ei32 278 | 14: {12: 9.155902e11i32} # 0x53552d6ei32 279 | 14: {12: 13.511091i32} # 0x41582d6ei32 280 | 14: {12: 216.17746i32} # 0x43582d6ei32 281 | 14: {"es"} 282 | 14: {12: 8.468711e11i32} # 0x53452d73i32 283 | 14: {12: 9.1559055e11i32} # 0x53552d73i32 284 | 14: {"et"} 285 | 14: {"eu"} 286 | 14: {"fa"} 287 | 14: {"fa-IR"} 288 | 14: {"fi"} 289 | 14: {"fi-FI"} 290 | 14: {"fil"} 291 | 14: {"fil-PH"} 292 | 14: {"fr"} 293 | 14: {"fr-CA"} 294 | 14: {"fr-FR"} 295 | 14: {"gl"} 296 | 14: {"gu"} 297 | 14: {13: 105} 298 | 14: {"hi-IN"} 299 | 14: {13: 114} 300 | 14: {"hr-HR"} 301 | 14: {13: 117} 302 | 14: {"hu-HU"} 303 | 14: {13: 121} 304 | 14: {"in"} 305 | 14: {"in-ID"} 306 | 14: {"is"} 307 | 14: {"it"} 308 | 14: {"it-IT"} 309 | 14: {"iw"} 310 | 14: {"iw-IL"} 311 | 14: {"ja"} 312 | 14: {"ja-JP"} 313 | 14: {"ka"} 314 | 14: { 315 | 13:SGROUP 316 | 13:SGROUP 317 | } 318 | 14: {"km"} 319 | 14: {"kn"} 320 | 14: {"ko"} 321 | 14: {"ko-KR"} 322 | 14: {"ky"} 323 | 14: {"lo"} 324 | 14: { 325 | 13:EGROUP 326 | 14:EGROUP 327 | } 328 | 14: {"lt-LT"} 329 | 14: {"lv"} 330 | 14: {"lv-LV"} 331 | 14: {"mk"} 332 | 14: {"ml"} 333 | 14: {"mn"} 334 | 14: {"mr"} 335 | 14: {"ms"} 336 | 14: {13: 3.6095214e15i32} # 0x594d2d73i32 337 | 14: {"my"} 338 | 14: {"nb"} 339 | 14: {"nb-NO"} 340 | 14: {"ne"} 341 | 14: {"nl"} 342 | 14: {"nl-NL"} 343 | 14: {"or"} 344 | 14: {14: 97} 345 | 14: {14: 108} 346 | 14: {"pl-PL"} 347 | 14: {14: 116} 348 | 14: {"pt-BR"} 349 | 14: {"pt-PT"} 350 | 14: {"ro"} 351 | 14: {"ro-RO"} 352 | 14: {"ru"} 353 | 14: {"ru-RU"} 354 | 14: {"si"} 355 | 14: { 356 | 14:SGROUP 357 | 13:SGROUP 358 | } 359 | 14: {"sk-SK"} 360 | 14: { 361 | 14:SGROUP 362 | 13:EGROUP 363 | } 364 | 14: {"sl-SI"} 365 | 14: {"sq"} 366 | 14: {"sr"} 367 | 14: {"sr-Latn"} 368 | 14: {"sr-RS"} 369 | 14: {"sv"} 370 | 14: {"sv-SE"} 371 | 14: {"sw"} 372 | 14: {"sw-TZ"} 373 | 14: {"ta"} 374 | 14: {"te"} 375 | 14: {"th"} 376 | 14: {"th-TH"} 377 | 14: {"tr"} 378 | 14: {"tr-TR"} 379 | 14: {"uk"} 380 | 14: {14: 13.323588i32} # 0x41552d6bi32 381 | 14: {"ur"} 382 | 14: {"uz"} 383 | 14: {"vi"} 384 | 14: {"vi-VN"} 385 | 14: {"zh-CN"} 386 | 14: {"zh-HK"} 387 | 14: {"zh-TW"} 388 | 14: {"zu"} 389 | 14: {"zu-ZA"} 390 | 15: {"GL_AMD_compressed_ATC_texture"} 391 | 15: {"GL_AMD_performance_monitor"} 392 | 15: {"GL_ANDROID_extension_pack_es31a"} 393 | 15: {"GL_APPLE_texture_2D_limited_npot"} 394 | 15: {"GL_ARB_vertex_buffer_object"} 395 | 15: {"GL_ARM_shader_framebuffer_fetch_depth_stencil"} 396 | 15: {"GL_EXT_EGL_image_array"} 397 | 15: {"GL_EXT_EGL_image_external_wrap_modes"} 398 | 15: {"GL_EXT_EGL_image_storage"} 399 | 15: {"GL_EXT_YUV_target"} 400 | 15: {"GL_EXT_blend_func_extended"} 401 | 15: {"GL_EXT_blit_framebuffer_params"} 402 | 15: {"GL_EXT_buffer_storage"} 403 | 15: {"GL_EXT_clip_control"} 404 | 15: {"GL_EXT_clip_cull_distance"} 405 | 15: {"GL_EXT_color_buffer_float"} 406 | 15: {"GL_EXT_color_buffer_half_float"} 407 | 15: {"GL_EXT_copy_image"} 408 | 15: {"GL_EXT_debug_label"} 409 | 15: {"GL_EXT_debug_marker"} 410 | 15: {"GL_EXT_discard_framebuffer"} 411 | 15: {"GL_EXT_disjoint_timer_query"} 412 | 15: {"GL_EXT_draw_buffers_indexed"} 413 | 15: {"GL_EXT_external_buffer"} 414 | 15: {"GL_EXT_geometry_shader"} 415 | 15: {"GL_EXT_gpu_shader5"} 416 | 15: {"GL_EXT_memory_object"} 417 | 15: {"GL_EXT_memory_object_fd"} 418 | 15: {"GL_EXT_multisampled_render_to_texture"} 419 | 15: {"GL_EXT_multisampled_render_to_texture2"} 420 | 15: {"GL_EXT_primitive_bounding_box"} 421 | 15: {"GL_EXT_protected_textures"} 422 | 15: {"GL_EXT_robustness"} 423 | 15: {"GL_EXT_sRGB"} 424 | 15: {"GL_EXT_sRGB_write_control"} 425 | 15: {"GL_EXT_shader_framebuffer_fetch"} 426 | 15: {"GL_EXT_shader_io_blocks"} 427 | 15: {"GL_EXT_shader_non_constant_global_initializers"} 428 | 15: {"GL_EXT_tessellation_shader"} 429 | 15: {"GL_EXT_texture_border_clamp"} 430 | 15: {"GL_EXT_texture_buffer"} 431 | 15: {"GL_EXT_texture_cube_map_array"} 432 | 15: {"GL_EXT_texture_filter_anisotropic"} 433 | 15: {"GL_EXT_texture_format_BGRA8888"} 434 | 15: {"GL_EXT_texture_format_sRGB_override"} 435 | 15: {"GL_EXT_texture_norm16"} 436 | 15: {"GL_EXT_texture_sRGB_R8"} 437 | 15: {"GL_EXT_texture_sRGB_decode"} 438 | 15: {"GL_EXT_texture_type_2_10_10_10_REV"} 439 | 15: {"GL_KHR_blend_equation_advanced"} 440 | 15: {"GL_KHR_blend_equation_advanced_coherent"} 441 | 15: {"GL_KHR_debug"} 442 | 15: {"GL_KHR_no_error"} 443 | 15: {"GL_KHR_robust_buffer_access_behavior"} 444 | 15: {"GL_KHR_texture_compression_astc_hdr"} 445 | 15: {"GL_KHR_texture_compression_astc_ldr"} 446 | 15: {"GL_NV_shader_noperspective_interpolation"} 447 | 15: {"GL_OES_EGL_image"} 448 | 15: {"GL_OES_EGL_image_external"} 449 | 15: {"GL_OES_EGL_image_external_essl3"} 450 | 15: {"GL_OES_EGL_sync"} 451 | 15: {"GL_OES_blend_equation_separate"} 452 | 15: {"GL_OES_blend_func_separate"} 453 | 15: {"GL_OES_blend_subtract"} 454 | 15: {"GL_OES_compressed_ETC1_RGB8_texture"} 455 | 15: {"GL_OES_compressed_paletted_texture"} 456 | 15: {"GL_OES_depth24"} 457 | 15: {"GL_OES_depth_texture"} 458 | 15: {"GL_OES_depth_texture_cube_map"} 459 | 15: {"GL_OES_draw_texture"} 460 | 15: {"GL_OES_element_index_uint"} 461 | 15: {"GL_OES_framebuffer_object"} 462 | 15: {"GL_OES_get_program_binary"} 463 | 15: {"GL_OES_matrix_palette"} 464 | 15: {"GL_OES_packed_depth_stencil"} 465 | 15: {"GL_OES_point_size_array"} 466 | 15: {"GL_OES_point_sprite"} 467 | 15: {"GL_OES_read_format"} 468 | 15: {"GL_OES_rgb8_rgba8"} 469 | 15: {"GL_OES_sample_shading"} 470 | 15: {"GL_OES_sample_variables"} 471 | 15: {"GL_OES_shader_image_atomic"} 472 | 15: {"GL_OES_shader_multisample_interpolation"} 473 | 15: {"GL_OES_standard_derivatives"} 474 | 15: {"GL_OES_stencil_wrap"} 475 | 15: {"GL_OES_surfaceless_context"} 476 | 15: {"GL_OES_texture_3D"} 477 | 15: {"GL_OES_texture_compression_astc"} 478 | 15: {"GL_OES_texture_cube_map"} 479 | 15: {"GL_OES_texture_env_crossbar"} 480 | 15: {"GL_OES_texture_float"} 481 | 15: {"GL_OES_texture_float_linear"} 482 | 15: {"GL_OES_texture_half_float"} 483 | 15: {"GL_OES_texture_half_float_linear"} 484 | 15: {"GL_OES_texture_mirrored_repeat"} 485 | 15: {"GL_OES_texture_npot"} 486 | 15: {"GL_OES_texture_stencil8"} 487 | 15: {"GL_OES_texture_storage_multisample_2d_array"} 488 | 15: {"GL_OES_vertex_array_object"} 489 | 15: {"GL_OES_vertex_half_float"} 490 | 15: {"GL_OVR_multiview"} 491 | 15: {"GL_OVR_multiview2"} 492 | 15: {"GL_OVR_multiview_multisampled_render_to_texture"} 493 | 15: {"GL_QCOM_alpha_test"} 494 | 15: {"GL_QCOM_extended_get"} 495 | 15: {"GL_QCOM_shader_framebuffer_fetch_noncoherent"} 496 | 15: {"GL_QCOM_texture_foveated"} 497 | 15: {"GL_QCOM_tiled_rendering"} 498 | 18: 360 499 | 19: 0 500 | 20: 3771199488 501 | 21: 8 502 | 26: { 503 | 1: {"android.hardware.audio.output"} 504 | 2: 0 505 | } 506 | 26: { 507 | 1: {"android.hardware.bluetooth"} 508 | 2: 0 509 | } 510 | 26: { 511 | 1: {"android.hardware.bluetooth_le"} 512 | 2: 0 513 | } 514 | 26: { 515 | 1: {"android.hardware.camera"} 516 | 2: 0 517 | } 518 | 26: { 519 | 1: { 520 | 12: 6.9331381010284776e193 # 0x682e64696f72646ei64 521 | 12: 5.735720279860719e169 # 0x632e657261776472i64 522 | 12: 8.414499393736517e276 # 0x796e612e6172656di64 523 | } 524 | 2: 0 525 | } 526 | 26: { 527 | 1: {"android.hardware.camera.autofocus"} 528 | 2: 0 529 | } 530 | 26: { 531 | 1: {"android.hardware.camera.capability.manual_post_processing"} 532 | 2: 0 533 | } 534 | 26: { 535 | 1: {"android.hardware.camera.capability.manual_sensor"} 536 | 2: 0 537 | } 538 | 26: { 539 | 1: {"android.hardware.camera.capability.raw"} 540 | 2: 0 541 | } 542 | 26: { 543 | 1: {"android.hardware.camera.flash"} 544 | 2: 0 545 | } 546 | 26: { 547 | 1: {"android.hardware.camera.front"} 548 | 2: 0 549 | } 550 | 26: { 551 | 1: { 552 | 12: 6.9331381010284776e193 # 0x682e64696f72646ei64 553 | 12: 5.735720279860719e169 # 0x632e657261776472i64 554 | 12: 2.1080362219100268e262 # 0x76656c2e6172656di64 555 | 12: 2.917895e32i32 # 0x75662e6ci32 556 | 13:EGROUP 557 | 13:EGROUP 558 | } 559 | 2: 0 560 | } 561 | 26: { 562 | 1: {"android.hardware.faketouch"} 563 | 2: 0 564 | } 565 | 26: { 566 | 1: { 567 | 12: 6.9331381010284776e193 # 0x682e64696f72646ei64 568 | 12: 1.6144617321926332e184 # 0x662e657261776472i64 569 | 13: 7.358746945031531e223 # 0x6e6972707265676ei64 570 | 14:EGROUP 571 | } 572 | 2: 0 573 | } 574 | 26: { 575 | 1: {"android.hardware.location"} 576 | 2: 0 577 | } 578 | 26: { 579 | 1: {"android.hardware.location.gps"} 580 | 2: 0 581 | } 582 | 26: { 583 | 1: {"android.hardware.location.network"} 584 | 2: 0 585 | } 586 | 26: { 587 | 1: { 588 | 12: 6.9331381010284776e193 # 0x682e64696f72646ei64 589 | 12: 8.382764580288506e217 # 0x6d2e657261776472i64 590 | 13: 3.9466026192472086e180 # 0x656e6f68706f7263i64 591 | } 592 | 2: 0 593 | } 594 | 26: { 595 | 1: {"android.hardware.nfc"} 596 | 2: 0 597 | } 598 | 26: { 599 | 1: {"android.hardware.nfc.any"} 600 | 2: 0 601 | } 602 | 26: { 603 | 1: {"android.hardware.nfc.hce"} 604 | 2: 0 605 | } 606 | 26: { 607 | 1: {"android.hardware.nfc.hcef"} 608 | 2: 0 609 | } 610 | 26: { 611 | 1: {"android.hardware.opengles.aep"} 612 | 2: 0 613 | } 614 | 26: { 615 | 1: { 616 | 12: 6.9331381010284776e193 # 0x682e64696f72646ei64 617 | 12: 1.0134140540861765e242 # 0x722e657261776472i64 618 | 12: 1.1733908802423856e214 # 0x6c616d726f6e2e6di64 619 | } 620 | 2: 0 621 | } 622 | 26: { 623 | 1: {"android.hardware.screen.landscape"} 624 | 2: 0 625 | } 626 | 26: { 627 | 1: {"android.hardware.screen.portrait"} 628 | 2: 0 629 | } 630 | 26: { 631 | 1: {"android.hardware.sensor.accelerometer"} 632 | 2: 0 633 | } 634 | 26: { 635 | 1: {"android.hardware.sensor.compass"} 636 | 2: 0 637 | } 638 | 26: { 639 | 1: {"android.hardware.sensor.gyroscope"} 640 | 2: 0 641 | } 642 | 26: { 643 | 1: {"android.hardware.sensor.light"} 644 | 2: 0 645 | } 646 | 26: { 647 | 1: {"android.hardware.sensor.proximity"} 648 | 2: 0 649 | } 650 | 26: { 651 | 1: {"android.hardware.sensor.stepcounter"} 652 | 2: 0 653 | } 654 | 26: { 655 | 1: {"android.hardware.sensor.stepdetector"} 656 | 2: 0 657 | } 658 | 26: { 659 | 1: {"android.hardware.telephony"} 660 | 2: 0 661 | } 662 | 26: { 663 | 1: {"android.hardware.telephony.cdma"} 664 | 2: 0 665 | } 666 | 26: { 667 | 1: {"android.hardware.telephony.gsm"} 668 | 2: 0 669 | } 670 | 26: { 671 | 1: {"android.hardware.touchscreen"} 672 | 2: 0 673 | } 674 | 26: { 675 | 1: {"android.hardware.touchscreen.multitouch"} 676 | 2: 0 677 | } 678 | 26: { 679 | 1: {"android.hardware.touchscreen.multitouch.distinct"} 680 | 2: 0 681 | } 682 | 26: { 683 | 1: {"android.hardware.touchscreen.multitouch.jazzhand"} 684 | 2: 0 685 | } 686 | 26: { 687 | 1: {"android.hardware.usb.accessory"} 688 | 2: 0 689 | } 690 | 26: { 691 | 1: {"android.hardware.usb.host"} 692 | 2: 0 693 | } 694 | 26: { 695 | 1: {"android.hardware.vulkan.compute"} 696 | 2: 0 697 | } 698 | 26: { 699 | 1: {"android.hardware.vulkan.level"} 700 | 2: 0 701 | } 702 | 26: { 703 | 1: {"android.hardware.vulkan.version"} 704 | 2: 0 705 | } 706 | 26: { 707 | 1: {"android.hardware.wifi"} 708 | 2: 0 709 | } 710 | 26: { 711 | 1: { 712 | 12: 6.9331381010284776e193 # 0x682e64696f72646ei64 713 | 12: 1.225142415945115e266 # 0x772e657261776472i64 714 | 13: 6.4751898111237e170 # 0x63657269642e6966i64 715 | 14:EGROUP 716 | } 717 | 2: 0 718 | } 719 | 26: { 720 | 1: {"android.software.activities_on_secondary_displays"} 721 | 2: 0 722 | } 723 | 26: { 724 | 1: {"android.software.app_widgets"} 725 | 2: 0 726 | } 727 | 26: { 728 | 1: {"android.software.autofill"} 729 | 2: 0 730 | } 731 | 26: { 732 | 1: {"android.software.backup"} 733 | 2: 0 734 | } 735 | 26: { 736 | 1: {"android.software.cant_save_state"} 737 | 2: 0 738 | } 739 | 26: { 740 | 1: {"android.software.companion_device_setup"} 741 | 2: 0 742 | } 743 | 26: { 744 | 1: {"android.software.connectionservice"} 745 | 2: 0 746 | } 747 | 26: { 748 | 1: {"android.software.cts"} 749 | 2: 0 750 | } 751 | 26: { 752 | 1: {"android.software.device_admin"} 753 | 2: 0 754 | } 755 | 26: { 756 | 1: {"android.software.file_based_encryption"} 757 | 2: 0 758 | } 759 | 26: { 760 | 1: {"android.software.home_screen"} 761 | 2: 0 762 | } 763 | 26: { 764 | 1: {"android.software.input_methods"} 765 | 2: 0 766 | } 767 | 26: { 768 | 1: {"android.software.live_wallpaper"} 769 | 2: 0 770 | } 771 | 26: { 772 | 1: {"android.software.managed_users"} 773 | 2: 0 774 | } 775 | 26: { 776 | 1: {"android.software.midi"} 777 | 2: 0 778 | } 779 | 26: { 780 | 1: {"android.software.picture_in_picture"} 781 | 2: 0 782 | } 783 | 26: { 784 | 1: {"android.software.print"} 785 | 2: 0 786 | } 787 | 26: { 788 | 1: {"android.software.securely_removes_users"} 789 | 2: 0 790 | } 791 | 26: { 792 | 1: {"android.software.sip"} 793 | 2: 0 794 | } 795 | 26: { 796 | 1: {"android.software.sip.voip"} 797 | 2: 0 798 | } 799 | 26: { 800 | 1: {"android.software.verified_boot"} 801 | 2: 0 802 | } 803 | 26: { 804 | 1: {"android.software.voice_recognizers"} 805 | 2: 0 806 | } 807 | 26: { 808 | 1: {"android.software.webview"} 809 | 2: 0 810 | } 811 | 26: { 812 | 1: {"com.google.android.apps.dialer.SUPPORTED"} 813 | 2: 0 814 | } 815 | 26: { 816 | 1: {"com.google.android.feature.EEA_DEVICE"} 817 | 2: 0 818 | } 819 | 26: { 820 | 1: {"com.google.android.feature.WELLBEING"} 821 | 2: 0 822 | } 823 | 26: { 824 | 1: {"com.google.android.paid.chrome"} 825 | 2: 0 826 | } 827 | 26: { 828 | 1: {"com.google.android.paid.search"} 829 | 2: 0 830 | } 831 | 26: { 832 | 1: {"com.nxp.mifare"} 833 | 2: 0 834 | } 835 | 28: 1 836 | 30: 2 837 | } 838 | 19: {"wifi"} 839 | 20: 0 840 | 22: 0 841 | 24: { 842 | "Cgb7JzxBBeDSEBMAAET7-QhPJjq-AMol--FoZl2a2gfpBQDroQgSZIbiBNGOqKex91YYv_GDlNeYIZuk" 843 | "yOor4zY5pZZAglr-TWSkk5aAM3V26f0Oc1snhjZeWBdRAqkVYqcgwbJJ-Ba4Lv_yVchqm8G9NmtvHfci" 844 | "c_WUeVC7IssDy-Kkj0fhIA2S7XyzIxmXF0dn3V3sR6KDBQEcA_arz0jTCch5iJI0liXaNRJvajssirII" 845 | "QAJZakDr8-fA1rSPS9dC9vqzm-N5WyGrU_mdPYTeVDSjRP1RaemtaUSPa_T7JTceM34XzOOc95j8ECJm" 846 | "s5rRZkfx29r-NFgRpEgTkz76WdxXoZGRCyjiuS-EBdC2olGqKjynYgzpcyk6m2G2QqSuXbdBuDz8iCgM" 847 | "mFiqWUSXfg8U8MB4x4zbS63nbVAy2WJsR2go1uxYbZq-2HHG4qaLiwQ6jKNsKYKQqhgWasnIyX_myyZG" 848 | "OIbincrIbsJWyc20Ul_umBaRQBy0BH3IUAtG3OXFj2o1TiHHtedQBIPjUuufKXcUCp0vTDZuGXw53eeM" 849 | "vZ2GZDoA_6X621G4LRLLeww4ITenMiGPY15TA7AXbCCRsS0yVG8AugnOf3dKb-XGQ36VC7sk1QTyE_yl" 850 | "qkDT4wem-SfH3rAM46fHkyG5eZWbJHWeJRB076YbgY9gKt6SwytKIDmDk8iTxm73HnMqE_yREE9mOqAA" 851 | "Va1Bb05zBBXyQVZ80FazzGoy8VeiJHUT70QMI3ks25FLOiyKI_TvLt52ZTj4PrPwgDVaivm5Yf1Imhcs" 852 | "dOX2JgrY7x_e5e-nSo4vnFuIA-uKmPgqZDFmyN8gja2bdMFfbZc0P98y0V3cSWJ1OfJy2F6E-uP5902F" 853 | "3QRn2piXq120-4zQQCGLZk9QWqiW0EMo5WLioeP-nmxetG-5zRkXzFRysShdcbF2bD4oHn53__LuGRU0" 854 | "qdlcyBzNCmyvK3CFKpaA_J-yjNRTczkScI9QLxDyCYyVG08tEDhOSoQGinSk_ax2xNUPKa_cCRsSPhc4" 855 | "YdAP0a2boJX-7-cZ6AHz66TpA-gBnufIHzhrOEsStUR66pwOMBYpTl7ni_5vibqU8y0WhlY7Cv8XEdoI" 856 | "qubecxDBewfY79noUMxRA1wLmw7hdeSd7WptQQT4ktefeRv1_vZnbHRAKO0Fj-as3WtvtsPRj7XUBRwB" 857 | "5qk0ApMvPz9EbruqSzhovSn6c8XA1d3wct0sdAntZqzrn0ZzHshQ2ZiF1y_7UFDm1gA86h2eBBeyxT59" 858 | "6vhE1n3bw1k3Sc8vbStoQr5GlPtK-GnFtRot-vjr9d-u3Tq2WtbgkRFu2FjBhrUVfQ4N92p1Zgt7WkLx" 859 | "wVIdkt0mv40beDHsO52dBsCkncaJMgTywgpALA8IPJ2pA4tKvdZtoazmnGPu68QV3p9w-kqfQUFuREjs" 860 | "yljX6L0DBvMU5R1sGZ1HEcImu4lwO9Q8NCgMJr6q9D3qwAzVc4vfHl1VIfsJP3NjOqr4tUilPrOrTsPk" 861 | "DGg_ZEFpOseh04itQopCUMKmK8I0vwFYYJ58gjw7ffp1OP_sp4qGkolm1qiOXKPM3wzmzGcOFZVwSQvw" 862 | "tGiDACBVJwBXZuoGtLEfKHG3teLzM-MFs1pV0sloydZHgbF9kLOXGDdduGmGrVWnm5lXTq0vw4eqTa6w" 863 | "7MN-q4UbhHUrupq5eBP-_E_S6koAEELE1dCgKDVdpGyMKCX8q4FgSB2flQwyGdAbxiKYyKepCNEMrMqu" 864 | "pASaUmlQ_9Q1745gg-3jBaJIi54VD32l89HuZtxLropwSRKN39Ih-g8cN-qtmJ8ESX4mGaTGAv0UPqMq" 865 | "ROl1Wj6IDjvSe4hzeTVhU50X_cxWTiJAiCIbm60Wlx3OSf59Y1AkpzEto46LksCjd4MWdZmBxrIkmebi" 866 | "J20uJ2NpBYnDAWWlolbtmLFOJ6MOUJfqRkj6r_RYGtWpTrfHpxBQFC7yiK6qqAs8QcODF6wBg9_2F82d" 867 | "EOZa3dFg3Qpw3JFrPXWEW0_GJ9mwzu4IMbYQsl1MPeIxtGLVo6wvPNdRgkToahP8dBMK-zx2n58SiIQ8" 868 | "-YEkmhi2wbg-6le3P2PR6adzBjnUD7HpSBdKV-fJiqDL76CQ-h0KJOH0ZU3u0dC1SNdOVrw4QOMQMk2i" 869 | "ABhob0GkSwwi_e3R3YCV-WWPJoRZKx-_e_jENx5z3CFYKnC0cs-LVvZAx3371DqmCKBoKkbg5sGpynX4" 870 | "ClTce2xwlqL4StOtz-58p2teaF7i-KvkE5n76QdCqLS58081rE_ROtO4uTA8u5hiBvsYaitOX5DYV7ue" 871 | "gMmj0bvKtjSloj83SIHB3eegXq3Iuf3Kg0WjaoDJdGnPqbGqVQDr4-5glGpj_6815pE_HBQMNXFfQqMv" 872 | "EcWUmlOGvcOam88wWTxxeLDaMDj3sH-da6ARv3b1HRcn0aVXhqwF8IbaTjRW3XA2TnKp2_cgmaWeT1m9" 873 | "C3RDu_nfc3Mf5NOezYmPkRy-N668v79nOjIMmUOu4zmJNPr-Wud0aqKwrr9_GxnGLwr6ZhaO32JO4Yjn" 874 | "lphs4aaqvh0P-hUnmgm989jzZkiBOwvk2ajqYYPAJdxDBWLthg6dh9b5tA8Y7arw8TAxxi2cejY2BJFz" 875 | "8pL-nn3L2_HcUX-ShrQuY9O7wje_ki0b25ah-xWzdSeN9sDYUN46rjafPF7F2qiQzO2qYJCMosMy-x5p" 876 | "zRxXbhITA2HRkyBCivsnfkPBRBP_GdQJD1nJ_yyyH-xMuSRErAkp1HHKfjc_a_ZAnOkPnPuxMChR5iDJ" 877 | "-Vxxr_PadaoI7enLsuH3Jo5oS9wtPY9vFmgbtuihQkRzGj4cfdYhA4MW6LAJZqQikRH1Dk8JCsP-SgMV" 878 | "Ajxcsrs8FS-S4iDV8NsSkmVjG7YSJtF93hmTNiF6lXB5gfi4qd_tyEiq86wl1MD6YQRPFD3-dhUWvHwR" 879 | "WL-9esWPwVuZSO8XcsjutWstii-JDjUeCl_OxCU7A01kpLNEOjnEcrCU960hKinOrcqyxhWnD1DInWVh" 880 | "5Lmj3ZM0Xhg9X8ncuyQviK_yC2ZpwRkbma0Rzz_jpisYLYLfQCDQvgYi5Zfq-h4XY0mMw01RzhcIq077" 881 | "y0Jlr7mn86-GlDFBdReuhu7PAXntBVRNpIkIvtpHcIKjaa39yyDI3E_WwO77B-B5FsFY8hlHxyGvMYkF" 882 | "Fd6Lt5Fs4Njr9JRAzOLkN-ZVy3K_o4DHZmYE6Hue_WDECbbiE4zkF-XLJRx0d4EPjevLpscc3rmnW4yc" 883 | "FOa46aCUAgz9UDovBG2b1brZIjDL-9MMhv3kLyT5fscFHNGztHkwROl-0QYJOEgyg73HR9hPaYwi8XiG" 884 | "ZDKSwB7UNB5hy2PzW1zcNoMlY1x7F4vXc6rKkrtFyUnN9MgFWRwZXB_CFTUBXP8G6TgQNyt1nz_zA7CT" 885 | "kISRkyX9oFIvozhhhYbZsr90_neZiLAmqpb-HrchIdbMMLROyJGIXXaHBYIzy7PBVUA1RznnJ9gULBa2" 886 | "qZivOsM9mfOmBGQDvkS23s5Nhp-xOLCaBpATrWAY88sNn8Yf3XAglav3e9sEq7NxtGoHPsXeI1cnHXpp" 887 | "2SMNxABNWpXK7VNc82dR2wuEHS53D4ptpA_7SLKpeDf65tfKFDoo05wcsd008DDjeW5TKgfWFzQPraNP" 888 | "RFzu8xOPncVEVOh2QQVofGbkNNwesPmCfpIxhsireVxLda3aLq9NHs0EjxkEm-ut1N4jJqzNAeSKrZaU" 889 | "YRna-ZPGWTDP--blK57fIxpQfZzpi20397gDM5Xu5KOiwvA7B11fBv_czlTmqRmAMijlm2akQ7J0vZjG" 890 | "-JR46la7lB3ubxnHdmidlWqDTIJO8y4651d8nf8D0485g1ybO3XwexWdBQsOQhXvWmd0VRgn7PALKnut" 891 | "5jw9FBH-eb4NH2rNUH6r_b7ASmkrpnkmLOJvhvD9gNvCRcVuL41il1LVOuR0QKRAvFo-D6FxA_JaqQK-" 892 | "4DSP_7tllLeYuT1LvzZt_gY_OGRYtXFiHmJaqng6Agx_-9bURLC6UVPCRcvZEK_OrH67s7K3uiLDXEmv" 893 | "LEqOoMmIsinwBkGGnl0KoS2FbeC9bKAqf89C0_i_jsPxKViAVBlVG42P3w2oKef4yXmyVPln6Q9vLNns" 894 | "HizD77ecV7A611PcxIi3fCXHF5bxKvvCTx1iAio7ayvHST29xXhP9WGfmN5gLs7dy4fhrZjAhRmEzj0E" 895 | "haov3hx87p-GJ92Mn3-_4Clu9AaP_EfmGKqmVZHpZQgwJVoOv-PoIa4t0mjpX0tHEXUQz6cfLNfOV5KB" 896 | "aP_6ffA0rO13mnCTj-BbQ8bOwEHhf0zkASDlk2_knsdYbR92Mkhs2PuFodwjHcw_xcpDtaPQtiBrIVzv" 897 | "XpJgKLDD-mFrHbiEZjDMELyYqxr8y93nH6Bs3er-0gscoqEsazrVQ61gYVUvv0ANny6uo3MPoQbGJNDZ" 898 | "tbwJzobMMci1dXs_-0otx22_cSaRWMGC0QsnTQac8FXcwPvwms3x8Tb8hVBHn-mg9nUS9HWBMxwIsCFg" 899 | "5mPxQrQGsQ21fayJdQhzS1_ILZdNUNOacZLtMfyyMaoXj97U038DiaR7oZqguhFEVGEui96uByfAqJz7" 900 | "ruiSMhmAOb7itq47Z0qXCDb0gHCl3kgqjicvuiYJHNOVdjmJMakSmTuoXzM9kknpBEboBXqCZJB1XOya" 901 | "L-9ROnXzKfd99klLp6RNzVWCm2i29ulTbhsx2T5719gkruxOu3sFYrTyyYVXQddAGY4J30LHh0YTPjm1" 902 | "8LGu9whur1-8dduCrUlIMIStlN4vfiFar-5mveBE6PZEy3mONzyxgoUQABEOBH2PDhfMZSn9isb9j7ow" 903 | "nbPyBuu29T6LOP__TAiruW1AULEPIZck535s_FyrapTikSvRDabTUmj2i6yOH2-eNrXqNQCJsVGZV9-a" 904 | "sLKUyxTs0OiiMRj-FuxgSNmvqzQnOru3nseu7GreUk96LmaulBAKDjU38Dw28rQQVXBRtViz7q_eaogr" 905 | "WoD0OedPBjN3hmAQEajXrryLeBpusq8NyYrrMErH0Qazjs7O33kLPfzknmZydm-fBRA2BY_5W8XQvgKP" 906 | "aHCXNxGKSAt1nh1wwTgE-WuNHxxWdl4UxVe2Ltp0DH1E2KVef619nEpPMRGCmlerdImhymC8ji6izirS" 907 | "3zyeyCtU1siOyYuXekwtb0UBgjYNRc-qgtL0sYkVfvs89GefXdYkooC3rEzGVwGr8kAtqGIx4jrKpmzx" 908 | "c7TspDHKyweniTUeQD34PDEZ7TRHddWg4EqVlGvhRezyTwl1-C1ux2ppOoh99GDkYsWvW1Ki2ZfkwfZj" 909 | "eGOe7Bt7nzfHRz0rVPJhA4gQY3kGX1EzWcfu-OotqO-Zb8VyucA3YWfY19XvnzsvbrDRBVMgRSrpNa6m" 910 | "lsSk0EfWu1xL24x7xg9hRfVa-2W_SZC-cRch4qjTeYQoI_EfmSJlHZqnEo9tFIczaggb51C8byPAU96b" 911 | "f9yMZSvgmp9VsRUoAolwDt2epZaTBsaxt9I4IdRaKv4PJa89_wZCLDoXrhqfdbwLH_k4bvELAto9J3pe" 912 | "WQhShTGLiqnoCZanhHt4KNLeLVRMeLAXijHMtzUZ1S7m8oUa5E0UsuYiKW1XGBAJz759ujYwlwhLNT52" 913 | "Ka13vglQb5nUUmMe0KfYJWN3gTRteUQNjMWs-9gUJoXVpiPQpmx1GI7hSjp_XllmytZLOsTuv4E5Ai4s" 914 | "2Cetk3FdvQRIpyevxhEuGXXt08uvC-F96YtTJv2sHgMM5pnj9VXDdabokLc4GAPH3n4BvWTRpdxgufWQ" 915 | "cKOEAj_bhGFIMI59QPK3tPSV_t-deK2cS4ugKuihXy1U5z9EUSfOMPesOiXNFC1iko72-ldLOO08LiUs" 916 | "mWgFvP0Uk1JpyR3wQg3mn-S7w6BCrUTvcc9upMt9ZI_Tv7GFS_tslJ_d0FeV1Rzn34QEEeo76DeovYwP" 917 | "IKObaQ1dViGg9-XyYwp9-fawKrBUcSofFy6cXfMl3eYJAKO2jUPzq8kIsk-xSHmPCA0iGzHhKf2rrEO_" 918 | "AR4Vb0Tk6B5-2H49pp6LhewRFGbJliyqbdtGGglUnoCB1sFU0nIyaG0qMjnXYZY3oEGvhqnNA9qe0k8f" 919 | "pzli9iadt_q09HYAY7QpWBZ3btb2KD4lp6Xtw75GvZRtBU9V5TCfKQ4NHz39swFlqeJUzSL4rDsotlWA" 920 | "Dii7MHYStMW0xrVEG11xHHqy0eY3s2RGR6ZJWem-QWdR8DAVWaeo_VYrnt-1fOepMgD_3oAhUoW0LiOy" 921 | "_O6U79nfY4jFKtFm0Im2MLQeJHU0W0YNhrHXIKY8s5R2KNz19xJWmqh5UPgZNCRsdEWxZJwPBMwc3uCz" 922 | "P3Hobw1E4qoNorEP0kR7qeOd2T0SbdQmyO1YHZWvpVduumAalMJfc5miVvKlb5QNqWkvQyGxLJ1Rg-LV" 923 | "qtTp_w-vG6QeSoaLzKcbc6_VQVd-M3ci6vDJeuQop5lcluqlf-W3fSblYkKeLARzl9vaeqBYwicMZcsK" 924 | "20_9od1OvUxf106_20Z6ojNLmp9e9zAFDTV0_vNvDoRu860bn8jxqvavdn_WdCPLgLByS7OBGNaL3RAa" 925 | "pdfyUyJhgHjX-x6YoPkNQ2Z7KTmJ96R2SyOTUrJQwJCkE6BvnJj073SowJVsyCxtf6rTZIUR6tHJPmOf" 926 | "jN6BGwDvXSsELdY2SkSRloC8tW00yZX3B3CWorbmf5_2GQ685pTaZS3CUfhdt7xdSX52RN4NfBZ1IZAZ" 927 | "dO7fylL0Nqh13ppZku7yC2HzHFvuKUy-TLErfjni0EuNcCJ0NMG_o4DDMSr1laGtTtkAoXjGPynPZC_r" 928 | "LwwyayQDcH-tZpoQKCpsE_95Eu2z8U2kMA4RyX9IvUiDoovEgp1pQNu1pfDatl--uWjLND9GYUchm8xm" 929 | "aQX8gRHW8u8SwczM7VtTiamLQP-6gItz75bNNxkxsS175mmRrgNI36fmbZaYINzzzxFmIAfsy8MHWnZd" 930 | "SvkuYQB3aUQRxINSBolu34LzFqBQZsOFwsl6LLJe7dLDW52Tlgmc_w2wqjOUKm4MccWw200bs5IjofMZ" 931 | "MSFqcYWjVcpvmfVlNDm7NzD35CPyBftwCOmLhXsNwZMhBQGRVRzwoibOtEHE4z1e8IOd0JpOqvbWGXTG" 932 | "kxY7Z27QF5lD2kd7h__6411vmxx6vOjDXHbRP_5AY8y_up83IkvLnplK56jaUSMETImsyRVOCTRqXSdJ" 933 | "dMJz8j4LD_a2ZPTYyulyArEfABRKxI1lP_shJr7puXXtyp55TpWRnIGHI9FPbJaoB7CnJTN1AtQMKDXQ" 934 | "_6ZgPoUecrxbm1GKp31XNSMgl1pcMOgikeEqbU-27a5VtST3OB4DcVxxs8v5b8lWTOkYn9dN60y33jSg" 935 | "-uku0j5RxkzvZdWlS0Gztb9Kyy0iZJbAFoYnPG5vIaHJSvxEyWbT5Mumi3O1SMsVvNwGBttbV7Q5VmgI" 936 | "2H0Q5YKi1BO53_Xl_MyD09E9bezGE-sC_1INOiaHq_tLAZRcghbp9Zw2ot-JDWfb9f2ej2ffBiTIOj49" 937 | "RsAkeQhd8aqwbyKfvLS5-hob1O24mXCkClJ3fijOaXQIV_o2gG-P6R-uJ9-t6QQSdZf99p27DuGbwaK2" 938 | "hb9_jDvRfGU_xu2aMtrMY7b3BY3qnqqCAIWPOv79sKA2YG8fRo0KnjcG0pajPtDxtBBSi1hWgllIYQlY" 939 | "Q4F3VI2vDXonyJnNrvdjWkkMVdud6NOUzUD_gE697zwGNNJ_RA1Daiix7DoUXxWkyBcu3M0QlRBsahTn" 940 | "-9lHme33tpyNGKBcK1_amSv6XmgrekGD1ThocGdVFQZr4Sn1EJEw_ScIkCmX32U26Z9yaxvNAtsLv3H7" 941 | "DpvmRNWjHvRc58JUB423YDsKrEIBYtsXSR_Gv5Kqt9pEWyPEG6oHlKRxqdmhLvgw5dc8M4nzGbJ7G3pr" 942 | "2wyzVPkRz2Us_ieh8_MgYnVqQYecZuaAR9E3QQ7IY5IWHJYZaPjp7Oe_46Fke7aZsAilhF9_dg1RIUAN" 943 | "wTjFZ1tLa9IeBTwFZkZ4Fnmk0-Ajb8PSvbejO1w83_0A_dH_aHvAq_jWz-Lo3mxPz2SJlgOah88kp08W" 944 | "0qGrxg0g4lVQa_0qAZ51oEczP3PVeQDhg7VDXXRhG6nUDkSbOhvfgV6jI15BlI7Bql0UcinmfzEwZ-l6" 945 | "eReF9Wdi2pz0UtWEE544GNc1RKWpxHLXY6_idNg9qtSPqQp-UeQkLjO1CfYi3eOWJwFt4Ra2Hwvsm7w9" 946 | "4Y1yYRvbMztfKuMN1hL1w9ABUW7EFJn6_X2o4HiZRM8NefrV0ad_ASrgPKcSp1_TwT1RYMJm05TKPYgU" 947 | "4faRNRGe0q50oppg0Nyd1J_IN9PZU4MGwrwo4fcE55xpW70frzYzajXi5uR78V3JSV8TNZ9hLZ9A2_wo" 948 | "DcNG7zeBfQFWtemZJ0qQUgMbX9kvJpLmwveIrJp4RTLcI9RDpg8e66s48jikItoBWuZr3c_aBmSzSaTj" 949 | "9TAVa1gyk7A7lVnI3wBDnCtpQA1ukDdwfA_II360Q2J1JPnmYl5lbDsJhO7VhpmUPPGY9kFF9i__qNTg" 950 | "spm9QvG_ZNWBgD-PaItPshoKpjeei49gG1aaV1fXRYFzuIc_R85NAJxGfalx41cfXKy5aA_KcuEd0NcK" 951 | "8BHMCBwm2SBlWT3FsmQLHbLVCSI6GsZOK3TkefrFROsWiE4l3uOEkVk7K3q860jc6VDJkm7L0kqKb2t2" 952 | "IqcIk1NJFBOuT8x7Wl8rh49O6W_pvOd8X0OHZ0gRIPCeJIMlFfPdr1fmRiJBZhMPRwibHYSubrD3I_Jz" 953 | "Y-aVdpeCPzsOELva_0m1ctndn1f2m3mGKOQDzB2Jzra_U4hZr8jBGLhc8HM4t7_zVOBX4sf8o4-EsxDj" 954 | "AV_0Kvj8hGUZcrbUtfk3Duv9CIOfRxV3ibZVKgWk3Y-GI9s9DjxHT-lFXz4lqmV1TrdA0E-DefSJvNAV" 955 | "qi1ojmh65M4pnT7fV4EwL4xvLsx7McpSYV-_7XUmGEWe_9h4Hu40iRDWwSY8ev-T4KD9CEnqXczA6Xg9" 956 | "gq_W50q9j-mAW_dfVUCeR9xl9yykWJBjoo7K2Hm4hTjePVDlCSNFNxDAqfJjbkeSfUjb2trTycGBRV52" 957 | "6x8uVvzWTsSO_MNao4bw6FRtVk4Jmzi5JAcjMt0NV45Gk4zU-PVW1ZHXw-rmmeYWn5FUOI1nqW7IEY7f" 958 | "wGyJi1UtqhwIcxztWRW3k7CxHGH_GQSAJfnOqISAuH_IpqKqKQHAE4Mis9TyuR9id-5ZywN7QE3eIkIe" 959 | "RzCskPnIvY__C8xhJSFPpfqw_ZQxaliCGc5vLH-RF-MJeZ22ZJBMKxJQws7c7WpusEUVMPODZFVmQ0d3" 960 | "v-sbfXLbwM7yjx8aV517CDhO1rR1k7sqqiOnP0X3v6eipxW67jFqrEbQBVQA_N1-j6Uob0kXjkrU4M09" 961 | "LLoq1XbZml10Mc4_oZ5ZB-YfVNPuR6LZkAZ7Kwm8-2OpoqbCHDSLl9-5LcyqOIATvgaq_vhAaPkjG7wA" 962 | "1TIf0DDur4NnXIBJlTK0rqHhr_1dvRZeJikkWmSG7P27cHzr5OjGX71LdBUT2lqq5BsTCc3HSMdokrGp" 963 | "-uKWsgIfboQ_LNtb4D9CXwOEMPcSHb1vknVhiaKvJ8xOq3auadLiR74XlUXUiLdPK33t8ksSKyGpDCfL" 964 | "X30znR85K4uR1wTSjA0JWhed045U2Xuu6XPKFMftpxfWl7bVtvF7IJ_kKPK48RY4PcKHwi2d8D32Ep0-" 965 | "IoIAahaAGmGPTjZ2EJYuFkGirntwHtk6NqwAVjB9zhXAk3vCK3D508EqV7bK1kuLt1mEJjI1qWjSaZsY" 966 | "Skxe5I5wK288k7fC5kGjMQM-ZdrrMr2ify3E-pV7UISoSPgvz7pl58ty1mkQAMJMJi0E-I_TjNefsV8j" 967 | "hrxplLRbCWRctaKtZBk_ffv69wFn9H9BwKg3_S2634HcFHtKeVbFiHz-NA2aJip2KUTgQsbWIXvgFrDL" 968 | "hJLXRiUIU_yCe4KVd8tRK9GaS4uzkSgYIUC_vB53JdCHcMOTomhIsM11WxBMdxlUlScIX1gPnDV2CslM" 969 | "CM0joD8JARsbfvnOp5jtO8-O-YwhPR7uzPy0X1FjHsolOK2wxDL7NZWpA9dV6RaaOO5Bgha8O9n3aPh2" 970 | "TCjK_gn3mwYYSNaqO_BY8HP5h0PLYoUov0oOPUbms5FiGr_ysUPUS8pyI20ed5Gy7a08CvMfWzCu8DqN" 971 | "ZEtiuez3G6arXM50RDIJdpJCYpDxpOopMxTvGw4YebotrRHMqyTq2ggDnkHlRobCRSTfa4zpCSen0gJw" 972 | "CDYvS0Coqkf5WKmsJ-mHtzu_XSq-TuT8kXiHBc6YKuLwH5xB69dhlnK3OqW-6w0xMCc1YjZfHxo1SXB8" 973 | "9mWVp_aUK1q5LGpxnemEhTKi0b0C-rEfl2gKhkSSvoj0ZrIEVsAyd-chj-cIwnh4x59iJnaSa0VFVhMA" 974 | "qb-ZvriWwLYBO-CXLjEU9gPOuWj8Is_sve00frVExrfrr3jqkpI7y8KgBABuRTLv1lzK-BW_St9aTufz" 975 | "wmCQFqz9bBerMRgbOo6KGefh-k_WbIKKkv8onmFT0-LlIi4vAnmpYpZPdyz3AfgSARj74dwVohCB-3_5" 976 | "hEudLWlOKHJb9lLk2KBoTxP8ORMgGDSg-t_g3LvngCquwVthlC_uFJtThA61j5Hn7jwLfPOopVwYsaV8" 977 | "SWJv64J5C6M9YQEQ5zjlu3LQ2CF4CN3c5mkR5bubx3VCUdoDp6XcR7JVjg0s7mn43FzuebT1Qm_CgaG4" 978 | "Fn3S-brY8PRYoywP70lm0gBVE1ogJ8wMpo4ChkooK5OudZRBtFYDDyAV67_WSvsmkvCzM5eo8rpXTP2p" 979 | "2NnfZJwdeedCFxj-n40wgu9XdWnUK2ZparylZvBqNn0ar2q2aYha0r_SdQFT1jaUWmk6iCOAEzOCMq3z" 980 | "_LWmNzrO9xgtnGsC1BbAZo6mO472ViJZhzgi86CgVXmV_x-xXTwwtXLrOrIDRCUpwm7fWgDiktKRKeWh" 981 | "xI98IwHPtljzWIf1nMfYz8gnyzPdDTBoeKR_YlBOB0Ei1wCQ96ae6zimWv7EwSZytb3XLlRhQLMJmI3c" 982 | "rGh0CLZhvjDpT7WJyWwV2ZWX4ogbUf77JzaWRp2dSYbBddnDQr0vJsUuLry8l-XJKHUxTU9S73gWAGtD" 983 | "NKBUxAG0o-Bcc23Ovqvw3WwnuZlv4pAO6hnNbD1E9Jz3FART0FHXFF26tAH2Jq6Rcf_WkLd7yVT-gGqy" 984 | "amzCDiLDrFmL1YbTuVi2FFoSbCV85X-7x4fhqAhLcSjVa3TfCygRkPIqArKjJ6-V92Zab-Uox5zADL45" 985 | "OUicvv3EKarSOkOGLl4fRINSPHLGcgD5nCKdeZCrmInYM0kctZ1E1_7UtbEVMiwBoDPhpIZnPoeesOJc" 986 | "VVXhVtLW4vLTXRrIylCIXgzFT8Bu4y4x9ro0AAAeeKnCmw1ZYvdTeFtgLxv7wwLWjgGqz3BdrrMJoOch" 987 | "heyMPDMHZHnb9dWsV_qtvSEAC1yol-p-f7clqDaNeAApN5v-yH8J-sS_H6lvgLDszWyVOcPWn0m6EloE" 988 | "cnKbwD-RMCo5Ijt7rP7Z9h8iubR4-PRWaVjnfXmkda9nU2Iwu0OVHDCFecKo9mccwP6w4f7Rjz-u7iB6" 989 | "zl1Vh5DqxaOIQnniPr5GO4XDLkCqTkaM_VGpVYa-b7UYavQyWpPEdVObvW6lYDxnVF3R7-Ww45BZMKG1" 990 | "Yhcrw8lDYyUiO99NcXR7Hxzb8toZn0cLNa2wVX-lXEa0pZOnGAWY8MusOJnFXCDldGOn0sUxMQjrk9UF" 991 | "M83zQM5r-lDPX_MEpQd6dXMFr0d3TrAnpD8h5thNVlZvraGZuX6q5suvyv6htpEICDy5nPTVIFajeygl" 992 | "bTcUTgJsuieDnyU-y_vCyT6IVk7FNwQD1jqCk5JlCvPiYpYbE_F77gZtrIEV476zdz62DKk5BOHpHrNs" 993 | "IvaO6ns45BASPcHFCxcvMMawmIR5ut1t__qdQ8BgMCRZtRxo4YNvNcpdnhw-IqDU6UFMIVehv6BSndc2" 994 | "gaUYewZRRlbtmh_bgMMA-LkMjGj0QexBZg_Be-QDQmijJDSDh3GjD4-uYkeFFKhMLDx_Dt7DJmePkX0T" 995 | "eaL-41TSKDGjNURdtTzZYcbfUIRAyzXANFG4qXDg8n5wtpKTDkJnsiOApeZoS4lWhhMxxECl6Ho_Nnb2" 996 | "qpnRa0csDPRfSP7yNqc1ymtOZcY0wJXKyXlQIb_V8o3DaysMhhNPPSNJVuI46dJhe1Ta1pFLFpwbSWeV" 997 | "gBVDZF9bVRZFornJzqIwdKvFYk3hcqMa0FvsT_WwOu_v8gCwO904FZanzmLlxFYIUfsI9Ju53kFW1SqR" 998 | "MQ3EA0ul_GK1zb26tdTLM_7YsCn3WgVVOToHYkezAqHFA5fbrYzpliXq7wRC9QvhP6rAx8fhQ7Bo1iDs" 999 | "-cJd2XtgLHEqx6tZwLV-LnWlgDHfhl9IDXQDEPDmUmhwfhaFpU2ftRBjPWo0Xyepz3jW8he54ERI3fcC" 1000 | "5G7rC-5jFuw6HNIOwYCNfcAXzi7XyVVxKgnk1rnbLQ2YbzspT5wfVrh2U57Tn9CUk6rGEzISZ0ogu4AI" 1001 | "kQltMJM3TGfVLKJFrKyN6r41ORN3IMfX99gsnNGqECAF5y_0VkHjxjd315bq__odv66ef_4fa8kavY_6" 1002 | "i_bLDw" 1003 | } 1004 | 29: 0 1005 | 30: 0 1006 | --------------------------------------------------------------------------------