mirror of
https://github.com/chiteroman/PlayIntegrityFix.git
synced 2025-01-19 03:22:39 +02:00
v15.7.1
This commit is contained in:
parent
bdef42962f
commit
0dd66bfe1d
6
.idea/vcs.xml
Normal file
6
.idea/vcs.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
@ -12,8 +12,8 @@ android {
|
|||||||
applicationId = "es.chiteroman.playintegrityfix"
|
applicationId = "es.chiteroman.playintegrityfix"
|
||||||
minSdk = 26
|
minSdk = 26
|
||||||
targetSdk = 34
|
targetSdk = 34
|
||||||
versionCode = 15700
|
versionCode = 15701
|
||||||
versionName = "v15.7"
|
versionName = "v15.7.1"
|
||||||
multiDexEnabled = false
|
multiDexEnabled = false
|
||||||
|
|
||||||
buildFeatures {
|
buildFeatures {
|
||||||
|
@ -200,6 +200,68 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void parseJson() {
|
void parseJson() {
|
||||||
|
if (json.contains("FIRST_API_LEVEL")) {
|
||||||
|
|
||||||
|
if (json["FIRST_API_LEVEL"].is_number_integer()) {
|
||||||
|
|
||||||
|
FIRST_API_LEVEL = std::to_string(json["FIRST_API_LEVEL"].get<int>());
|
||||||
|
|
||||||
|
} else if (json["FIRST_API_LEVEL"].is_string()) {
|
||||||
|
|
||||||
|
FIRST_API_LEVEL = json["FIRST_API_LEVEL"].get<std::string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
json.erase("FIRST_API_LEVEL");
|
||||||
|
|
||||||
|
} else if (json.contains("DEVICE_INITIAL_SDK_INT")) {
|
||||||
|
|
||||||
|
if (json["DEVICE_INITIAL_SDK_INT"].is_number_integer()) {
|
||||||
|
|
||||||
|
FIRST_API_LEVEL = std::to_string(json["DEVICE_INITIAL_SDK_INT"].get<int>());
|
||||||
|
|
||||||
|
} else if (json["DEVICE_INITIAL_SDK_INT"].is_string()) {
|
||||||
|
|
||||||
|
FIRST_API_LEVEL = json["DEVICE_INITIAL_SDK_INT"].get<std::string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
LOGD("JSON file doesn't contain FIRST_API_LEVEL or DEVICE_INITIAL_SDK_INT keys :(");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.contains("SECURITY_PATCH")) {
|
||||||
|
|
||||||
|
if (json["SECURITY_PATCH"].is_string()) {
|
||||||
|
|
||||||
|
SECURITY_PATCH = json["SECURITY_PATCH"].get<std::string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
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>();
|
||||||
|
}
|
||||||
|
|
||||||
|
json["ID"] = BUILD_ID;
|
||||||
|
json.erase("BUILD_ID");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
LOGD("JSON file doesn't contain ID/BUILD_ID keys :(");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -0,0 +1,105 @@
|
|||||||
|
package es.chiteroman.playintegrityfix;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.security.Key;
|
||||||
|
import java.security.KeyStoreException;
|
||||||
|
import java.security.KeyStoreSpi;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.UnrecoverableKeyException;
|
||||||
|
import java.security.cert.Certificate;
|
||||||
|
import java.security.cert.CertificateException;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
public final class CustomKeyStoreSpi extends KeyStoreSpi {
|
||||||
|
public static volatile KeyStoreSpi keyStoreSpi;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Key engineGetKey(String alias, char[] password) throws NoSuchAlgorithmException, UnrecoverableKeyException {
|
||||||
|
return keyStoreSpi.engineGetKey(alias, password);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Certificate[] engineGetCertificateChain(String alias) {
|
||||||
|
for (StackTraceElement stackTraceElement : Thread.currentThread().getStackTrace()) {
|
||||||
|
if (stackTraceElement.getClassName().toLowerCase(Locale.US).contains("droidguard")) {
|
||||||
|
EntryPoint.LOG("DroidGuard call certificate chain! Throw exception.");
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return keyStoreSpi.engineGetCertificateChain(alias);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Certificate engineGetCertificate(String alias) {
|
||||||
|
return keyStoreSpi.engineGetCertificate(alias);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Date engineGetCreationDate(String alias) {
|
||||||
|
return keyStoreSpi.engineGetCreationDate(alias);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void engineSetKeyEntry(String alias, Key key, char[] password, Certificate[] chain) throws KeyStoreException {
|
||||||
|
keyStoreSpi.engineSetKeyEntry(alias, key, password, chain);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void engineSetKeyEntry(String alias, byte[] key, Certificate[] chain) throws KeyStoreException {
|
||||||
|
keyStoreSpi.engineSetKeyEntry(alias, key, chain);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void engineSetCertificateEntry(String alias, Certificate cert) throws KeyStoreException {
|
||||||
|
keyStoreSpi.engineSetCertificateEntry(alias, cert);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void engineDeleteEntry(String alias) throws KeyStoreException {
|
||||||
|
keyStoreSpi.engineDeleteEntry(alias);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Enumeration<String> engineAliases() {
|
||||||
|
return keyStoreSpi.engineAliases();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean engineContainsAlias(String alias) {
|
||||||
|
return keyStoreSpi.engineContainsAlias(alias);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int engineSize() {
|
||||||
|
return keyStoreSpi.engineSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean engineIsKeyEntry(String alias) {
|
||||||
|
return keyStoreSpi.engineIsKeyEntry(alias);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean engineIsCertificateEntry(String alias) {
|
||||||
|
return keyStoreSpi.engineIsCertificateEntry(alias);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String engineGetCertificateAlias(Certificate cert) {
|
||||||
|
return keyStoreSpi.engineGetCertificateAlias(cert);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void engineStore(OutputStream stream, char[] password) throws CertificateException, IOException, NoSuchAlgorithmException {
|
||||||
|
keyStoreSpi.engineStore(stream, password);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void engineLoad(InputStream stream, char[] password) throws CertificateException, IOException, NoSuchAlgorithmException {
|
||||||
|
keyStoreSpi.engineLoad(stream, password);
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,6 @@
|
|||||||
package es.chiteroman.playintegrityfix;
|
package es.chiteroman.playintegrityfix;
|
||||||
|
|
||||||
import java.security.Provider;
|
import java.security.Provider;
|
||||||
import java.security.ProviderException;
|
|
||||||
|
|
||||||
public final class CustomProvider extends Provider {
|
public final class CustomProvider extends Provider {
|
||||||
|
|
||||||
@ -9,19 +8,15 @@ public final class CustomProvider extends Provider {
|
|||||||
super(provider.getName(), provider.getVersion(), provider.getInfo());
|
super(provider.getName(), provider.getVersion(), provider.getInfo());
|
||||||
|
|
||||||
putAll(provider);
|
putAll(provider);
|
||||||
|
|
||||||
|
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.spoofFields();
|
|
||||||
|
|
||||||
EntryPoint.LOG(String.format("Service: '%s' | Algorithm: '%s'", type, algorithm));
|
EntryPoint.LOG(String.format("Service: '%s' | Algorithm: '%s'", type, algorithm));
|
||||||
|
|
||||||
if ("AndroidKeyStore".equals(algorithm)) {
|
EntryPoint.spoofFields();
|
||||||
Service service = super.getService(type, algorithm);
|
|
||||||
EntryPoint.LOG(service.toString());
|
|
||||||
throw new ProviderException();
|
|
||||||
}
|
|
||||||
|
|
||||||
return super.getService(type, algorithm);
|
return super.getService(type, algorithm);
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,8 @@ import android.util.Log;
|
|||||||
import org.json.JSONObject;
|
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.HashMap;
|
import java.util.HashMap;
|
||||||
@ -15,6 +17,17 @@ public final class EntryPoint {
|
|||||||
private static final Map<Field, String> map = new HashMap<>();
|
private static final Map<Field, String> map = new HashMap<>();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
try {
|
||||||
|
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
|
||||||
|
|
||||||
|
Field field = keyStore.getClass().getDeclaredField("keyStoreSpi");
|
||||||
|
field.setAccessible(true);
|
||||||
|
|
||||||
|
CustomKeyStoreSpi.keyStoreSpi = (KeyStoreSpi) field.get(keyStore);
|
||||||
|
} catch (Throwable 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);
|
||||||
|
17
changelog.md
17
changelog.md
@ -2,12 +2,17 @@ We have a Telegram group!
|
|||||||
If you want to share your knowledge join:
|
If you want to share your knowledge join:
|
||||||
https://t.me/playintegrityfix
|
https://t.me/playintegrityfix
|
||||||
|
|
||||||
# v15.6
|
|
||||||
|
|
||||||
- Fix bootloop issue in modern devices.
|
|
||||||
- Move code logic to C.
|
|
||||||
- Minor improvements.
|
|
||||||
|
|
||||||
Device verdict should pass by default.
|
Device verdict should pass by default.
|
||||||
If not, try removing /data/adb/pif.json file.
|
If not, try removing /data/adb/pif.json file.
|
||||||
DO NOT REMOVE pif.json in module's folder!
|
DO NOT REMOVE pif.json in module's folder!
|
||||||
|
|
||||||
|
# v15.7.1
|
||||||
|
|
||||||
|
- Fix crash issue when JSON file have comments.
|
||||||
|
- Fix hooking in older Android versions.
|
||||||
|
- Fix CTS profile / Device verdict failures in few devices due bad spoofing code.
|
||||||
|
- Fix spoofing Provider issue.
|
||||||
|
- Added post-fs-data.sh script.
|
||||||
|
- Using latest (compileable) version of Dobby.
|
||||||
|
- Using RikkaW libcxx prefab.
|
||||||
|
- Update Gradle.
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
4
gradle/wrapper/gradle-wrapper.properties
vendored
4
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,9 +1,7 @@
|
|||||||
#Wed Feb 07 09:57:46 CET 2024
|
#Wed Feb 07 18:13:12 CET 2024
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionSha256Sum=9d926787066a081739e8200858338b4a69e837c3a821a33aca9db09dd4a41026
|
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
validateDistributionUrl=true
|
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
29
gradlew
vendored
29
gradlew
vendored
@ -83,8 +83,10 @@ done
|
|||||||
# This is normally unused
|
# This is normally unused
|
||||||
# shellcheck disable=SC2034
|
# shellcheck disable=SC2034
|
||||||
APP_BASE_NAME=${0##*/}
|
APP_BASE_NAME=${0##*/}
|
||||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||||
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
|
|
||||||
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||||
|
|
||||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
MAX_FD=maximum
|
MAX_FD=maximum
|
||||||
@ -131,13 +133,10 @@ location of your Java installation."
|
|||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
JAVACMD=java
|
JAVACMD=java
|
||||||
if ! command -v java >/dev/null 2>&1
|
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
then
|
|
||||||
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
|
||||||
|
|
||||||
Please set the JAVA_HOME variable in your environment to match the
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
location of your Java installation."
|
location of your Java installation."
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Increase the maximum file descriptors if we can.
|
# Increase the maximum file descriptors if we can.
|
||||||
@ -145,7 +144,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
|||||||
case $MAX_FD in #(
|
case $MAX_FD in #(
|
||||||
max*)
|
max*)
|
||||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||||
# shellcheck disable=SC2039,SC3045
|
# shellcheck disable=SC3045
|
||||||
MAX_FD=$( ulimit -H -n ) ||
|
MAX_FD=$( ulimit -H -n ) ||
|
||||||
warn "Could not query maximum file descriptor limit"
|
warn "Could not query maximum file descriptor limit"
|
||||||
esac
|
esac
|
||||||
@ -153,7 +152,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
|||||||
'' | soft) :;; #(
|
'' | soft) :;; #(
|
||||||
*)
|
*)
|
||||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||||
# shellcheck disable=SC2039,SC3045
|
# shellcheck disable=SC3045
|
||||||
ulimit -n "$MAX_FD" ||
|
ulimit -n "$MAX_FD" ||
|
||||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||||
esac
|
esac
|
||||||
@ -198,15 +197,11 @@ if "$cygwin" || "$msys" ; then
|
|||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Collect all arguments for the java command;
|
||||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
# shell script including quotes and variable substitutions, so put them in
|
||||||
|
# double quotes to make sure that they get re-expanded; and
|
||||||
# Collect all arguments for the java command:
|
# * put everything else in single quotes, so that it's not re-expanded.
|
||||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
|
||||||
# and any embedded shellness will be escaped.
|
|
||||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
|
||||||
# treated as '${Hostname}' itself on the command line.
|
|
||||||
|
|
||||||
set -- \
|
set -- \
|
||||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
id=playintegrityfix
|
id=playintegrityfix
|
||||||
name=Play Integrity Fix
|
name=Play Integrity Fix
|
||||||
version=v15.7
|
version=v15.7.1
|
||||||
versionCode=15700
|
versionCode=15701
|
||||||
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,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"version": "v15.6",
|
"version": "v15.7.1",
|
||||||
"versionCode": 15600,
|
"versionCode": 15701,
|
||||||
"zipUrl": "https://github.com/chiteroman/PlayIntegrityFix/releases/download/v15.6/PlayIntegrityFix_v15.6.zip",
|
"zipUrl": "https://github.com/chiteroman/PlayIntegrityFix/releases/download/v15.7/PlayIntegrityFix_v15.7.1.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