Merge remote-tracking branch 'upstream/custom' into upstream

This commit is contained in:
osm0sis
2023-11-30 08:48:54 -04:00
23 changed files with 1209 additions and 947 deletions

4
.gitignore vendored
View File

@@ -13,3 +13,7 @@
.externalNativeBuild
.cxx
local.properties
/module/classes.dex
/module/pif.json
/module/zygisk/*
/out/*

10
.idea/deploymentTargetDropDown.xml generated Normal file
View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="deploymentTargetDropDown">
<value>
<entry key="app">
<State />
</entry>
</value>
</component>
</project>

6
.idea/encodings.xml generated
View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="file://$PROJECT_DIR$/app/src/main/cpp/stlsoft/stlsoft/stlsoft.h" charset="windows-1252" />
</component>
</project>

5
.idea/gradle.xml generated
View File

@@ -4,16 +4,15 @@
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="testRunner" value="GRADLE" />
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="jbr-17" />
<option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
<option name="resolveExternalAnnotations" value="false" />
</GradleProjectSettings>
</option>
</component>

10
.idea/migrations.xml generated Normal file
View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectMigrations">
<option name="MigrateToGradleLocalJavaHome">
<set>
<option value="$PROJECT_DIR$" />
</set>
</option>
</component>
</project>

1
.idea/vcs.xml generated
View File

@@ -2,5 +2,6 @@
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
<mapping directory="$PROJECT_DIR$/app/src/main/cpp/libcxx" vcs="Git" />
</component>
</project>

View File

@@ -1,9 +1,8 @@
# Play Integrity Fix
A Zygisk module which fix "ctsProfileMatch" (SafetyNet) and "MEETS_DEVICE_INTEGRITY" (Play
Integrity).
A Zygisk module which fixes "ctsProfileMatch" (SafetyNet) and "MEETS_DEVICE_INTEGRITY" (Play Integrity).
To use this module you must have one of this:
To use this module you must have one of the following:
- Magisk with Zygisk enabled.
- KernelSU with [ZygiskNext](https://github.com/Dr-TSNG/ZygiskNext) module installed.
@@ -24,46 +23,41 @@ https://t.me/playintegrityfix
## About module
It injects a classes.dex file to modify few fields in android.os.Build class. Also, in native code
it creates a hook to modify system properties.
It injects a classes.dex file to modify a few fields in the android.os.Build class. Also, it creates a hook in the native code to modify system properties. These are spoofed only to Google Play Services' DroidGuard (SafetyNet/Play Integrity) service.
The purpose of the module is to avoid a hardware attestation.
## About 'pif.json' file
## About 'custom.pif.json' file
You can modify this file to spoof android.os.Build fields in GMS unstable process and try to pass Device verdict.
You can't use values from recent devices due this devices must use a hardware attestation.
You can create this file in the module directory to spoof custom values to the GMS unstable process. It will be used instead of the included pif.json.
## Failing BASIC verdict
If you are failing basicIntegrity (SafetyNet) or MEETS_BASIC_INTEGRITY (Play Integrity) something is
wrong in your setup. My recommended steps in order to find the problem:
- Disable all modules except mine.
- Check your SELinux (must be enforced).
Some modules which modify system can trigger DroidGuard detection, never hook GMS processes.
## Certify Play Store and fix Google Wallet
Follow this steps:
- Flash my module in Magisk/KernelSU (if you already have my module, just ignore this step).
- Clear Google Wallet cache (if you have it).
- Clear Google Play Store cache and data.
- Clear Google Play Services (com.google.android.gms) cache and data (Optionally skip clearing data and wait some time, ~24h, for it to resolve on its own).
- Reboot
You can't use values from recent devices due them triggering hardware backed attestation.
## Troubleshooting
### Fails to meet device integrity (KernelSU)
### Failing BASIC verdict
If you are failing basicIntegrity (SafetyNet) or MEETS_BASIC_INTEGRITY (Play Integrity) something is wrong in your setup. Recommended steps in order to find the problem:
- Disable all modules except this one
Some modules which modify system can trigger DroidGuard detection, never hook GMS processes.
### Failing DEVICE verdict (on KernelSU)
- Disable ZygiskNext
- Reboot
- Enable ZygiskNext
### Passes device integrity, but fails in Wallet (even after clearing cache)
### Play Protect/Store Certification and Google Wallet Tap To Pay Setup Security Requirements
- Remove all data from Google Play Services
Follow these steps:
- Flash the module in Magisk/KernelSU
- Clear Google Wallet cache (if you have it)
- Clear Google Play Store cache and data
- Clear Google Play Services (com.google.android.gms) cache and data (Optionally skip clearing data and wait some time, ~24h, for it to resolve on its own)
- Reboot
<details>
<summary>Guide</summary>
@@ -73,9 +67,9 @@ Follow this steps:
</details>
## Read module logs
### Read module logs
You can read module logs using this command:
You can read module logs using this command directly after boot:
```
adb shell "logcat | grep 'PIF'"

View File

@@ -42,4 +42,33 @@ android {
path = file("src/main/cpp/Android.mk")
}
}
}
tasks.register("copyFiles") {
doLast {
val moduleFolder = project.rootDir.resolve("module")
val dexFile = project.buildDir.resolve("intermediates/dex/release/minifyReleaseWithR8/classes.dex")
val soDir = project.buildDir.resolve("intermediates/stripped_native_libs/release/out/lib")
dexFile.copyTo(moduleFolder.resolve("classes.dex"), overwrite = true)
soDir.walk().filter { it.isFile && it.extension == "so" }.forEach { soFile ->
val abiFolder = soFile.parentFile.name
val destination = moduleFolder.resolve("zygisk/$abiFolder.so")
soFile.copyTo(destination, overwrite = true)
}
}
}
tasks.register<Zip>("zip") {
dependsOn("copyFiles")
archiveFileName.set("PlayIntegrityFix.zip")
destinationDirectory.set(project.rootDir.resolve("out"))
from(project.rootDir.resolve("module"))
}
afterEvaluate {
tasks["assembleRelease"].finalizedBy("copyFiles", "zip")
}

View File

@@ -1,4 +1,3 @@
APP_STL := none
APP_CFLAGS := -Oz -fno-exceptions -fno-rtti -fvisibility=hidden -fvisibility-inlines-hidden
APP_CPPFLAGS := -std=c++20
APP_LDFLAGS := -Oz
APP_CPPFLAGS := -std=c++20

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,6 @@
#include <android/log.h>
#include <sys/system_properties.h>
#include <unistd.h>
#include <fstream>
#include "zygisk.hpp"
#include "shadowhook.h"
@@ -11,7 +10,9 @@
#define DEX_FILE_PATH "/data/adb/modules/playintegrityfix/classes.dex"
#define PROP_FILE_PATH "/data/adb/modules/playintegrityfix/pif.json"
#define JSON_FILE_PATH "/data/adb/modules/playintegrityfix/pif.json"
#define CUSTOM_JSON_FILE_PATH "/data/adb/modules/playintegrityfix/custom.pif.json"
static std::string FIRST_API_LEVEL, SECURITY_PATCH;
@@ -28,15 +29,17 @@ static void modify_callback(void *cookie, const char *name, const char *value, u
std::string_view prop(name);
if (prop.ends_with("api_level")) {
if (FIRST_API_LEVEL == "NULL") {
if (FIRST_API_LEVEL.empty()) {
LOGD("FIRST_API_LEVEL is empty, ignoring it...");
} else if (FIRST_API_LEVEL == "nullptr") {
value = nullptr;
} else {
value = FIRST_API_LEVEL.c_str();
}
LOGD("[%s] -> %s", name, value);
} else if (prop.ends_with("security_patch")) {
if (SECURITY_PATCH == "NULL") {
value = nullptr;
if (SECURITY_PATCH.empty()) {
LOGD("SECURITY_PATCH is empty, ignoring it...");
} else {
value = SECURITY_PATCH.c_str();
}
@@ -72,27 +75,6 @@ static void doHook() {
LOGD("Found '__system_property_read_callback' handle at %p", handle);
}
static void sendVector(int fd, const std::vector<char> &vec) {
// Send the size of the vector
size_t size = vec.size();
write(fd, &size, sizeof(size_t));
// Send the vector data
write(fd, vec.data(), size);
}
static std::vector<char> receiveVector(int fd) {
// Receive the size of the vector
size_t size;
read(fd, &size, sizeof(size_t));
// Receive the vector data
std::vector<char> vec(size);
read(fd, vec.data(), size);
return vec;
}
class PlayIntegrityFix : public zygisk::ModuleBase {
public:
void onLoad(zygisk::Api *api, JNIEnv *env) override {
@@ -101,15 +83,17 @@ public:
}
void preAppSpecialize(zygisk::AppSpecializeArgs *args) override {
bool isGms = false;
bool isGmsUnstable = false;
bool isGms = false, isGmsUnstable = false;
auto rawProcess = env->GetStringUTFChars(args->nice_name, nullptr);
if (rawProcess) {
std::string_view process(rawProcess);
isGms = process.starts_with("com.google.android.gms");
isGmsUnstable = process.compare("com.google.android.gms.unstable") == 0;
}
env->ReleaseStringUTFChars(args->nice_name, rawProcess);
if (!isGms) {
@@ -124,32 +108,55 @@ public:
return;
}
long dexSize = 0, jsonSize = 0;
int fd = api->connectCompanion();
dexVector = receiveVector(fd);
propVector = receiveVector(fd);
read(fd, &dexSize, sizeof(long));
read(fd, &jsonSize, sizeof(long));
if (dexSize < 1) {
close(fd);
LOGD("Couldn't read classes.dex");
api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY);
return;
}
if (jsonSize < 1) {
close(fd);
LOGD("Couldn't read pif.json");
api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY);
return;
}
dexVector.resize(dexSize);
read(fd, dexVector.data(), dexSize);
std::vector<char> jsonVector(jsonSize);
read(fd, jsonVector.data(), jsonSize);
close(fd);
LOGD("Read from file descriptor file 'classes.dex' -> %d bytes",
static_cast<int>(dexVector.size()));
LOGD("Read from file descriptor file 'pif.json' -> %d bytes",
static_cast<int>(propVector.size()));
LOGD("Read from file descriptor file 'classes.dex' -> %ld bytes", dexSize);
LOGD("Read from file descriptor file 'pif.json' -> %ld bytes", jsonSize);
if (dexVector.empty() || propVector.empty()) api->setOption(zygisk::DLCLOSE_MODULE_LIBRARY);
std::string data(jsonVector.cbegin(), jsonVector.cend());
json = nlohmann::json::parse(data, nullptr, false, true);
jsonVector.clear();
data.clear();
}
void postAppSpecialize(const zygisk::AppSpecializeArgs *args) override {
if (dexVector.empty() || propVector.empty()) return;
if (dexVector.empty() || json.empty()) return;
readJson();
inject();
doHook();
inject();
dexVector.clear();
propVector.clear();
json.clear();
}
void preServerSpecialize(zygisk::ServerSpecializeArgs *args) override {
@@ -159,19 +166,35 @@ public:
private:
zygisk::Api *api = nullptr;
JNIEnv *env = nullptr;
std::vector<char> dexVector, propVector;
std::vector<char> dexVector;
nlohmann::json json;
void readJson() {
std::string data(propVector.cbegin(), propVector.cend());
nlohmann::json json = nlohmann::json::parse(data, nullptr, false, true);
if (json.contains("SECURITY_PATCH")) {
if (json["SECURITY_PATCH"].is_null()) {
LOGD("Key SECURITY_PATCH is null!");
} else if (json["SECURITY_PATCH"].is_string()) {
SECURITY_PATCH = json["SECURITY_PATCH"].get<std::string>();
} else {
LOGD("Error parsing SECURITY_PATCH!");
}
} else {
LOGD("Key SECURITY_PATCH doesn't exist in JSON file!");
}
auto getStringFromJson = [&json](const std::string &key) {
return json.contains(key) && !json[key].is_null() ? json[key].get<std::string>()
: "NULL";
};
SECURITY_PATCH = getStringFromJson("SECURITY_PATCH");
FIRST_API_LEVEL = getStringFromJson("FIRST_API_LEVEL");
if (json.contains("FIRST_API_LEVEL")) {
if (json["FIRST_API_LEVEL"].is_null()) {
LOGD("Key FIRST_API_LEVEL is null!");
FIRST_API_LEVEL = "nullptr";
} else if (json["FIRST_API_LEVEL"].is_string()) {
FIRST_API_LEVEL = json["FIRST_API_LEVEL"].get<std::string>();
} else {
LOGD("Error parsing FIRST_API_LEVEL!");
}
json.erase("FIRST_API_LEVEL");
} else {
LOGD("Key FIRST_API_LEVEL doesn't exist in JSON file!");
}
}
void inject() {
@@ -200,8 +223,7 @@ private:
LOGD("read json");
auto readProps = env->GetStaticMethodID(entryClass, "readJson",
"(Ljava/lang/String;)V");
std::string data(propVector.cbegin(), propVector.cend());
auto javaStr = env->NewStringUTF(data.c_str());
auto javaStr = env->NewStringUTF(json.dump().c_str());
env->CallStaticVoidMethod(entryClass, readProps, javaStr);
LOGD("call init");
@@ -211,22 +233,45 @@ private:
};
static void companion(int fd) {
std::ifstream dex(DEX_FILE_PATH, std::ios::binary);
std::ifstream prop(PROP_FILE_PATH);
long dexSize = 0, jsonSize = 0;
std::vector<char> dexVector, jsonVector;
std::vector<char> dexVector((std::istreambuf_iterator<char>(dex)),
std::istreambuf_iterator<char>());
std::vector<char> propVector((std::istreambuf_iterator<char>(prop)),
std::istreambuf_iterator<char>());
FILE *dex = fopen(DEX_FILE_PATH, "rb");
dex.close();
prop.close();
if (dex) {
fseek(dex, 0, SEEK_END);
dexSize = ftell(dex);
fseek(dex, 0, SEEK_SET);
sendVector(fd, dexVector);
sendVector(fd, propVector);
dexVector.resize(dexSize);
fread(dexVector.data(), 1, dexSize, dex);
fclose(dex);
}
FILE *json = fopen(CUSTOM_JSON_FILE_PATH, "r");
if (!json)
FILE *json = fopen(JSON_FILE_PATH, "r");
if (json) {
fseek(json, 0, SEEK_END);
jsonSize = ftell(json);
fseek(json, 0, SEEK_SET);
jsonVector.resize(jsonSize);
fread(jsonVector.data(), 1, jsonSize, json);
fclose(json);
}
write(fd, &dexSize, sizeof(long));
write(fd, &jsonSize, sizeof(long));
write(fd, dexVector.data(), dexSize);
write(fd, jsonVector.data(), jsonSize);
dexVector.clear();
propVector.clear();
jsonVector.clear();
}
REGISTER_ZYGISK_MODULE(PlayIntegrityFix)

View File

@@ -2,15 +2,12 @@ We have a Telegram channel!
If you want to share your knowledge join:
https://t.me/playintegrityfix
# v13.7
# CUSTOM SPOOF v2.1
DO NOT USE THIS BUILD IF YOU AREN'T A DEVELOPER, ALWAYS USE LATEST STABLE.
THIS BUILD IS JUST FOR TESTING PURPOSES.
- Removed custom resetprop.
- Removed custom props spoof.
- Removed weird code.
If you want an undetectable resetprop, use Kitsune Magisk.
If you want to spoof your own props, modify the props in source code and build by yourself.
Or you can use unstable build, you can download in GitHub repo.
Should work and don't crash nothing.
I recommend to clear GMS data and cache before reboot.
- Fix JSON parsing.
- Less libs size.
- Few code improvements.

View File

@@ -1 +1 @@
#MAGISK
#MAGISK

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,14 +1,23 @@
# Error on < Android 8
if [ "$API" -lt 26 ]; then
abort "!!! You can't use this module on Android < 8.0."
abort "!!! You can't use this module on Android < 8.0"
fi
# safetynet-fix module is incompatible
if [ -d "/data/adb/modules/safetynet-fix" ]; then
touch "/data/adb/modules/safetynet-fix/remove"
ui_print "!!! safetynet-fix module removed!"
# Remove/warn if conflicting modules are installed
if [ -d /data/adb/modules/safetynet-fix ]; then
touch /data/adb/modules/safetynet-fix/remove
ui_print "- 'safetynet-fix' module will be removed on next reboot"
fi
if [ -d /data/adb/modules/MagiskHidePropsConf ]; then
ui_print "- Warning, 'MagiskHidePropsConf' module may cause issues with PIF"
fi
# use our resetprop
mv -f "$MODPATH/bin/$ABI/resetprop" "$MODPATH"
rm -rf "$MODPATH/bin"
# Copy any custom.pif.json to updated module
if [ -f /data/adb/modules/playintegrityfix/custom.pif.json ]; then
ui_print "- Restoring custom.pif.json"
cp -af /data/adb/modules/playintegrityfix/custom.pif.json $MODPATH/custom.pif.json
fi
# Clean up any leftover files from previous deprecated methods
rm -f /data/data/com.google.android.gms/cache/pif.prop /data/data/com.google.android.gms/pif.prop
rm -f /data/data/com.google.android.gms/cache/pif.json /data/data/com.google.android.gms/pif.json

View File

@@ -1,6 +1,7 @@
id=playintegrityfix
name=Play Integrity Fix
version=v1.2-PROPS
versionCode=12
version=PROPS-v2.1
versionCode=2101
author=chiteroman
description=Fix CTS profile (SafetyNet) and DEVICE verdict (Play Integrity).
description=Fix CTS profile (SafetyNet) and DEVICE verdict (Play Integrity).
updateJson=https://raw.githubusercontent.com/chiteroman/PlayIntegrityFix/custom/update.json

View File

@@ -1,10 +0,0 @@
{
"PRODUCT": "taimen",
"DEVICE": "taimen",
"MANUFACTURER": "Google",
"BRAND": "google",
"MODEL": "Pixel 2 XL",
"FINGERPRINT": "google/taimen/taimen:8.1.0/OPM4.171019.021.R1/4833808:user/release-keys",
"SECURITY_PATCH": "2018-07-05",
"FIRST_API_LEVEL": "25"
}

View File

@@ -1,9 +1,43 @@
# Remove Play Services from the Magisk Denylist when set to enforcing
# Remove Play Services from Magisk Denylist when set to enforcing
if magisk --denylist status; then
magisk --denylist rm com.google.android.gms
fi
# Check if safetynet-fix is installed
if [ -d "/data/adb/modules/safetynet-fix" ]; then
touch "/data/adb/modules/safetynet-fix/remove"
fi
# Remove conflicting modules if installed
if [ -d /data/adb/modules/safetynet-fix ]; then
touch /data/adb/modules/safetynet-fix/remove
fi
# Conditional early sensitive properties
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
}
# RootBeer, Microsoft
resetprop_if_diff ro.build.tags release-keys
# Samsung
resetprop_if_diff ro.boot.warranty_bit 0
resetprop_if_diff ro.vendor.boot.warranty_bit 0
resetprop_if_diff ro.vendor.warranty_bit 0
resetprop_if_diff ro.warranty_bit 0
# OnePlus
resetprop_if_diff ro.is_ever_orange 0
# Other
resetprop_if_diff ro.build.type user
resetprop_if_diff ro.debuggable 0
resetprop_if_diff ro.secure 1

View File

@@ -1,76 +1,53 @@
# Sensitive properties
# Conditional sensitive properties
RESETPROP="${0%/*}/resetprop"
resetprop_if_diff() {
local NAME=$1
local EXPECTED=$2
local CURRENT=$(resetprop $NAME)
chmod 755 $RESETPROP
check_resetprop() {
local NAME=$1
local EXPECTED=$2
local VALUE=$(resetprop $NAME)
[ -z $VALUE ] || [ $VALUE = $EXPECTED ] || $RESETPROP -n $NAME $EXPECTED
[ -z "$CURRENT" ] || [ "$CURRENT" == "$EXPECTED" ] || resetprop $NAME $EXPECTED
}
resetprop_if_match() {
local NAME=$1
local CONTAINS=$2
local VALUE=$3
maybe_set_prop() {
local prop="$1"
local contains="$2"
local value="$3"
if [[ "$(getprop "$prop")" == *"$contains"* ]]; then
$RESETPROP -n "$prop" "$value"
fi
[[ "$(resetprop $NAME)" == *"$CONTAINS"* ]] && resetprop $NAME $VALUE
}
# Magisk recovery mode
maybe_set_prop ro.bootmode recovery unknown
maybe_set_prop ro.boot.mode recovery unknown
maybe_set_prop vendor.boot.mode recovery unknown
resetprop_if_match ro.bootmode recovery unknown
resetprop_if_match ro.boot.mode recovery unknown
resetprop_if_match vendor.boot.mode recovery unknown
# Hiding SELinux | Permissive status
if [ -n "$(getprop ro.build.selinux)" ]; then
resetprop --delete ro.build.selinux
# SELinux
if [ -n "$(resetprop ro.build.selinux)" ]; then
resetprop --delete ro.build.selinux
fi
# Hiding SELinux | Use toybox to protect *stat* access time reading
if [[ "$(toybox cat /sys/fs/selinux/enforce)" == "0" ]]; then
# use toybox to protect *stat* access time reading
if [ "$(toybox cat /sys/fs/selinux/enforce)" == "0" ]; then
chmod 640 /sys/fs/selinux/enforce
chmod 440 /sys/fs/selinux/policy
fi
# Reset props after boot completed to avoid breaking some weird devices/ROMs...
# SafetyNet/Play Integrity
{
until [[ "$(getprop sys.boot_completed)" == "1" ]]; do
# late props which must be set after boot_completed for various OEMs
until [ "$(getprop sys.boot_completed)" == "1" ]; do
sleep 1
done
# SafetyNet/Play Integrity | Avoid breaking Realme fingerprint scanners
check_resetprop ro.boot.flash.locked 1
# Avoid breaking Realme fingerprint scanners
resetprop_if_diff ro.boot.flash.locked 1
# SafetyNet/Play Integrity | Avoid breaking Oppo fingerprint scanners
check_resetprop ro.boot.vbmeta.device_state locked
# Avoid breaking Oppo fingerprint scanners
resetprop_if_diff ro.boot.vbmeta.device_state locked
# SafetyNet/Play Integrity | Avoid breaking OnePlus display modes/fingerprint scanners
check_resetprop vendor.boot.verifiedbootstate green
# Avoid breaking OnePlus display modes/fingerprint scanners
resetprop_if_diff vendor.boot.verifiedbootstate green
# SafetyNet/Play Integrity | Avoid breaking OnePlus display modes/fingerprint scanners on OOS 12
check_resetprop ro.boot.verifiedbootstate green
check_resetprop ro.boot.veritymode enforcing
check_resetprop vendor.boot.vbmeta.device_state locked
# RootBeer, Microsoft
check_resetprop ro.build.tags release-keys
# Samsung
check_resetprop ro.boot.warranty_bit 0
check_resetprop ro.vendor.boot.warranty_bit 0
check_resetprop ro.vendor.warranty_bit 0
check_resetprop ro.warranty_bit 0
# OnePlus
check_resetprop ro.is_ever_orange 0
# Other
check_resetprop ro.build.type user
check_resetprop ro.debuggable 0
check_resetprop ro.secure 1
}&
# 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
}&

View File

@@ -1,6 +1,6 @@
{
"version": "v13.7",
"versionCode": 137,
"zipUrl": "https://github.com/chiteroman/PlayIntegrityFix/releases/download/v13.7/PlayIntegrityFix_v13.7.zip",
"changelog": "https://raw.githubusercontent.com/chiteroman/PlayIntegrityFix/main/changelog.md"
}
"version": "v2.1",
"versionCode": 2101,
"zipUrl": "https://github.com/chiteroman/PlayIntegrityFix/releases/download/PROPS/PlayIntegrityFix_PROPS-v2.1.zip",
"changelog": "https://raw.githubusercontent.com/chiteroman/PlayIntegrityFix/custom/changelog.md"
}