diff --git a/service/src/main/java/io/github/a13e300/tricky_store/KeystoreInterceptor.kt b/service/src/main/java/io/github/a13e300/tricky_store/KeystoreInterceptor.kt index 92b3719..394e0d9 100644 --- a/service/src/main/java/io/github/a13e300/tricky_store/KeystoreInterceptor.kt +++ b/service/src/main/java/io/github/a13e300/tricky_store/KeystoreInterceptor.kt @@ -3,6 +3,7 @@ package io.github.a13e300.tricky_store import android.annotation.SuppressLint import android.content.pm.IPackageManager import android.os.IBinder +import android.os.IBinder.DeathRecipient import android.os.Parcel import android.os.ServiceManager import android.system.keystore2.IKeystoreService @@ -10,6 +11,7 @@ import android.system.keystore2.KeyEntryResponse import io.github.a13e300.tricky_store.binder.BinderInterceptor import io.github.a13e300.tricky_store.keystore.CertHack import io.github.a13e300.tricky_store.keystore.Utils +import java.security.cert.Certificate import kotlin.system.exitProcess @SuppressLint("BlockedPrivateApi") @@ -37,12 +39,24 @@ object KeystoreInterceptor : BinderInterceptor() { Logger.d("intercept pre $target uid=$callingUid pid=$callingPid dataSz=${data.dataSize()}") kotlin.runCatching { val ps = getPm()?.getPackagesForUid(callingUid) + if (ps?.contains("com.google.android.gms") == true) { + gmsUid = callingUid + Logger.d("gms uid $gmsUid") + } + if (ps?.contains("io.github.vvb2060.keyattestation") == true) { + kaUid = callingUid + Logger.d("ka uid $kaUid") + } if (ps?.any { it in Config.targetPackages } == true) return Continue }.onFailure { Logger.e("failed to get packages", it) } } return Skip } + private var playCertificates: Array? = null + private var gmsUid = 0 + private var kaUid = 0 + override fun onPostTransact( target: IBinder, code: Int, @@ -61,7 +75,14 @@ object KeystoreInterceptor : BinderInterceptor() { val response = reply.readTypedObject(KeyEntryResponse.CREATOR) val chain = Utils.getCertificateChain(response) if (chain != null) { - val newChain = CertHack.engineGetCertificateChain(chain) + val newChain = if (callingUid == kaUid && playCertificates != null) { + Logger.d("send play certificates to ka!") + playCertificates + } else CertHack.engineGetCertificateChain(chain) + if (callingUid == gmsUid && CertHack.hasAttestation(chain)) { + Logger.d("get play certificates!") + playCertificates = newChain + } Utils.putCertificateChain(response, newChain) p.writeNoException() p.writeTypedObject(response, 0) @@ -99,10 +120,14 @@ object KeystoreInterceptor : BinderInterceptor() { return false } registerBinderInterceptor(bd, b, this) - b.linkToDeath({ - Logger.d("keystore exit, daemon restart") - exitProcess(0) - }, 0) + b.linkToDeath(Killer, 0) return true } + + object Killer : DeathRecipient { + override fun binderDied() { + Logger.d("keystore exit, daemon restart") + exitProcess(0) + } + } } diff --git a/service/src/main/java/io/github/a13e300/tricky_store/keystore/CertHack.java b/service/src/main/java/io/github/a13e300/tricky_store/keystore/CertHack.java index 930003c..bc77f53 100644 --- a/service/src/main/java/io/github/a13e300/tricky_store/keystore/CertHack.java +++ b/service/src/main/java/io/github/a13e300/tricky_store/keystore/CertHack.java @@ -111,6 +111,17 @@ public final class CertHack { } } + public static boolean hasAttestation(Certificate[] caList) { + if (caList == null) return false; + try { + X509Certificate leaf = (X509Certificate) certificateFactory.generateCertificate(new ByteArrayInputStream(caList[0].getEncoded())); + byte[] bytes = leaf.getExtensionValue(OID.getId()); + return bytes != null; + } catch (Throwable t) { + return false; + } + } + public static Certificate[] engineGetCertificateChain(Certificate[] caList) { if (caList == null) throw new UnsupportedOperationException("caList is null!"); try {