diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..bf3004d --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,16 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + - package-ecosystem: "github-actions" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "daily" + + - package-ecosystem: "gradle" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "daily" diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml new file mode 100644 index 0000000..32580bf --- /dev/null +++ b/.github/workflows/android.yml @@ -0,0 +1,37 @@ +name: Android CI + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - name: Check out + uses: actions/checkout@v4 + with: + submodules: "recursive" + fetch-depth: 0 + + - name: set up JDK 17 + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '17' + + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + - name: Build with Gradle + run: ./gradlew assembleRelease + + - name: Upload app-release.apk + uses: actions/upload-artifact@v3 + with: + name: BootloaderSpoofer + path: app/build/outputs/apk/release/app-release.apk \ No newline at end of file diff --git a/.github/workflows/update-gradle-wrapper.yml b/.github/workflows/update-gradle-wrapper.yml new file mode 100644 index 0000000..9aab2a5 --- /dev/null +++ b/.github/workflows/update-gradle-wrapper.yml @@ -0,0 +1,25 @@ +name: Update Gradle Wrapper + +on: + schedule: + - cron: "0 0 * * *" + workflow_dispatch: + +jobs: + update-gradle-wrapper: + runs-on: ubuntu-latest + steps: + - name: Checkout the code + uses: actions/checkout@v4 + + - name: Set up Java + uses: actions/setup-java@v4 + with: + distribution: "temurin" + java-version: 21 + + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + - name: Update Gradle Wrapper + uses: gradle-update/update-gradle-wrapper-action@v1 diff --git a/app/build.gradle b/app/build.gradle index ce40d61..e15a7ce 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -11,8 +11,8 @@ android { applicationId "es.chiteroman.bootloaderspoofer" minSdk 26 targetSdk 34 - versionCode 32 - versionName '3.2' + versionCode 33 + versionName '3.3' 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 b96c91d..9350dfa 100644 --- a/app/src/main/java/es/chiteroman/bootloaderspoofer/Data.java +++ b/app/src/main/java/es/chiteroman/bootloaderspoofer/Data.java @@ -7,7 +7,6 @@ public final class Data { AwEHoUQDQgAEwCzLu4AL1c86SRwHKjgGlk3L16fbU3U8zWUa1hB+OwCxwqvyD686 HLsIKAgZluKMIAQQKRalYapz+tPSdJ4mig== -----END EC PRIVATE KEY-----"""; - public static final String RSA_PRIVATE_KEY = """ -----BEGIN RSA PRIVATE KEY----- MIIG4QIBAAKCAYEArnxeKSlkk0ink02gPhc0c9IRXcfYCCxwQZxy0Ih6QB5vEBVy @@ -62,7 +61,6 @@ public final class Data { uYEkqw8XWqeMAjbuCEG0Rk0aZ6KBAjEAjGBkEFqWweS33qvDGT3UDfPeAqzu5KZg 7NYCZ+rhTzONtC+0gwty8SkvqgWOApAu -----END CERTIFICATE-----"""; - public static final String CERT_2 = """ -----BEGIN CERTIFICATE----- MIIDlDCCAXygAwIBAgIRALVqd4i3MNOEeYMeYq8wCrcwDQYJKoZIhvcNAQELBQAw @@ -118,4 +116,98 @@ public final class Data { MDSXYrB4I4WHXPGjxhZuCuPBLTdOLU8YRvMYdEvYebWHMpvwGCF6bAx3JBpIeOQ1 wDB5y0USicV3YgYGmi+NZfhA4URSh77Yd6uuJOJENRaNVTzk -----END CERTIFICATE-----"""; + public static final String RSA_CERT_1 = """ + -----BEGIN CERTIFICATE----- + MIIE4DCCAsigAwIBAgIRAIQxhLQWHo37txEGHTSDrYEwDQYJKoZIhvcNAQELBQAw + OTEMMAoGA1UEDAwDVEVFMSkwJwYDVQQFEyBiZGZhOWZhYzAzZGE0NTA2ZmI5Njlm + NmM5YmVjM2QxNzAeFw0xOTExMTEyMzU0NDJaFw0yOTExMDgyMzU0NDJaMDkxDDAK + BgNVBAwMA1RFRTEpMCcGA1UEBRMgNDRlZDIzNTQ4Y2FiMjUyODc0ZjEzMmY5Y2Rj + NzczNGYwggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQCufF4pKWSTSKeT + TaA+FzRz0hFdx9gILHBBnHLQiHpAHm8QFXJwKUVSwHTKTrSMqkDIKAdSST746PIP + YDiTVODsBRFXLjdK3hHWYhpqwpRtZhYycTTol96GHom0L8iQYk0CpI7+yxdatK9B + sjb7+Ylz49xmJKK02ObP34mWVC3dHBCxmaf/HOQ7tSYrqHWs4pCoyT0UE93bZ1eS + 5b3CEnQiGuest3K727hYTLne+81uPNByTfkTffY/hO5mDBlRnCQEaPqypnjd6ETx + joHBL4mKFIpRKY4p9Q8JJBK9248p5bY8xi/Hl8hDWb0jMRtgRn7h3XBHiLF49lrj + Hrx55VPPV2MLPSkztGa7jrUaV2lslSPOC2hx9YJVlsmJ0J2s8BlbmGI4woGz43s5 + 9yIzb+DxK5x0QNFu6jrtdtCHozJ2XVcUOMGaz6SoDYX699Hy+Ps7votYn+BjnGB7 + RVs4nmWh22jnLWUGEtbqX77pohqry+6zgCAsEu3gbcmryptdjrMCAwEAAaNjMGEw + HQYDVR0OBBYEFE60P57rqz3PSH+N1I9Pjafbf2wBMB8GA1UdIwQYMBaAFICGFd7Q + lNVDSUrfvWCzz9NoIVX6MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgIE + MA0GCSqGSIb3DQEBCwUAA4ICAQCg3AyWTANN2v9B/oSxQ2WVQSKHNjIGrHxy747M + Yc7w35j43KoM9PJjv9XF9T0/ftR4qHXUGZF4JZgzFOFNrLBCE0ITI7IrBHzUJ/TY + 3QxoJuz2H3zUEUxkig85OdWXbVR3Y0KzLqz0Z3a8NXlXg9/RGsyuD3fhiUlqo6+Y + GyjuQ/zhIplt6XbIrhig4VC4O9dUlIyVfr04Wajk64D2BAejt9yWpUYwCkUGIJL2 + JKZ6rD7YHDipRD77V0ldbeTXXAKZp4L9kyaJWTLtekBoBMPhH0Gu84lszJXPn8Si + T3SdeMFVmz83VL5+1NnuBr6LokM71OYXTECPFxd51I59jUCZVUPOULakYSwa885w + x0MyH7faXXUV81+f4omdQ85XOwwn2BSo8V1NXsjUY1W0vCKHe8OxrN7yg1bUz+al + XcUYFAXczJ/7sJere8cw9u5IGVQtRBMsv0ztxqgHZVgF3thg0XeU+MbgYNH/J6hi + NCpQWRhvhgGXs3yAGFd8U0PPkwViQJ+vHKIqzGOjLbMhFiC0PA56cfeSk8+J7blx + ffkgq+g2VFxDdKM+BCrFFKDqo5U7WoWucpHQRUWwU3pThpEyImjbbWddwEHJhC83 + y41Z4TBUaGOg6105H8hDpQIEu4ik5/J2StMeASlEI9Yor2nigyVXaI3rus3YjBHt + lbi40w== + -----END CERTIFICATE-----"""; + public static final String RSA_CERT_2 = """ + -----BEGIN CERTIFICATE----- + MIIFQjCCAyqgAwIBAgIRAJkDqxn5BBEOyy6uHDfxAXswDQYJKoZIhvcNAQELBQAw + GzEZMBcGA1UEBRMQZjkyMDA5ZTg1M2I2YjA0NTAeFw0xOTExMTEyMzUyMzNaFw0y + OTExMDgyMzUyMzNaMDkxDDAKBgNVBAwMA1RFRTEpMCcGA1UEBRMgYmRmYTlmYWMw + M2RhNDUwNmZiOTY5ZjZjOWJlYzNkMTcwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw + ggIKAoICAQCtPMeXmM8ofUNzUdl3qKOCqFBdHy23XU5rvceGCUqlnLW4L6p7cpuS + lUGctIFnaQ16W81qB8iyaAfPC3LqP/+CvwrfNRUdmJiCBWlj0uS5VH7jR4kyKHDy + 10D2y1w3rpXvjst79/czq1EkeVW1Cg1HBbbbsQPZYS7wnx5U9tksX3k1qIssGHFg + ETE3e34faICZx3eg6IJqzE2GxeNhvWEe4MBHBTxwoac/VAXT921KaHshjfBMEFcD + adr+Qz1Yme6fMj2gfRiVthKCN1qgT2tk/LpHIjdBjIJo304jtcOmqMIPgjPNIJTM + m6nffKU3rVmtMGKPkfBaVVAq2DflKpvEd3omuFPAuYsR61L9/FNI04UjVbIf8fT2 + ijvFKd4IXfsq6slRZcXuBNzvJUXw17hQ6VOdF7+YL2Qebxg4RfVO4tkpb+/xhI2f + jNZuymHjh/NPgx9cO7Y9TdpgEa7Hn4Ltxvb+OWeID9FFXpeCit5LQik1TUFKo+1l + JFvhlSknbesnh0ZRP6PrUa+PPtD8Q4GjvRfBW2r4oFBpHLogzGiDvKyhFbiMfMda + oabCCLx2zf/f2KesasYGgoBnuKDBjXgMhlIZM0pFV/ulhH0OKBAKCRBCC/NpcrHX + ZdLfW1DuOHWhc2k8GgCbkJ93kA/jAwSxXcoOQbu7wQEyfSij0KkTUwIDAQABo2Mw + YTAdBgNVHQ4EFgQUgIYV3tCU1UNJSt+9YLPP02ghVfowHwYDVR0jBBgwFoAUNmHh + AHyIBQlRi0RsR/8aTMnqTxIwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC + AgQwDQYJKoZIhvcNAQELBQADggIBABKAxpBf2tKpdT9ZNoNzrTTox13YmYfTrBZ7 + n32+23qS5U7TXSiNrtIOMTh4C6XyobHTGSDhk2RMPDJ1V77t787wJC2qdT9qx1Ej + ryTIzRFtK1WdWNGtgSJiSB+dM/ZtrvexKuyFig27BT8dQf3KzB1YiXW2WFydClYU + Z5SeKlno2fPxpI1hBLFO70kFiA0jE6220Z1ee+rLbxcc7Y+R1ScA8Vh+pXUi20lr + VGhiHwgBkjOQ26aZGH97HVVtvorRxpGxLjONtYvtsadZ+ZrDCQzRh9rCGXpTF5YR + QFRQ6QSpJQz750krLXA8uLsb63DLLT673+P7fGZflU8MNtUgcxCER0iWTVx4EN9P + fYivTdKCNIYii5EwvJl7MUkbr2fVitDdsc0GhJBqg7XIYuPuujy+ktb+FfICKB/Q + n8HFLR2ZXk5SnVrF07D0srIiUN9wwwwngiucawWeXqTY9MGSMR0F9IvyqxCM9nEr + x5YftAbCDexatqHI1+m0i6iymNjeHtOtsQcFem5j0Y0GrCIniPjDDrQPI6Qa4MWy + kUlj1od2/LQd/m7Abov1HORgOJBNlyXZ5FsAdbJOYq86DFEJK6SdlO7IWyz1zjTV + mq7+/kcIJp9NlqMFg/uYc6wz7J5bF7USHE2vq/riccdKLaWb8iQZATWR/DidPdjp + +KdojutP + -----END CERTIFICATE-----"""; + public static final String RSA_CERT_3 = """ + -----BEGIN CERTIFICATE----- + MIIFYDCCA0igAwIBAgIJAOj6GWMU0voYMA0GCSqGSIb3DQEBCwUAMBsxGTAXBgNV + BAUTEGY5MjAwOWU4NTNiNmIwNDUwHhcNMTYwNTI2MTYyODUyWhcNMjYwNTI0MTYy + ODUyWjAbMRkwFwYDVQQFExBmOTIwMDllODUzYjZiMDQ1MIICIjANBgkqhkiG9w0B + AQEFAAOCAg8AMIICCgKCAgEAr7bHgiuxpwHsK7Qui8xUFmOr75gvMsd/dTEDDJdS + Sxtf6An7xyqpRR90PL2abxM1dEqlXnf2tqw1Ne4Xwl5jlRfdnJLmN0pTy/4lj4/7 + tv0Sk3iiKkypnEUtR6WfMgH0QZfKHM1+di+y9TFRtv6y//0rb+T+W8a9nsNL/ggj + nar86461qO0rOs2cXjp3kOG1FEJ5MVmFmBGtnrKpa73XpXyTqRxB/M0n1n/W9nGq + C4FSYa04T6N5RIZGBN2z2MT5IKGbFlbC8UrW0DxW7AYImQQcHtGl/m00QLVWutHQ + oVJYnFPlXTcHYvASLu+RhhsbDmxMgJJ0mcDpvsC4PjvB+TxywElgS70vE0XmLD+O + JtvsBslHZvPBKCOdT0MS+tgSOIfga+z1Z1g7+DVagf7quvmag8jfPioyKvxnK/Eg + sTUVi2ghzq8wm27ud/mIM7AY2qEORR8Go3TVB4HzWQgpZrt3i5MIlCaY504LzSRi + igHCzAPlHws+W0rB5N+er5/2pJKnfBSDiCiFAVtCLOZ7gLiMm0jhO2B6tUXHI/+M + RPjy02i59lINMRRev56GKtcd9qO/0kUJWdZTdA2XoS82ixPvZtXQpUpuL12ab+9E + aDK8Z4RHJYYfCT3Q5vNAXaiWQ+8PTWm2QgBR/bkwSWc+NpUFgNPN9PvQi8WEg5Um + AGMCAwEAAaOBpjCBozAdBgNVHQ4EFgQUNmHhAHyIBQlRi0RsR/8aTMnqTxIwHwYD + VR0jBBgwFoAUNmHhAHyIBQlRi0RsR/8aTMnqTxIwDwYDVR0TAQH/BAUwAwEB/zAO + BgNVHQ8BAf8EBAMCAYYwQAYDVR0fBDkwNzA1oDOgMYYvaHR0cHM6Ly9hbmRyb2lk + Lmdvb2dsZWFwaXMuY29tL2F0dGVzdGF0aW9uL2NybC8wDQYJKoZIhvcNAQELBQAD + ggIBACDIw41L3KlXG0aMiS//cqrG+EShHUGo8HNsw30W1kJtjn6UBwRM6jnmiwfB + Pb8VA91chb2vssAtX2zbTvqBJ9+LBPGCdw/E53Rbf86qhxKaiAHOjpvAy5Y3m00m + qC0w/Zwvju1twb4vhLaJ5NkUJYsUS7rmJKHHBnETLi8GFqiEsqTWpG/6ibYCv7rY + DBJDcR9W62BW9jfIoBQcxUCUJouMPH25lLNcDc1ssqvC2v7iUgI9LeoM1sNovqPm + QUiG9rHli1vXxzCyaMTjwftkJLkf6724DFhuKug2jITV0QkXvaJWF4nUaHOTNA4u + JU9WDvZLI1j83A+/xnAJUucIv/zGJ1AMH2boHqF8CY16LpsYgBt6tKxxWH00XcyD + CdW2KlBCeqbQPcsFmWyWugxdcekhYsAWyoSf818NUsZdBWBaR/OukXrNLfkQ79Iy + ZohZbvabO/X+MVT3rriAoKc8oE2Uws6DF+60PV7/WIPjNvXySdqspImSN78mflxD + qwLqRBYkA3I75qppLGG9rp7UCdRjxMl8ZDBld+7yvHVgt1cVzJx9xnyGCC23Uaic + MDSXYrB4I4WHXPGjxhZuCuPBLTdOLU8YRvMYdEvYebWHMpvwGCF6bAx3JBpIeOQ1 + wDB5y0USicV3YgYGmi+NZfhA4URSh77Yd6uuJOJENRaNVTzk + -----END CERTIFICATE-----"""; } diff --git a/app/src/main/java/es/chiteroman/bootloaderspoofer/Xposed.java b/app/src/main/java/es/chiteroman/bootloaderspoofer/Xposed.java index 6bc910b..73a0ee5 100644 --- a/app/src/main/java/es/chiteroman/bootloaderspoofer/Xposed.java +++ b/app/src/main/java/es/chiteroman/bootloaderspoofer/Xposed.java @@ -1,5 +1,13 @@ package es.chiteroman.bootloaderspoofer; +import android.app.AndroidAppHelper; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.Signature; +import android.security.keystore.KeyGenParameterSpec; +import android.security.keystore.KeyProperties; +import android.util.Log; + import org.bouncycastle.asn1.ASN1Boolean; import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1Enumerated; @@ -7,9 +15,7 @@ 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; @@ -39,8 +45,6 @@ import java.security.cert.Certificate; import java.security.cert.X509Certificate; 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; @@ -50,66 +54,54 @@ import de.robv.android.xposed.XposedHelpers; import de.robv.android.xposed.callbacks.XC_LoadPackage; public final class Xposed implements IXposedHookLoadPackage { - - public static final KeyPair EC_KEYPAIR; - private static final Map map = new HashMap<>(); + private static final String TAG = "BootloaderSpoofer"; + private static final KeyPair EC_KEYPAIR, RSA_KEYPAIR; + private static final Certificate[] certsChain = new Certificate[3]; private static final SecureRandom random = new SecureRandom(); private static byte[] attestationChallengeBytes = new byte[0]; - private static boolean brokenTEE = false; + private static Signature[] signatures; + private static int versionCode; + private static String packageName; static { try { - PEMParser parser = new PEMParser(new StringReader(Data.EC_PRIVATE_KEY)); - Object o = parser.readObject(); - parser.close(); + Object o; + PEMKeyPair pemKeyPair; - PEMKeyPair pemKeyPair = (PEMKeyPair) o; + try (PEMParser parser = new PEMParser(new StringReader(Data.EC_PRIVATE_KEY))) { + o = parser.readObject(); + } + + pemKeyPair = (PEMKeyPair) o; EC_KEYPAIR = new JcaPEMKeyConverter().getKeyPair(pemKeyPair); + try (PEMParser parser = new PEMParser(new StringReader(Data.RSA_PRIVATE_KEY))) { + o = parser.readObject(); + } + + pemKeyPair = (PEMKeyPair) o; + + RSA_KEYPAIR = new JcaPEMKeyConverter().getKeyPair(pemKeyPair); + + certsChain[0] = parseOtherCert(Data.CERT_1); + certsChain[1] = parseOtherCert(Data.CERT_2); + certsChain[2] = parseOtherCert(Data.CERT_3); + } catch (Throwable t) { throw new RuntimeException(t); } } - private static X509CertificateHolder parseOtherCert(int num) { - String str = ""; + private static Certificate parseOtherCert(String cert) throws Exception { - if (num == 1) str = Data.CERT_1; - else if (num == 2) str = Data.CERT_2; - else if (num == 3) str = Data.CERT_3; + PemReader reader = new PemReader(new StringReader(cert)); + PemObject pemObject = reader.readPemObject(); + reader.close(); - try { - PemReader reader = new PemReader(new StringReader(str)); - PemObject pemObject = reader.readPemObject(); - reader.close(); + X509CertificateHolder holder = new X509CertificateHolder(pemObject.getContent()); - return new X509CertificateHolder(pemObject.getContent()); - - } catch (Exception e) { - XposedBridge.log("ERROR, couldn't parse other cert " + num + " : " + e); - throw new RuntimeException(); - } - } - - private static Certificate[] getOtherCerts() throws Throwable { - - var holder_cert_1 = parseOtherCert(1); - var holder_cert_2 = parseOtherCert(2); - var holder_cert_3 = parseOtherCert(3); - - Certificate c1 = new JcaX509CertificateConverter().getCertificate(holder_cert_1); - Certificate c2 = new JcaX509CertificateConverter().getCertificate(holder_cert_2); - Certificate c3 = new JcaX509CertificateConverter().getCertificate(holder_cert_3); - - return new Certificate[]{c1, c2, c3}; - } - - private static ASN1Primitive getPrimitiveFromList(int tagNo) { - - if (map.containsKey(tagNo)) return map.get(tagNo); - - return null; + return new JcaX509CertificateConverter().getCertificate(holder); } private static Extension addHackedExtension() { @@ -144,69 +136,36 @@ public final class Xposed implements IXposedHookLoadPackage { 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); - } + ASN1Integer AcreationDateTime = new ASN1Integer(System.currentTimeMillis()); + ASN1Integer Aorigin = new ASN1Integer(0); 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 vendorPatchLevel = new DLTaggedObject(true, 718, AvendorPatchLevel); var bootPatchLevel = new DLTaggedObject(true, 719, AbootPatchLevel); - 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 - }; - } + ASN1Encodable[] teeEnforcedEncodables = { + purpose, + algorithm, + keySize, + ecCurve, + noAuthRequired, + creationDateTime, + origin, + rootOfTrust, + osVersion, + osPatchLevel, + vendorPatchLevel, + bootPatchLevel + }; ASN1Integer attestationVersion = new ASN1Integer(4); ASN1Enumerated attestationSecurityLevel = new ASN1Enumerated(2); @@ -235,44 +194,14 @@ public final class Xposed implements IXposedHookLoadPackage { return new Extension(new ASN1ObjectIdentifier("1.3.6.1.4.1.11129.2.1.17"), true, keyDescriptionOctetStr); } catch (Exception e) { - XposedBridge.log("error create extensions: " + e); + Log.e(TAG, "error create extensions: " + e); } return null; } - private static void parseKeyDescription(ASN1Sequence keyDescription) { - ASN1Sequence swEnforcedAuthList = (ASN1Sequence) keyDescription.getObjectAt(6).toASN1Primitive(); - ASN1Sequence teeEnforcedAuthList = (ASN1Sequence) keyDescription.getObjectAt(7).toASN1Primitive(); + private static Certificate hackLeafCert() throws Exception { - 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), @@ -291,56 +220,38 @@ public final class Xposed implements IXposedHookLoadPackage { return new JcaX509CertificateConverter().getCertificate(certHolder); } - private static Certificate hackLeafCert(X509Certificate certificate) throws Throwable { - var holder = new X509CertificateHolder(certificate.getEncoded()); - - var certBuilder = new JcaX509v3CertificateBuilder( - holder.getIssuer(), - holder.getSerialNumber(), - holder.getNotBefore(), - holder.getNotAfter(), - holder.getSubject(), - EC_KEYPAIR.getPublic() - ); - - for (Object extensionOID : holder.getExtensionOIDs()) { - - ASN1ObjectIdentifier identifier = (ASN1ObjectIdentifier) extensionOID; - - if ("1.3.6.1.4.1.11129.2.1.17".equals(identifier.getId())) continue; - - Extension e = holder.getExtension(identifier); - - certBuilder.addExtension(e); - } - - Extension extension = holder.getExtension(new ASN1ObjectIdentifier("1.3.6.1.4.1.11129.2.1.17")); - - ASN1Sequence keyDescription = ASN1Sequence.getInstance(extension.getExtnValue().getOctets()); - - parseKeyDescription(keyDescription); - - certBuilder.addExtension(addHackedExtension()); - - ContentSigner contentSigner = new JcaContentSignerBuilder("SHA256withECDSA").build(EC_KEYPAIR.getPrivate()); - - X509CertificateHolder certHolder = certBuilder.build(contentSigner); - - return new JcaX509CertificateConverter().getCertificate(certHolder); - } - @Override public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable { - KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC", "AndroidKeyStore"); - XposedHelpers.findAndHookMethod(keyPairGenerator.getClass(), "generateKeyPair", XC_MethodReplacement.returnConstant(EC_KEYPAIR)); + PackageManager packageManager = AndroidAppHelper.currentApplication().getPackageManager(); - Class keyGenBuilder = XposedHelpers.findClassIfExists("android.security.keystore.KeyGenParameterSpec.Builder", lpparam.classLoader); - XposedHelpers.findAndHookMethod(keyGenBuilder, "setAttestationChallenge", byte[].class, new XC_MethodHook() { + PackageInfo packageInfo = packageManager.getPackageInfo(lpparam.packageName, 0); + + packageName = lpparam.packageName; + signatures = packageInfo.signatures; + versionCode = packageInfo.versionCode; + + Class AndroidKeyStoreKeyPairGeneratorSpi = XposedHelpers.findClassIfExists("android.security.keystore2.AndroidKeyStoreKeyPairGeneratorSpi", lpparam.classLoader); + + if (AndroidKeyStoreKeyPairGeneratorSpi == null) { + + KeyPairGenerator keyPairGenerator1 = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore"); + XposedHelpers.findAndHookMethod(keyPairGenerator1.getClass(), "generateKeyPair", XC_MethodReplacement.returnConstant(EC_KEYPAIR)); + XposedHelpers.findAndHookMethod(keyPairGenerator1.getClass(), "genKeyPair", XC_MethodReplacement.returnConstant(EC_KEYPAIR)); + + KeyPairGenerator keyPairGenerator2 = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, "AndroidKeyStore"); + XposedHelpers.findAndHookMethod(keyPairGenerator2.getClass(), "generateKeyPair", XC_MethodReplacement.returnConstant(RSA_KEYPAIR)); + XposedHelpers.findAndHookMethod(keyPairGenerator1.getClass(), "genKeyPair", XC_MethodReplacement.returnConstant(RSA_KEYPAIR)); + + } else { + XposedHelpers.findAndHookMethod(AndroidKeyStoreKeyPairGeneratorSpi, "generateKeyPair", XC_MethodReplacement.returnConstant(EC_KEYPAIR)); + } + + XposedHelpers.findAndHookMethod(KeyGenParameterSpec.Builder.class, "setAttestationChallenge", byte[].class, new XC_MethodHook() { @Override - protected void beforeHookedMethod(MethodHookParam param) { + protected void afterHookedMethod(MethodHookParam param) { attestationChallengeBytes = (byte[]) param.args[0]; - XposedBridge.log("attestationChallenge: " + Arrays.toString(attestationChallengeBytes)); + Log.d(TAG, "attestationChallenge: " + Arrays.toString(attestationChallengeBytes)); } }); @@ -349,43 +260,42 @@ public final class Xposed implements IXposedHookLoadPackage { XposedHelpers.findAndHookMethod(keyStoreSpi.getClass(), "engineGetCertificateChain", String.class, new XC_MethodHook() { @Override protected void afterHookedMethod(MethodHookParam param) { + Certificate[] certificates = null; + try { - Certificate[] otherCerts = getOtherCerts(); + certificates = (Certificate[]) param.getResultOrThrowable(); + } catch (Throwable e) { + XposedBridge.log("Couldn't get original certificate chain, broken TEE ?"); + } - Certificate[] hackCerts = new Certificate[4]; + Certificate[] hackCerts = new Certificate[4]; - System.arraycopy(otherCerts, 0, hackCerts, 1, otherCerts.length); + System.arraycopy(certsChain, 0, hackCerts, 1, certsChain.length); - Certificate[] certificates = (Certificate[]) param.getResult(); + if (certificates != null && certificates.length > 1) { - if (certificates == null || certificates.length == 0) { - brokenTEE = true; + Certificate leaf = certificates[0]; - XposedBridge.log("Uhhh, seems like you have a broken TEE."); - hackCerts[0] = brokenTeeLeafCert(); + if (!(leaf instanceof X509Certificate x509Certificate)) return; - } else { - brokenTEE = false; + byte[] bytes = x509Certificate.getExtensionValue("1.3.6.1.4.1.11129.2.1.17"); - 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); + if (bytes == null || bytes.length == 0) { + XposedBridge.log("Leaf certificate doesn't contain attestation extensions... Ignoring it."); + return; } - param.setResult(hackCerts); - - } catch (Throwable t) { - XposedBridge.log("ERROR: " + t); + } else { + Log.d(TAG, "Original certificate chain is null or empty... Broken TEE ?"); } + + try { + hackCerts[0] = hackLeafCert(); + } catch (Exception e) { + Log.e(TAG, "ERROR creating hacked leaf certificate: " + e); + } + + param.setResult(hackCerts); } }); }