mirror of
https://github.com/chiteroman/PlayIntegrityFix.git
synced 2025-01-19 03:22:39 +02:00
v15.0
This commit is contained in:
parent
325fbdc2f5
commit
aa340e742e
3
.idea/.gitignore
vendored
3
.idea/.gitignore
vendored
@ -1,3 +0,0 @@
|
|||||||
# Default ignored files
|
|
||||||
/shelf/
|
|
||||||
/workspace.xml
|
|
@ -1,11 +1,10 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="GradleMigrationSettings" migrationVersion="1" />
|
|
||||||
<component name="GradleSettings">
|
<component name="GradleSettings">
|
||||||
<option name="linkedExternalProjectsSettings">
|
<option name="linkedExternalProjectsSettings">
|
||||||
<GradleProjectSettings>
|
<GradleProjectSettings>
|
||||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||||
<option name="gradleJvm" value="jbr-17" />
|
<option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" />
|
||||||
<option name="modules">
|
<option name="modules">
|
||||||
<set>
|
<set>
|
||||||
<option value="$PROJECT_DIR$" />
|
<option value="$PROJECT_DIR$" />
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" project-jdk-type="JavaSDK">
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="VcsDirectoryMappings">
|
<component name="VcsDirectoryMappings">
|
||||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
<mapping directory="" vcs="Git" />
|
||||||
<mapping directory="$PROJECT_DIR$/app/src/main/cpp/Dobby" vcs="Git" />
|
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
3
app/proguard-rules.pro
vendored
3
app/proguard-rules.pro
vendored
@ -1,6 +1,3 @@
|
|||||||
-ignorewarnings
|
|
||||||
-dontobfuscate
|
|
||||||
-keep class es.chiteroman.playintegrityfix.EntryPoint {public <methods>;}
|
-keep class es.chiteroman.playintegrityfix.EntryPoint {public <methods>;}
|
||||||
-keep class es.chiteroman.playintegrityfix.CustomProvider
|
-keep class es.chiteroman.playintegrityfix.CustomProvider
|
||||||
-keep class es.chiteroman.playintegrityfix.CustomKeyStoreSpi
|
-keep class es.chiteroman.playintegrityfix.CustomKeyStoreSpi
|
||||||
-keep class es.chiteroman.playintegrityfix.CustomCertificates
|
|
@ -1,7 +1,6 @@
|
|||||||
#include <android/log.h>
|
#include <android/log.h>
|
||||||
#include <sys/system_properties.h>
|
#include <sys/system_properties.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <filesystem>
|
|
||||||
|
|
||||||
#include "zygisk.hpp"
|
#include "zygisk.hpp"
|
||||||
#include "dobby.h"
|
#include "dobby.h"
|
||||||
@ -48,6 +47,10 @@ static void modify_callback(void *cookie, const char *name, const char *value, u
|
|||||||
value = BUILD_ID.c_str();
|
value = BUILD_ID.c_str();
|
||||||
LOGD("Set '%s' to '%s'", name, value);
|
LOGD("Set '%s' to '%s'", name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else if (prop == "sys.usb.state") {
|
||||||
|
|
||||||
|
value = "none";
|
||||||
}
|
}
|
||||||
|
|
||||||
return o_callback(cookie, name, value, serial);
|
return o_callback(cookie, name, value, serial);
|
||||||
@ -87,6 +90,11 @@ public:
|
|||||||
|
|
||||||
void preAppSpecialize(zygisk::AppSpecializeArgs *args) override {
|
void preAppSpecialize(zygisk::AppSpecializeArgs *args) override {
|
||||||
|
|
||||||
|
if (args->is_child_zygote && *args->is_child_zygote) {
|
||||||
|
api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
auto name = env->GetStringUTFChars(args->nice_name, nullptr);
|
auto name = env->GetStringUTFChars(args->nice_name, nullptr);
|
||||||
|
|
||||||
if (name && strncmp(name, "com.google.android.gms", 22) == 0) {
|
if (name && strncmp(name, "com.google.android.gms", 22) == 0) {
|
||||||
@ -95,24 +103,39 @@ public:
|
|||||||
|
|
||||||
if (strcmp(name, "com.google.android.gms.unstable") == 0) {
|
if (strcmp(name, "com.google.android.gms.unstable") == 0) {
|
||||||
|
|
||||||
auto rawDir = env->GetStringUTFChars(args->app_data_dir, nullptr);
|
|
||||||
dir = rawDir;
|
|
||||||
env->ReleaseStringUTFChars(args->app_data_dir, rawDir);
|
|
||||||
|
|
||||||
long size = dir.size();
|
|
||||||
bool done = false;
|
|
||||||
|
|
||||||
int fd = api->connectCompanion();
|
int fd = api->connectCompanion();
|
||||||
|
|
||||||
write(fd, &size, sizeof(long));
|
read(fd, &dexSize, sizeof(long));
|
||||||
write(fd, dir.data(), size);
|
|
||||||
|
|
||||||
read(fd, &done, sizeof(bool));
|
if (dexSize > 0) {
|
||||||
|
|
||||||
|
dexBuffer = new unsigned char[dexSize];
|
||||||
|
read(fd, dexBuffer, 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) {
|
||||||
|
|
||||||
|
jsonBuffer = new char[jsonSize];
|
||||||
|
read(fd, jsonBuffer, jsonSize);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
LOGD("Couldn't load pif.json file in memory!");
|
||||||
|
delete[] dexBuffer;
|
||||||
|
api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
end:
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
||||||
LOGD("Files copied: %d", done);
|
|
||||||
|
|
||||||
goto clear;
|
goto clear;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -124,31 +147,10 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void postAppSpecialize(const zygisk::AppSpecializeArgs *args) override {
|
void postAppSpecialize(const zygisk::AppSpecializeArgs *args) override {
|
||||||
if (dir.empty()) return;
|
if (dexSize < 1 || jsonSize < 1 || dexBuffer == nullptr || jsonBuffer == nullptr) return;
|
||||||
|
|
||||||
std::string classesDex(dir + "/classes.dex");
|
std::string_view jsonStr(jsonBuffer, jsonSize);
|
||||||
|
nlohmann::json json = nlohmann::json::parse(jsonStr, nullptr, false, true);
|
||||||
FILE *dexFile = fopen(classesDex.c_str(), "rb");
|
|
||||||
|
|
||||||
if (dexFile == nullptr) {
|
|
||||||
|
|
||||||
LOGD("classes.dex doesn't exist... This is weird.");
|
|
||||||
dir.clear();
|
|
||||||
api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(dexFile);
|
|
||||||
|
|
||||||
doHook();
|
|
||||||
|
|
||||||
std::string pifJson(dir + "/pif.json");
|
|
||||||
|
|
||||||
FILE *jsonFile = fopen(pifJson.c_str(), "r");
|
|
||||||
|
|
||||||
nlohmann::json json = nlohmann::json::parse(jsonFile, nullptr, false, true);
|
|
||||||
|
|
||||||
fclose(jsonFile);
|
|
||||||
|
|
||||||
if (json.contains("FIRST_API_LEVEL")) {
|
if (json.contains("FIRST_API_LEVEL")) {
|
||||||
|
|
||||||
@ -180,20 +182,20 @@ public:
|
|||||||
LOGD("JSON file doesn't contain SECURITY_PATCH key :(");
|
LOGD("JSON file doesn't contain SECURITY_PATCH key :(");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (json.contains("BUILD_ID")) {
|
if (json.contains("ID")) {
|
||||||
|
|
||||||
if (json["BUILD_ID"].is_string()) {
|
if (json["ID"].is_string()) {
|
||||||
|
|
||||||
BUILD_ID = json["BUILD_ID"].get<std::string>();
|
BUILD_ID = json["ID"].get<std::string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
json.erase("BUILD_ID");
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
LOGD("JSON file doesn't contain BUILD_ID key :(");
|
LOGD("JSON file doesn't contain BUILD_ID key :(");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
doHook();
|
||||||
|
|
||||||
LOGD("get system classloader");
|
LOGD("get system classloader");
|
||||||
auto clClass = env->FindClass("java/lang/ClassLoader");
|
auto clClass = env->FindClass("java/lang/ClassLoader");
|
||||||
auto getSystemClassLoader = env->GetStaticMethodID(clClass, "getSystemClassLoader",
|
auto getSystemClassLoader = env->GetStaticMethodID(clClass, "getSystemClassLoader",
|
||||||
@ -201,11 +203,11 @@ public:
|
|||||||
auto systemClassLoader = env->CallStaticObjectMethod(clClass, getSystemClassLoader);
|
auto systemClassLoader = env->CallStaticObjectMethod(clClass, getSystemClassLoader);
|
||||||
|
|
||||||
LOGD("create class loader");
|
LOGD("create class loader");
|
||||||
auto dexClClass = env->FindClass("dalvik/system/PathClassLoader");
|
auto dexClClass = env->FindClass("dalvik/system/InMemoryDexClassLoader");
|
||||||
auto dexClInit = env->GetMethodID(dexClClass, "<init>",
|
auto dexClInit = env->GetMethodID(dexClClass, "<init>",
|
||||||
"(Ljava/lang/String;Ljava/lang/ClassLoader;)V");
|
"(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V");
|
||||||
auto dexStr = env->NewStringUTF(classesDex.c_str());
|
auto buffer = env->NewDirectByteBuffer(dexBuffer, dexSize);
|
||||||
auto dexCl = env->NewObject(dexClClass, dexClInit, dexStr, systemClassLoader);
|
auto dexCl = env->NewObject(dexClClass, dexClInit, buffer, systemClassLoader);
|
||||||
|
|
||||||
LOGD("load class");
|
LOGD("load class");
|
||||||
auto loadClass = env->GetMethodID(clClass, "loadClass",
|
auto loadClass = env->GetMethodID(clClass, "loadClass",
|
||||||
@ -220,7 +222,16 @@ public:
|
|||||||
auto str = env->NewStringUTF(json.dump().c_str());
|
auto str = env->NewStringUTF(json.dump().c_str());
|
||||||
env->CallStaticVoidMethod(entryClass, entryInit, str);
|
env->CallStaticVoidMethod(entryClass, entryInit, str);
|
||||||
|
|
||||||
dir.clear();
|
env->DeleteLocalRef(clClass);
|
||||||
|
env->DeleteLocalRef(dexClClass);
|
||||||
|
env->DeleteLocalRef(buffer);
|
||||||
|
env->DeleteLocalRef(dexCl);
|
||||||
|
env->DeleteLocalRef(entryClassName);
|
||||||
|
env->DeleteLocalRef(entryClassObj);
|
||||||
|
env->DeleteLocalRef(str);
|
||||||
|
|
||||||
|
delete[] dexBuffer;
|
||||||
|
delete[] jsonBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void preServerSpecialize(zygisk::ServerSpecializeArgs *args) override {
|
void preServerSpecialize(zygisk::ServerSpecializeArgs *args) override {
|
||||||
@ -230,42 +241,53 @@ public:
|
|||||||
private:
|
private:
|
||||||
zygisk::Api *api = nullptr;
|
zygisk::Api *api = nullptr;
|
||||||
JNIEnv *env = nullptr;
|
JNIEnv *env = nullptr;
|
||||||
std::string dir;
|
long dexSize = 0, jsonSize = 0;
|
||||||
|
unsigned char *dexBuffer = nullptr;
|
||||||
|
char *jsonBuffer = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void companion(int fd) {
|
static void companion(int fd) {
|
||||||
|
long dexSize = 0, jsonSize = 0;
|
||||||
|
unsigned char *dexBuffer = nullptr;
|
||||||
|
char *jsonBuffer = nullptr;
|
||||||
|
|
||||||
long size = 0;
|
FILE *dexFile = fopen(CLASSES_DEX, "rb");
|
||||||
std::string dir;
|
|
||||||
|
|
||||||
read(fd, &size, sizeof(long));
|
if (dexFile) {
|
||||||
|
|
||||||
dir.resize(size);
|
fseek(dexFile, 0, SEEK_END);
|
||||||
|
dexSize = ftell(dexFile);
|
||||||
|
fseek(dexFile, 0, SEEK_SET);
|
||||||
|
|
||||||
read(fd, dir.data(), size);
|
dexBuffer = new unsigned char[dexSize];
|
||||||
|
fread(dexBuffer, 1, dexSize, dexFile);
|
||||||
|
|
||||||
LOGD("[ROOT] GMS dir: %s", dir.c_str());
|
fclose(dexFile);
|
||||||
|
}
|
||||||
|
|
||||||
std::string classesDex(dir + "/classes.dex");
|
write(fd, &dexSize, sizeof(long));
|
||||||
std::string pifJson(dir + "/pif.json");
|
write(fd, dexBuffer, dexSize);
|
||||||
|
|
||||||
bool a = std::filesystem::copy_file(CLASSES_DEX, classesDex,
|
delete[] dexBuffer;
|
||||||
std::filesystem::copy_options::overwrite_existing);
|
|
||||||
|
|
||||||
std::filesystem::permissions(classesDex, std::filesystem::perms::owner_read |
|
FILE *jsonFile = fopen(PIF_JSON, "r");
|
||||||
std::filesystem::perms::group_read |
|
|
||||||
std::filesystem::perms::others_read);
|
|
||||||
|
|
||||||
bool b = std::filesystem::copy_file(PIF_JSON, pifJson,
|
if (jsonFile) {
|
||||||
std::filesystem::copy_options::overwrite_existing);
|
|
||||||
|
|
||||||
std::filesystem::permissions(pifJson, std::filesystem::perms::owner_read |
|
fseek(jsonFile, 0, SEEK_END);
|
||||||
std::filesystem::perms::group_read |
|
jsonSize = ftell(jsonFile);
|
||||||
std::filesystem::perms::others_read);
|
fseek(jsonFile, 0, SEEK_SET);
|
||||||
|
|
||||||
bool done = a && b;
|
jsonBuffer = new char[jsonSize];
|
||||||
|
fread(jsonBuffer, 1, jsonSize, jsonFile);
|
||||||
|
|
||||||
write(fd, &done, sizeof(bool));
|
fclose(jsonFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
write(fd, &jsonSize, sizeof(long));
|
||||||
|
write(fd, jsonBuffer, jsonSize);
|
||||||
|
|
||||||
|
delete[] jsonBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
REGISTER_ZYGISK_MODULE(PlayIntegrityFix)
|
REGISTER_ZYGISK_MODULE(PlayIntegrityFix)
|
||||||
|
@ -14,7 +14,8 @@ import java.util.Date;
|
|||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
|
|
||||||
public class CustomKeyStoreSpi extends KeyStoreSpi {
|
public class CustomKeyStoreSpi extends KeyStoreSpi {
|
||||||
public static volatile KeyStoreSpi keyStoreSpi;
|
public static KeyStoreSpi keyStoreSpi;
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Key engineGetKey(String alias, char[] password) throws NoSuchAlgorithmException, UnrecoverableKeyException {
|
public Key engineGetKey(String alias, char[] password) throws NoSuchAlgorithmException, UnrecoverableKeyException {
|
||||||
@ -23,14 +24,8 @@ public class CustomKeyStoreSpi extends KeyStoreSpi {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Certificate[] engineGetCertificateChain(String alias) {
|
public Certificate[] engineGetCertificateChain(String alias) {
|
||||||
|
EntryPoint.LOG("Tried to get certificate chain, throwing exception!");
|
||||||
if (EntryPoint.isDroidGuard()) {
|
throw new UnsupportedOperationException();
|
||||||
|
|
||||||
EntryPoint.LOG("engineGetCertificateChain call! Throw exception");
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
return keyStoreSpi.engineGetCertificateChain(alias);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -2,7 +2,7 @@ package es.chiteroman.playintegrityfix;
|
|||||||
|
|
||||||
import java.security.Provider;
|
import java.security.Provider;
|
||||||
|
|
||||||
public class CustomProvider extends Provider {
|
public final class CustomProvider extends Provider {
|
||||||
|
|
||||||
public CustomProvider(Provider provider) {
|
public CustomProvider(Provider provider) {
|
||||||
super(provider.getName(), provider.getVersion(), provider.getInfo());
|
super(provider.getName(), provider.getVersion(), provider.getInfo());
|
||||||
@ -14,7 +14,6 @@ public class CustomProvider extends Provider {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized Service getService(String type, String algorithm) {
|
public synchronized Service getService(String type, String algorithm) {
|
||||||
EntryPoint.LOG("[SERVICE] Type: " + type + " | Algorithm: " + algorithm);
|
|
||||||
|
|
||||||
EntryPoint.spoofDevice();
|
EntryPoint.spoofDevice();
|
||||||
|
|
||||||
|
@ -1,66 +1,58 @@
|
|||||||
package es.chiteroman.playintegrityfix;
|
package es.chiteroman.playintegrityfix;
|
||||||
|
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.util.JsonReader;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import java.io.StringReader;
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.security.KeyStore;
|
|
||||||
import java.security.KeyStoreSpi;
|
|
||||||
import java.security.Provider;
|
import java.security.Provider;
|
||||||
import java.security.Security;
|
import java.security.Security;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class EntryPoint {
|
public final class EntryPoint {
|
||||||
private static final Map<String, String> map = new HashMap<>();
|
private static JSONObject jsonObject = new JSONObject();
|
||||||
|
|
||||||
public static void init(String json) {
|
public static void init(String json) {
|
||||||
|
|
||||||
try (JsonReader reader = new JsonReader(new StringReader(json))) {
|
try {
|
||||||
reader.beginObject();
|
jsonObject = new JSONObject(json);
|
||||||
while (reader.hasNext()) {
|
} catch (JSONException e) {
|
||||||
String key = reader.nextName();
|
LOG("Couldn't parse JSON from Zygisk");
|
||||||
String value = reader.nextString();
|
|
||||||
map.put(key, value);
|
|
||||||
}
|
|
||||||
reader.endObject();
|
|
||||||
} catch (Exception e) {
|
|
||||||
LOG("Error parsing JSON: " + e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG("Map info (keys and values):");
|
boolean FORCE_BASIC_ATTESTATION = true;
|
||||||
map.forEach((s, s2) -> LOG(String.format("[%s] -> %s", s, s2)));
|
|
||||||
|
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();
|
spoofDevice();
|
||||||
spoofProvider();
|
|
||||||
|
if (FORCE_BASIC_ATTESTATION) spoofProvider();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static void LOG(String msg) {
|
static void LOG(String msg) {
|
||||||
Log.d("PIF/Java", msg);
|
Log.d("PIF/Java", msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static void spoofDevice() {
|
static void spoofDevice() {
|
||||||
map.forEach(EntryPoint::setFieldValue);
|
jsonObject.keys().forEachRemaining(s -> {
|
||||||
}
|
try {
|
||||||
|
Object value = jsonObject.get(s);
|
||||||
protected static boolean isDroidGuard() {
|
setFieldValue(s, value);
|
||||||
return Arrays.stream(Thread.currentThread().getStackTrace()).anyMatch(e -> e.getClassName().toLowerCase(Locale.US).contains("droidguard"));
|
} catch (JSONException ignored) {
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void spoofProvider() {
|
private static void spoofProvider() {
|
||||||
try {
|
try {
|
||||||
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
|
|
||||||
|
|
||||||
Field field = keyStore.getClass().getDeclaredField("keyStoreSpi");
|
|
||||||
|
|
||||||
field.setAccessible(true);
|
|
||||||
CustomKeyStoreSpi.keyStoreSpi = (KeyStoreSpi) field.get(keyStore);
|
|
||||||
field.setAccessible(false);
|
|
||||||
|
|
||||||
Provider provider = Security.getProvider("AndroidKeyStore");
|
Provider provider = Security.getProvider("AndroidKeyStore");
|
||||||
|
|
||||||
Provider customProvider = new CustomProvider(provider);
|
Provider customProvider = new CustomProvider(provider);
|
||||||
@ -70,14 +62,18 @@ public class EntryPoint {
|
|||||||
|
|
||||||
LOG("Spoof KeyStoreSpi and Provider done!");
|
LOG("Spoof KeyStoreSpi and Provider done!");
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Throwable t) {
|
||||||
LOG("spoofProvider exception: " + e);
|
LOG("spoofProvider exception: " + t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void setFieldValue(String name, String value) {
|
private static void setFieldValue(String name, Object value) {
|
||||||
if (name == null || value == null || name.isEmpty() || value.isEmpty()) return;
|
if (name == null || value == null || name.isEmpty()) return;
|
||||||
|
|
||||||
|
if (value instanceof String str) if (str.isEmpty() || str.isBlank()) return;
|
||||||
|
|
||||||
Field field = null;
|
Field field = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
field = Build.class.getDeclaredField(name);
|
field = Build.class.getDeclaredField(name);
|
||||||
} catch (NoSuchFieldException e) {
|
} catch (NoSuchFieldException e) {
|
||||||
@ -87,16 +83,23 @@ public class EntryPoint {
|
|||||||
LOG("Couldn't find field: " + e);
|
LOG("Couldn't find field: " + e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (field == null) return;
|
if (field == null) return;
|
||||||
|
|
||||||
field.setAccessible(true);
|
field.setAccessible(true);
|
||||||
String oldValue = null;
|
|
||||||
try {
|
try {
|
||||||
oldValue = (String) field.get(null);
|
|
||||||
if (value.equals(oldValue)) return;
|
Object oldValue = field.get(null);
|
||||||
field.set(null, value);
|
|
||||||
|
if (!value.equals(oldValue)) {
|
||||||
|
|
||||||
|
field.set(null, value);
|
||||||
|
LOG("Set [" + name + "] field value to [" + value + "]");
|
||||||
|
}
|
||||||
|
|
||||||
} catch (IllegalAccessException e) {
|
} catch (IllegalAccessException e) {
|
||||||
LOG("Couldn't get or set field: " + e);
|
LOG("Couldn't modify field :(");
|
||||||
}
|
}
|
||||||
LOG(String.format("Field '%s' with value '%s' is now set to '%s'", name, oldValue, value));
|
field.setAccessible(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,6 +2,6 @@ We have a Telegram channel!
|
|||||||
If you want to share your knowledge join:
|
If you want to share your knowledge join:
|
||||||
https://t.me/playintegrityfix
|
https://t.me/playintegrityfix
|
||||||
|
|
||||||
# v14.9
|
# v15.0
|
||||||
|
|
||||||
- Fix DEVICE verdict not passing with some fingerprints.
|
- Fix issues.
|
@ -1,32 +0,0 @@
|
|||||||
resetprop_if_diff() {
|
|
||||||
local NAME=$1
|
|
||||||
local EXPECTED=$2
|
|
||||||
local CURRENT=$(resetprop $NAME)
|
|
||||||
|
|
||||||
[ -z "$CURRENT" ] || [ "$CURRENT" == "$EXPECTED" ] || resetprop $NAME $EXPECTED
|
|
||||||
}
|
|
||||||
|
|
||||||
resetprop_if_match() {
|
|
||||||
local NAME=$1
|
|
||||||
local CONTAINS=$2
|
|
||||||
local VALUE=$3
|
|
||||||
|
|
||||||
[[ "$(resetprop $NAME)" == *"$CONTAINS"* ]] && resetprop $NAME $VALUE
|
|
||||||
}
|
|
||||||
|
|
||||||
# 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
|
|
||||||
resetprop_if_diff vendor.boot.vbmeta.device_state locked
|
|
||||||
|
|
||||||
# Restrict permissions to socket file
|
|
||||||
chmod 440 /proc/net/unix
|
|
@ -52,7 +52,7 @@ if [ -d "/system/app/EliteDevelopmentModule" ]; then
|
|||||||
ui_print "- EliteDevelopmentModule app removed."
|
ui_print "- EliteDevelopmentModule app removed."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Move pif.json file
|
# Move empty pif.json file
|
||||||
if [ ! -f "/data/adb/pif.json" ]; then
|
if [ ! -f "/data/adb/pif.json" ]; then
|
||||||
mv -f $MODPATH/pif.json /data/adb/
|
mv -f $MODPATH/pif.json /data/adb/
|
||||||
fi
|
fi
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
id=playintegrityfix
|
id=playintegrityfix
|
||||||
name=Play Integrity Fix
|
name=Play Integrity Fix
|
||||||
version=v14.9
|
version=v15.0
|
||||||
versionCode=14900
|
versionCode=15000
|
||||||
author=chiteroman
|
author=chiteroman
|
||||||
description=Universal modular fix for Play Integrity (and SafetyNet) on devices running Android 8+.
|
description=Universal modular fix for Play Integrity (and SafetyNet) on devices running Android 8+.
|
||||||
updateJson=https://raw.githubusercontent.com/chiteroman/PlayIntegrityFix/main/update.json
|
updateJson=https://raw.githubusercontent.com/chiteroman/PlayIntegrityFix/main/update.json
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
{
|
{
|
||||||
"PRODUCT": "",
|
"PRODUCT": "",
|
||||||
"DEVICE": "",
|
"DEVICE": "",
|
||||||
"MANUFACTURER": "",
|
"MANUFACTURER": "",
|
||||||
"BRAND": "",
|
"BRAND": "",
|
||||||
"MODEL": "",
|
"MODEL": "",
|
||||||
"FINGERPRINT": "",
|
"FINGERPRINT": "",
|
||||||
"FIRST_API_LEVEL": 21,
|
"SECURITY_PATCH": "",
|
||||||
"SECURITY_PATCH": "",
|
"ID": "",
|
||||||
"BUILD_ID": ""
|
"FIRST_API_LEVEL": 24,
|
||||||
|
"FORCE_BASIC_ATTESTATION": true
|
||||||
}
|
}
|
||||||
|
@ -32,29 +32,21 @@ if [ "$(toybox cat /sys/fs/selinux/enforce)" == "0" ]; then
|
|||||||
chmod 440 /sys/fs/selinux/policy
|
chmod 440 /sys/fs/selinux/policy
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# KernelSU handles boot completed state in different file.
|
# late props which must be set after boot_completed for various OEMs
|
||||||
if [ -z "$KSU" ] || [ "$KSU" = false ]; then
|
until [ "$(resetprop sys.boot_completed)" == "1" ]; do
|
||||||
{
|
sleep 1
|
||||||
# late props which must be set after boot_completed for various OEMs
|
done
|
||||||
until [ "$(resetprop sys.boot_completed)" == "1" ]; do
|
|
||||||
sleep 1
|
|
||||||
done
|
|
||||||
|
|
||||||
# Avoid breaking Realme fingerprint scanners
|
# Avoid breaking Realme fingerprint scanners
|
||||||
resetprop_if_diff ro.boot.flash.locked 1
|
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
|
||||||
|
resetprop_if_diff vendor.boot.vbmeta.device_state locked
|
||||||
|
|
||||||
# Avoid breaking Oppo fingerprint scanners
|
# Restrict permissions to socket file
|
||||||
resetprop_if_diff ro.boot.vbmeta.device_state locked
|
chmod 440 /proc/net/unix
|
||||||
|
|
||||||
# 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
|
|
||||||
resetprop_if_diff vendor.boot.vbmeta.device_state locked
|
|
||||||
|
|
||||||
# Restrict permissions to socket file
|
|
||||||
chmod 440 /proc/net/unix
|
|
||||||
}&
|
|
||||||
fi
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"version": "v14.9",
|
"version": "v15.0",
|
||||||
"versionCode": 14900,
|
"versionCode": 15000,
|
||||||
"zipUrl": "https://github.com/chiteroman/PlayIntegrityFix/releases/download/v14.9/PlayIntegrityFix_v14.9.zip",
|
"zipUrl": "https://github.com/chiteroman/PlayIntegrityFix/releases/download/v15.0/PlayIntegrityFix_v15.0.zip",
|
||||||
"changelog": "https://raw.githubusercontent.com/chiteroman/PlayIntegrityFix/main/changelog.md"
|
"changelog": "https://raw.githubusercontent.com/chiteroman/PlayIntegrityFix/main/changelog.md"
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user