From 3649341939b7961fbe600c0c372548d9d3c86878 Mon Sep 17 00:00:00 2001
From: chiteroman <98092901+chiteroman@users.noreply.github.com>
Date: Thu, 20 Jun 2024 23:59:48 +0200
Subject: [PATCH] v16.3

---
 app/build.gradle.kts                          |   6 +-
 app/proguard-rules.pro                        |   3 +-
 app/src/main/cpp/main.cpp                     | 158 +++++++++---------
 .../playintegrityfix/CustomKeyStoreSpi.java   |   2 +-
 .../playintegrityfix/EntryPoint.java          |   8 +-
 .../chiteroman/playintegrityfix/Keybox.java   | 107 ------------
 .../{Android.java => KeyboxUtils.java}        |  98 ++++++++---
 changelog.md                                  |  14 +-
 module/keybox.xml                             | 114 +++++++++++++
 module/module.prop                            |   8 +-
 module/pif.json                               |   4 +-
 update.json                                   |   6 +-
 12 files changed, 305 insertions(+), 223 deletions(-)
 delete mode 100644 app/src/main/java/es/chiteroman/playintegrityfix/Keybox.java
 rename app/src/main/java/es/chiteroman/playintegrityfix/{Android.java => KeyboxUtils.java} (58%)
 create mode 100644 module/keybox.xml

diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 52a8b6f..f47207a 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -16,8 +16,8 @@ android {
         applicationId = "es.chiteroman.playintegrityfix"
         minSdk = 26
         targetSdk = 34
-        versionCode = 16000
-        versionName = "v16.0"
+        versionCode = 16300
+        versionName = "v16.3"
         multiDexEnabled = false
 
         packaging {
@@ -94,7 +94,7 @@ tasks.register("copyFiles") {
         val dexFile = project.layout.buildDirectory.get().asFile.resolve("intermediates/dex/release/minifyReleaseWithR8/classes.dex")
         val soDir = project.layout.buildDirectory.get().asFile.resolve("intermediates/stripped_native_libs/release/stripReleaseDebugSymbols/out/lib")
 
-//        dexFile.copyTo(moduleFolder.resolve("classes.dex"), overwrite = true)
+        dexFile.copyTo(moduleFolder.resolve("classes.dex"), overwrite = true)
 
         soDir.walk().filter { it.isFile && it.extension == "so" }.forEach { soFile ->
             val abiFolder = soFile.parentFile.name
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
index c65bd56..31d16a3 100644
--- a/app/proguard-rules.pro
+++ b/app/proguard-rules.pro
@@ -1,3 +1,4 @@
 -keep class es.chiteroman.playintegrityfix.EntryPoint {public <methods>;}
 -keep class es.chiteroman.playintegrityfix.CustomProvider
--keep class es.chiteroman.playintegrityfix.CustomKeyStoreSpi
\ No newline at end of file
+-keep class es.chiteroman.playintegrityfix.CustomKeyStoreSpi
+-keep class es.chiteroman.playintegrityfix.KeyboxUtils
\ No newline at end of file
diff --git a/app/src/main/cpp/main.cpp b/app/src/main/cpp/main.cpp
index d8062c2..8fa0889 100644
--- a/app/src/main/cpp/main.cpp
+++ b/app/src/main/cpp/main.cpp
@@ -1,20 +1,24 @@
 #include <android/log.h>
 #include <sys/system_properties.h>
 #include <unistd.h>
+#include <fstream>
 #include "dobby.h"
 #include "json.hpp"
 #include "zygisk.hpp"
-#include "dex.h"
 
 #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, "PIF", __VA_ARGS__)
 
+#define DEX_PATH "/data/adb/modules/playintegrityfix/classes.dex"
+
 #define PIF_JSON "/data/adb/pif.json"
 
 #define PIF_JSON_DEFAULT "/data/adb/modules/playintegrityfix/pif.json"
 
-static std::string DEVICE_INITIAL_SDK_INT, SECURITY_PATCH, ID;
+#define KEYBOX_JSON "/data/adb/keybox.xml"
 
-static inline ssize_t xread(int fd, void *buffer, size_t count) {
+#define KEYBOX_JSON_DEFAULT "/data/adb/modules/playintegrityfix/keybox.xml"
+
+static ssize_t xread(int fd, void *buffer, size_t count) {
     ssize_t total = 0;
     char *buf = (char *) buffer;
     while (count > 0) {
@@ -27,7 +31,7 @@ static inline ssize_t xread(int fd, void *buffer, size_t count) {
     return total;
 }
 
-static inline ssize_t xwrite(int fd, void *buffer, size_t count) {
+static ssize_t xwrite(int fd, void *buffer, size_t count) {
     ssize_t total = 0;
     char *buf = (char *) buffer;
     while (count > 0) {
@@ -40,6 +44,8 @@ static inline ssize_t xwrite(int fd, void *buffer, size_t count) {
     return total;
 }
 
+static std::string DEVICE_INITIAL_SDK_INT;
+
 typedef void (*T_Callback)(void *, const char *, const char *, uint32_t);
 
 static T_Callback o_callback = nullptr;
@@ -50,17 +56,8 @@ static void modify_callback(void *cookie, const char *name, const char *value, u
 
     std::string_view prop(name);
 
-    if (prop.ends_with("api_level") && !DEVICE_INITIAL_SDK_INT.empty()) {
+    if (prop.ends_with("first_api_level") && !DEVICE_INITIAL_SDK_INT.empty()) {
         value = DEVICE_INITIAL_SDK_INT.c_str();
-    } else if (prop.ends_with(".security_patch") && !SECURITY_PATCH.empty()) {
-        value = SECURITY_PATCH.c_str();
-    } else if (prop.ends_with(".id") && !ID.empty()) {
-        value = ID.c_str();
-    } else if (prop == "sys.usb.state") {
-        value = "none";
-    }
-
-    if (!prop.starts_with("persist") && !prop.starts_with("cache") && !prop.starts_with("debug")) {
         LOGD("[%s]: %s", name, value);
     }
 
@@ -98,71 +95,81 @@ public:
 
     void preAppSpecialize(zygisk::AppSpecializeArgs *args) override {
 
-        api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY);
-
         if (!args) {
             api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY);
             return;
         }
 
-        const char *dir = env->GetStringUTFChars(args->app_data_dir, nullptr);
+        auto dir = env->GetStringUTFChars(args->app_data_dir, nullptr);
 
         if (!dir) {
             api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY);
             return;
         }
 
-        if (!std::string_view(dir).ends_with("/com.google.android.gms")) {
-            env->ReleaseStringUTFChars(args->app_data_dir, dir);
+        bool isGms = std::string_view(dir).ends_with("/com.google.android.gms");
+
+        env->ReleaseStringUTFChars(args->app_data_dir, dir);
+
+        if (!isGms) {
             api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY);
             return;
         }
 
-        env->ReleaseStringUTFChars(args->app_data_dir, dir);
-
         api->setOption(zygisk::FORCE_DENYLIST_UNMOUNT);
 
-        const char *name = env->GetStringUTFChars(args->nice_name, nullptr);
+        auto name = env->GetStringUTFChars(args->nice_name, nullptr);
 
         if (!name) {
             api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY);
             return;
         }
 
-        if (strncmp(name, "com.google.android.gms.unstable", 31) != 0) {
-            env->ReleaseStringUTFChars(args->nice_name, name);
+        bool isGmsUnstable = std::string_view(name) == "com.google.android.gms.unstable";
+
+        env->ReleaseStringUTFChars(args->nice_name, name);
+
+        if (!isGmsUnstable) {
             api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY);
             return;
         }
 
-        env->ReleaseStringUTFChars(args->nice_name, name);
-
-        long size = 0;
-        std::vector<char> vector;
-
         int fd = api->connectCompanion();
 
-        xread(fd, &size, sizeof(long));
+        int dexSize = 0, jsonSize = 0, keyboxSize = 0;
+        std::vector<char> jsonVector, keyboxVector;
 
-        if (size > 0) {
-            vector.resize(size);
-            xread(fd, vector.data(), size);
-            json = nlohmann::json::parse(vector, nullptr, false, true);
-        } else {
-            api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY);
-        }
+        xread(fd, &dexSize, sizeof(int));
+        xread(fd, &jsonSize, sizeof(int));
+        xread(fd, &keyboxSize, sizeof(int));
+
+        dexVector.resize(dexSize);
+        xread(fd, dexVector.data(), dexSize);
+
+        jsonVector.resize(jsonSize);
+        xread(fd, jsonVector.data(), jsonSize);
+
+        keyboxVector.resize(keyboxSize);
+        xread(fd, keyboxVector.data(), keyboxSize);
 
         close(fd);
+
+        json = nlohmann::json::parse(jsonVector, nullptr, false, true);
+
+        keyboxString = std::string(keyboxVector.cbegin(), keyboxVector.cend());
     }
 
     void postAppSpecialize(const zygisk::AppSpecializeArgs *args) override {
-        if (json.empty()) return;
+        if (dexVector.empty() || json.empty()) return;
 
-        parseJson();
+        if (json.contains("DEVICE_INITIAL_SDK_INT")) {
+            DEVICE_INITIAL_SDK_INT = json["DEVICE_INITIAL_SDK_INT"].get<std::string>();
+            json.erase("DEVICE_INITIAL_SDK_INT"); // You can't modify field value
+        }
+
+        doHook();
 
         injectDex();
-
-//        doHook();
     }
 
     void preServerSpecialize(zygisk::ServerSpecializeArgs *args) override {
@@ -172,20 +179,9 @@ public:
 private:
     zygisk::Api *api = nullptr;
     JNIEnv *env = nullptr;
+    std::vector<char> dexVector;
     nlohmann::json json;
-
-    void parseJson() {
-        if (json.contains("DEVICE_INITIAL_SDK_INT")) {
-            DEVICE_INITIAL_SDK_INT = json["DEVICE_INITIAL_SDK_INT"].get<std::string>();
-            json.erase("DEVICE_INITIAL_SDK_INT"); // You can't modify field value
-        }
-        if (json.contains("SECURITY_PATCH")) {
-            SECURITY_PATCH = json["SECURITY_PATCH"].get<std::string>();
-        }
-        if (json.contains("ID")) {
-            ID = json["ID"].get<std::string>();
-        }
-    }
+    std::string keyboxString;
 
     void injectDex() {
         LOGD("get system classloader");
@@ -198,7 +194,7 @@ private:
         auto dexClClass = env->FindClass("dalvik/system/InMemoryDexClassLoader");
         auto dexClInit = env->GetMethodID(dexClClass, "<init>",
                                           "(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V");
-        auto buffer = env->NewDirectByteBuffer(classes_dex, classes_dex_len);
+        auto buffer = env->NewDirectByteBuffer(dexVector.data(), dexVector.size());
         auto dexCl = env->NewObject(dexClClass, dexClInit, buffer, systemClassLoader);
 
         LOGD("load class");
@@ -210,45 +206,47 @@ private:
         auto entryPointClass = (jclass) entryClassObj;
 
         LOGD("call init");
-        auto entryInit = env->GetStaticMethodID(entryPointClass, "init", "(Ljava/lang/String;)V");
-        auto str = env->NewStringUTF(json.dump().c_str());
-        env->CallStaticVoidMethod(entryPointClass, entryInit, str);
+        auto entryInit = env->GetStaticMethodID(entryPointClass, "init",
+                                                "(Ljava/lang/String;Ljava/lang/String;)V");
+        auto jsonStr = env->NewStringUTF(json.dump().c_str());
+        auto keyboxStr = env->NewStringUTF(keyboxString.c_str());
+        env->CallStaticVoidMethod(entryPointClass, entryInit, jsonStr, keyboxStr);
     }
 };
 
-static std::vector<char> readFile(const char *path) {
+static std::vector<char> readFile(const std::string &path) {
 
-    std::vector<char> vector;
+    std::ifstream ifs(path);
 
-    FILE *file = fopen(path, "rb");
-
-    if (file) {
-        fseek(file, 0, SEEK_END);
-        long size = ftell(file);
-        fseek(file, 0, SEEK_SET);
-
-        vector.resize(size);
-        fread(vector.data(), 1, size, file);
-        fclose(file);
-    } else {
-        LOGD("Couldn't read %s file!", path);
+    if (!ifs || ifs.bad()) {
+        return std::vector<char>();
     }
 
-    return vector;
+    return std::vector<char>((std::istreambuf_iterator<char>(ifs)),
+                             std::istreambuf_iterator<char>());
 }
 
 static void companion(int fd) {
-    long size = 0;
-    std::vector<char> vector;
 
-    vector = readFile(PIF_JSON);
+    auto dex = readFile(DEX_PATH);
 
-    if (vector.empty()) vector = readFile(PIF_JSON_DEFAULT);
+    auto json = readFile(PIF_JSON);
+    if (json.empty()) json = readFile(PIF_JSON_DEFAULT);
 
-    size = vector.size();
+    auto keybox = readFile(KEYBOX_JSON);
+    if (keybox.empty()) keybox = readFile(KEYBOX_JSON_DEFAULT);
 
-    xwrite(fd, &size, sizeof(long));
-    xwrite(fd, vector.data(), size);
+    int dexSize = dex.size();
+    int jsonSize = json.size();
+    int keyboxSize = keybox.size();
+
+    xwrite(fd, &dexSize, sizeof(int));
+    xwrite(fd, &jsonSize, sizeof(int));
+    xwrite(fd, &keyboxSize, sizeof(int));
+
+    xwrite(fd, dex.data(), dexSize * sizeof(char));
+    xwrite(fd, json.data(), jsonSize * sizeof(char));
+    xwrite(fd, keybox.data(), keyboxSize * sizeof(char));
 }
 
 REGISTER_ZYGISK_MODULE(PlayIntegrityFix)
diff --git a/app/src/main/java/es/chiteroman/playintegrityfix/CustomKeyStoreSpi.java b/app/src/main/java/es/chiteroman/playintegrityfix/CustomKeyStoreSpi.java
index 1f4b170..853b5db 100644
--- a/app/src/main/java/es/chiteroman/playintegrityfix/CustomKeyStoreSpi.java
+++ b/app/src/main/java/es/chiteroman/playintegrityfix/CustomKeyStoreSpi.java
@@ -26,7 +26,7 @@ public final class CustomKeyStoreSpi extends KeyStoreSpi {
     @Override
     public Certificate[] engineGetCertificateChain(String alias) {
         if (Arrays.stream(Thread.currentThread().getStackTrace()).anyMatch(e -> e.getClassName().toLowerCase(Locale.US).contains("droidguard"))) {
-            return Android.engineGetCertificateChain(keyStoreSpi.engineGetCertificateChain(alias));
+            return KeyboxUtils.engineGetCertificateChain(keyStoreSpi.engineGetCertificateChain(alias));
         }
         return keyStoreSpi.engineGetCertificateChain(alias);
     }
diff --git a/app/src/main/java/es/chiteroman/playintegrityfix/EntryPoint.java b/app/src/main/java/es/chiteroman/playintegrityfix/EntryPoint.java
index 3807760..c478600 100644
--- a/app/src/main/java/es/chiteroman/playintegrityfix/EntryPoint.java
+++ b/app/src/main/java/es/chiteroman/playintegrityfix/EntryPoint.java
@@ -37,7 +37,7 @@ public final class EntryPoint {
         Security.insertProviderAt(customProvider, 1);
     }
 
-    public static void init(String json) {
+    public static void init(String json, String kbox) {
 
         try {
             JSONObject jsonObject = new JSONObject(json);
@@ -65,6 +65,12 @@ public final class EntryPoint {
         } catch (Throwable t) {
             LOG("Error loading json file: " + t);
         }
+
+        try {
+            KeyboxUtils.parseXml(kbox);
+        } catch (Throwable t) {
+            LOG("Error parsing keybox file: " + t);
+        }
     }
 
     static void spoofFields() {
diff --git a/app/src/main/java/es/chiteroman/playintegrityfix/Keybox.java b/app/src/main/java/es/chiteroman/playintegrityfix/Keybox.java
deleted file mode 100644
index b2c0521..0000000
--- a/app/src/main/java/es/chiteroman/playintegrityfix/Keybox.java
+++ /dev/null
@@ -1,107 +0,0 @@
-package es.chiteroman.playintegrityfix;
-
-public final class Keybox {
-    public static final class EC {
-        public static final String PRIVATE_KEY = """
-                -----BEGIN EC PRIVATE KEY-----
-                MHcCAQEEICHghkMqFRmEWc82OlD8FMnarfk19SfC39ceTW28QuVEoAoGCCqGSM49
-                AwEHoUQDQgAE6555+EJjWazLKpFMiYbMcK2QZpOCqXMmE/6sy/ghJ0whdJdKKv6l
-                uU1/ZtTgZRBmNbxTt6CjpnFYPts+Ea4QFA==
-                -----END EC PRIVATE KEY-----
-                """;
-        public static final String CERTIFICATE_1 = """
-                -----BEGIN CERTIFICATE-----
-                MIICeDCCAh6gAwIBAgICEAEwCgYIKoZIzj0EAwIwgZgxCzAJBgNVBAYTAlVTMRMw
-                EQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MRUwEwYD
-                VQQKDAxHb29nbGUsIEluYy4xEDAOBgNVBAsMB0FuZHJvaWQxMzAxBgNVBAMMKkFu
-                ZHJvaWQgS2V5c3RvcmUgU29mdHdhcmUgQXR0ZXN0YXRpb24gUm9vdDAeFw0xNjAx
-                MTEwMDQ2MDlaFw0yNjAxMDgwMDQ2MDlaMIGIMQswCQYDVQQGEwJVUzETMBEGA1UE
-                CAwKQ2FsaWZvcm5pYTEVMBMGA1UECgwMR29vZ2xlLCBJbmMuMRAwDgYDVQQLDAdB
-                bmRyb2lkMTswOQYDVQQDDDJBbmRyb2lkIEtleXN0b3JlIFNvZnR3YXJlIEF0dGVz
-                dGF0aW9uIEludGVybWVkaWF0ZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABOue
-                efhCY1msyyqRTImGzHCtkGaTgqlzJhP+rMv4ISdMIXSXSir+pblNf2bU4GUQZjW8
-                U7ego6ZxWD7bPhGuEBSjZjBkMB0GA1UdDgQWBBQ//KzWGrE6noEguNUlHMVlux6R
-                qTAfBgNVHSMEGDAWgBTIrel3TEXDo88NFhDkeUM6IVowzzASBgNVHRMBAf8ECDAG
-                AQH/AgEAMA4GA1UdDwEB/wQEAwIChDAKBggqhkjOPQQDAgNIADBFAiBLipt77oK8
-                wDOHri/AiZi03cONqycqRZ9pDMfDktQPjgIhAO7aAV229DLp1IQ7YkyUBO86fMy9
-                Xvsiu+f+uXc/WT/7
-                -----END CERTIFICATE-----
-                """;
-        public static final String CERTIFICATE_2 = """
-                -----BEGIN CERTIFICATE-----
-                MIICizCCAjKgAwIBAgIJAKIFntEOQ1tXMAoGCCqGSM49BAMCMIGYMQswCQYDVQQG
-                EwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmll
-                dzEVMBMGA1UECgwMR29vZ2xlLCBJbmMuMRAwDgYDVQQLDAdBbmRyb2lkMTMwMQYD
-                VQQDDCpBbmRyb2lkIEtleXN0b3JlIFNvZnR3YXJlIEF0dGVzdGF0aW9uIFJvb3Qw
-                HhcNMTYwMTExMDA0MzUwWhcNMzYwMTA2MDA0MzUwWjCBmDELMAkGA1UEBhMCVVMx
-                EzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxFTAT
-                BgNVBAoMDEdvb2dsZSwgSW5jLjEQMA4GA1UECwwHQW5kcm9pZDEzMDEGA1UEAwwq
-                QW5kcm9pZCBLZXlzdG9yZSBTb2Z0d2FyZSBBdHRlc3RhdGlvbiBSb290MFkwEwYH
-                KoZIzj0CAQYIKoZIzj0DAQcDQgAE7l1ex+HA220Dpn7mthvsTWpdamguD/9/SQ59
-                dx9EIm29sa/6FsvHrcV30lacqrewLVQBXT5DKyqO107sSHVBpKNjMGEwHQYDVR0O
-                BBYEFMit6XdMRcOjzw0WEOR5QzohWjDPMB8GA1UdIwQYMBaAFMit6XdMRcOjzw0W
-                EOR5QzohWjDPMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgKEMAoGCCqG
-                SM49BAMCA0cAMEQCIDUho++LNEYenNVg8x1YiSBq3KNlQfYNns6KGYxmSGB7AiBN
-                C/NR2TB8fVvaNTQdqEcbY6WFZTytTySn502vQX3xvw==
-                -----END CERTIFICATE-----
-                """;
-    }
-
-    public static final class RSA {
-        public static final String PRIVATE_KEY = """
-                -----BEGIN RSA PRIVATE KEY-----
-                MIICXQIBAAKBgQDAgyPcVogbuDAgafWwhWHG7r5/BeL1qEIEir6LR752/q7yXPKb
-                KvoyABQWAUKZiaFfz8aBXrNjWDwv0vIL5Jgyg92BSxbX4YVBeuVKvClqOm21wAQI
-                O2jFVsHwIzmRZBmGTVC3TUCuykhMdzVsiVoMJ1q/rEmdXX0jYvKcXgLocQIDAQAB
-                AoGBAL6GCwuZqAKm+xpZQ4p7txUGWwmjbcbpysxr88AsNNfXnpTGYGQo2Ix7f2V3
-                wc3qZAdKvo5yht8fCBHclygmCGjeldMu/Ja20IT/JxpfYN78xwPno45uKbqaPF/C
-                woB2tqiWrx0014gozpvdsfNPnJQEQweBKY4gExZyW728mTpBAkEA4cbZJ2RsCRbs
-                NoJtWUmDdAwh8bB0xKGlmGfGaXlchdPcRkxbkp6Uv7NODcxQFLEPEzQat/3V9gQU
-                0qMmytQcxQJBANpIWZd4XNVjD7D9jFJU+Y5TjhiYOq6ea35qWntdNDdVuSGOvUAy
-                DSg4fXifdvohi8wti2il9kGPu+ylF5qzr70CQFD+/DJklVlhbtZTThVFCTKdk6PY
-                ENvlvbmCKSz3i9i624Agro1X9LcdBThv/p6dsnHKNHejSZnbdvjl7OnA1J0CQBW3
-                TPJ8zv+Ls2vwTZ2DRrCaL3DS9EObDyasfgP36dH3fUuRX9KbKCPwOstdUgDghX/y
-                qAPpPu6W1iNc6VRCvCECQQCQp0XaiXCyzWSWYDJCKMX4KFb/1mW6moXI1g8bi+5x
-                fs0scurgHa2GunZU1M9FrbXx8rMdn4Eiz6XxpVcPmy0l
-                -----END RSA PRIVATE KEY-----
-                """;
-        public static final String CERTIFICATE_1 = """
-                -----BEGIN CERTIFICATE-----
-                MIICtjCCAh+gAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwYzELMAkGA1UEBhMCVVMx
-                EzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxFTAT
-                BgNVBAoMDEdvb2dsZSwgSW5jLjEQMA4GA1UECwwHQW5kcm9pZDAeFw0xNjAxMDQx
-                MjQwNTNaFw0zNTEyMzAxMjQwNTNaMHYxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApD
-                YWxpZm9ybmlhMRUwEwYDVQQKDAxHb29nbGUsIEluYy4xEDAOBgNVBAsMB0FuZHJv
-                aWQxKTAnBgNVBAMMIEFuZHJvaWQgU29mdHdhcmUgQXR0ZXN0YXRpb24gS2V5MIGf
-                MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDAgyPcVogbuDAgafWwhWHG7r5/BeL1
-                qEIEir6LR752/q7yXPKbKvoyABQWAUKZiaFfz8aBXrNjWDwv0vIL5Jgyg92BSxbX
-                4YVBeuVKvClqOm21wAQIO2jFVsHwIzmRZBmGTVC3TUCuykhMdzVsiVoMJ1q/rEmd
-                XX0jYvKcXgLocQIDAQABo2YwZDAdBgNVHQ4EFgQU1AwQG/jNY7n3OVK1DhNcpteZ
-                k4YwHwYDVR0jBBgwFoAUKfrxrMxN0kyWQCd1trDpMuUH/i4wEgYDVR0TAQH/BAgw
-                BgEB/wIBADAOBgNVHQ8BAf8EBAMCAoQwDQYJKoZIhvcNAQELBQADgYEAni1IX4xn
-                M9waha2Z11Aj6hTsQ7DhnerCI0YecrUZ3GAi5KVoMWwLVcTmnKItnzpPk2sxixZ4
-                Fg2Iy9mLzICdhPDCJ+NrOPH90ecXcjFZNX2W88V/q52PlmEmT7K+gbsNSQQiis6f
-                9/VCLiVE+iEHElqDtVWtGIL4QBSbnCBjBH8=
-                -----END CERTIFICATE-----
-                """;
-        public static final String CERTIFICATE_2 = """
-                -----BEGIN CERTIFICATE-----
-                MIICpzCCAhCgAwIBAgIJAP+U2d2fB8gMMA0GCSqGSIb3DQEBCwUAMGMxCzAJBgNV
-                BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBW
-                aWV3MRUwEwYDVQQKDAxHb29nbGUsIEluYy4xEDAOBgNVBAsMB0FuZHJvaWQwHhcN
-                MTYwMTA0MTIzMTA4WhcNMzUxMjMwMTIzMTA4WjBjMQswCQYDVQQGEwJVUzETMBEG
-                A1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEVMBMGA1UE
-                CgwMR29vZ2xlLCBJbmMuMRAwDgYDVQQLDAdBbmRyb2lkMIGfMA0GCSqGSIb3DQEB
-                AQUAA4GNADCBiQKBgQCia63rbi5EYe/VDoLmt5TRdSMfd5tjkWP/96r/C3JHTsAs
-                Q+wzfNes7UA+jCigZtX3hwszl94OuE4TQKuvpSe/lWmgMdsGUmX4RFlXYfC78hdL
-                t0GAZMAoDo9Sd47b0ke2RekZyOmLw9vCkT/X11DEHTVm+Vfkl5YLCazOkjWFmwID
-                AQABo2MwYTAdBgNVHQ4EFgQUKfrxrMxN0kyWQCd1trDpMuUH/i4wHwYDVR0jBBgw
-                FoAUKfrxrMxN0kyWQCd1trDpMuUH/i4wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B
-                Af8EBAMCAoQwDQYJKoZIhvcNAQELBQADgYEAT3LzNlmNDsG5dFsxWfbwjSVJMJ6j
-                HBwp0kUtILlNX2S06IDHeHqcOd6os/W/L3BfRxBcxebrTQaZYdKumgf/93y4q+uc
-                DyQHXrF/unlx/U1bnt8Uqf7f7XzAiF343ZtkMlbVNZriE/mPzsF83O+kqrJVw4Op
-                Lvtc9mL1J1IXvmM=
-                -----END CERTIFICATE-----
-                """;
-    }
-}
diff --git a/app/src/main/java/es/chiteroman/playintegrityfix/Android.java b/app/src/main/java/es/chiteroman/playintegrityfix/KeyboxUtils.java
similarity index 58%
rename from app/src/main/java/es/chiteroman/playintegrityfix/Android.java
rename to app/src/main/java/es/chiteroman/playintegrityfix/KeyboxUtils.java
index 155ac6b..3c1c19d 100644
--- a/app/src/main/java/es/chiteroman/playintegrityfix/Android.java
+++ b/app/src/main/java/es/chiteroman/playintegrityfix/KeyboxUtils.java
@@ -1,6 +1,7 @@
 package es.chiteroman.playintegrityfix;
 
 import android.security.keystore.KeyProperties;
+import android.text.TextUtils;
 
 import org.spongycastle.asn1.ASN1Boolean;
 import org.spongycastle.asn1.ASN1Encodable;
@@ -23,39 +24,84 @@ import org.spongycastle.openssl.jcajce.JcaPEMKeyConverter;
 import org.spongycastle.operator.ContentSigner;
 import org.spongycastle.operator.jcajce.JcaContentSignerBuilder;
 import org.spongycastle.util.io.pem.PemReader;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
 
 import java.io.ByteArrayInputStream;
 import java.io.StringReader;
 import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
 import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
-import java.util.ArrayList;
 import java.util.LinkedList;
-import java.util.List;
 import java.util.concurrent.ThreadLocalRandom;
 
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
 
-public final class Android {
-    private static final PEMKeyPair EC, RSA;
+public final class KeyboxUtils {
     private static final ASN1ObjectIdentifier OID = new ASN1ObjectIdentifier("1.3.6.1.4.1.11129.2.1.17");
-    private static final List<Certificate> EC_CERTS = new ArrayList<>();
-    private static final List<Certificate> RSA_CERTS = new ArrayList<>();
+    private static final LinkedList<Certificate> EC_CERTS = new LinkedList<>();
+    private static final LinkedList<Certificate> RSA_CERTS = new LinkedList<>();
     private static final CertificateFactory certificateFactory;
+    private static PEMKeyPair EC, RSA;
 
     static {
         try {
             certificateFactory = CertificateFactory.getInstance("X.509");
+        } catch (CertificateException e) {
+            throw new RuntimeException(e);
+        }
+    }
 
-            EC = parseKeyPair(Keybox.EC.PRIVATE_KEY);
-            EC_CERTS.add(parseCert(Keybox.EC.CERTIFICATE_1));
-            EC_CERTS.add(parseCert(Keybox.EC.CERTIFICATE_2));
+    public static void parseXml(String kbox) throws Throwable {
+        if (TextUtils.isEmpty(kbox)) return;
 
-            RSA = parseKeyPair(Keybox.RSA.PRIVATE_KEY);
-            RSA_CERTS.add(parseCert(Keybox.RSA.CERTIFICATE_1));
-            RSA_CERTS.add(parseCert(Keybox.RSA.CERTIFICATE_2));
-        } catch (Throwable t) {
-            EntryPoint.LOG(t.toString());
-            throw new RuntimeException(t);
+        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+        DocumentBuilder builder = factory.newDocumentBuilder();
+        Document doc = builder.parse(new ByteArrayInputStream(kbox.getBytes()));
+
+        doc.getDocumentElement().normalize();
+
+        NodeList keyboxList = doc.getElementsByTagName("Keybox");
+        Node keyboxNode = keyboxList.item(0);
+        if (keyboxNode.getNodeType() == Node.ELEMENT_NODE) {
+            Element keyboxElement = (Element) keyboxNode;
+
+            NodeList keyList = keyboxElement.getElementsByTagName("Key");
+            for (int j = 0; j < keyList.getLength(); j++) {
+                Element keyElement = (Element) keyList.item(j);
+                String algorithm = keyElement.getAttribute("algorithm");
+
+                NodeList privateKeyList = keyElement.getElementsByTagName("PrivateKey");
+                if (privateKeyList.getLength() > 0) {
+                    Element privateKeyElement = (Element) privateKeyList.item(0);
+                    String privateKeyContent = privateKeyElement.getTextContent().trim();
+                    if ("ecdsa".equals(algorithm)) {
+                        EC = parseKeyPair(privateKeyContent);
+                    } else if ("rsa".equals(algorithm)) {
+                        RSA = parseKeyPair(privateKeyContent);
+                    }
+                }
+
+                NodeList certificateChainList = keyElement.getElementsByTagName("CertificateChain");
+                if (certificateChainList.getLength() > 0) {
+                    Element certificateChainElement = (Element) certificateChainList.item(0);
+
+                    NodeList certificateList = certificateChainElement.getElementsByTagName("Certificate");
+                    for (int k = 0; k < certificateList.getLength(); k++) {
+                        Element certificateElement = (Element) certificateList.item(k);
+                        String certificateContent = certificateElement.getTextContent().trim();
+                        if ("ecdsa".equals(algorithm)) {
+                            EC_CERTS.add(parseCert(certificateContent));
+                        } else if ("rsa".equals(algorithm)) {
+                            RSA_CERTS.add(parseCert(certificateContent));
+                        }
+                    }
+                }
+            }
         }
     }
 
@@ -72,7 +118,18 @@ public final class Android {
     }
 
     public static Certificate[] engineGetCertificateChain(Certificate[] caList) {
-        if (caList == null) throw new UnsupportedOperationException();
+        if (caList == null) {
+            EntryPoint.LOG("Certificate chain is null!");
+            throw new UnsupportedOperationException();
+        }
+        if (EC == null && RSA == null) {
+            EntryPoint.LOG("EC and RSA private keys are null!");
+            throw new UnsupportedOperationException();
+        }
+        if (EC_CERTS.isEmpty() && RSA_CERTS.isEmpty()) {
+            EntryPoint.LOG("EC and RSA certs are empty!");
+            throw new UnsupportedOperationException();
+        }
         try {
             X509Certificate leaf = (X509Certificate) certificateFactory.generateCertificate(new ByteArrayInputStream(caList[0].getEncoded()));
 
@@ -103,14 +160,17 @@ public final class Android {
             X509v3CertificateBuilder builder;
             ContentSigner signer;
 
-            if (KeyProperties.KEY_ALGORITHM_EC.equals(leaf.getPublicKey().getAlgorithm())) {
+            // Not all keyboxes have EC keys :)
+            if (EC != null && !EC_CERTS.isEmpty() && KeyProperties.KEY_ALGORITHM_EC.equals(leaf.getPublicKey().getAlgorithm())) {
+                EntryPoint.LOG("Using EC");
                 certificates = new LinkedList<>(EC_CERTS);
                 builder = new X509v3CertificateBuilder(new X509CertificateHolder(EC_CERTS.get(0).getEncoded()).getSubject(), holder.getSerialNumber(), holder.getNotBefore(), holder.getNotAfter(), holder.getSubject(), EC.getPublicKeyInfo());
                 signer = new JcaContentSignerBuilder(leaf.getSigAlgName()).build(new JcaPEMKeyConverter().getPrivateKey(EC.getPrivateKeyInfo()));
             } else {
+                EntryPoint.LOG("Using RSA");
                 certificates = new LinkedList<>(RSA_CERTS);
                 builder = new X509v3CertificateBuilder(new X509CertificateHolder(RSA_CERTS.get(0).getEncoded()).getSubject(), holder.getSerialNumber(), holder.getNotBefore(), holder.getNotAfter(), holder.getSubject(), RSA.getPublicKeyInfo());
-                signer = new JcaContentSignerBuilder(leaf.getSigAlgName()).build(new JcaPEMKeyConverter().getPrivateKey(RSA.getPrivateKeyInfo()));
+                signer = new JcaContentSignerBuilder("SHA256withRSA").build(new JcaPEMKeyConverter().getPrivateKey(RSA.getPrivateKeyInfo()));
             }
 
             byte[] verifiedBootKey = new byte[32];
@@ -151,6 +211,6 @@ public final class Android {
         } catch (Throwable t) {
             EntryPoint.LOG(t.toString());
         }
-        return caList;
+        throw new UnsupportedOperationException();
     }
 }
\ No newline at end of file
diff --git a/changelog.md b/changelog.md
index 051cef2..9b73903 100644
--- a/changelog.md
+++ b/changelog.md
@@ -7,6 +7,16 @@ If not, try removing /data/adb/pif.json file.
 Donations:
 https://www.paypal.com/paypalme/chiteroman
 
-# v16.0
+# v16.3
 
-- WORKING TEE = STRONG PASS
+Google fixed the bug, no more Strong pass with SW keybox 😢
+
+- Improve C++ and Java code
+- Downgrade first_api_level to 24, so all devices (should) be able to pass Device
+- Included keybox.xml parsing! You can create /data/adb/keybox.xml to define your own keybox (Strong passing with my private one :D)
+
+By default, inside module folder, it exits pif.json and keybox.xml, do NOT delete these files
+
+keybox.xml included in the module is SW one
+
+Keybox "hack" does NOT work on broken TEE devices, like OnePlus
diff --git a/module/keybox.xml b/module/keybox.xml
new file mode 100644
index 0000000..9c02996
--- /dev/null
+++ b/module/keybox.xml
@@ -0,0 +1,114 @@
+<?xml version="1.0"?>
+<AndroidAttestation>
+    <NumberOfKeyboxes>1</NumberOfKeyboxes>
+    <Keybox DeviceID="sw">
+        <Key algorithm="ecdsa">
+            <PrivateKey format="pem">
+                -----BEGIN EC PRIVATE KEY-----
+                MHcCAQEEICHghkMqFRmEWc82OlD8FMnarfk19SfC39ceTW28QuVEoAoGCCqGSM49
+                AwEHoUQDQgAE6555+EJjWazLKpFMiYbMcK2QZpOCqXMmE/6sy/ghJ0whdJdKKv6l
+                uU1/ZtTgZRBmNbxTt6CjpnFYPts+Ea4QFA==
+                -----END EC PRIVATE KEY-----
+            </PrivateKey>
+            <CertificateChain>
+                <NumberOfCertificates>2</NumberOfCertificates>
+                <Certificate format="pem">
+                    -----BEGIN CERTIFICATE-----
+                    MIICeDCCAh6gAwIBAgICEAEwCgYIKoZIzj0EAwIwgZgxCzAJBgNVBAYTAlVTMRMw
+                    EQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MRUwEwYD
+                    VQQKDAxHb29nbGUsIEluYy4xEDAOBgNVBAsMB0FuZHJvaWQxMzAxBgNVBAMMKkFu
+                    ZHJvaWQgS2V5c3RvcmUgU29mdHdhcmUgQXR0ZXN0YXRpb24gUm9vdDAeFw0xNjAx
+                    MTEwMDQ2MDlaFw0yNjAxMDgwMDQ2MDlaMIGIMQswCQYDVQQGEwJVUzETMBEGA1UE
+                    CAwKQ2FsaWZvcm5pYTEVMBMGA1UECgwMR29vZ2xlLCBJbmMuMRAwDgYDVQQLDAdB
+                    bmRyb2lkMTswOQYDVQQDDDJBbmRyb2lkIEtleXN0b3JlIFNvZnR3YXJlIEF0dGVz
+                    dGF0aW9uIEludGVybWVkaWF0ZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABOue
+                    efhCY1msyyqRTImGzHCtkGaTgqlzJhP+rMv4ISdMIXSXSir+pblNf2bU4GUQZjW8
+                    U7ego6ZxWD7bPhGuEBSjZjBkMB0GA1UdDgQWBBQ//KzWGrE6noEguNUlHMVlux6R
+                    qTAfBgNVHSMEGDAWgBTIrel3TEXDo88NFhDkeUM6IVowzzASBgNVHRMBAf8ECDAG
+                    AQH/AgEAMA4GA1UdDwEB/wQEAwIChDAKBggqhkjOPQQDAgNIADBFAiBLipt77oK8
+                    wDOHri/AiZi03cONqycqRZ9pDMfDktQPjgIhAO7aAV229DLp1IQ7YkyUBO86fMy9
+                    Xvsiu+f+uXc/WT/7
+                    -----END CERTIFICATE-----
+                </Certificate>
+                <Certificate format="pem">
+                    -----BEGIN CERTIFICATE-----
+                    MIICizCCAjKgAwIBAgIJAKIFntEOQ1tXMAoGCCqGSM49BAMCMIGYMQswCQYDVQQG
+                    EwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmll
+                    dzEVMBMGA1UECgwMR29vZ2xlLCBJbmMuMRAwDgYDVQQLDAdBbmRyb2lkMTMwMQYD
+                    VQQDDCpBbmRyb2lkIEtleXN0b3JlIFNvZnR3YXJlIEF0dGVzdGF0aW9uIFJvb3Qw
+                    HhcNMTYwMTExMDA0MzUwWhcNMzYwMTA2MDA0MzUwWjCBmDELMAkGA1UEBhMCVVMx
+                    EzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxFTAT
+                    BgNVBAoMDEdvb2dsZSwgSW5jLjEQMA4GA1UECwwHQW5kcm9pZDEzMDEGA1UEAwwq
+                    QW5kcm9pZCBLZXlzdG9yZSBTb2Z0d2FyZSBBdHRlc3RhdGlvbiBSb290MFkwEwYH
+                    KoZIzj0CAQYIKoZIzj0DAQcDQgAE7l1ex+HA220Dpn7mthvsTWpdamguD/9/SQ59
+                    dx9EIm29sa/6FsvHrcV30lacqrewLVQBXT5DKyqO107sSHVBpKNjMGEwHQYDVR0O
+                    BBYEFMit6XdMRcOjzw0WEOR5QzohWjDPMB8GA1UdIwQYMBaAFMit6XdMRcOjzw0W
+                    EOR5QzohWjDPMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgKEMAoGCCqG
+                    SM49BAMCA0cAMEQCIDUho++LNEYenNVg8x1YiSBq3KNlQfYNns6KGYxmSGB7AiBN
+                    C/NR2TB8fVvaNTQdqEcbY6WFZTytTySn502vQX3xvw==
+                    -----END CERTIFICATE-----
+                </Certificate>
+            </CertificateChain>
+        </Key>
+        <Key algorithm="rsa">
+            <PrivateKey format="pem">
+                -----BEGIN RSA PRIVATE KEY-----
+                MIICXQIBAAKBgQDAgyPcVogbuDAgafWwhWHG7r5/BeL1qEIEir6LR752/q7yXPKb
+                KvoyABQWAUKZiaFfz8aBXrNjWDwv0vIL5Jgyg92BSxbX4YVBeuVKvClqOm21wAQI
+                O2jFVsHwIzmRZBmGTVC3TUCuykhMdzVsiVoMJ1q/rEmdXX0jYvKcXgLocQIDAQAB
+                AoGBAL6GCwuZqAKm+xpZQ4p7txUGWwmjbcbpysxr88AsNNfXnpTGYGQo2Ix7f2V3
+                wc3qZAdKvo5yht8fCBHclygmCGjeldMu/Ja20IT/JxpfYN78xwPno45uKbqaPF/C
+                woB2tqiWrx0014gozpvdsfNPnJQEQweBKY4gExZyW728mTpBAkEA4cbZJ2RsCRbs
+                NoJtWUmDdAwh8bB0xKGlmGfGaXlchdPcRkxbkp6Uv7NODcxQFLEPEzQat/3V9gQU
+                0qMmytQcxQJBANpIWZd4XNVjD7D9jFJU+Y5TjhiYOq6ea35qWntdNDdVuSGOvUAy
+                DSg4fXifdvohi8wti2il9kGPu+ylF5qzr70CQFD+/DJklVlhbtZTThVFCTKdk6PY
+                ENvlvbmCKSz3i9i624Agro1X9LcdBThv/p6dsnHKNHejSZnbdvjl7OnA1J0CQBW3
+                TPJ8zv+Ls2vwTZ2DRrCaL3DS9EObDyasfgP36dH3fUuRX9KbKCPwOstdUgDghX/y
+                qAPpPu6W1iNc6VRCvCECQQCQp0XaiXCyzWSWYDJCKMX4KFb/1mW6moXI1g8bi+5x
+                fs0scurgHa2GunZU1M9FrbXx8rMdn4Eiz6XxpVcPmy0l
+                -----END RSA PRIVATE KEY-----
+            </PrivateKey>
+            <CertificateChain>
+                <NumberOfCertificates>2</NumberOfCertificates>
+                <Certificate format="pem">
+                    -----BEGIN CERTIFICATE-----
+                    MIICtjCCAh+gAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwYzELMAkGA1UEBhMCVVMx
+                    EzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxFTAT
+                    BgNVBAoMDEdvb2dsZSwgSW5jLjEQMA4GA1UECwwHQW5kcm9pZDAeFw0xNjAxMDQx
+                    MjQwNTNaFw0zNTEyMzAxMjQwNTNaMHYxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApD
+                    YWxpZm9ybmlhMRUwEwYDVQQKDAxHb29nbGUsIEluYy4xEDAOBgNVBAsMB0FuZHJv
+                    aWQxKTAnBgNVBAMMIEFuZHJvaWQgU29mdHdhcmUgQXR0ZXN0YXRpb24gS2V5MIGf
+                    MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDAgyPcVogbuDAgafWwhWHG7r5/BeL1
+                    qEIEir6LR752/q7yXPKbKvoyABQWAUKZiaFfz8aBXrNjWDwv0vIL5Jgyg92BSxbX
+                    4YVBeuVKvClqOm21wAQIO2jFVsHwIzmRZBmGTVC3TUCuykhMdzVsiVoMJ1q/rEmd
+                    XX0jYvKcXgLocQIDAQABo2YwZDAdBgNVHQ4EFgQU1AwQG/jNY7n3OVK1DhNcpteZ
+                    k4YwHwYDVR0jBBgwFoAUKfrxrMxN0kyWQCd1trDpMuUH/i4wEgYDVR0TAQH/BAgw
+                    BgEB/wIBADAOBgNVHQ8BAf8EBAMCAoQwDQYJKoZIhvcNAQELBQADgYEAni1IX4xn
+                    M9waha2Z11Aj6hTsQ7DhnerCI0YecrUZ3GAi5KVoMWwLVcTmnKItnzpPk2sxixZ4
+                    Fg2Iy9mLzICdhPDCJ+NrOPH90ecXcjFZNX2W88V/q52PlmEmT7K+gbsNSQQiis6f
+                    9/VCLiVE+iEHElqDtVWtGIL4QBSbnCBjBH8=
+                    -----END CERTIFICATE-----
+                </Certificate>
+                <Certificate format="pem">
+                    -----BEGIN CERTIFICATE-----
+                    MIICpzCCAhCgAwIBAgIJAP+U2d2fB8gMMA0GCSqGSIb3DQEBCwUAMGMxCzAJBgNV
+                    BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBW
+                    aWV3MRUwEwYDVQQKDAxHb29nbGUsIEluYy4xEDAOBgNVBAsMB0FuZHJvaWQwHhcN
+                    MTYwMTA0MTIzMTA4WhcNMzUxMjMwMTIzMTA4WjBjMQswCQYDVQQGEwJVUzETMBEG
+                    A1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEVMBMGA1UE
+                    CgwMR29vZ2xlLCBJbmMuMRAwDgYDVQQLDAdBbmRyb2lkMIGfMA0GCSqGSIb3DQEB
+                    AQUAA4GNADCBiQKBgQCia63rbi5EYe/VDoLmt5TRdSMfd5tjkWP/96r/C3JHTsAs
+                    Q+wzfNes7UA+jCigZtX3hwszl94OuE4TQKuvpSe/lWmgMdsGUmX4RFlXYfC78hdL
+                    t0GAZMAoDo9Sd47b0ke2RekZyOmLw9vCkT/X11DEHTVm+Vfkl5YLCazOkjWFmwID
+                    AQABo2MwYTAdBgNVHQ4EFgQUKfrxrMxN0kyWQCd1trDpMuUH/i4wHwYDVR0jBBgw
+                    FoAUKfrxrMxN0kyWQCd1trDpMuUH/i4wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B
+                    Af8EBAMCAoQwDQYJKoZIhvcNAQELBQADgYEAT3LzNlmNDsG5dFsxWfbwjSVJMJ6j
+                    HBwp0kUtILlNX2S06IDHeHqcOd6os/W/L3BfRxBcxebrTQaZYdKumgf/93y4q+uc
+                    DyQHXrF/unlx/U1bnt8Uqf7f7XzAiF343ZtkMlbVNZriE/mPzsF83O+kqrJVw4Op
+                    Lvtc9mL1J1IXvmM=
+                    -----END CERTIFICATE-----
+                </Certificate>
+            </CertificateChain>
+        </Key>
+    </Keybox>
+</AndroidAttestation>
diff --git a/module/module.prop b/module/module.prop
index 6f03f42..a37022c 100644
--- a/module/module.prop
+++ b/module/module.prop
@@ -1,7 +1,7 @@
 id=playintegrityfix
-name=Play Integrity Fix (STRONG)
-version=v16.0
-versionCode=16000
+name=Play Integrity Fix
+version=v16.3
+versionCode=16300
 author=chiteroman
-description=WORKING TEE = STRONG PASS | THANKS GOOGLE
+description=Universal modular fix for Play Integrity (and SafetyNet) on devices running Android 8-15
 updateJson=https://raw.githubusercontent.com/chiteroman/PlayIntegrityFix/main/update.json
diff --git a/module/pif.json b/module/pif.json
index 564df3f..bb0780c 100644
--- a/module/pif.json
+++ b/module/pif.json
@@ -11,5 +11,5 @@
     "TYPE": "user",
     "TAGS": "release-keys",
     "SECURITY_PATCH": "2017-12-05",
-    "DEVICE_INITIAL_SDK_INT": "25"
-}
\ No newline at end of file
+    "DEVICE_INITIAL_SDK_INT": "24"
+}
diff --git a/update.json b/update.json
index 6ae5102..305fff3 100644
--- a/update.json
+++ b/update.json
@@ -1,6 +1,6 @@
 {
-  "version": "v16.0",
-  "versionCode": 16000,
-  "zipUrl": "https://github.com/chiteroman/PlayIntegrityFix/releases/download/v16.0/PlayIntegrityFix_v16.0.zip",
+  "version": "v16.3",
+  "versionCode": 16300,
+  "zipUrl": "https://github.com/chiteroman/PlayIntegrityFix/releases/download/v16.3/PlayIntegrityFix_v16.3.zip",
   "changelog": "https://raw.githubusercontent.com/chiteroman/PlayIntegrityFix/main/changelog.md"
 }