From acca37b3becccb7a4d5f08af6859623e23d1d831 Mon Sep 17 00:00:00 2001 From: chiteroman Date: Mon, 19 Aug 2024 13:13:48 +0200 Subject: [PATCH] Bring back spoofing fields in Java + code refine --- app/src/main/cpp/main.cpp | 66 +++++++++---------- .../playintegrityfix/CustomProvider.java | 6 ++ .../playintegrityfix/EntryPoint.java | 62 ++++++++++++++++- module/pif.json | 2 + 4 files changed, 102 insertions(+), 34 deletions(-) diff --git a/app/src/main/cpp/main.cpp b/app/src/main/cpp/main.cpp index c0a58e1..feaaf87 100644 --- a/app/src/main/cpp/main.cpp +++ b/app/src/main/cpp/main.cpp @@ -184,7 +184,8 @@ public: parseJSON(); if (trickyStore) { - LOGD("TrickyStore module installed and enabled, disabling spoofProps and spoofProvider"); + LOGD("TrickyStore module installed and enabled, disabling spoofBuild (Java), spoofProps and spoofProvider"); + spoofBuild = false; spoofProps = false; spoofProvider = false; } @@ -193,16 +194,18 @@ public: void postAppSpecialize(const zygisk::AppSpecializeArgs *args) override { if (dexVector.empty()) return; - UpdateBuildFields(); - - cJSON_Delete(json); + if (spoofBuildZygisk) UpdateBuildFields(); if (spoofProps) doHook(); else api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY); - if (spoofProvider || spoofSignature) injectDex(); + if (spoofBuild || spoofProvider || spoofSignature) injectDex(); else - LOGD("Don't inject dex, spoofProvider and spoofSignature are false"); + LOGD("Don't inject dex: spoofBuild (Java), spoofProvider and spoofSignature are false"); + + cJSON_Delete(json); + dexVector.clear(); + dexVector.shrink_to_fit(); } void preServerSpecialize(zygisk::ServerSpecializeArgs *args) override { @@ -214,6 +217,8 @@ private: JNIEnv *env = nullptr; std::vector dexVector; cJSON *json = nullptr; + bool spoofBuild = true; + bool spoofBuildZygisk = true; bool spoofProps = true; bool spoofProvider = true; bool spoofSignature = false; @@ -225,6 +230,9 @@ private: const cJSON *security_patch = cJSON_GetObjectItemCaseSensitive(json, "SECURITY_PATCH"); const cJSON *build_id = cJSON_GetObjectItemCaseSensitive(json, "ID"); const cJSON *isDebug = cJSON_GetObjectItemCaseSensitive(json, "DEBUG"); + const cJSON *spoof_build = cJSON_GetObjectItemCaseSensitive(json, "spoofBuild"); + const cJSON *spoof_build_zygisk = cJSON_GetObjectItemCaseSensitive(json, + "spoofBuildZygisk"); const cJSON *spoof_props = cJSON_GetObjectItemCaseSensitive(json, "spoofProps"); const cJSON *spoof_provider = cJSON_GetObjectItemCaseSensitive(json, "spoofProvider"); const cJSON *spoof_signature = cJSON_GetObjectItemCaseSensitive(json, "spoofSignature"); @@ -251,6 +259,16 @@ private: cJSON_DeleteItemFromObjectCaseSensitive(json, "DEBUG"); } + if (spoof_build && cJSON_IsBool(spoof_build)) { + spoofBuild = cJSON_IsTrue(spoof_build); + cJSON_DeleteItemFromObjectCaseSensitive(json, "spoofBuild"); + } + + if (spoof_build_zygisk && cJSON_IsBool(spoof_build_zygisk)) { + spoofBuildZygisk = cJSON_IsTrue(spoof_build_zygisk); + cJSON_DeleteItemFromObjectCaseSensitive(json, "spoofBuildZygisk"); + } + if (spoof_props && cJSON_IsBool(spoof_props)) { spoofProps = cJSON_IsTrue(spoof_props); cJSON_DeleteItemFromObjectCaseSensitive(json, "spoofProps"); @@ -291,8 +309,15 @@ private: auto entryPointClass = (jclass) entryClassObj; LOGD("call init"); - auto entryInit = env->GetStaticMethodID(entryPointClass, "init", "(ZZ)V"); - env->CallStaticVoidMethod(entryPointClass, entryInit, spoofProvider, spoofSignature); + auto entryInit = env->GetStaticMethodID(entryPointClass, "init", "(Ljava/lang/String;ZZ)V"); + jstring jsonStr; + if (spoofBuild) { + jsonStr = env->NewStringUTF(cJSON_Print(json)); + } else { + jsonStr = env->NewStringUTF(""); + } + env->CallStaticVoidMethod(entryPointClass, entryInit, jsonStr, spoofProvider, + spoofSignature); } void UpdateBuildFields() { @@ -329,31 +354,6 @@ private: LOGD("Set '%s' to '%s'", key, value); } - } else if (cJSON_IsNumber(currentElement)) { - int value = currentElement->valueint; - jfieldID fieldID = env->GetStaticFieldID(buildClass, key, "I"); - - if (env->ExceptionCheck()) { - env->ExceptionClear(); - - fieldID = env->GetStaticFieldID(versionClass, key, "I"); - - if (env->ExceptionCheck()) { - env->ExceptionClear(); - continue; - } - } - - if (fieldID != nullptr) { - env->SetStaticIntField(buildClass, fieldID, value); - - if (env->ExceptionCheck()) { - env->ExceptionClear(); - continue; - } - - LOGD("Set '%s' to '%d'", key, value); - } } } } diff --git a/app/src/main/java/es/chiteroman/playintegrityfix/CustomProvider.java b/app/src/main/java/es/chiteroman/playintegrityfix/CustomProvider.java index c288b74..b45420a 100644 --- a/app/src/main/java/es/chiteroman/playintegrityfix/CustomProvider.java +++ b/app/src/main/java/es/chiteroman/playintegrityfix/CustomProvider.java @@ -9,4 +9,10 @@ public final class CustomProvider extends Provider { putAll(provider); put("KeyStore.AndroidKeyStore", CustomKeyStoreSpi.class.getName()); } + + @Override + public synchronized Service getService(String type, String algorithm) { + EntryPoint.spoofFields(); + return super.getService(type, algorithm); + } } diff --git a/app/src/main/java/es/chiteroman/playintegrityfix/EntryPoint.java b/app/src/main/java/es/chiteroman/playintegrityfix/EntryPoint.java index 59edec0..47e4103 100644 --- a/app/src/main/java/es/chiteroman/playintegrityfix/EntryPoint.java +++ b/app/src/main/java/es/chiteroman/playintegrityfix/EntryPoint.java @@ -6,9 +6,11 @@ import android.content.pm.Signature; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; +import android.text.TextUtils; import android.util.Base64; import android.util.Log; +import org.json.JSONObject; import org.lsposed.hiddenapibypass.HiddenApiBypass; import java.lang.reflect.Field; @@ -134,7 +136,21 @@ public final class EntryPoint { throw new NoSuchFieldException("Field '" + fieldName + "' not found in class hierarchy of " + Objects.requireNonNull(currentClass).getName()); } - public static void init(boolean spoofProvider, boolean spoofSignature) { + private static Field getBuildField(String name) { + Field field; + try { + field = Build.class.getField(name); + } catch (NoSuchFieldException e) { + try { + field = Build.VERSION.class.getField(name); + } catch (NoSuchFieldException ex) { + return null; + } + } + return field; + } + + public static void init(String json, boolean spoofProvider, boolean spoofSignature) { if (spoofProvider) { spoofProvider(); } else { @@ -146,5 +162,49 @@ public final class EntryPoint { } else { Log.i(TAG, "Don't spoof signature"); } + + if (TextUtils.isEmpty(json)) { + Log.e(TAG, "Json is empty!"); + return; + } + + JSONObject jsonObject; + try { + jsonObject = new JSONObject(json); + } catch (Throwable t) { + Log.e(TAG, "init", t); + return; + } + + jsonObject.keys().forEachRemaining(key -> { + Field field = getBuildField(key); + if (field == null) return; + field.setAccessible(true); + String value; + try { + value = jsonObject.getString(key); + } catch (Throwable t) { + Log.e(TAG, "init", t); + return; + } + map.putIfAbsent(field, value); + }); + + Log.i(TAG, "Parsed " + map.size() + " fields from JSON"); + + spoofFields(); + } + + public static void spoofFields() { + map.forEach((field, value) -> { + try { + String oldValue = (String) field.get(null); + if (value.equals(oldValue)) return; + field.set(null, value); + Log.i(TAG, "Set '" + field.getName() + "' to '" + value + "'"); + } catch (Throwable t) { + Log.e(TAG, "spoofFields", t); + } + }); } } diff --git a/module/pif.json b/module/pif.json index efb0ca9..bad20ba 100644 --- a/module/pif.json +++ b/module/pif.json @@ -8,6 +8,8 @@ "PRODUCT": "akita_beta", "SECURITY_PATCH": "2024-08-05", "DEVICE_INITIAL_SDK_INT": 21, + "spoofBuild": true, + "spoofBuildZygisk": true, "spoofProps": true, "spoofProvider": true, "spoofSignature": false