Skip to content

Commit

Permalink
Spoof build fingerprint for Google Play Services
Browse files Browse the repository at this point in the history
SafetyNet's CTS profile attestation checks whether Build.FINGERPRINT
matches that of the device's stock OS, which has passed CTS testing.
Spoof the fingerprint for Google Play Services to help pass SafetyNet.

We used to set the real system build fingerprint to the stock one, but
Android relies on each build having a unique fingerprint in order to
clear the correct caches and update persistent state for system changes.
On devices that no longer receive updates from the OEM, the build
fingerprint never changes and Android doesn't account for updates
correctly, which causes issues when updating without wiping data.
Only spoofing the fingerprint for Google Play Services fixes this issue.

Corresponding vendor commit:
"Only use stock build fingerprint for Google Play Services"

Change-Id: I415b6760ecf4032bd60f886c319d43bc6d63aef6
Signed-off-by: goodmeow <[email protected]>
  • Loading branch information
kdrag0n authored and goodmeow committed May 12, 2021
1 parent 24c0306 commit b9641c3
Showing 1 changed file with 35 additions and 24 deletions.
59 changes: 35 additions & 24 deletions core/java/com/android/internal/os/Zygote.java
Original file line number Diff line number Diff line change
Expand Up @@ -851,31 +851,43 @@ private static void boostUsapPriority() {

private static native void nativeBoostUsapPriority();

private static void maybeSetGoogleModel(String packageName, String loggingTag) {
private static void setBuildField(String loggingTag, String key, String value) {
/*
* This would be much prettier if we just removed "final" from the Build fields,
* but that requires changing the API.
*
* While this an awful hack, it's technically safe because the fields are
* populated at runtime.
*/
try {
// Unlock
Field field = Build.class.getDeclaredField(key);
field.setAccessible(true);

// Edit
field.set(null, value);

// Lock
field.setAccessible(false);
} catch (NoSuchFieldException | IllegalAccessException e) {
Log.e(loggingTag, "Failed to spoof Build." + key, e);
}
}

private static void maybeSpoofBuild(String packageName, String loggingTag) {
// Set device model to defy NGA in Google Assistant
if (PRODUCT_NEEDS_MODEL_EDIT &&
packageName != null &&
packageName.startsWith("com.google.android.googlequicksearchbox")) {
/*
* This would be much prettier if we just removed "final" from the MODEL field in Build,
* but that requires changing the API.
*
* While this an awful hack, it's technically safe because the field was populated at
* runtime (in pre-fork Zygote) and it's not a primitive.
*/
try {
// Unlock
Field field = Build.class.getDeclaredField("MODEL");
field.setAccessible(true);

// Edit
String newModel = "Pixel 3 XL";
field.set(null, newModel);

// Lock
field.setAccessible(false);
} catch (NoSuchFieldException | IllegalAccessException e) {
Log.w(loggingTag, "Failed to set fake model name for Google", e);
}
setBuildField(loggingTag, "MODEL", "Pixel 3 XL");
}

// Set fingerprint to make SafetyNet pass
String stockFp = SystemProperties.get("ro.build.stock_fingerprint");
if (stockFp != null &&
packageName != null &&
packageName.startsWith("com.google.android.gms")) {
setBuildField(loggingTag, "FINGERPRINT", stockFp);
}
}

Expand All @@ -888,8 +900,7 @@ static void setAppProcessName(ZygoteArguments args, String loggingTag) {
Log.w(loggingTag, "Unable to set package name.");
}

// Modify model to defy Next-Generation Assistant in the Google app
maybeSetGoogleModel(args.mPackageName, loggingTag);
maybeSpoofBuild(args.mPackageName, loggingTag);

// Set pixel props
PixelPropsUtils.setProps(args.mPackageName);
Expand Down

0 comments on commit b9641c3

Please sign in to comment.