diff --git a/.gitmodules b/.gitmodules index b79ccd4..15d4b83 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ -[submodule "app/src/main/cpp/Dobby"] - path = app/src/main/cpp/Dobby - url = https://github.com/jmpews/Dobby.git +[submodule "app/src/main/cpp/libcxx"] + path = app/src/main/cpp/libcxx + url = https://github.com/topjohnwu/libcxx.git diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..c8397c9 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 4c659c5..177d9d0 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -8,10 +8,6 @@ android { ndkVersion = "26.1.10909125" buildToolsVersion = "34.0.0" - buildFeatures { - prefab = true - } - packaging { jniLibs { excludes += "**/liblog.so" @@ -27,18 +23,8 @@ android { versionName = "v15.2" externalNativeBuild { - cmake { - arguments += "-DANDROID_STL=none" - arguments += "-DCMAKE_BUILD_TYPE=Release" - arguments += "-DCMAKE_CXX_STANDARD=20" - arguments += "-DCMAKE_CXX_STANDARD_REQUIRED=True" - arguments += "-DCMAKE_CXX_EXTENSIONS=False" - arguments += "-DCMAKE_CXX_VISIBILITY_PRESET=hidden" - arguments += "-DCMAKE_VISIBILITY_INLINES_HIDDEN=True" - arguments += "-DPlugin.Android.BionicLinkerUtil=ON" - - cppFlags += "-fno-exceptions" - cppFlags += "-fno-rtti" + ndk { + jobs = Runtime.getRuntime().availableProcessors() } } } @@ -57,17 +43,12 @@ android { } externalNativeBuild { - cmake { - path = file("src/main/cpp/CMakeLists.txt") - version = "3.22.1" + ndkBuild { + path = file("src/main/cpp/Android.mk") } } } -dependencies { - implementation("dev.rikka.ndk.thirdparty:cxx:1.2.0") -} - tasks.register("updateModuleProp") { doLast { val versionName = project.android.defaultConfig.versionName diff --git a/app/src/main/cpp/Android.mk b/app/src/main/cpp/Android.mk new file mode 100644 index 0000000..bd44239 --- /dev/null +++ b/app/src/main/cpp/Android.mk @@ -0,0 +1,16 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := dobby +LOCAL_SRC_FILES := $(LOCAL_PATH)/dobby/$(TARGET_ARCH_ABI)/libdobby.a +LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/dobby +include $(PREBUILT_STATIC_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE := zygisk +LOCAL_SRC_FILES := main.cpp +LOCAL_STATIC_LIBRARIES := libcxx dobby +LOCAL_LDLIBS := -llog +include $(BUILD_SHARED_LIBRARY) + +include $(LOCAL_PATH)/libcxx/Android.mk \ No newline at end of file diff --git a/app/src/main/cpp/Application.mk b/app/src/main/cpp/Application.mk new file mode 100644 index 0000000..6e01d55 --- /dev/null +++ b/app/src/main/cpp/Application.mk @@ -0,0 +1,6 @@ +APP_ABI := armeabi-v7a arm64-v8a x86 x86_64 +APP_CFLAGS := -fvisibility=hidden -fvisibility-inlines-hidden -ffunction-sections -fdata-sections -Oz -flto +APP_CPPFLAGS := -std=c++20 -fno-exceptions -fno-rtti +APP_LDFLAGS := -Oz -flto -Wl,--exclude-libs,ALL -Wl,--gc-sections +APP_STL := none +APP_PLATFORM := android-26 \ No newline at end of file diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt deleted file mode 100644 index 75435e5..0000000 --- a/app/src/main/cpp/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -cmake_minimum_required(VERSION 3.22.1) - -project(playintegrityfix) - -find_package(cxx REQUIRED CONFIG) - -link_libraries(cxx::cxx) - -add_library(${CMAKE_PROJECT_NAME} SHARED module.cpp) - -add_subdirectory(Dobby) - -target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE log dobby_static) \ No newline at end of file diff --git a/app/src/main/cpp/Dobby b/app/src/main/cpp/Dobby deleted file mode 160000 index b0176de..0000000 --- a/app/src/main/cpp/Dobby +++ /dev/null @@ -1 +0,0 @@ -Subproject commit b0176de574104726bb68dff3b77ee666300fc338 diff --git a/app/src/main/cpp/dobby/arm64-v8a/libdobby.a b/app/src/main/cpp/dobby/arm64-v8a/libdobby.a new file mode 100644 index 0000000..e7acac6 Binary files /dev/null and b/app/src/main/cpp/dobby/arm64-v8a/libdobby.a differ diff --git a/app/src/main/cpp/dobby/armeabi-v7a/libdobby.a b/app/src/main/cpp/dobby/armeabi-v7a/libdobby.a new file mode 100644 index 0000000..069292c Binary files /dev/null and b/app/src/main/cpp/dobby/armeabi-v7a/libdobby.a differ diff --git a/app/src/main/cpp/dobby/dobby.h b/app/src/main/cpp/dobby/dobby.h new file mode 100644 index 0000000..484d314 --- /dev/null +++ b/app/src/main/cpp/dobby/dobby.h @@ -0,0 +1,152 @@ +#ifndef dobby_h +#define dobby_h + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +typedef uintptr_t addr_t; +typedef uint32_t addr32_t; +typedef uint64_t addr64_t; + +typedef void *dobby_dummy_func_t; +typedef void *asm_func_t; + +#if defined(__arm__) +typedef struct { + uint32_t dummy_0; + uint32_t dummy_1; + + uint32_t dummy_2; + uint32_t sp; + + union { + uint32_t r[13]; + struct { + uint32_t r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12; + } regs; + } general; + + uint32_t lr; +} DobbyRegisterContext; +#elif defined(__arm64__) || defined(__aarch64__) +#define ARM64_TMP_REG_NDX_0 17 + +typedef union _FPReg { + __int128_t q; + struct { + double d1; + double d2; + } d; + struct { + float f1; + float f2; + float f3; + float f4; + } f; +} FPReg; + +// register context +typedef struct { + uint64_t dmmpy_0; // dummy placeholder + uint64_t sp; + + uint64_t dmmpy_1; // dummy placeholder + union { + uint64_t x[29]; + struct { + uint64_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21, x22, + x23, x24, x25, x26, x27, x28; + } regs; + } general; + + uint64_t fp; + uint64_t lr; + + union { + FPReg q[32]; + struct { + FPReg q0, q1, q2, q3, q4, q5, q6, q7; + // [!!! READ ME !!!] + // for Arm64, can't access q8 - q31, unless you enable full floating-point register pack + FPReg q8, q9, q10, q11, q12, q13, q14, q15, q16, q17, q18, q19, q20, q21, q22, q23, q24, q25, q26, q27, q28, q29, + q30, q31; + } regs; + } floating; +} DobbyRegisterContext; +#elif defined(_M_IX86) || defined(__i386__) +typedef struct _RegisterContext { + uint32_t dummy_0; + uint32_t esp; + + uint32_t dummy_1; + uint32_t flags; + + union { + struct { + uint32_t eax, ebx, ecx, edx, ebp, esp, edi, esi; + } regs; + } general; + +} DobbyRegisterContext; +#elif defined(_M_X64) || defined(__x86_64__) +typedef struct { + uint64_t dummy_0; + uint64_t rsp; + + union { + struct { + uint64_t rax, rbx, rcx, rdx, rbp, rsp, rdi, rsi, r8, r9, r10, r11, r12, r13, r14, r15; + } regs; + } general; + + uint64_t dummy_1; + uint64_t flags; +} DobbyRegisterContext; +#endif + +#define install_hook_name(name, fn_ret_t, fn_args_t...) \ + static fn_ret_t fake_##name(fn_args_t); \ + static fn_ret_t (*orig_##name)(fn_args_t); \ + /* __attribute__((constructor)) */ static void install_hook_##name(void *sym_addr) { \ + DobbyHook(sym_addr, (dobby_dummy_func_t)fake_##name, (dobby_dummy_func_t *)&orig_##name); \ + return; \ + } \ + fn_ret_t fake_##name(fn_args_t) + +// memory code patch +int DobbyCodePatch(void *address, uint8_t *buffer, uint32_t buffer_size); + +// function inline hook +int DobbyHook(void *address, dobby_dummy_func_t replace_func, dobby_dummy_func_t *origin_func); + +// dynamic binary instruction instrument +// for Arm64, can't access q8 - q31, unless enable full floating-point register pack +typedef void (*dobby_instrument_callback_t)(void *address, DobbyRegisterContext *ctx); +int DobbyInstrument(void *address, dobby_instrument_callback_t pre_handler); + +// destroy and restore code patch +int DobbyDestroy(void *address); + +const char *DobbyGetVersion(); + +// symbol resolver +void *DobbySymbolResolver(const char *image_name, const char *symbol_name); + +// import table replace +int DobbyImportTableReplace(char *image_name, char *symbol_name, dobby_dummy_func_t fake_func, + dobby_dummy_func_t *orig_func); + +// for arm, Arm64, try use b xxx instead of ldr absolute indirect branch +// for x86, x64, always use absolute indirect jump +void dobby_enable_near_branch_trampoline(); +void dobby_disable_near_branch_trampoline(); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/app/src/main/cpp/dobby/x86/libdobby.a b/app/src/main/cpp/dobby/x86/libdobby.a new file mode 100644 index 0000000..bfe8ff9 Binary files /dev/null and b/app/src/main/cpp/dobby/x86/libdobby.a differ diff --git a/app/src/main/cpp/dobby/x86_64/libdobby.a b/app/src/main/cpp/dobby/x86_64/libdobby.a new file mode 100644 index 0000000..ebb072f Binary files /dev/null and b/app/src/main/cpp/dobby/x86_64/libdobby.a differ diff --git a/app/src/main/cpp/libcxx b/app/src/main/cpp/libcxx new file mode 160000 index 0000000..12c8f4e --- /dev/null +++ b/app/src/main/cpp/libcxx @@ -0,0 +1 @@ +Subproject commit 12c8f4e93f196a700137e983dcceeac43cf807f2 diff --git a/app/src/main/cpp/module.cpp b/app/src/main/cpp/main.cpp similarity index 84% rename from app/src/main/cpp/module.cpp rename to app/src/main/cpp/main.cpp index be8ad97..e2b5dda 100644 --- a/app/src/main/cpp/module.cpp +++ b/app/src/main/cpp/main.cpp @@ -1,8 +1,6 @@ #include #include #include -#include -#include #include "zygisk.hpp" #include "dobby.h" #include "json.hpp" @@ -53,6 +51,7 @@ static void modify_callback(void *cookie, const char *name, const char *value, u } else if (prop == "sys.usb.state") { value = "none"; + } if (!prop.starts_with("debug") && !prop.starts_with("cache") && !prop.starts_with("persist")) { @@ -104,25 +103,22 @@ public: return; } - std::string_view process(name); - - bool isGms = process.starts_with("com.google.android.gms"); - bool isGmsUnstable = process == "com.google.android.gms.unstable"; - - env->ReleaseStringUTFChars(args->nice_name, name); - - if (!isGms) { + if (strncmp(name, "com.google.android.gms", 22) != 0) { + env->ReleaseStringUTFChars(args->nice_name, name); api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY); return; } api->setOption(zygisk::FORCE_DENYLIST_UNMOUNT); - if (!isGmsUnstable) { + if (strcmp(name, "com.google.android.gms.unstable") != 0) { + env->ReleaseStringUTFChars(args->nice_name, name); api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY); return; } + env->ReleaseStringUTFChars(args->nice_name, name); + long dexSize = 0, jsonSize = 0; int fd = api->connectCompanion(); @@ -130,15 +126,18 @@ public: read(fd, &dexSize, sizeof(long)); read(fd, &jsonSize, sizeof(long)); + LOGD("Dex file size: %ld", dexSize); + LOGD("Json file size: %ld", jsonSize); + vector.resize(dexSize); read(fd, vector.data(), dexSize); - char jsonBufer[jsonSize]; - read(fd, jsonBufer, jsonSize); + std::vector jsonVector(jsonSize); + read(fd, jsonVector.data(), jsonSize); close(fd); - std::string_view jsonStr(jsonBufer, jsonSize); + std::string_view jsonStr(jsonVector.cbegin(), jsonVector.cend()); json = nlohmann::json::parse(jsonStr, nullptr, false, true); if (json.contains("FIRST_API_LEVEL")) { @@ -238,34 +237,38 @@ private: }; static void companion(int fd) { - std::ifstream dexFile(CLASSES_DEX, std::ios::in | std::ios::binary); + long dexSize = 0, jsonSize = 0; + std::vector dexVector, jsonVector; - if (!dexFile) { - long i = 0; - write(fd, &i, sizeof(i)); - return; + FILE *dexFile = fopen(CLASSES_DEX, "rb"); + + if (dexFile) { + + fseek(dexFile, 0, SEEK_END); + dexSize = ftell(dexFile); + fseek(dexFile, 0, SEEK_SET); + + dexVector.resize(dexSize); + fread(dexVector.data(), 1, dexSize, dexFile); + + fclose(dexFile); } - std::vector dexVector((std::istreambuf_iterator(dexFile)), - std::istreambuf_iterator()); - long dexSize = dexVector.size(); + FILE *jsonFile = fopen(PIF_JSON, "rb"); + if (jsonFile == nullptr) jsonFile = fopen(PIF_JSON_2, "rb"); - std::ifstream jsonFile; + if (jsonFile) { - if (std::filesystem::exists(PIF_JSON)) { - jsonFile = std::ifstream(PIF_JSON, std::ios::in); - } else if (std::filesystem::exists(PIF_JSON_2)) { - jsonFile = std::ifstream(PIF_JSON_2, std::ios::in); - } else { - long i = 0; - write(fd, &i, sizeof(i)); - return; + fseek(jsonFile, 0, SEEK_END); + jsonSize = ftell(jsonFile); + fseek(jsonFile, 0, SEEK_SET); + + jsonVector.resize(jsonSize); + fread(jsonVector.data(), 1, jsonSize, jsonFile); + + fclose(jsonFile); } - std::vector jsonVector((std::istreambuf_iterator(jsonFile)), - std::istreambuf_iterator()); - long jsonSize = jsonVector.size(); - write(fd, &dexSize, sizeof(long)); write(fd, &jsonSize, sizeof(long)); diff --git a/app/src/main/java/es/chiteroman/playintegrityfix/EntryPoint.java b/app/src/main/java/es/chiteroman/playintegrityfix/EntryPoint.java index 54b0cd3..d1f8cec 100644 --- a/app/src/main/java/es/chiteroman/playintegrityfix/EntryPoint.java +++ b/app/src/main/java/es/chiteroman/playintegrityfix/EntryPoint.java @@ -15,45 +15,7 @@ import java.security.Security; public final class EntryPoint { private static JSONObject jsonObject = new JSONObject(); - public static void init(String json) { - - try { - jsonObject = new JSONObject(json); - } catch (JSONException e) { - LOG("Couldn't parse JSON from Zygisk"); - } - - boolean FORCE_BASIC_ATTESTATION = true; - - if (jsonObject.has("FORCE_BASIC_ATTESTATION")) { - try { - FORCE_BASIC_ATTESTATION = jsonObject.getBoolean("FORCE_BASIC_ATTESTATION"); - } catch (JSONException e) { - LOG("Couldn't parse FORCE_BASIC_ATTESTATION from JSON"); - } - jsonObject.remove("FORCE_BASIC_ATTESTATION"); - } - - spoofDevice(); - - if (FORCE_BASIC_ATTESTATION) spoofProvider(); - } - - static void LOG(String msg) { - Log.d("PIF/Java", msg); - } - - static void spoofDevice() { - jsonObject.keys().forEachRemaining(s -> { - try { - Object value = jsonObject.get(s); - setFieldValue(s, value); - } catch (JSONException ignored) { - } - }); - } - - private static void spoofProvider() { + static { try { KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); keyStore.load(null); @@ -77,6 +39,31 @@ public final class EntryPoint { } } + public static void init(String json) { + + try { + jsonObject = new JSONObject(json); + } catch (JSONException e) { + LOG("Couldn't parse JSON from Zygisk"); + } + + spoofDevice(); + } + + static void LOG(String msg) { + Log.d("PIF/Java", msg); + } + + static void spoofDevice() { + jsonObject.keys().forEachRemaining(s -> { + try { + Object value = jsonObject.get(s); + setFieldValue(s, value); + } catch (JSONException ignored) { + } + }); + } + private static void setFieldValue(String name, Object value) { if (name == null || value == null || name.isEmpty()) return; diff --git a/build.gradle.kts b/build.gradle.kts index ff974c6..2d4a654 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,3 +1,3 @@ plugins { - id("com.android.application") version "8.2.0" apply false + id("com.android.application") version "8.2.1" apply false } \ No newline at end of file diff --git a/module/customize.sh b/module/customize.sh index d49d61e..8be9094 100644 --- a/module/customize.sh +++ b/module/customize.sh @@ -5,8 +5,8 @@ fi # safetynet-fix module is obsolete and it's incompatible with PIF. if [ -d /data/adb/modules/safetynet-fix ]; then - rm -rf /data/adb/modules/safetynet-fix - rm -f /data/adb/SNFix.dex + rm -rf /data/adb/modules/safetynet-fix + rm -f /data/adb/SNFix.dex ui_print "! safetynet-fix module will be removed. Do NOT install it again along PIF." fi @@ -18,41 +18,41 @@ fi # Remove xiaomi.eu apps if [ -d "/product/app/XiaomiEUInject" ]; then - - directory="$MODPATH/product/app/XiaomiEUInject" - - [ -d "$directory" ] || mkdir -p "$directory" - - touch "$directory/.replace" - - ui_print "- XiaomiEUInject app removed." + + directory="$MODPATH/product/app/XiaomiEUInject" + + [ -d "$directory" ] || mkdir -p "$directory" + + touch "$directory/.replace" + + ui_print "- XiaomiEUInject app removed." fi # Remove EliteRoms app - + if [ -d "/system/app/XInjectModule" ]; then - - directory="$MODPATH/system/app/XInjectModule" - - [ -d "$directory" ] || mkdir -p "$directory" - - touch "$directory/.replace" - - ui_print "- XInjectModule app removed." + + directory="$MODPATH/system/app/XInjectModule" + + [ -d "$directory" ] || mkdir -p "$directory" + + touch "$directory/.replace" + + ui_print "- XInjectModule app removed." fi if [ -d "/system/app/EliteDevelopmentModule" ]; then - - directory="$MODPATH/system/app/EliteDevelopmentModule" - - [ -d "$directory" ] || mkdir -p "$directory" - - touch "$directory/.replace" - - ui_print "- EliteDevelopmentModule app removed." + + directory="$MODPATH/system/app/EliteDevelopmentModule" + + [ -d "$directory" ] || mkdir -p "$directory" + + touch "$directory/.replace" + + ui_print "- EliteDevelopmentModule app removed." fi if [ -f "/data/adb/pif.json" ]; then - mv -f "/data/adb/pif.json" "/data/adb/pif.json.old" - ui_print "- Backup pif.json" + mv -f "/data/adb/pif.json" "/data/adb/pif.json.old" + ui_print "- Backup pif.json" fi \ No newline at end of file diff --git a/module/pif.json b/module/pif.json index a154748..fba7312 100644 --- a/module/pif.json +++ b/module/pif.json @@ -7,6 +7,5 @@ "FINGERPRINT": "acer/c01_ww/acer_c01:7.1.1/NMF26F/1521514970:user/release-keys", "SECURITY_PATCH": "2018-04-01", "FIRST_API_LEVEL": 24, - "ID": "NMF26F", - "FORCE_BASIC_ATTESTATION": true -} + "ID": "NMF26F" +} \ No newline at end of file diff --git a/module/post-fs-data.sh b/module/post-fs-data.sh index 1ca4671..249fb7d 100644 --- a/module/post-fs-data.sh +++ b/module/post-fs-data.sh @@ -9,16 +9,16 @@ resetprop_if_diff() { local NAME=$1 local EXPECTED=$2 local CURRENT=$(resetprop $NAME) - - [ -z "$CURRENT" ] || [ "$CURRENT" == "$EXPECTED" ] || resetprop $NAME $EXPECTED + + [ -z "$CURRENT" ] || [ "$CURRENT" == "$EXPECTED" ] || resetprop -n $NAME $EXPECTED } resetprop_if_match() { local NAME=$1 local CONTAINS=$2 local VALUE=$3 - - [[ "$(resetprop $NAME)" == *"$CONTAINS"* ]] && resetprop $NAME $VALUE + + [[ "$(resetprop $NAME)" == *"$CONTAINS"* ]] && resetprop -n $NAME $VALUE } # RootBeer, Microsoft diff --git a/module/service.sh b/module/service.sh index 887e4e2..15862c5 100644 --- a/module/service.sh +++ b/module/service.sh @@ -4,16 +4,16 @@ resetprop_if_diff() { local NAME=$1 local EXPECTED=$2 local CURRENT=$(resetprop $NAME) - - [ -z "$CURRENT" ] || [ "$CURRENT" == "$EXPECTED" ] || resetprop $NAME $EXPECTED + + [ -z "$CURRENT" ] || [ "$CURRENT" == "$EXPECTED" ] || resetprop -n $NAME $EXPECTED } resetprop_if_match() { local NAME=$1 local CONTAINS=$2 local VALUE=$3 - - [[ "$(resetprop $NAME)" == *"$CONTAINS"* ]] && resetprop $NAME $VALUE + + [[ "$(resetprop $NAME)" == *"$CONTAINS"* ]] && resetprop -n $NAME $VALUE } # Magisk recovery mode @@ -34,15 +34,18 @@ fi # late props which must be set after boot_completed for various OEMs until [ "$(resetprop sys.boot_completed)" == "1" ]; do - sleep 1 + sleep 1 done # Avoid breaking Realme fingerprint scanners resetprop_if_diff ro.boot.flash.locked 1 + # Avoid breaking Oppo fingerprint scanners resetprop_if_diff ro.boot.vbmeta.device_state locked + # Avoid breaking OnePlus display modes/fingerprint scanners resetprop_if_diff vendor.boot.verifiedbootstate green + # Avoid breaking OnePlus/Oppo display fingerprint scanners on OOS/ColorOS 12+ resetprop_if_diff ro.boot.verifiedbootstate green resetprop_if_diff ro.boot.veritymode enforcing