From 40cc836ae3a73516ef3817ce963158ce4e676a89 Mon Sep 17 00:00:00 2001 From: chiteroman <98092901+chiteroman@users.noreply.github.com> Date: Sun, 17 Dec 2023 19:32:49 +0100 Subject: [PATCH] v3.1 --- app/build.gradle | 4 +- .../es/chiteroman/bootloaderspoofer/Data.java | 41 +++ .../chiteroman/bootloaderspoofer/Xposed.java | 342 +++++++++++------- 3 files changed, 246 insertions(+), 141 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index a0f9f3b..ce40d61 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -11,8 +11,8 @@ android { applicationId "es.chiteroman.bootloaderspoofer" minSdk 26 targetSdk 34 - versionCode 30 - versionName '3.0' + versionCode 32 + versionName '3.2' multiDexEnabled false } diff --git a/app/src/main/java/es/chiteroman/bootloaderspoofer/Data.java b/app/src/main/java/es/chiteroman/bootloaderspoofer/Data.java index 6c320c7..b96c91d 100644 --- a/app/src/main/java/es/chiteroman/bootloaderspoofer/Data.java +++ b/app/src/main/java/es/chiteroman/bootloaderspoofer/Data.java @@ -7,6 +7,47 @@ public final class Data { AwEHoUQDQgAEwCzLu4AL1c86SRwHKjgGlk3L16fbU3U8zWUa1hB+OwCxwqvyD686 HLsIKAgZluKMIAQQKRalYapz+tPSdJ4mig== -----END EC PRIVATE KEY-----"""; + + public static final String RSA_PRIVATE_KEY = """ + -----BEGIN RSA PRIVATE KEY----- + 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 + -----END RSA PRIVATE KEY-----"""; public static final String CERT_1 = """ -----BEGIN CERTIFICATE----- MIIB9DCCAXqgAwIBAgIRAM/Qn0kkZ6jXjzyH+K6CsO0wCgYIKoZIzj0EAwIwOTEM diff --git a/app/src/main/java/es/chiteroman/bootloaderspoofer/Xposed.java b/app/src/main/java/es/chiteroman/bootloaderspoofer/Xposed.java index 189f686..5927b23 100644 --- a/app/src/main/java/es/chiteroman/bootloaderspoofer/Xposed.java +++ b/app/src/main/java/es/chiteroman/bootloaderspoofer/Xposed.java @@ -4,14 +4,18 @@ import org.bouncycastle.asn1.ASN1Boolean; import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1Enumerated; import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Null; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1OctetString; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERNull; import org.bouncycastle.asn1.DEROctetString; import org.bouncycastle.asn1.DLSequence; +import org.bouncycastle.asn1.DLSet; import org.bouncycastle.asn1.DLTaggedObject; +import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.asn1.x509.Extension; import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; @@ -25,17 +29,19 @@ import org.bouncycastle.util.io.pem.PemObject; import org.bouncycastle.util.io.pem.PemReader; import java.io.StringReader; +import java.math.BigInteger; import java.security.KeyPair; -import java.security.KeyStore; -import java.security.KeyStoreSpi; import java.security.SecureRandom; import java.security.cert.Certificate; import java.security.cert.X509Certificate; -import java.util.ArrayList; -import java.util.List; +import java.util.Arrays; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; import de.robv.android.xposed.IXposedHookLoadPackage; import de.robv.android.xposed.XC_MethodHook; +import de.robv.android.xposed.XC_MethodReplacement; import de.robv.android.xposed.XposedBridge; import de.robv.android.xposed.XposedHelpers; import de.robv.android.xposed.callbacks.XC_LoadPackage; @@ -43,8 +49,10 @@ import de.robv.android.xposed.callbacks.XC_LoadPackage; public final class Xposed implements IXposedHookLoadPackage { private static final KeyPair EC_KEYPAIR; - private static final X509CertificateHolder holder_cert_1, holder_cert_2, holder_cert_3; - private static ASN1Sequence swEnforcedAuthList, teeEnforcedAuthList; + private static final Map map = new HashMap<>(); + private static final SecureRandom random = new SecureRandom(); + private static byte[] attestationChallengeBytes = new byte[0]; + private static boolean brokenTEE = false; static { try { @@ -56,109 +64,58 @@ public final class Xposed implements IXposedHookLoadPackage { EC_KEYPAIR = new JcaPEMKeyConverter().getKeyPair(pemKeyPair); - PemReader reader_cert_1 = new PemReader(new StringReader(Data.CERT_1)); - PemObject pemObject = reader_cert_1.readPemObject(); - parser.close(); - - holder_cert_1 = new X509CertificateHolder(pemObject.getContent()); - - PemReader reader_cert_2 = new PemReader(new StringReader(Data.CERT_2)); - pemObject = reader_cert_2.readPemObject(); - parser.close(); - - holder_cert_2 = new X509CertificateHolder(pemObject.getContent()); - - PemReader reader_cert_3 = new PemReader(new StringReader(Data.CERT_3)); - pemObject = reader_cert_3.readPemObject(); - parser.close(); - - holder_cert_3 = new X509CertificateHolder(pemObject.getContent()); - } catch (Throwable t) { throw new RuntimeException(t); } } - private static List getOtherCertList() throws Throwable { - List certificates = new ArrayList<>(); + private static X509CertificateHolder parseOtherCert(int num) { + String str = ""; - var c1 = new JcaX509v3CertificateBuilder( - holder_cert_1.getSubject(), - holder_cert_1.getSerialNumber(), - holder_cert_1.getNotBefore(), - holder_cert_1.getNotAfter(), - holder_cert_1.getSubject(), - EC_KEYPAIR.getPublic() - ); + if (num == 1) str = Data.CERT_1; + else if (num == 2) str = Data.CERT_2; + else if (num == 3) str = Data.CERT_3; - var c2 = new JcaX509v3CertificateBuilder( - holder_cert_2.getSubject(), - holder_cert_2.getSerialNumber(), - holder_cert_2.getNotBefore(), - holder_cert_2.getNotAfter(), - holder_cert_2.getSubject(), - EC_KEYPAIR.getPublic() - ); + try { + PemReader reader = new PemReader(new StringReader(str)); + PemObject pemObject = reader.readPemObject(); + reader.close(); - var c3 = new JcaX509v3CertificateBuilder( - holder_cert_3.getSubject(), - holder_cert_3.getSerialNumber(), - holder_cert_3.getNotBefore(), - holder_cert_3.getNotAfter(), - holder_cert_3.getSubject(), - EC_KEYPAIR.getPublic() - ); + return new X509CertificateHolder(pemObject.getContent()); - ContentSigner contentSigner = new JcaContentSignerBuilder("SHA256withECDSA").build(EC_KEYPAIR.getPrivate()); - - X509CertificateHolder holder1 = c1.build(contentSigner); - X509CertificateHolder holder2 = c2.build(contentSigner); - X509CertificateHolder holder3 = c3.build(contentSigner); - - certificates.add(new JcaX509CertificateConverter().getCertificate(holder1)); - certificates.add(new JcaX509CertificateConverter().getCertificate(holder2)); - certificates.add(new JcaX509CertificateConverter().getCertificate(holder3)); - - return certificates; + } catch (Exception e) { + XposedBridge.log("ERROR, couldn't parse other cert " + num + " : " + e); + throw new RuntimeException(); + } } - private static ASN1Primitive getEncodableFromList(int tagNo) { + private static Certificate[] getOtherCerts() throws Throwable { - for (ASN1Encodable asn1Encodable : teeEnforcedAuthList) { - ASN1TaggedObject taggedObject = (ASN1TaggedObject) asn1Encodable; + var holder_cert_1 = parseOtherCert(1); + var holder_cert_2 = parseOtherCert(2); + var holder_cert_3 = parseOtherCert(3); - if (taggedObject.getTagNo() == tagNo) { - return taggedObject.getBaseObject().toASN1Primitive(); - } - } + Certificate c1 = new JcaX509CertificateConverter().getCertificate(holder_cert_1); + Certificate c2 = new JcaX509CertificateConverter().getCertificate(holder_cert_2); + Certificate c3 = new JcaX509CertificateConverter().getCertificate(holder_cert_3); - XposedBridge.log("Couldn't found " + tagNo + " object in TEE list"); + return new Certificate[]{c1, c2, c3}; + } - for (ASN1Encodable asn1Encodable : swEnforcedAuthList) { - ASN1TaggedObject taggedObject = (ASN1TaggedObject) asn1Encodable; + private static ASN1Primitive getPrimitiveFromList(int tagNo) { - if (taggedObject.getTagNo() == tagNo) { - return taggedObject.getBaseObject().toASN1Primitive(); - } - } - - XposedBridge.log("Couldn't found " + tagNo + " object in SW list"); + if (map.containsKey(tagNo)) return map.get(tagNo); return null; } - private static Extension addHackedExtension(ASN1Sequence keyDescription) { + private static Extension addHackedExtension() { try { - swEnforcedAuthList = (ASN1Sequence) keyDescription.getObjectAt(6).toASN1Primitive(); - teeEnforcedAuthList = (ASN1Sequence) keyDescription.getObjectAt(7).toASN1Primitive(); - byte[] bytes1 = new byte[32]; byte[] bytes2 = new byte[32]; - SecureRandom secureRandom = new SecureRandom(); - - secureRandom.nextBytes(bytes1); - secureRandom.nextBytes(bytes2); + random.nextBytes(bytes1); + random.nextBytes(bytes2); ASN1Encodable[] rootOfTrustEncodables = { new DEROctetString(bytes1), @@ -169,54 +126,90 @@ public final class Xposed implements IXposedHookLoadPackage { ASN1Sequence rootOfTrustSeq = new DLSequence(rootOfTrustEncodables); - var Apurpose = getEncodableFromList(1); - var Aalgorithm = getEncodableFromList(2); - var AkeySize = getEncodableFromList(3); - var AecCurve = getEncodableFromList(10); - var AnoAuthRequired = getEncodableFromList(503); - var AcreationDateTime = getEncodableFromList(701); - var Aorigin = getEncodableFromList(702); - var AosVersion = getEncodableFromList(705); - var AosPatchLevel = getEncodableFromList(706); - var AattestationApplicationId = getEncodableFromList(709); - var AvendorPatchLevel = getEncodableFromList(718); - var AbootPatchLevel = getEncodableFromList(719); + ASN1Integer[] purposesArray = { + new ASN1Integer(2), + new ASN1Integer(3) + }; + + DLSet Apurpose = new DLSet(purposesArray); + ASN1Integer Aalgorithm = new ASN1Integer(3); + ASN1Integer AkeySize = new ASN1Integer(256); + ASN1Integer AecCurve = new ASN1Integer(1); + ASN1Null AnoAuthRequired = DERNull.INSTANCE; + ASN1Integer AosVersion = new ASN1Integer(140000); + ASN1Integer AosPatchLevel = new ASN1Integer(202312); + ASN1Integer AvendorPatchLevel = new ASN1Integer(20231217); + ASN1Integer AbootPatchLevel = new ASN1Integer(20231217); + + ASN1Primitive AcreationDateTime = null; + ASN1Primitive Aorigin = null; + ASN1Primitive AattestationApplicationId = null; + + if (!brokenTEE) { + AcreationDateTime = getPrimitiveFromList(701); + Aorigin = getPrimitiveFromList(702); + AattestationApplicationId = getPrimitiveFromList(709); + } var purpose = new DLTaggedObject(true, 1, Apurpose); var algorithm = new DLTaggedObject(true, 2, Aalgorithm); var keySize = new DLTaggedObject(true, 3, AkeySize); var ecCurve = new DLTaggedObject(true, 10, AecCurve); var noAuthRequired = new DLTaggedObject(true, 503, AnoAuthRequired); - var creationDateTime = new DLTaggedObject(true, 701, AcreationDateTime); - var origin = new DLTaggedObject(true, 702, Aorigin); var rootOfTrust = new DLTaggedObject(true, 704, rootOfTrustSeq); var osVersion = new DLTaggedObject(true, 705, AosVersion); var osPatchLevel = new DLTaggedObject(true, 706, AosPatchLevel); - var attestationApplicationId = new DLTaggedObject(true, 709, AattestationApplicationId); var vendorPatchLevel = new DLTaggedObject(true, 718, AvendorPatchLevel); var bootPatchLevel = new DLTaggedObject(true, 719, AbootPatchLevel); - ASN1Encodable[] teeEnforcedEncodables = { - purpose, - algorithm, - keySize, - ecCurve, - noAuthRequired, - creationDateTime, - origin, - rootOfTrust, - osVersion, - osPatchLevel, - attestationApplicationId, - vendorPatchLevel, - bootPatchLevel - }; + ASN1TaggedObject creationDateTime = null; + ASN1TaggedObject origin = null; + ASN1TaggedObject attestationApplicationId = null; + + if (!brokenTEE) { + creationDateTime = new DLTaggedObject(true, 701, AcreationDateTime); + origin = new DLTaggedObject(true, 702, Aorigin); + attestationApplicationId = new DLTaggedObject(true, 709, AattestationApplicationId); + } + + ASN1Encodable[] teeEnforcedEncodables; + + if (brokenTEE) { + teeEnforcedEncodables = new ASN1Encodable[]{ + purpose, + algorithm, + keySize, + ecCurve, + noAuthRequired, + rootOfTrust, + osVersion, + osPatchLevel, + vendorPatchLevel, + bootPatchLevel + }; + } else { + teeEnforcedEncodables = new ASN1Encodable[]{ + purpose, + algorithm, + keySize, + ecCurve, + noAuthRequired, + creationDateTime, + origin, + rootOfTrust, + osVersion, + osPatchLevel, + attestationApplicationId, + vendorPatchLevel, + bootPatchLevel + }; + } ASN1Integer attestationVersion = new ASN1Integer(4); ASN1Enumerated attestationSecurityLevel = new ASN1Enumerated(2); ASN1Integer keymasterVersion = new ASN1Integer(41); ASN1Enumerated keymasterSecurityLevel = new ASN1Enumerated(2); - ASN1OctetString attestationChallenge = (ASN1OctetString) keyDescription.getObjectAt(4).toASN1Primitive(); + ASN1OctetString attestationChallenge = new DEROctetString(attestationChallengeBytes); ASN1OctetString uniqueId = new DEROctetString("".getBytes()); ASN1Sequence softwareEnforced = new DLSequence(); ASN1Sequence teeEnforced = new DLSequence(teeEnforcedEncodables); @@ -245,6 +238,56 @@ public final class Xposed implements IXposedHookLoadPackage { return null; } + private static void parseKeyDescription(ASN1Sequence keyDescription) { + ASN1Sequence swEnforcedAuthList = (ASN1Sequence) keyDescription.getObjectAt(6).toASN1Primitive(); + ASN1Sequence teeEnforcedAuthList = (ASN1Sequence) keyDescription.getObjectAt(7).toASN1Primitive(); + + for (ASN1Encodable encodable : swEnforcedAuthList) { + ASN1TaggedObject taggedObject = (ASN1TaggedObject) encodable; + + int tagNo = taggedObject.getTagNo(); + ASN1Primitive asn1Primitive = taggedObject.getBaseObject().toASN1Primitive(); + + if (asn1Primitive == null) { + XposedBridge.log("ERROR, couldn't parse " + tagNo + " object!"); + } else { + map.put(tagNo, asn1Primitive); + } + } + + for (ASN1Encodable encodable : teeEnforcedAuthList) { + ASN1TaggedObject taggedObject = (ASN1TaggedObject) encodable; + + int tagNo = taggedObject.getTagNo(); + ASN1Primitive asn1Primitive = taggedObject.getBaseObject().toASN1Primitive(); + + if (asn1Primitive == null) { + XposedBridge.log("ERROR, couldn't parse " + tagNo + " object!"); + } else { + map.put(tagNo, asn1Primitive); + } + } + } + + private static Certificate brokenTeeLeafCert() throws Throwable { + var certBuilder = new JcaX509v3CertificateBuilder( + new X500Name("CN=chiteroman"), + new BigInteger(128, random), + new Date(System.currentTimeMillis()), + new Date(System.currentTimeMillis() + 365L * 24 * 60 * 60 * 1000), + new X500Name("CN=Android Keystore Key"), + EC_KEYPAIR.getPublic() + ); + + certBuilder.addExtension(addHackedExtension()); + + ContentSigner contentSigner = new JcaContentSignerBuilder("SHA256withECDSA").build(EC_KEYPAIR.getPrivate()); + + X509CertificateHolder certHolder = certBuilder.build(contentSigner); + + return new JcaX509CertificateConverter().getCertificate(certHolder); + } + private static Certificate hackLeafCert(X509Certificate certificate) throws Throwable { var holder = new X509CertificateHolder(certificate.getEncoded()); @@ -272,7 +315,9 @@ public final class Xposed implements IXposedHookLoadPackage { ASN1Sequence keyDescription = ASN1Sequence.getInstance(extension.getExtnValue().getOctets()); - certBuilder.addExtension(addHackedExtension(keyDescription)); + parseKeyDescription(keyDescription); + + certBuilder.addExtension(addHackedExtension()); ContentSigner contentSigner = new JcaContentSignerBuilder("SHA256withECDSA").build(EC_KEYPAIR.getPrivate()); @@ -284,34 +329,53 @@ public final class Xposed implements IXposedHookLoadPackage { @Override public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) { try { - KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); - KeyStoreSpi keyStoreSpi = (KeyStoreSpi) XposedHelpers.getObjectField(keyStore, "keyStoreSpi"); - XposedHelpers.findAndHookMethod(keyStoreSpi.getClass(), "engineGetCertificateChain", String.class, new XC_MethodHook() { + Class keyGenBuilder = XposedHelpers.findClass("android.security.keystore.KeyGenParameterSpec.Builder", lpparam.classLoader); + XposedHelpers.findAndHookMethod(keyGenBuilder, "setAttestationChallenge", byte[].class, new XC_MethodHook() { + @Override + protected void beforeHookedMethod(MethodHookParam param) { + attestationChallengeBytes = (byte[]) param.args[0]; + XposedBridge.log("attestationChallenge: " + Arrays.toString(attestationChallengeBytes)); + } + }); + + Class keyPairGenerator = XposedHelpers.findClass("android.security.keystore2.AndroidKeyStoreKeyPairGeneratorSpi", lpparam.classLoader); + XposedHelpers.findAndHookMethod(keyPairGenerator, "generateKeyPair", XC_MethodReplacement.returnConstant(EC_KEYPAIR)); + + Class keyStoreSpi = XposedHelpers.findClass("android.security.keystore2.AndroidKeyStoreSpi", lpparam.classLoader); + XposedHelpers.findAndHookMethod(keyStoreSpi, "engineGetCertificateChain", String.class, new XC_MethodHook() { @Override protected void afterHookedMethod(MethodHookParam param) { try { - Certificate[] certificates = (Certificate[]) param.getResultOrThrowable(); - - Certificate leaf = certificates[0]; - - if (!(leaf instanceof X509Certificate x509Certificate)) return; - - byte[] bytes = x509Certificate.getExtensionValue("1.3.6.1.4.1.11129.2.1.17"); - - if (bytes == null || bytes.length == 0) { - XposedBridge.log("Leaf certificate doesn't contain attestation extensions... Ignoring it."); - return; - } - - List otherCerts = getOtherCertList(); + Certificate[] otherCerts = getOtherCerts(); Certificate[] hackCerts = new Certificate[4]; - hackCerts[0] = hackLeafCert(x509Certificate); + System.arraycopy(otherCerts, 0, hackCerts, 1, otherCerts.length); - hackCerts[1] = otherCerts.get(0); - hackCerts[2] = otherCerts.get(1); - hackCerts[3] = otherCerts.get(2); + Certificate[] certificates = (Certificate[]) param.getResult(); + + if (certificates == null || certificates.length == 0) { + brokenTEE = true; + + XposedBridge.log("Uhhh, seems like you have a broken TEE."); + hackCerts[0] = brokenTeeLeafCert(); + + } else { + brokenTEE = false; + + Certificate leaf = certificates[0]; + + if (!(leaf instanceof X509Certificate x509Certificate)) return; + + byte[] bytes = x509Certificate.getExtensionValue("1.3.6.1.4.1.11129.2.1.17"); + + if (bytes == null || bytes.length == 0) { + XposedBridge.log("Leaf certificate doesn't contain attestation extensions... Ignoring it."); + return; + } + + hackCerts[0] = hackLeafCert(x509Certificate); + } param.setResult(hackCerts); @@ -321,7 +385,7 @@ public final class Xposed implements IXposedHookLoadPackage { } }); } catch (Throwable t) { - XposedBridge.log(t); + XposedBridge.log("ERROR: " + t); } } }