From 0a6f93607415d3c9bedd3c6c972def0c33078b37 Mon Sep 17 00:00:00 2001
From: chiteroman <98092901+chiteroman@users.noreply.github.com>
Date: Thu, 4 Jan 2024 22:01:38 +0100
Subject: [PATCH] Prepare v15.2
---
.idea/vcs.xml | 7 -
app/build.gradle.kts | 37 +++-
app/src/main/cpp/CMakeLists.txt | 4 +-
app/src/main/cpp/module.cpp | 199 +++++++++---------
.../playintegrityfix/CustomProvider.java | 3 +-
module/module.prop | 4 +-
module/pif.json | 1 +
7 files changed, 139 insertions(+), 116 deletions(-)
delete mode 100644 .idea/vcs.xml
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
deleted file mode 100644
index aa851fd..0000000
--- a/.idea/vcs.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 02c7cfd..4c659c5 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -14,6 +14,7 @@ android {
packaging {
jniLibs {
+ excludes += "**/liblog.so"
excludes += "**/libdobby.so"
}
}
@@ -22,19 +23,22 @@ android {
applicationId = "es.chiteroman.playintegrityfix"
minSdk = 26
targetSdk = 34
- versionCode = 1
- versionName = "1.0"
+ versionCode = 15200
+ 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 += "-std=c++20"
cppFlags += "-fno-exceptions"
cppFlags += "-fno-rtti"
- cppFlags += "-fvisibility=hidden"
- cppFlags += "-fvisibility-inlines-hidden"
}
}
}
@@ -64,7 +68,26 @@ dependencies {
implementation("dev.rikka.ndk.thirdparty:cxx:1.2.0")
}
+tasks.register("updateModuleProp") {
+ doLast {
+ val versionName = project.android.defaultConfig.versionName
+ val versionCode = project.android.defaultConfig.versionCode
+
+ val modulePropFile = project.rootDir.resolve("module/module.prop")
+
+ var content = modulePropFile.readText()
+
+ content = content.replace(Regex("version=.*"), "version=$versionName")
+ content = content.replace(Regex("versionCode=.*"), "versionCode=$versionCode")
+
+ modulePropFile.writeText(content)
+ }
+}
+
+
tasks.register("copyFiles") {
+ dependsOn("updateModuleProp")
+
doLast {
val moduleFolder = project.rootDir.resolve("module")
val dexFile = project.layout.buildDirectory.get().asFile.resolve("intermediates/dex/release/minifyReleaseWithR8/classes.dex")
@@ -83,12 +106,12 @@ tasks.register("copyFiles") {
tasks.register("zip") {
dependsOn("copyFiles")
- archiveFileName.set("PlayIntegrityFix.zip")
+ archiveFileName.set("PlayIntegrityFix_${project.android.defaultConfig.versionName}.zip")
destinationDirectory.set(project.rootDir.resolve("out"))
from(project.rootDir.resolve("module"))
}
afterEvaluate {
- tasks["assembleRelease"].finalizedBy("copyFiles", "zip")
+ tasks["assembleRelease"].finalizedBy("updateModuleProp", "copyFiles", "zip")
}
diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt
index 4d5c343..75435e5 100644
--- a/app/src/main/cpp/CMakeLists.txt
+++ b/app/src/main/cpp/CMakeLists.txt
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.22.1)
-project("playintegrityfix")
+project(playintegrityfix)
find_package(cxx REQUIRED CONFIG)
@@ -10,6 +10,4 @@ add_library(${CMAKE_PROJECT_NAME} SHARED module.cpp)
add_subdirectory(Dobby)
-SET_OPTION(Plugin.Android.BionicLinkerUtil ON)
-
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE log dobby_static)
\ No newline at end of file
diff --git a/app/src/main/cpp/module.cpp b/app/src/main/cpp/module.cpp
index 68c0ffb..be8ad97 100644
--- a/app/src/main/cpp/module.cpp
+++ b/app/src/main/cpp/module.cpp
@@ -1,7 +1,8 @@
#include
#include
#include
-
+#include
+#include
#include "zygisk.hpp"
#include "dobby.h"
#include "json.hpp"
@@ -14,15 +15,17 @@
#define PIF_JSON_2 "/data/adb/modules/playintegrityfix/pif.json"
-static std::string FIRST_API_LEVEL, SECURITY_PATCH;
+static std::string FIRST_API_LEVEL, SECURITY_PATCH, BUILD_ID;
typedef void (*T_Callback)(void *, const char *, const char *, uint32_t);
-static T_Callback o_callback = nullptr;
+static std::map callbacks;
static void modify_callback(void *cookie, const char *name, const char *value, uint32_t serial) {
- if (cookie == nullptr || name == nullptr || o_callback == nullptr) return;
+ if (cookie == nullptr || name == nullptr || value == nullptr ||
+ !callbacks.contains(cookie))
+ return;
std::string_view prop(name);
@@ -40,6 +43,13 @@ static void modify_callback(void *cookie, const char *name, const char *value, u
value = FIRST_API_LEVEL.c_str();
}
+ } else if (prop.ends_with("build.id")) {
+
+ if (!BUILD_ID.empty()) {
+
+ value = BUILD_ID.c_str();
+ }
+
} else if (prop == "sys.usb.state") {
value = "none";
@@ -50,7 +60,7 @@ static void modify_callback(void *cookie, const char *name, const char *value, u
LOGD("[%s] -> %s", name, value);
}
- return o_callback(cookie, name, value, serial);
+ return callbacks[cookie](cookie, name, value, serial);
}
static void (*o_system_property_read_callback)(const prop_info *, T_Callback, void *);
@@ -60,12 +70,12 @@ my_system_property_read_callback(const prop_info *pi, T_Callback callback, void
if (pi == nullptr || callback == nullptr || cookie == nullptr) {
return o_system_property_read_callback(pi, callback, cookie);
}
- o_callback = callback;
+ callbacks[cookie] = callback;
return o_system_property_read_callback(pi, modify_callback, cookie);
}
static void doHook() {
- void *handle = DobbySymbolResolver(nullptr, "__system_property_read_callback");
+ 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;
@@ -87,68 +97,49 @@ public:
void preAppSpecialize(zygisk::AppSpecializeArgs *args) override {
- if (args->is_child_zygote && *args->is_child_zygote) {
+ auto name = env->GetStringUTFChars(args->nice_name, nullptr);
+
+ if (name == nullptr) {
api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY);
return;
}
- auto name = env->GetStringUTFChars(args->nice_name, nullptr);
+ std::string_view process(name);
- if (name && strncmp(name, "com.google.android.gms", 22) == 0) {
+ bool isGms = process.starts_with("com.google.android.gms");
+ bool isGmsUnstable = process == "com.google.android.gms.unstable";
- api->setOption(zygisk::FORCE_DENYLIST_UNMOUNT);
+ env->ReleaseStringUTFChars(args->nice_name, name);
- if (strcmp(name, "com.google.android.gms.unstable") == 0) {
-
- long dexSize = 0, jsonSize = 0;
- int fd = api->connectCompanion();
-
- read(fd, &dexSize, sizeof(long));
-
- if (dexSize > 0) {
-
- dexVector.resize(dexSize);
- read(fd, dexVector.data(), dexSize);
-
- } else {
-
- LOGD("Couldn't load classes.dex file in memory!");
- api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY);
- goto end;
- }
-
- read(fd, &jsonSize, sizeof(long));
-
- if (jsonSize > 0) {
-
- jsonVector.resize(jsonSize);
- read(fd, jsonVector.data(), jsonSize);
-
- } else {
-
- LOGD("Couldn't load pif.json file in memory!");
- dexVector.clear();
- api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY);
- goto end;
- }
-
- end:
- close(fd);
- goto clear;
- }
+ if (!isGms) {
+ api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY);
+ return;
}
- api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY);
+ api->setOption(zygisk::FORCE_DENYLIST_UNMOUNT);
- clear:
- env->ReleaseStringUTFChars(args->nice_name, name);
- }
+ if (!isGmsUnstable) {
+ api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY);
+ return;
+ }
- void postAppSpecialize(const zygisk::AppSpecializeArgs *args) override {
- if (dexVector.empty() || jsonVector.empty()) return;
+ long dexSize = 0, jsonSize = 0;
- std::string jsonStr(jsonVector.cbegin(), jsonVector.cend());
- nlohmann::json json = nlohmann::json::parse(jsonStr, nullptr, false, true);
+ int fd = api->connectCompanion();
+
+ read(fd, &dexSize, sizeof(long));
+ read(fd, &jsonSize, sizeof(long));
+
+ vector.resize(dexSize);
+ read(fd, vector.data(), dexSize);
+
+ char jsonBufer[jsonSize];
+ read(fd, jsonBufer, jsonSize);
+
+ close(fd);
+
+ std::string_view jsonStr(jsonBufer, jsonSize);
+ json = nlohmann::json::parse(jsonStr, nullptr, false, true);
if (json.contains("FIRST_API_LEVEL")) {
@@ -180,6 +171,29 @@ public:
LOGD("JSON file doesn't contain SECURITY_PATCH key :(");
}
+ if (json.contains("ID")) {
+
+ if (json["ID"].is_string()) {
+
+ BUILD_ID = json["ID"].get();
+ }
+
+ } else if (json.contains("BUILD_ID")) {
+
+ if (json["BUILD_ID"].is_string()) {
+
+ BUILD_ID = json["BUILD_ID"].get();
+ }
+
+ } else {
+
+ LOGD("JSON file doesn't contain ID/BUILD_ID keys :(");
+ }
+ }
+
+ void postAppSpecialize(const zygisk::AppSpecializeArgs *args) override {
+ if (vector.empty() || json.empty()) return;
+
doHook();
LOGD("get system classloader");
@@ -192,7 +206,7 @@ public:
auto dexClClass = env->FindClass("dalvik/system/InMemoryDexClassLoader");
auto dexClInit = env->GetMethodID(dexClClass, "",
"(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V");
- auto buffer = env->NewDirectByteBuffer(dexVector.data(), dexVector.size());
+ auto buffer = env->NewDirectByteBuffer(vector.data(), vector.size());
auto dexCl = env->NewObject(dexClClass, dexClInit, buffer, systemClassLoader);
LOGD("load class");
@@ -208,8 +222,8 @@ public:
auto str = env->NewStringUTF(json.dump().c_str());
env->CallStaticVoidMethod(entryClass, entryInit, str);
- dexVector.clear();
- jsonVector.clear();
+ vector.clear();
+ json.clear();
}
void preServerSpecialize(zygisk::ServerSpecializeArgs *args) override {
@@ -219,50 +233,43 @@ public:
private:
zygisk::Api *api = nullptr;
JNIEnv *env = nullptr;
- std::vector dexVector, jsonVector;
+ std::vector vector;
+ nlohmann::json json;
};
static void companion(int fd) {
- long dexSize = 0, jsonSize = 0;
- std::vector dexVector, jsonVector;
+ std::ifstream dexFile(CLASSES_DEX, std::ios::in | std::ios::binary);
- 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);
+ if (!dexFile) {
+ long i = 0;
+ write(fd, &i, sizeof(i));
+ return;
}
+ std::vector dexVector((std::istreambuf_iterator(dexFile)),
+ std::istreambuf_iterator());
+ long dexSize = dexVector.size();
+
+ std::ifstream 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;
+ }
+
+ std::vector jsonVector((std::istreambuf_iterator(jsonFile)),
+ std::istreambuf_iterator());
+ long jsonSize = jsonVector.size();
+
write(fd, &dexSize, sizeof(long));
- write(fd, dexVector.data(), dexSize);
-
- FILE *jsonFile = fopen(PIF_JSON, "r");
-
- if (jsonFile == nullptr) {
-
- jsonFile = fopen(PIF_JSON_2, "r");
- }
-
- if (jsonFile) {
-
- fseek(jsonFile, 0, SEEK_END);
- jsonSize = ftell(jsonFile);
- fseek(jsonFile, 0, SEEK_SET);
-
- jsonVector.resize(jsonSize);
- fread(jsonVector.data(), 1, jsonSize, jsonFile);
-
- fclose(jsonFile);
- }
-
write(fd, &jsonSize, sizeof(long));
+
+ write(fd, dexVector.data(), dexSize);
write(fd, jsonVector.data(), jsonSize);
}
diff --git a/app/src/main/java/es/chiteroman/playintegrityfix/CustomProvider.java b/app/src/main/java/es/chiteroman/playintegrityfix/CustomProvider.java
index 77fec53..3ec3fb4 100644
--- a/app/src/main/java/es/chiteroman/playintegrityfix/CustomProvider.java
+++ b/app/src/main/java/es/chiteroman/playintegrityfix/CustomProvider.java
@@ -14,8 +14,9 @@ public final class CustomProvider extends Provider {
@Override
public synchronized Service getService(String type, String algorithm) {
+ EntryPoint.LOG(String.format("[Service] Type: '%s' | Algorithm: '%s'", type, algorithm));
- EntryPoint.spoofDevice();
+ if ("KeyStore".equals(type)) EntryPoint.spoofDevice();
return super.getService(type, algorithm);
}
diff --git a/module/module.prop b/module/module.prop
index b999caa..aed930b 100644
--- a/module/module.prop
+++ b/module/module.prop
@@ -1,7 +1,7 @@
id=playintegrityfix
name=Play Integrity Fix
-version=v15.1
-versionCode=15100
+version=v15.2
+versionCode=15200
author=chiteroman
description=Universal modular fix for Play Integrity (and SafetyNet) on devices running Android 8+.
updateJson=https://raw.githubusercontent.com/chiteroman/PlayIntegrityFix/main/update.json
diff --git a/module/pif.json b/module/pif.json
index ae3dfb3..a154748 100644
--- a/module/pif.json
+++ b/module/pif.json
@@ -7,5 +7,6 @@
"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
}