mirror of
https://github.com/chiteroman/PlayIntegrityFix.git
synced 2025-01-19 03:22:39 +02:00
Prepare v15.2
This commit is contained in:
parent
0b21f031de
commit
0a6f936074
@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/app/src/main/cpp/Dobby" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
@ -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>("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")
|
||||
}
|
||||
|
@ -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)
|
@ -1,7 +1,8 @@
|
||||
#include <android/log.h>
|
||||
#include <sys/system_properties.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <filesystem>
|
||||
#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<void *, T_Callback> 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";
|
||||
|
||||
env->ReleaseStringUTFChars(args->nice_name, name);
|
||||
|
||||
if (!isGms) {
|
||||
api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY);
|
||||
return;
|
||||
}
|
||||
|
||||
api->setOption(zygisk::FORCE_DENYLIST_UNMOUNT);
|
||||
|
||||
if (strcmp(name, "com.google.android.gms.unstable") == 0) {
|
||||
if (!isGmsUnstable) {
|
||||
api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY);
|
||||
return;
|
||||
}
|
||||
|
||||
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) {
|
||||
vector.resize(dexSize);
|
||||
read(fd, vector.data(), dexSize);
|
||||
|
||||
jsonVector.resize(jsonSize);
|
||||
read(fd, jsonVector.data(), jsonSize);
|
||||
char jsonBufer[jsonSize];
|
||||
read(fd, jsonBufer, 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;
|
||||
}
|
||||
}
|
||||
|
||||
api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY);
|
||||
|
||||
clear:
|
||||
env->ReleaseStringUTFChars(args->nice_name, name);
|
||||
}
|
||||
|
||||
void postAppSpecialize(const zygisk::AppSpecializeArgs *args) override {
|
||||
if (dexVector.empty() || jsonVector.empty()) return;
|
||||
|
||||
std::string jsonStr(jsonVector.cbegin(), jsonVector.cend());
|
||||
nlohmann::json json = nlohmann::json::parse(jsonStr, nullptr, false, true);
|
||||
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<std::string>();
|
||||
}
|
||||
|
||||
} else if (json.contains("BUILD_ID")) {
|
||||
|
||||
if (json["BUILD_ID"].is_string()) {
|
||||
|
||||
BUILD_ID = json["BUILD_ID"].get<std::string>();
|
||||
}
|
||||
|
||||
} 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, "<init>",
|
||||
"(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<char> dexVector, jsonVector;
|
||||
std::vector<char> vector;
|
||||
nlohmann::json json;
|
||||
};
|
||||
|
||||
static void companion(int fd) {
|
||||
long dexSize = 0, jsonSize = 0;
|
||||
std::vector<char> 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<char> dexVector((std::istreambuf_iterator<char>(dexFile)),
|
||||
std::istreambuf_iterator<char>());
|
||||
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<char> jsonVector((std::istreambuf_iterator<char>(jsonFile)),
|
||||
std::istreambuf_iterator<char>());
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user