From 78dde206eed54e81733ccc438e18852d6926ffe5 Mon Sep 17 00:00:00 2001 From: chiteroman <98092901+chiteroman@users.noreply.github.com> Date: Wed, 22 Nov 2023 18:08:47 +0100 Subject: [PATCH] Improve code --- app/build.gradle.kts | 3 +- app/src/main/cpp/main.cpp | 129 ++++++++++-------- app/src/main/cpp/zygisk.hpp | 35 ++--- .../playintegrityfix/EntryPoint.java | 22 ++- 4 files changed, 97 insertions(+), 92 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 2e88dab..4bdc43e 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -28,8 +28,7 @@ android { externalNativeBuild { cmake { arguments += setOf("-DANDROID_STL=none", "-DCMAKE_BUILD_TYPE=MinSizeRel") - cFlags += setOf("-flto=full", "-fvisibility=hidden", "-fvisibility-inlines-hidden", "-ffunction-sections", "-fdata-sections") - cppFlags += setOf("-std=c++20", "-fno-exceptions", "-fno-rtti", "-flto=full", "-fvisibility=hidden", "-fvisibility-inlines-hidden", "-ffunction-sections", "-fdata-sections") + cppFlags += setOf("-std=c++20", "-fno-exceptions", "-fno-rtti", "-fvisibility=hidden", "-fvisibility-inlines-hidden") } } } diff --git a/app/src/main/cpp/main.cpp b/app/src/main/cpp/main.cpp index 304990a..419fb16 100644 --- a/app/src/main/cpp/main.cpp +++ b/app/src/main/cpp/main.cpp @@ -19,8 +19,6 @@ static std::string SECURITY_PATCH; #define PROP_FILE_PATH "/data/adb/modules/playintegrityfix/pif.prop" -#define MAX_LINE_LENGTH 256 - typedef void (*T_Callback)(void *, const char *, const char *, uint32_t); static std::map callbacks; @@ -33,8 +31,19 @@ static void modify_callback(void *cookie, const char *name, const char *value, u std::string_view prop(name); - if (prop.ends_with("api_level")) value = API_LEVEL.c_str(); - else if (prop.ends_with("security_patch")) value = SECURITY_PATCH.c_str(); + if (prop.ends_with("api_level")) { + if (API_LEVEL.empty()) { + value = nullptr; + } else { + value = API_LEVEL.c_str(); + } + } else if (prop.ends_with("security_patch")) { + if (SECURITY_PATCH.empty()) { + value = nullptr; + } else { + value = SECURITY_PATCH.c_str(); + } + } if (!prop.starts_with("cache") && !prop.starts_with("debug")) LOGD("[%s] -> %s", name, value); @@ -58,9 +67,9 @@ static void parsePropsFile(const char *filename) { FILE *file = fopen(filename, "r"); - char line[MAX_LINE_LENGTH]; + char line[256]; - while (fgets(line, sizeof(line), file) != nullptr) { + while (fgets(line, sizeof(line), file)) { std::string key, value; @@ -83,33 +92,21 @@ static void parsePropsFile(const char *filename) { if (key == "SECURITY_PATCH") { SECURITY_PATCH = value; LOGD("Set SECURITY_PATCH to '%s'", value.c_str()); - } else if (key == "API_LEVEL") { + } 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(); - key.shrink_to_fit(); - key.shrink_to_fit(); + value.shrink_to_fit(); } fclose(file); } -static void doHook(const std::string &str) { - parsePropsFile(str.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); -} - class PlayIntegrityFix : public zygisk::ModuleBase { public: void onLoad(zygisk::Api *api, JNIEnv *env) override { @@ -129,49 +126,49 @@ public: if (isGms) api->setOption(zygisk::FORCE_DENYLIST_UNMOUNT); - if (isGmsUnstable) { - - callbacks.clear(); - API_LEVEL.clear(); - SECURITY_PATCH.clear(); - API_LEVEL.shrink_to_fit(); - 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); - - propsFile = propsFile + "/pif.prop"; - - int strSize = static_cast(propsFile.size()); - - write(fd, &strSize, sizeof(strSize)); - write(fd, propsFile.data(), strSize); - - long size; - read(fd, &size, sizeof(size)); - - char buffer[size]; - read(fd, buffer, size); - - close(fd); - - moduleDex.insert(moduleDex.end(), buffer, buffer + size); - + if (!isGmsUnstable) { + api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY); return; } - api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY); + 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); + + propsFile = propsFile + "/cache/pif.prop"; + + int strSize = static_cast(propsFile.size()); + + write(fd, &strSize, sizeof(strSize)); + write(fd, propsFile.data(), strSize); + + long size; + read(fd, &size, sizeof(size)); + + char buffer[size]; + read(fd, buffer, size); + + close(fd); + + moduleDex.insert(moduleDex.end(), buffer, buffer + size); } void postAppSpecialize(const zygisk::AppSpecializeArgs *args) override { if (!isGmsUnstable) return; - doHook(propsFile); + doHook(); - if (!moduleDex.empty()) injectDex(); + injectDex(); LOGD("clean"); propsFile.clear(); @@ -191,7 +188,25 @@ private: std::string propsFile; 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() { + if (moduleDex.empty()) { + LOGD("Dex not loaded in memory"); + return; + } + LOGD("Preparing to inject %d bytes to the process", static_cast(moduleDex.size())); LOGD("get system classloader"); @@ -232,7 +247,7 @@ static void companion(int fd) { std::filesystem::copy_file(PROP_FILE_PATH, propsFile, std::filesystem::copy_options::overwrite_existing); - std::filesystem::permissions(propsFile, std::filesystem::perms::others_all); + std::filesystem::permissions(propsFile, std::filesystem::perms::all); propsFile.clear(); propsFile.shrink_to_fit(); diff --git a/app/src/main/cpp/zygisk.hpp b/app/src/main/cpp/zygisk.hpp index 7c861ad..7272633 100644 --- a/app/src/main/cpp/zygisk.hpp +++ b/app/src/main/cpp/zygisk.hpp @@ -19,7 +19,7 @@ #include -#define ZYGISK_API_VERSION 4 +#define ZYGISK_API_VERSION 2 /* @@ -142,7 +142,6 @@ struct AppSpecializeArgs { jint &gid; jintArray &gids; jint &runtime_flags; - jobjectArray &rlimits; jint &mount_external; jstring &se_info; jstring &nice_name; @@ -150,7 +149,6 @@ struct AppSpecializeArgs { jstring &app_data_dir; // Optional arguments. Please check whether the pointer is null before de-referencing - jintArray *const fds_to_ignore; jboolean *const is_child_zygote; jboolean *const is_top_app; jobjectArray *const pkg_data_info_list; @@ -243,14 +241,6 @@ struct Api { // Returns bitwise-or'd zygisk::StateFlag values. uint32_t getFlags(); - // Exempt the provided file descriptor from being automatically closed. - // - // This API only make sense in preAppSpecialize; calling this method in any other situation - // is either a no-op (returns true) or an error (returns false). - // - // When false is returned, the provided file descriptor will eventually be closed by zygote. - bool exemptFd(int fd); - // Hook JNI native methods for a class // // Lookup all registered JNI native methods and replace it with your own methods. @@ -267,10 +257,13 @@ struct Api { // 56b4346000-56b4347000 r-xp 00002000 fe:00 235 /system/bin/app_process64 // (More details: https://man7.org/linux/man-pages/man5/proc.5.html) // - // The `dev` and `inode` pair uniquely identifies a file being mapped into memory. - // For matching ELFs loaded in memory, replace function `symbol` with `newFunc`. + // For ELFs loaded in memory with pathname matching `regex`, replace function `symbol` with `newFunc`. // If `oldFunc` is not nullptr, the original function pointer will be saved to `oldFunc`. - void pltHookRegister(dev_t dev, ino_t inode, const char *symbol, void *newFunc, void **oldFunc); + void pltHookRegister(const char *regex, const char *symbol, void *newFunc, void **oldFunc); + + // For ELFs loaded in memory with pathname matching `regex`, exclude hooks registered for `symbol`. + // If `symbol` is nullptr, then all symbols will be excluded. + void pltHookExclude(const char *regex, const char *symbol); // Commit all the hooks that was previously registered. // Returns false if an error occurred. @@ -331,8 +324,8 @@ struct api_table { bool (*registerModule)(api_table *, module_abi *); void (*hookJniNativeMethods)(JNIEnv *, const char *, JNINativeMethod *, int); - void (*pltHookRegister)(dev_t, ino_t, const char *, void *, void **); - bool (*exemptFd)(int); + void (*pltHookRegister)(const char *, const char *, void *, void **); + void (*pltHookExclude)(const char *, const char *); bool (*pltHookCommit)(); int (*connectCompanion)(void * /* impl */); void (*setOption)(void * /* impl */, Option); @@ -365,14 +358,14 @@ inline void Api::setOption(Option opt) { inline uint32_t Api::getFlags() { return tbl->getFlags ? tbl->getFlags(tbl->impl) : 0; } -inline bool Api::exemptFd(int fd) { - return tbl->exemptFd != nullptr && tbl->exemptFd(fd); -} inline void Api::hookJniNativeMethods(JNIEnv *env, const char *className, JNINativeMethod *methods, int numMethods) { if (tbl->hookJniNativeMethods) tbl->hookJniNativeMethods(env, className, methods, numMethods); } -inline void Api::pltHookRegister(dev_t dev, ino_t inode, const char *symbol, void *newFunc, void **oldFunc) { - if (tbl->pltHookRegister) tbl->pltHookRegister(dev, inode, symbol, newFunc, oldFunc); +inline void Api::pltHookRegister(const char *regex, const char *symbol, void *newFunc, void **oldFunc) { + if (tbl->pltHookRegister) tbl->pltHookRegister(regex, symbol, newFunc, oldFunc); +} +inline void Api::pltHookExclude(const char *regex, const char *symbol) { + if (tbl->pltHookExclude) tbl->pltHookExclude(regex, symbol); } inline bool Api::pltHookCommit() { return tbl->pltHookCommit != nullptr && tbl->pltHookCommit(); diff --git a/app/src/main/java/es/chiteroman/playintegrityfix/EntryPoint.java b/app/src/main/java/es/chiteroman/playintegrityfix/EntryPoint.java index 08244ae..4365864 100644 --- a/app/src/main/java/es/chiteroman/playintegrityfix/EntryPoint.java +++ b/app/src/main/java/es/chiteroman/playintegrityfix/EntryPoint.java @@ -17,19 +17,17 @@ import java.util.Properties; public final class EntryPoint { private static final Properties props = new Properties(); - private static final File file = new File("/data/data/com.google.android.gms/pif.prop"); + private static final File file = new File("/data/data/com.google.android.gms/cache/pif.prop"); 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!"); - return; + LOG("Couldn't load pif.prop file: " + e); } - LOG("Loaded " + props.size() + " fields!"); - spoofDevice(); spoofProvider(); } @@ -62,13 +60,13 @@ public final class EntryPoint { } public static void spoofDevice() { - setProp("PRODUCT", props.getProperty("PRODUCT")); - setProp("DEVICE", props.getProperty("DEVICE")); - setProp("MANUFACTURER", props.getProperty("MANUFACTURER")); - setProp("BRAND", props.getProperty("BRAND")); - setProp("MODEL", props.getProperty("MODEL")); - setProp("FINGERPRINT", props.getProperty("FINGERPRINT")); - setVersionProp("SECURITY_PATCH", props.getProperty("SECURITY_PATCH")); + 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")); } private static void setProp(String name, String value) {