You've already forked PlayIntegrityFork
mirror of
https://github.com/osm0sis/PlayIntegrityFork.git
synced 2025-09-06 06:37:06 +00:00
Add spoofVendingSdk to force legacy verdicts from new PI
Squashed: Add spoofVendingSdk for forcing new PI legacy verdicts Squashed: Move vending SDK spoof to EntryPointVending, replace killgms.sh with killpi.sh
This commit is contained in:
committed by
Chris Renshaw
parent
e2b8a3c4b0
commit
4740d2048d
@@ -56,13 +56,13 @@ A migration may also be performed manually with `sh migrate.sh` and custom.pif.j
|
|||||||
|
|
||||||
You can customize the included default [example.app_replace.list](https://raw.githubusercontent.com/osm0sis/PlayIntegrityFork/main/module/example.app_replace.list) from the module directory (/data/adb/modules/playintegrityfix) then rename it to custom.app_replace.list to systemlessly replace any additional conflicting custom ROM spoof injection app paths to disable them.
|
You can customize the included default [example.app_replace.list](https://raw.githubusercontent.com/osm0sis/PlayIntegrityFork/main/module/example.app_replace.list) from the module directory (/data/adb/modules/playintegrityfix) then rename it to custom.app_replace.list to systemlessly replace any additional conflicting custom ROM spoof injection app paths to disable them.
|
||||||
|
|
||||||
## About 'autopif2.sh' and 'killgms.sh' script files
|
## About 'autopif2.sh' and 'killpi.sh' script files
|
||||||
|
|
||||||
There's intentionally no pif.json in the module because the goal remains to be futureproof, and including something that may be banned and obsolete within days would be contrary to that goal. If you don't care to have your own private fingerprint to use or don't have time to look for one currently then simply run the generation script from a root manager app that supports the module Action button, a root prompt with `sh autopif2.sh` in the module directory (/data/adb/modules/playintegrityfix), or from a file explorer app that supports script execution.
|
There's intentionally no pif.json in the module because the goal remains to be futureproof, and including something that may be banned and obsolete within days would be contrary to that goal. If you don't care to have your own private fingerprint to use or don't have time to look for one currently then simply run the generation script from a root manager app that supports the module Action button, a root prompt with `sh autopif2.sh` in the module directory (/data/adb/modules/playintegrityfix), or from a file explorer app that supports script execution.
|
||||||
|
|
||||||
The autopif2 script generates a random device fingerprint from the latest Pixel Beta, ideally only to test an initial setup, since they expire roughly every 6 weeks from the Pixel Beta release date (dates included in the generated fingerprint), and the public mass-used ones from other modules or ROMs may also get banned or may be banned for RCS use while otherwise passing Play Integrity and SafetyNet in that time.
|
The autopif2 script generates a random device fingerprint from the latest Pixel Beta, ideally only to test an initial setup, since they expire roughly every 6 weeks from the Pixel Beta release date (dates included in the generated fingerprint), and the public mass-used ones from other modules or ROMs may also get banned or may be banned for RCS use while otherwise passing Play Integrity and SafetyNet in that time.
|
||||||
|
|
||||||
The killgms script forces the Google Play Services DroidGuard process (com.google.android.gms.unstable) to end, making it restart with the next attestation attempt; useful for testing out different fingerprints without requiring a reboot in between.
|
The killpi script forces the Google Play Services DroidGuard (com.google.android.gms.unstable) and Play Store (com.android.vending) processes to end, making them restart with the next attestation attempt; useful for testing out different fingerprints without requiring a reboot in between.
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
|
|||||||
1
app/proguard-rules.pro
vendored
1
app/proguard-rules.pro
vendored
@@ -1,4 +1,5 @@
|
|||||||
-keep class es.chiteroman.playintegrityfix.EntryPoint {public <methods>;}
|
-keep class es.chiteroman.playintegrityfix.EntryPoint {public <methods>;}
|
||||||
|
-keep class es.chiteroman.playintegrityfix.EntryPointVending {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.CustomPackageInfoCreator
|
-keep class es.chiteroman.playintegrityfix.CustomPackageInfoCreator
|
||||||
|
|||||||
@@ -12,12 +12,14 @@
|
|||||||
|
|
||||||
#define JSON_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"
|
#define CUSTOM_JSON_FILE_PATH "/data/adb/modules/playintegrityfix/custom.pif.json"
|
||||||
|
#define VENDING_PACKAGE "com.android.vending"
|
||||||
|
|
||||||
static int verboseLogs = 0;
|
static int verboseLogs = 0;
|
||||||
static int spoofBuild = 1;
|
static int spoofBuild = 1;
|
||||||
static int spoofProps = 1;
|
static int spoofProps = 1;
|
||||||
static int spoofProvider = 1;
|
static int spoofProvider = 1;
|
||||||
static int spoofSignature = 0;
|
static int spoofSignature = 0;
|
||||||
|
static int spoofVendingSdk = 0;
|
||||||
|
|
||||||
static std::map<std::string, std::string> jsonProps;
|
static std::map<std::string, std::string> jsonProps;
|
||||||
|
|
||||||
@@ -95,11 +97,11 @@ public:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string_view process(rawProcess);
|
pkgName = rawProcess;
|
||||||
std::string_view dir(rawDir);
|
std::string_view dir(rawDir);
|
||||||
|
|
||||||
isGms = dir.ends_with("/com.google.android.gms");
|
isGms = dir.ends_with("/com.google.android.gms") || dir.ends_with("/com.android.vending");
|
||||||
isGmsUnstable = process == "com.google.android.gms.unstable";
|
isGmsUnstable = pkgName == "com.google.android.gms.unstable" || pkgName == VENDING_PACKAGE;
|
||||||
|
|
||||||
env->ReleaseStringUTFChars(args->nice_name, rawProcess);
|
env->ReleaseStringUTFChars(args->nice_name, rawProcess);
|
||||||
env->ReleaseStringUTFChars(args->app_data_dir, rawDir);
|
env->ReleaseStringUTFChars(args->app_data_dir, rawDir);
|
||||||
@@ -161,6 +163,10 @@ public:
|
|||||||
if (dexVector.empty() || json.empty()) return;
|
if (dexVector.empty() || json.empty()) return;
|
||||||
|
|
||||||
readJson();
|
readJson();
|
||||||
|
|
||||||
|
if (pkgName == VENDING_PACKAGE) spoofProps = spoofBuild = spoofProvider = 0;
|
||||||
|
else spoofVendingSdk = 0;
|
||||||
|
|
||||||
if (spoofProps > 0) doHook();
|
if (spoofProps > 0) doHook();
|
||||||
inject();
|
inject();
|
||||||
|
|
||||||
@@ -177,6 +183,7 @@ private:
|
|||||||
JNIEnv *env = nullptr;
|
JNIEnv *env = nullptr;
|
||||||
std::vector<char> dexVector;
|
std::vector<char> dexVector;
|
||||||
nlohmann::json json;
|
nlohmann::json json;
|
||||||
|
std::string pkgName;
|
||||||
|
|
||||||
void readJson() {
|
void readJson() {
|
||||||
LOGD("JSON contains %d keys!", static_cast<int>(json.size()));
|
LOGD("JSON contains %d keys!", static_cast<int>(json.size()));
|
||||||
@@ -193,6 +200,19 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Advanced spoofing settings
|
// Advanced spoofing settings
|
||||||
|
if (json.contains("spoofVendingSdk")) {
|
||||||
|
if (!json["spoofVendingSdk"].is_null() && json["spoofVendingSdk"].is_string() && json["spoofVendingSdk"] != "") {
|
||||||
|
spoofVendingSdk = stoi(json["spoofVendingSdk"].get<std::string>());
|
||||||
|
if (verboseLogs > 0) LOGD("Spoofing SDK Level in Play Store %s!", (spoofVendingSdk > 0) ? "enabled" : "disabled");
|
||||||
|
} else {
|
||||||
|
LOGD("Error parsing spoofVendingSdk!");
|
||||||
|
}
|
||||||
|
json.erase("spoofVendingSdk");
|
||||||
|
}
|
||||||
|
if (pkgName == VENDING_PACKAGE) {
|
||||||
|
json.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (json.contains("spoofBuild")) {
|
if (json.contains("spoofBuild")) {
|
||||||
if (!json["spoofBuild"].is_null() && json["spoofBuild"].is_string() && json["spoofBuild"] != "") {
|
if (!json["spoofBuild"].is_null() && json["spoofBuild"].is_string() && json["spoofBuild"] != "") {
|
||||||
spoofBuild = stoi(json["spoofBuild"].get<std::string>());
|
spoofBuild = stoi(json["spoofBuild"].get<std::string>());
|
||||||
@@ -255,33 +275,40 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void inject() {
|
void inject() {
|
||||||
LOGD("JNI: Getting system classloader");
|
LOGD("JNI %s: Getting system classloader", pkgName.c_str());
|
||||||
auto clClass = env->FindClass("java/lang/ClassLoader");
|
auto clClass = env->FindClass("java/lang/ClassLoader");
|
||||||
auto getSystemClassLoader = env->GetStaticMethodID(clClass, "getSystemClassLoader", "()Ljava/lang/ClassLoader;");
|
auto getSystemClassLoader = env->GetStaticMethodID(clClass, "getSystemClassLoader", "()Ljava/lang/ClassLoader;");
|
||||||
auto systemClassLoader = env->CallStaticObjectMethod(clClass, getSystemClassLoader);
|
auto systemClassLoader = env->CallStaticObjectMethod(clClass, getSystemClassLoader);
|
||||||
|
|
||||||
LOGD("JNI: Creating module classloader");
|
LOGD("JNI %s: Creating module classloader", pkgName.c_str());
|
||||||
auto dexClClass = env->FindClass("dalvik/system/InMemoryDexClassLoader");
|
auto dexClClass = env->FindClass("dalvik/system/InMemoryDexClassLoader");
|
||||||
auto dexClInit = env->GetMethodID(dexClClass, "<init>", "(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V");
|
auto dexClInit = env->GetMethodID(dexClClass, "<init>", "(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V");
|
||||||
auto buffer = env->NewDirectByteBuffer(dexVector.data(), static_cast<jlong>(dexVector.size()));
|
auto buffer = env->NewDirectByteBuffer(dexVector.data(), static_cast<jlong>(dexVector.size()));
|
||||||
auto dexCl = env->NewObject(dexClClass, dexClInit, buffer, systemClassLoader);
|
auto dexCl = env->NewObject(dexClClass, dexClInit, buffer, systemClassLoader);
|
||||||
|
|
||||||
LOGD("JNI: Loading module class");
|
LOGD("JNI %s: Loading module class", pkgName.c_str());
|
||||||
auto loadClass = env->GetMethodID(clClass, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
|
auto loadClass = env->GetMethodID(clClass, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
|
||||||
auto entryClassName = env->NewStringUTF("es.chiteroman.playintegrityfix.EntryPoint");
|
const char* className = pkgName == VENDING_PACKAGE ? "es.chiteroman.playintegrityfix.EntryPointVending" : "es.chiteroman.playintegrityfix.EntryPoint";
|
||||||
|
auto entryClassName = env->NewStringUTF(className);
|
||||||
auto entryClassObj = env->CallObjectMethod(dexCl, loadClass, entryClassName);
|
auto entryClassObj = env->CallObjectMethod(dexCl, loadClass, entryClassName);
|
||||||
|
|
||||||
auto entryClass = (jclass) entryClassObj;
|
auto entryClass = (jclass) entryClassObj;
|
||||||
|
|
||||||
LOGD("JNI: Sending JSON");
|
if (pkgName == VENDING_PACKAGE) {
|
||||||
|
LOGD("JNI %s: Calling EntryPointVending.init", pkgName.c_str());
|
||||||
|
auto entryInit = env->GetStaticMethodID(entryClass, "init", "(II)V");
|
||||||
|
env->CallStaticVoidMethod(entryClass, entryInit, verboseLogs, spoofVendingSdk);
|
||||||
|
} else {
|
||||||
|
LOGD("JNI %s: Sending JSON", pkgName.c_str());
|
||||||
auto receiveJson = env->GetStaticMethodID(entryClass, "receiveJson", "(Ljava/lang/String;)V");
|
auto receiveJson = env->GetStaticMethodID(entryClass, "receiveJson", "(Ljava/lang/String;)V");
|
||||||
auto javaStr = env->NewStringUTF(json.dump().c_str());
|
auto javaStr = env->NewStringUTF(json.dump().c_str());
|
||||||
env->CallStaticVoidMethod(entryClass, receiveJson, javaStr);
|
env->CallStaticVoidMethod(entryClass, receiveJson, javaStr);
|
||||||
|
|
||||||
LOGD("JNI: Calling init");
|
LOGD("JNI %s: Calling EntryPoint.init", pkgName.c_str());
|
||||||
auto entryInit = env->GetStaticMethodID(entryClass, "init", "(IIII)V");
|
auto entryInit = env->GetStaticMethodID(entryClass, "init", "(IIII)V");
|
||||||
env->CallStaticVoidMethod(entryClass, entryInit, verboseLogs, spoofBuild, spoofProvider, spoofSignature);
|
env->CallStaticVoidMethod(entryClass, entryInit, verboseLogs, spoofBuild, spoofProvider, spoofSignature);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static void companion(int fd) {
|
static void companion(int fd) {
|
||||||
|
|||||||
@@ -265,6 +265,6 @@ public final class EntryPoint {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void LOG(String msg) {
|
static void LOG(String msg) {
|
||||||
Log.d("PIF/Java", msg);
|
Log.d("PIF/Java:DG", msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package es.chiteroman.playintegrityfix;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.os.Build;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
public final class EntryPointVending {
|
||||||
|
|
||||||
|
private static void LOG(String msg) {
|
||||||
|
Log.d("PIF/Java:vending", msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("DefaultLocale")
|
||||||
|
public static void init(int verboseLogs, int spoofVendingSdk) {
|
||||||
|
if (spoofVendingSdk < 1) return;
|
||||||
|
int requestSdk = spoofVendingSdk == 1 ? 32 : spoofVendingSdk;
|
||||||
|
int targetSdk = Math.min(Build.VERSION.SDK_INT, requestSdk);
|
||||||
|
int oldValue;
|
||||||
|
try {
|
||||||
|
Field field = Build.VERSION.class.getDeclaredField("SDK_INT");
|
||||||
|
field.setAccessible(true);
|
||||||
|
oldValue = field.getInt(null);
|
||||||
|
if (oldValue == targetSdk) {
|
||||||
|
if (verboseLogs > 2) LOG(String.format("[SDK_INT]: %d (unchanged)", oldValue));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
field.set(null, targetSdk);
|
||||||
|
field.setAccessible(false);
|
||||||
|
LOG(String.format("[SDK_INT]: %d -> %d", oldValue, targetSdk));
|
||||||
|
} catch (NoSuchFieldException e) {
|
||||||
|
LOG("SDK_INT field not found: " + e);
|
||||||
|
} catch (SecurityException | IllegalAccessException | IllegalArgumentException |
|
||||||
|
NullPointerException | ExceptionInInitializerError e) {
|
||||||
|
LOG("SDK_INT field not accessible: " + e);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -158,7 +158,7 @@ if [ -f "$MIGRATE" ]; then
|
|||||||
if [ -n "$ARGS" ]; then
|
if [ -n "$ARGS" ]; then
|
||||||
grep_json() { [ -f "$2" ] && grep -m1 "$1" $2 | cut -d\" -f4; }
|
grep_json() { [ -f "$2" ] && grep -m1 "$1" $2 | cut -d\" -f4; }
|
||||||
verboseLogs=$(grep_json "VERBOSE_LOGS" $OLDJSON);
|
verboseLogs=$(grep_json "VERBOSE_LOGS" $OLDJSON);
|
||||||
ADVSETTINGS="spoofBuild spoofProps spoofProvider spoofSignature verboseLogs";
|
ADVSETTINGS="spoofBuild spoofProps spoofProvider spoofSignature spoofVendingSdk verboseLogs";
|
||||||
for SETTING in $ADVSETTINGS; do
|
for SETTING in $ADVSETTINGS; do
|
||||||
eval [ -z \"\$$SETTING\" ] \&\& $SETTING=$(grep_json "$SETTING" $OLDJSON);
|
eval [ -z \"\$$SETTING\" ] \&\& $SETTING=$(grep_json "$SETTING" $OLDJSON);
|
||||||
eval TMPVAL=\$$SETTING;
|
eval TMPVAL=\$$SETTING;
|
||||||
@@ -182,8 +182,8 @@ if [ "$DIR" = /data/adb/modules/playintegrityfix/autopif2 ]; then
|
|||||||
fi;
|
fi;
|
||||||
item "Installing new json ...";
|
item "Installing new json ...";
|
||||||
cp -fv $NEWNAME ..;
|
cp -fv $NEWNAME ..;
|
||||||
if [ -f /data/adb/modules/playintegrityfix/killgms.sh ]; then
|
if [ -f /data/adb/modules/playintegrityfix/killpi.sh ]; then
|
||||||
item "Killing any running GMS DroidGuard process ...";
|
item "Killing any running GMS DroidGuard/Play Store processes ...";
|
||||||
sh /data/adb/modules/playintegrityfix/killgms.sh 2>&1 || true;
|
sh /data/adb/modules/playintegrityfix/killpi.sh 2>&1 || true;
|
||||||
fi;
|
fi;
|
||||||
fi;
|
fi;
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
#!/system/bin/sh
|
|
||||||
# killgms.sh by osm0sis @ xda-developers
|
|
||||||
#
|
|
||||||
# Kill the Google Play services DroidGuard process
|
|
||||||
# (com.google.android.gms.unstable)
|
|
||||||
|
|
||||||
if [ "$USER" != "root" -a "$(whoami 2>/dev/null)" != "root" ]; then
|
|
||||||
echo "killgms: need root permissions";
|
|
||||||
exit 1;
|
|
||||||
fi;
|
|
||||||
|
|
||||||
killall -v com.google.android.gms.unstable;
|
|
||||||
13
module/killpi.sh
Normal file
13
module/killpi.sh
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#!/system/bin/sh
|
||||||
|
# killpi.sh by osm0sis @ xda-developers
|
||||||
|
#
|
||||||
|
# Kill the Google Play services DroidGuard and Play Store processes
|
||||||
|
# (com.google.android.gms.unstable and com.android.vending)
|
||||||
|
|
||||||
|
if [ "$USER" != "root" -a "$(whoami 2>/dev/null)" != "root" ]; then
|
||||||
|
echo "killpi: need root permissions";
|
||||||
|
exit 1;
|
||||||
|
fi;
|
||||||
|
|
||||||
|
killall -v com.google.android.gms.unstable;
|
||||||
|
killall -v com.android.vending;
|
||||||
@@ -114,12 +114,13 @@ if [ -z "$DEVICE_INITIAL_SDK_INT" -o "$DEVICE_INITIAL_SDK_INT" = "null" ]; then
|
|||||||
DEVICE_INITIAL_SDK_INT=25;
|
DEVICE_INITIAL_SDK_INT=25;
|
||||||
fi;
|
fi;
|
||||||
|
|
||||||
ADVSETTINGS="spoofBuild spoofProps spoofProvider spoofSignature verboseLogs";
|
ADVSETTINGS="spoofBuild spoofProps spoofProvider spoofSignature spoofVendingSdk verboseLogs";
|
||||||
|
|
||||||
spoofBuild=1;
|
spoofBuild=1;
|
||||||
spoofProps=1;
|
spoofProps=1;
|
||||||
spoofProvider=1;
|
spoofProvider=1;
|
||||||
spoofSignature=0;
|
spoofSignature=0;
|
||||||
|
spoofVendingSdk=0;
|
||||||
verboseLogs=0;
|
verboseLogs=0;
|
||||||
|
|
||||||
if [ -f "$OUT" ]; then
|
if [ -f "$OUT" ]; then
|
||||||
|
|||||||
Reference in New Issue
Block a user