v3.1
This commit is contained in:
parent
9152f7d661
commit
40cc836ae3
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<Integer, ASN1Primitive> 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<Certificate> getOtherCertList() throws Throwable {
|
||||
List<Certificate> 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<Certificate> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue