Add advanced setting spoofVendingFingerprint (#38)

spoofVendingFingerprint = 0 / 1

When 0, no impact on Vending
When 1, same FINGERPRINT from custom.pif.json is injected into Vending

Unless spoofVendingSdk is enabled also, in which case FINGERPRINT is not injected since it's not used
This commit is contained in:
gavdoc38
2025-08-30 19:02:50 +01:00
committed by GitHub
parent ffd8d77d6f
commit 9c6f065bb6
5 changed files with 65 additions and 27 deletions

View File

@@ -20,6 +20,7 @@ static int spoofBuild = 1;
static int spoofProps = 1;
static int spoofProvider = 1;
static int spoofSignature = 0;
static int spoofVendingFingerprint = 0;
static int spoofVendingSdk = 0;
static std::map<std::string, std::string> jsonProps;
@@ -166,10 +167,10 @@ public:
readJson();
if (pkgName == VENDING_PACKAGE) spoofProps = spoofBuild = spoofProvider = spoofSignature = 0;
else spoofVendingSdk = 0;
else spoofVendingFingerprint = spoofVendingSdk = 0;
if (spoofProps > 0) doHook();
if (spoofBuild + spoofProvider + spoofSignature + spoofVendingSdk > 0) inject();
if (spoofBuild + spoofProvider + spoofSignature + spoofVendingFingerprint + spoofVendingSdk > 0) inject();
dexVector.clear();
json.clear();
@@ -185,6 +186,7 @@ private:
std::vector<char> dexVector;
nlohmann::json json;
std::string pkgName;
std::string spoofFingerprintValue = "";
void readJson() {
LOGD("JSON contains %d keys!", static_cast<int>(json.size()));
@@ -210,6 +212,17 @@ private:
}
json.erase("spoofVendingSdk");
}
if (json.contains("spoofVendingFingerprint")) {
if (!json["spoofVendingFingerprint"].is_null() && json["spoofVendingFingerprint"].is_string() && json["spoofVendingFingerprint"] != "" &&
json.contains("FINGERPRINT") && !json["FINGERPRINT"].is_null() && json["FINGERPRINT"].is_string() && json["FINGERPRINT"] != "") {
spoofVendingFingerprint = stoi(json["spoofVendingFingerprint"].get<std::string>());
spoofFingerprintValue = json["FINGERPRINT"].get<std::string>();
if (verboseLogs > 0) LOGD("Spoofing Fingerprint in Play Store %s!", (spoofVendingFingerprint > 0) ? "enabled" : "disabled");
} else {
LOGD("Error parsing spoofVendingFingerprint or FINGERPRINT field!");
}
json.erase("spoofVendingFingerprint");
}
if (pkgName == VENDING_PACKAGE) {
json.clear();
return;
@@ -299,8 +312,9 @@ private:
if (pkgName == VENDING_PACKAGE) {
LOGD("JNI %s: Calling EntryPointVending.init", niceName);
auto entryInit = env->GetStaticMethodID(entryClass, "init", "(II)V");
env->CallStaticVoidMethod(entryClass, entryInit, verboseLogs, spoofVendingSdk);
auto entryInit = env->GetStaticMethodID(entryClass, "init", "(IIILjava/lang/String;)V");
auto javaStr = env->NewStringUTF(spoofFingerprintValue.c_str());
env->CallStaticVoidMethod(entryClass, entryInit, verboseLogs, spoofVendingFingerprint, spoofVendingSdk, javaStr);
} else {
LOGD("JNI %s: Sending JSON", niceName);
auto receiveJson = env->GetStaticMethodID(entryClass, "receiveJson", "(Ljava/lang/String;)V");

View File

@@ -12,29 +12,51 @@ public final class EntryPointVending {
}
@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));
public static void init(int verboseLogs, int spoofVendingFingerprint, int spoofVendingSdk, String spoofFingerprintValue) {
if (spoofVendingSdk < 1){
// Only spoof FINGERPRINT to Play Store if not forcing legacy verdict
if (spoofVendingFingerprint < 1) return;
String oldValue;
try {
Field field = Build.class.getDeclaredField("FINGERPRINT");
field.setAccessible(true);
oldValue = String.valueOf(field.get(null));
if (oldValue.equals(spoofFingerprintValue)) {
if (verboseLogs > 2) LOG(String.format("[FINGERPRINT]: %s (unchanged)", oldValue));
field.setAccessible(false);
return;
}
field.set(null, spoofFingerprintValue);
field.setAccessible(false);
return;
LOG(String.format("[FINGERPRINT]: %s -> %s", oldValue, spoofFingerprintValue));
} catch (NoSuchFieldException e) {
LOG("FINGERPRINT field not found: " + e);
} catch (SecurityException | IllegalAccessException | IllegalArgumentException |
NullPointerException | ExceptionInInitializerError e) {
LOG("FINGERPRINT field not accessible: " + e);
}
} else {
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));
field.setAccessible(false);
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);
}
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);
}
}
}

View File

@@ -162,7 +162,7 @@ if [ -f "$MIGRATE" ]; then
if [ -n "$ARGS" ]; then
grep_json() { [ -f "$2" ] && grep -m1 "$1" $2 | cut -d\" -f4; }
verboseLogs=$(grep_json "VERBOSE_LOGS" $OLDJSON);
ADVSETTINGS="spoofBuild spoofProps spoofProvider spoofSignature spoofVendingSdk verboseLogs";
ADVSETTINGS="spoofBuild spoofProps spoofProvider spoofSignature spoofVendingFingerprint spoofVendingSdk verboseLogs";
for SETTING in $ADVSETTINGS; do
eval [ -z \"\$$SETTING\" ] \&\& $SETTING=$(grep_json "$SETTING" $OLDJSON);
eval TMPVAL=\$$SETTING;

View File

@@ -31,6 +31,7 @@
"spoofProps": "1",
"spoofProvider": "1",
"spoofSignature": "0",
"spoofVendingFingerprint": "0",
"spoofVendingSdk": "0",
"verboseLogs": "0"
}

View File

@@ -114,12 +114,13 @@ if [ -z "$DEVICE_INITIAL_SDK_INT" -o "$DEVICE_INITIAL_SDK_INT" = "null" ]; then
DEVICE_INITIAL_SDK_INT=25;
fi;
ADVSETTINGS="spoofBuild spoofProps spoofProvider spoofSignature spoofVendingSdk verboseLogs";
ADVSETTINGS="spoofBuild spoofProps spoofProvider spoofSignature spoofVendingFingerprint spoofVendingSdk verboseLogs";
spoofBuild=1;
spoofProps=1;
spoofProvider=1;
spoofSignature=0;
spoofVendingFingerprint=0;
spoofVendingSdk=0;
verboseLogs=0;