From c31569f24929bb297dcb15b836ceffcfbef3d0ad Mon Sep 17 00:00:00 2001 From: chiteroman <98092901+chiteroman@users.noreply.github.com> Date: Thu, 23 Nov 2023 00:07:43 +0100 Subject: [PATCH] Release v13.4 --- app/proguard-rules.pro | 2 +- app/src/main/cpp/main.cpp | 210 ++++++++++-------- .../playintegrityfix/EntryPoint.java | 39 ++-- changelog.md | 9 +- update.json | 6 +- 5 files changed, 141 insertions(+), 125 deletions(-) diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index c9e4d6a..2f11af0 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -1,3 +1,3 @@ --keep class es.chiteroman.playintegrityfix.EntryPoint {init();} +-keep class es.chiteroman.playintegrityfix.EntryPoint {public ;} -keep class es.chiteroman.playintegrityfix.CustomProvider -keep class es.chiteroman.playintegrityfix.CustomKeyStoreSpi \ No newline at end of file diff --git a/app/src/main/cpp/main.cpp b/app/src/main/cpp/main.cpp index 419fb16..c987095 100644 --- a/app/src/main/cpp/main.cpp +++ b/app/src/main/cpp/main.cpp @@ -4,16 +4,13 @@ #include #include #include -#include #include "zygisk.hpp" #include "dobby.h" #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, "PIF/Native", __VA_ARGS__) -static std::string API_LEVEL; - -static std::string SECURITY_PATCH; +static std::string SECURITY_PATCH, FIRST_API_LEVEL; #define DEX_FILE_PATH "/data/adb/modules/playintegrityfix/classes.dex" @@ -32,10 +29,10 @@ static void modify_callback(void *cookie, const char *name, const char *value, u std::string_view prop(name); if (prop.ends_with("api_level")) { - if (API_LEVEL.empty()) { + if (FIRST_API_LEVEL.empty()) { value = nullptr; } else { - value = API_LEVEL.c_str(); + value = FIRST_API_LEVEL.c_str(); } } else if (prop.ends_with("security_patch")) { if (SECURITY_PATCH.empty()) { @@ -62,49 +59,15 @@ my_system_property_read_callback(const prop_info *pi, T_Callback callback, void return o_system_property_read_callback(pi, modify_callback, cookie); } -static void parsePropsFile(const char *filename) { - LOGD("Proceed to parse '%s' file", filename); - - FILE *file = fopen(filename, "r"); - - char line[256]; - - while (fgets(line, sizeof(line), file)) { - - std::string key, value; - - char *data = strtok(line, "="); - - while (data) { - if (key.empty()) { - key = data; - } else { - value = data; - } - data = strtok(nullptr, "="); - } - - key.erase(std::remove_if(key.begin(), key.end(), - [](unsigned char x) { return std::isspace(x); }), key.end()); - value.erase(std::remove_if(value.begin(), value.end(), - [](unsigned char x) { return std::isspace(x); }), value.end()); - - if (key == "SECURITY_PATCH") { - SECURITY_PATCH = value; - LOGD("Set SECURITY_PATCH to '%s'", value.c_str()); - } else if (key == "FIRST_API_LEVEL") { - API_LEVEL = value; - LOGD("Set API_LEVEL to '%s'", value.c_str()); - } - - key.clear(); - key.shrink_to_fit(); - - value.clear(); - value.shrink_to_fit(); +static void doHook() { + void *handle = DobbySymbolResolver("libc.so", "__system_property_read_callback"); + if (handle == nullptr) { + LOGD("Couldn't find '__system_property_read_callback' handle. Report to @chiteroman"); + return; } - - fclose(file); + LOGD("Found '__system_property_read_callback' handle at %p", handle); + DobbyHook(handle, (void *) my_system_property_read_callback, + (void **) &o_system_property_read_callback); } class PlayIntegrityFix : public zygisk::ModuleBase { @@ -131,26 +94,26 @@ public: return; } - callbacks.clear(); - - API_LEVEL.clear(); - API_LEVEL.shrink_to_fit(); - - SECURITY_PATCH.clear(); - SECURITY_PATCH.shrink_to_fit(); - int fd = api->connectCompanion(); - auto rawDir = env->GetStringUTFChars(args->app_data_dir, nullptr); - propsFile = rawDir; - env->ReleaseStringUTFChars(args->app_data_dir, rawDir); + int mapSize; + read(fd, &mapSize, sizeof(mapSize)); - propsFile = propsFile + "/cache/pif.prop"; + for (int i = 0; i < mapSize; ++i) { + int keyLenght, valueLenght; + std::string key, value; - int strSize = static_cast(propsFile.size()); + read(fd, &keyLenght, sizeof(keyLenght)); + read(fd, &valueLenght, sizeof(valueLenght)); - write(fd, &strSize, sizeof(strSize)); - write(fd, propsFile.data(), strSize); + key.resize(keyLenght); + value.resize(valueLenght); + + read(fd, key.data(), keyLenght); + read(fd, value.data(), valueLenght); + + props.insert({key, value}); + } long size; read(fd, &size, sizeof(size)); @@ -161,6 +124,16 @@ public: close(fd); moduleDex.insert(moduleDex.end(), buffer, buffer + size); + + LOGD("Received from socket %d props!", static_cast(props.size())); + + for (const auto &item: props) { + if (item.first == "SECURITY_PATCH") { + SECURITY_PATCH = item.second; + } else if (item.first == "FIRST_API_LEVEL") { + FIRST_API_LEVEL = item.second; + } + } } void postAppSpecialize(const zygisk::AppSpecializeArgs *args) override { @@ -168,13 +141,12 @@ public: doHook(); - injectDex(); + inject(); LOGD("clean"); - propsFile.clear(); - propsFile.shrink_to_fit(); moduleDex.clear(); moduleDex.shrink_to_fit(); + props.clear(); } void preServerSpecialize(zygisk::ServerSpecializeArgs *args) override { @@ -185,28 +157,20 @@ private: zygisk::Api *api = nullptr; JNIEnv *env = nullptr; bool isGmsUnstable = false; - std::string propsFile; + std::map props; std::vector moduleDex; - void doHook() { - if (!propsFile.empty()) parsePropsFile(propsFile.c_str()); - - void *handle = DobbySymbolResolver("libc.so", "__system_property_read_callback"); - if (handle == nullptr) { - LOGD("Couldn't find '__system_property_read_callback' handle. Report to @chiteroman"); - return; - } - LOGD("Found '__system_property_read_callback' handle at %p", handle); - DobbyHook(handle, (void *) my_system_property_read_callback, - (void **) &o_system_property_read_callback); - } - - void injectDex() { + void inject() { if (moduleDex.empty()) { LOGD("Dex not loaded in memory"); return; } + if (props.empty()) { + LOGD("No props loaded in memory"); + return; + } + LOGD("Preparing to inject %d bytes to the process", static_cast(moduleDex.size())); LOGD("get system classloader"); @@ -229,28 +193,82 @@ private: auto entryClassName = env->NewStringUTF("es.chiteroman.playintegrityfix.EntryPoint"); auto entryClassObj = env->CallObjectMethod(dexCl, loadClass, entryClassName); - LOGD("call init"); auto entryClass = (jclass) entryClassObj; + + LOGD("call add prop"); + auto addProp = env->GetStaticMethodID(entryClass, "addProp", + "(Ljava/lang/String;Ljava/lang/String;)V"); + for (const auto &item: props) { + auto key = env->NewStringUTF(item.first.c_str()); + auto value = env->NewStringUTF(item.second.c_str()); + env->CallStaticVoidMethod(entryClass, addProp, key, value); + } + + LOGD("call init"); auto entryInit = env->GetStaticMethodID(entryClass, "init", "()V"); env->CallStaticVoidMethod(entryClass, entryInit); } }; +static void parsePropsFile(int fd) { + LOGD("Proceed to parse '%s' file", PROP_FILE_PATH); + + std::map props; + + FILE *file = fopen(PROP_FILE_PATH, "r"); + + char line[256]; + + while (fgets(line, sizeof(line), file)) { + + std::string key, value; + + char *data = strtok(line, "="); + + while (data) { + if (key.empty()) { + key = data; + } else { + value = data; + } + data = strtok(nullptr, "="); + } + + key.erase(std::remove_if(key.begin(), key.end(), + [](unsigned char x) { return std::isspace(x); }), key.end()); + value.erase(std::remove(value.begin(), value.end(), '\n'), value.cend()); + + props.insert({key, value}); + + key.clear(); + key.shrink_to_fit(); + + value.clear(); + value.shrink_to_fit(); + } + + fclose(file); + + int mapSize = static_cast(props.size()); + + write(fd, &mapSize, sizeof(mapSize)); + + for (const auto &item: props) { + int keyLenght = static_cast(item.first.size()); + int valueLenght = static_cast(item.second.size()); + + write(fd, &keyLenght, sizeof(keyLenght)); + write(fd, &valueLenght, sizeof(valueLenght)); + + write(fd, item.first.data(), keyLenght); + write(fd, item.second.data(), valueLenght); + } + + props.clear(); +} + static void companion(int fd) { - int strSize; - read(fd, &strSize, sizeof(strSize)); - - std::string propsFile; - - propsFile.resize(strSize); - read(fd, propsFile.data(), strSize); - - std::filesystem::copy_file(PROP_FILE_PATH, propsFile, - std::filesystem::copy_options::overwrite_existing); - std::filesystem::permissions(propsFile, std::filesystem::perms::all); - - propsFile.clear(); - propsFile.shrink_to_fit(); + parsePropsFile(fd); FILE *dex = fopen(DEX_FILE_PATH, "rb"); diff --git a/app/src/main/java/es/chiteroman/playintegrityfix/EntryPoint.java b/app/src/main/java/es/chiteroman/playintegrityfix/EntryPoint.java index 4365864..1c38763 100644 --- a/app/src/main/java/es/chiteroman/playintegrityfix/EntryPoint.java +++ b/app/src/main/java/es/chiteroman/playintegrityfix/EntryPoint.java @@ -3,33 +3,26 @@ package es.chiteroman.playintegrityfix; import android.os.Build; import android.util.Log; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; -import java.io.Reader; import java.lang.reflect.Field; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.KeyStoreSpi; import java.security.Provider; import java.security.Security; -import java.util.Properties; +import java.util.HashMap; +import java.util.Map; public final class EntryPoint { - private static final Properties props = new Properties(); - private static final File file = new File("/data/data/com.google.android.gms/cache/pif.prop"); + private static final Map map = new HashMap<>(); public static void init() { - - try (Reader reader = new FileReader(file)) { - props.load(reader); - LOG("Loaded " + props.size() + " fields!"); - } catch (IOException e) { - LOG("Couldn't load pif.prop file: " + e); - } - - spoofDevice(); spoofProvider(); + spoofDevice(); + } + + public static void addProp(String key, String value) { + map.put(key, value); + LOG(String.format("Received from Zygisk lib: [%s] -> '%s'", key, value)); } private static void spoofProvider() { @@ -60,13 +53,13 @@ public final class EntryPoint { } public static void spoofDevice() { - setProp("PRODUCT", props.getProperty("PRODUCT", "bullhead")); - setProp("DEVICE", props.getProperty("DEVICE", "bullhead")); - setProp("MANUFACTURER", props.getProperty("MANUFACTURER", "LGE")); - setProp("BRAND", props.getProperty("BRAND", "google")); - setProp("MODEL", props.getProperty("MODEL", "Nexus 5X")); - setProp("FINGERPRINT", props.getProperty("FINGERPRINT", "google/bullhead/bullhead:8.0.0/OPR6.170623.013/4283548:user/release-keys")); - setVersionProp("SECURITY_PATCH", props.getProperty("SECURITY_PATCH", "2017-08-05")); + setProp("PRODUCT", map.get("PRODUCT")); + setProp("DEVICE", map.get("DEVICE")); + setProp("MANUFACTURER", map.get("MANUFACTURER")); + setProp("BRAND", map.get("BRAND")); + setProp("MODEL", map.get("MODEL")); + setProp("FINGERPRINT", map.get("FINGERPRINT")); + setVersionProp("SECURITY_PATCH", map.get("SECURITY_PATCH")); } private static void setProp(String name, String value) { diff --git a/changelog.md b/changelog.md index 7c5d2bf..b34b438 100644 --- a/changelog.md +++ b/changelog.md @@ -4,6 +4,11 @@ https://t.me/playintegrityfix Also, if Google blacklist the fingerprint (again), you can post your custom pif.prop and I will update the module. -# v13.3 +# v13.4 -- Spoof security patch and api level to DroidGuard. \ No newline at end of file +- Custom resetprop utility! Thanks to @HuskyDG. +- Don't write in GMS folder, everything stored in memory. (Issue from @osm0sis :D) +- Downgrade to Zygisk API 2. +- Should fix crashes. + +This build includes 'pif.prop', you can modify it and use your custom props to pass Device verdict. \ No newline at end of file diff --git a/update.json b/update.json index 5b4cc61..d5cd072 100644 --- a/update.json +++ b/update.json @@ -1,6 +1,6 @@ { - "version": "v13.3", - "versionCode": 133, - "zipUrl": "https://github.com/chiteroman/PlayIntegrityFix/releases/download/v13.3/PlayIntegrityFix_v13.3.zip", + "version": "v13.4", + "versionCode": 134, + "zipUrl": "https://github.com/chiteroman/PlayIntegrityFix/releases/download/v13.4/PlayIntegrityFix_v13.4.zip", "changelog": "https://raw.githubusercontent.com/chiteroman/PlayIntegrityFix/main/changelog.md" } \ No newline at end of file