Dynamically patch build fingerprint in GMS process

"AndroidCAStore" always seems to be used early in the attestation
process, before the fingerprint is checked.

Dynamic patching avoids problems with device detection and functionality
that can be caused by permanently spoofing another device.

Closes #207, closes #224, closes #222, closes #220, closes #218, closes #212, closes #211, closes #210, closes #204, closes #203, closes #201, closes #196, closes #188, closes #171, closes #170
This commit is contained in:
Danny Lin 2023-01-01 04:53:41 -08:00
parent 2f18d85a9b
commit 73c8587a80

View File

@ -1,8 +1,12 @@
package dev.kdrag0n.safetynetfix.proxy
import android.os.Build
import dev.kdrag0n.safetynetfix.SecurityHooks
import dev.kdrag0n.safetynetfix.logDebug
import java.security.Provider
import kotlin.concurrent.thread
private const val PATCH_DURATION = 2000L
// This is mostly just a pass-through provider that exists to change the provider's ClassLoader.
// This works because Service looks up the class by name from the *provider* ClassLoader, not
@ -19,6 +23,25 @@ class ProxyProvider(
override fun getService(type: String?, algorithm: String?): Service? {
logDebug("Provider: get service - type=$type algorithm=$algorithm")
if (algorithm == "AndroidCAStore") {
val orig = Build.FINGERPRINT
val patched = "google/angler/angler:6.0/MDB08L/2343525:user/release-keys"
logDebug("patch build for castore $orig -> $patched")
// Append a space to the device model name
Build::class.java.getDeclaredField("FINGERPRINT").let { field ->
field.isAccessible = true
field.set(null, patched)
}
thread(isDaemon = true) {
Thread.sleep(PATCH_DURATION)
logDebug("unpatch")
Build::class.java.getDeclaredField("FINGERPRINT").let { field ->
field.isAccessible = true
field.set(null, orig)
}
}
}
return super.getService(type, algorithm)
}