This commit is contained in:
chiteroman 2024-02-08 12:33:37 +01:00
parent 0dd66bfe1d
commit 1f6fadf058
8 changed files with 81 additions and 60 deletions

View File

@ -12,8 +12,8 @@ android {
applicationId = "es.chiteroman.playintegrityfix" applicationId = "es.chiteroman.playintegrityfix"
minSdk = 26 minSdk = 26
targetSdk = 34 targetSdk = 34
versionCode = 15701 versionCode = 15702
versionName = "v15.7.1" versionName = "v15.7.2"
multiDexEnabled = false multiDexEnabled = false
buildFeatures { buildFeatures {

View File

@ -16,11 +16,13 @@ static std::string FIRST_API_LEVEL, SECURITY_PATCH, BUILD_ID;
typedef void (*T_Callback)(void *, const char *, const char *, uint32_t); 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) { static void modify_callback(void *cookie, const char *name, const char *value, uint32_t serial) {
if (cookie == nullptr || name == nullptr || value == nullptr || o_callback == nullptr) return; if (cookie == nullptr || name == nullptr || value == nullptr ||
!callbacks.contains(cookie))
return;
std::string_view prop(name); std::string_view prop(name);
@ -52,7 +54,7 @@ static void modify_callback(void *cookie, const char *name, const char *value, u
} }
return o_callback(cookie, name, value, serial); return callbacks[cookie](cookie, name, value, serial);
} }
static void (*o_system_property_read_callback)(const void *, T_Callback, void *); static void (*o_system_property_read_callback)(const void *, T_Callback, void *);
@ -62,12 +64,12 @@ my_system_property_read_callback(const void *pi, T_Callback callback, void *cook
if (pi == nullptr || callback == nullptr || cookie == nullptr) { if (pi == nullptr || callback == nullptr || cookie == nullptr) {
return o_system_property_read_callback(pi, callback, cookie); 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); return o_system_property_read_callback(pi, modify_callback, cookie);
} }
static void doHook() { static void doHook() {
void *handle = DobbySymbolResolver("libc.so", "__system_property_read_callback"); void *handle = DobbySymbolResolver(nullptr, "__system_property_read_callback");
if (handle == nullptr) { if (handle == nullptr) {
LOGD("Couldn't hook '__system_property_read_callback'. Report to @chiteroman"); LOGD("Couldn't hook '__system_property_read_callback'. Report to @chiteroman");
return; return;

View File

@ -15,7 +15,7 @@ import java.util.Enumeration;
import java.util.Locale; import java.util.Locale;
public final class CustomKeyStoreSpi extends KeyStoreSpi { public final class CustomKeyStoreSpi extends KeyStoreSpi {
public static volatile KeyStoreSpi keyStoreSpi; public static volatile KeyStoreSpi keyStoreSpi = null;
@Override @Override
public Key engineGetKey(String alias, char[] password) throws NoSuchAlgorithmException, UnrecoverableKeyException { public Key engineGetKey(String alias, char[] password) throws NoSuchAlgorithmException, UnrecoverableKeyException {

View File

@ -4,19 +4,19 @@ import java.security.Provider;
public final class CustomProvider extends Provider { public final class CustomProvider extends Provider {
public CustomProvider(Provider provider) { public CustomProvider(Provider provider, boolean spoof) {
super(provider.getName(), provider.getVersion(), provider.getInfo()); super(provider.getName(), provider.getVersion(), provider.getInfo());
putAll(provider); putAll(provider);
put("KeyStore.AndroidKeyStore", CustomKeyStoreSpi.class.getName()); if (spoof) put("KeyStore.AndroidKeyStore", CustomKeyStoreSpi.class.getName());
} }
@Override @Override
public synchronized Service getService(String type, String algorithm) { public synchronized Service getService(String type, String algorithm) {
EntryPoint.LOG(String.format("Service: '%s' | Algorithm: '%s'", type, algorithm)); EntryPoint.LOG(String.format("Service: '%s' | Algorithm: '%s'", type, algorithm));
EntryPoint.spoofFields(); if ("AndroidKeyStore".equals(algorithm)) EntryPoint.spoofFields();
return super.getService(type, algorithm); return super.getService(type, algorithm);
} }

View File

@ -17,6 +17,7 @@ public final class EntryPoint {
private static final Map<Field, String> map = new HashMap<>(); private static final Map<Field, String> map = new HashMap<>();
static { static {
boolean spoof = false;
try { try {
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
@ -24,13 +25,16 @@ public final class EntryPoint {
field.setAccessible(true); field.setAccessible(true);
CustomKeyStoreSpi.keyStoreSpi = (KeyStoreSpi) field.get(keyStore); CustomKeyStoreSpi.keyStoreSpi = (KeyStoreSpi) field.get(keyStore);
if (CustomKeyStoreSpi.keyStoreSpi != null) spoof = true;
} catch (Throwable t) { } catch (Throwable t) {
LOG("Error spoofing AndroidKeyStore: " + t); LOG("Error spoofing AndroidKeyStore: " + t);
} }
Provider provider = Security.getProvider("AndroidKeyStore"); Provider provider = Security.getProvider("AndroidKeyStore");
Provider customProvider = new CustomProvider(provider); Provider customProvider = new CustomProvider(provider, spoof);
Security.removeProvider("AndroidKeyStore"); Security.removeProvider("AndroidKeyStore");
Security.insertProviderAt(customProvider, 1); Security.insertProviderAt(customProvider, 1);

View File

@ -1,7 +1,7 @@
id=playintegrityfix id=playintegrityfix
name=Play Integrity Fix name=Play Integrity Fix
version=v15.7.1 version=v15.7.2
versionCode=15701 versionCode=15702
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

View File

@ -8,3 +8,30 @@ if [ -d /data/adb/modules/safetynet-fix ]; then
rm -rf /data/adb/modules/safetynet-fix rm -rf /data/adb/modules/safetynet-fix
rm -rf /data/adb/SNFix.dex rm -rf /data/adb/SNFix.dex
fi fi
resetprop_if_diff() {
local NAME="$1"
local EXPECTED="$2"
local CURRENT="$(resetprop "$NAME")"
[ -z "$CURRENT" ] || [ "$CURRENT" = "$EXPECTED" ] || resetprop "$NAME" "$EXPECTED"
}
# Conditional early sensitive properties
# 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
# Microsoft, RootBeer
resetprop_if_diff ro.build.tags release-keys
# Other
resetprop_if_diff ro.build.type user
resetprop_if_diff ro.debuggable 0
resetprop_if_diff ro.secure 1

View File

@ -1,19 +1,19 @@
# Conditional sensitive properties # Conditional sensitive properties
resetprop_if_diff() { resetprop_if_diff() {
local NAME=$1 local NAME="$1"
local EXPECTED=$2 local EXPECTED="$2"
local CURRENT=$(resetprop $NAME) local CURRENT="$(resetprop "$NAME")"
[ -z "$CURRENT" ] || [ "$CURRENT" == "$EXPECTED" ] || resetprop $NAME $EXPECTED [ -z "$CURRENT" ] || [ "$CURRENT" = "$EXPECTED" ] || resetprop "$NAME" "$EXPECTED"
} }
resetprop_if_match() { resetprop_if_match() {
local NAME=$1 local NAME="$1"
local CONTAINS=$2 local CONTAINS="$2"
local VALUE=$3 local VALUE="$3"
[[ "$(resetprop $NAME)" == *"$CONTAINS"* ]] && resetprop $NAME $VALUE [[ "$(resetprop "$NAME")" = *"$CONTAINS"* ]] && resetprop "$NAME" "$VALUE"
} }
# Magisk recovery mode # Magisk recovery mode
@ -32,34 +32,15 @@ if [ "$(toybox cat /sys/fs/selinux/enforce)" == "0" ]; then
chmod 440 /sys/fs/selinux/policy chmod 440 /sys/fs/selinux/policy
fi fi
# Conditional late sensitive properties
# SafetyNet/Play Integrity
{
# must be set after boot_completed for various OEMs # must be set after boot_completed for various OEMs
until [ "$(getprop sys.boot_completed)" == "1" ]; do until [ "$(getprop sys.boot_completed)" = "1" ]; do
sleep 1 sleep 1
done done
# 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
# Xiaomi
resetprop_if_diff ro.secureboot.lockstate locked
# Realme
resetprop_if_diff ro.boot.realmebootstate green
# 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
# 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
resetprop_if_diff ro.boot.realme.lockstate 1 resetprop_if_diff ro.boot.realme.lockstate 1
@ -74,3 +55,10 @@ resetprop_if_diff vendor.boot.verifiedbootstate green
resetprop_if_diff ro.boot.verifiedbootstate green resetprop_if_diff ro.boot.verifiedbootstate green
resetprop_if_diff ro.boot.veritymode enforcing resetprop_if_diff ro.boot.veritymode enforcing
resetprop_if_diff vendor.boot.vbmeta.device_state locked resetprop_if_diff vendor.boot.vbmeta.device_state locked
# Xiaomi
resetprop_if_diff ro.secureboot.lockstate locked
# Realme
resetprop_if_diff ro.boot.realmebootstate green
}&