This commit is contained in:
chiteroman 2023-12-18 01:27:14 +01:00
parent 6cd483afce
commit 4425a3bb58
No known key found for this signature in database
GPG Key ID: 19171A27D600CC72
6 changed files with 284 additions and 204 deletions

16
.github/dependabot.yml vendored Normal file
View File

@ -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"

37
.github/workflows/android.yml vendored Normal file
View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -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-----""";
}

View File

@ -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<Integer, ASN1Primitive> 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);
}
});
}