This commit is contained in:
chiteroman 2023-12-17 15:32:05 +01:00
parent 5de0cda36e
commit 9152f7d661
No known key found for this signature in database
GPG Key ID: 19171A27D600CC72
4 changed files with 329 additions and 133 deletions

View File

@ -11,8 +11,8 @@ android {
applicationId "es.chiteroman.bootloaderspoofer" applicationId "es.chiteroman.bootloaderspoofer"
minSdk 26 minSdk 26
targetSdk 34 targetSdk 34
versionCode 21 versionCode 30
versionName '2.1' versionName '3.0'
multiDexEnabled false multiDexEnabled false
} }
@ -34,5 +34,5 @@ android {
dependencies { dependencies {
compileOnly 'de.robv.android.xposed:api:82' compileOnly 'de.robv.android.xposed:api:82'
implementation 'org.bouncycastle:bcpkix-lts8on:2.73.3' implementation 'org.bouncycastle:bcpkix-jdk18on:1.77'
} }

View File

@ -1 +1,3 @@
-ignorewarnings
-dontobfuscate
-keep class es.chiteroman.bootloaderspoofer.Xposed {public <methods>;} -keep class es.chiteroman.bootloaderspoofer.Xposed {public <methods>;}

View File

@ -0,0 +1,80 @@
package es.chiteroman.bootloaderspoofer;
public final class Data {
public static final String EC_PRIVATE_KEY = """
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEINe7CzSlS7CEOgdCH9Zg8IP+GfhVVNT0tDzgQNuDXtDSoAoGCCqGSM49
AwEHoUQDQgAEwCzLu4AL1c86SRwHKjgGlk3L16fbU3U8zWUa1hB+OwCxwqvyD686
HLsIKAgZluKMIAQQKRalYapz+tPSdJ4mig==
-----END EC PRIVATE KEY-----""";
public static final String CERT_1 = """
-----BEGIN CERTIFICATE-----
MIIB9DCCAXqgAwIBAgIRAM/Qn0kkZ6jXjzyH+K6CsO0wCgYIKoZIzj0EAwIwOTEM
MAoGA1UEDAwDVEVFMSkwJwYDVQQFEyBiZGZhOWZhYzAzZGE0NTA2ZmI5NjlmNmM5
YmVjM2QxNzAeFw0xOTExMTEyMzU0NDJaFw0yOTExMDgyMzU0NDJaMDkxDDAKBgNV
BAwMA1RFRTEpMCcGA1UEBRMgNDRlZDIzNTQ4Y2FiMjUyODc0ZjEzMmY5Y2RjNzcz
NGYwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATALMu7gAvVzzpJHAcqOAaWTcvX
p9tTdTzNZRrWEH47ALHCq/IPrzocuwgoCBmW4owgBBApFqVhqnP609J0niaKo2Mw
YTAdBgNVHQ4EFgQUlGSg1+oyzEu37ungNj341PMOvk0wHwYDVR0jBBgwFoAUBPEA
vvdDAhpX9Xt/RL1yD9YU6ckwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
AgQwCgYIKoZIzj0EAwIDaAAwZQIwVftvDTBnJsiJpdYew5lCTheSq/ZjXowgIs6d
uYEkqw8XWqeMAjbuCEG0Rk0aZ6KBAjEAjGBkEFqWweS33qvDGT3UDfPeAqzu5KZg
7NYCZ+rhTzONtC+0gwty8SkvqgWOApAu
-----END CERTIFICATE-----""";
public static final String CERT_2 = """
-----BEGIN CERTIFICATE-----
MIIDlDCCAXygAwIBAgIRALVqd4i3MNOEeYMeYq8wCrcwDQYJKoZIhvcNAQELBQAw
GzEZMBcGA1UEBRMQZjkyMDA5ZTg1M2I2YjA0NTAeFw0xOTExMTEyMzUyNTBaFw0y
OTExMDgyMzUyNTBaMDkxDDAKBgNVBAwMA1RFRTEpMCcGA1UEBRMgYmRmYTlmYWMw
M2RhNDUwNmZiOTY5ZjZjOWJlYzNkMTcwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATv
oM6LGOSsxFxqblxvbf4+A/dajU/a500Cmf/xMVHwAKU4kb1gTwhbVUwi8D2ZCoBD
3ZrJa01753DecVP6Jfz5wt/HxA6djWbx1OP7Prr7e/gn/6QcJmb+/hdATeLnQ5Kj
YzBhMB0GA1UdDgQWBBQE8QC+90MCGlf1e39EvXIP1hTpyTAfBgNVHSMEGDAWgBQ2
YeEAfIgFCVGLRGxH/xpMyepPEjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE
AwICBDANBgkqhkiG9w0BAQsFAAOCAgEAJ9bMFKIyzg1M4SOLVCFjf5tuxu8mpy+H
Ok4X/Z3nOSyWWZUxBnsI3ke278Qa5L5IcDgfQJXknVQrY9ibgFNmd6wXI17sYOJA
oBiPmxuMHm4O7KiRMwEWtnfjzXuvyGcF9EFXGyOIofn0TprGHPWNmyQ/pTfn4qmA
DreD5SMKtp5USYX3gOhPYqyycPLv9vU0PYRH01zf4hyd0aHzA9ND02P5/t0Cp9uw
jNb/lGwEGdjGJwMDpM3YDlIkFNB15X8Lt1asMWXBWE8hGUv14/gQHu4newAOQaqX
goDi00ddLr2qV9J0fgKzSbxLrmnjO4zYGvJhOUTWHj9q34MRgrgIvNAKQh7xMqdC
4qE6AnMWt9LTZBApdGj02BFiMdX+2/tKWekhQIbHvYF3Avg3aC4i2y6nMfjnEEeG
2K2UZJ/vavIhzT5v4bo4YpAvjXSrT7xVYDrcjrY5cH7gsnaivmCMqFrUvfxfAz7E
A0lbo8MJIoR+XnB3j/NtzmchUgNcwboUIJdnpw31C2T3imf/CZMm4fhyrNzQ/lSc
K3wd1Eww5f/SAiV15uO4Xg1iNKz+oPiA8o0752DVanuA8axtnCSYpc5Oet0QjMI9
lkDXiaGK9E5isP0X7aIH0b8e3C25Jbcm7UygzrGTmu/ETeBjIvvoe6jIoJN8+D6I
okDkrORrlNI=
-----END CERTIFICATE-----""";
public static final String 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,12 +1,19 @@
package es.chiteroman.bootloaderspoofer; package es.chiteroman.bootloaderspoofer;
import org.bouncycastle.asn1.ASN1Boolean;
import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1Enumerated;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.ASN1TaggedObject; import org.bouncycastle.asn1.ASN1TaggedObject;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DLSequence;
import org.bouncycastle.asn1.DLTaggedObject;
import org.bouncycastle.asn1.x509.Extension; import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder; import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.openssl.PEMKeyPair; import org.bouncycastle.openssl.PEMKeyPair;
@ -14,196 +21,303 @@ import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter; import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.bouncycastle.operator.ContentSigner; import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader;
import java.io.StringReader; import java.io.StringReader;
import java.lang.reflect.Method;
import java.security.KeyPair; import java.security.KeyPair;
import java.security.KeyStore; import java.security.KeyStore;
import java.security.KeyStoreSpi; import java.security.KeyStoreSpi;
import java.security.SecureRandom;
import java.security.cert.Certificate; import java.security.cert.Certificate;
import java.security.cert.CertificateException; import java.security.cert.X509Certificate;
import java.util.Locale; import java.util.ArrayList;
import java.util.List;
import de.robv.android.xposed.IXposedHookLoadPackage; import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook; 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.XposedBridge;
import de.robv.android.xposed.XposedHelpers; import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage; import de.robv.android.xposed.callbacks.XC_LoadPackage;
public final class Xposed implements IXposedHookLoadPackage { public final class Xposed implements IXposedHookLoadPackage {
private static final String SW_RSA_ATTEST_ROOT_KEY = """
-----BEGIN RSA PRIVATE KEY----- private static final KeyPair EC_KEYPAIR;
MIICXQIBAAKBgQCia63rbi5EYe/VDoLmt5TRdSMfd5tjkWP/96r/C3JHTsAsQ+wz private static final X509CertificateHolder holder_cert_1, holder_cert_2, holder_cert_3;
fNes7UA+jCigZtX3hwszl94OuE4TQKuvpSe/lWmgMdsGUmX4RFlXYfC78hdLt0GA private static ASN1Sequence swEnforcedAuthList, teeEnforcedAuthList;
ZMAoDo9Sd47b0ke2RekZyOmLw9vCkT/X11DEHTVm+Vfkl5YLCazOkjWFmwIDAQAB
AoGAU8dxXchmqzVNbbvff7zgUa63YErk51Yem/EXzhkMaIXRkMO0edaCtZtnkRvg
9OQ2qEiLWaCTlUoyU7H/HUn2lwTQsOXyZI7dHijVDRMIv1mmrHCrGW/JC8FXfPLS
r3L3KoHXQVYL2mslbR8Rpogxq4WwnwK6XqSTH9mynFwQwEkCQQDMX3EZk3ricWVH
ruXD0BpXOMMpZuLu4rg5+1L51WEJvItIMeSjLuNa+g3AI8AYTYYi/aSLk6XEv82L
iXFGmJ2XAkEAy3M8k8Z0QzHae4olduqoHVWEarBtDE+fqFQBWgdm8fZhdHWrvlAc
qwJIXMUVc+dWm/FAQarCjbqWqhCRdaYgnQJBAJ7z7GdUCVNtlrQ2F4ZAqPwFreTZ
nM7njxmpm1Os3hhQiJPSGl3A7huoOGGkbJd6VEWKuRvF7jwkYZ2RfITH1mkCQAvh
X9E1Toa5+4spRwTJsSV9X+0m/kcwwx7+QNH0CrPockptsKi9Xt8xk+4u6BDLmogi
r2DmStQh6DhoHUZkfBUCQQCOgBkqH/15drpdR+BQH3VaP4/ALFfxR9E3G+lS+M5a
IqJEk9kh8vjuGzTaAZyU5keUmpWNc1gI7OvDMaH4+8vQ
-----END RSA PRIVATE KEY-----
""";
private static final KeyPair keyPair;
private static boolean hardwareAttesatation = false;
static { static {
try { try {
PEMParser parser = new PEMParser(new StringReader(SW_RSA_ATTEST_ROOT_KEY)); PEMParser parser = new PEMParser(new StringReader(Data.EC_PRIVATE_KEY));
PEMKeyPair pemKeyPair = (PEMKeyPair) parser.readObject(); Object o = parser.readObject();
parser.close(); parser.close();
JcaPEMKeyConverter jcaPEMKeyConverter = new JcaPEMKeyConverter(); PEMKeyPair pemKeyPair = (PEMKeyPair) o;
keyPair = jcaPEMKeyConverter.getKeyPair(pemKeyPair); EC_KEYPAIR = new JcaPEMKeyConverter().getKeyPair(pemKeyPair);
} catch (Exception e) { PemReader reader_cert_1 = new PemReader(new StringReader(Data.CERT_1));
throw new RuntimeException("Couldn't read keypair"); 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 int indexOf(byte[] array, byte[] target) { private static List<Certificate> getOtherCertList() throws Throwable {
outer: List<Certificate> certificates = new ArrayList<>();
for (int i = 0; i < array.length - target.length + 1; i++) {
for (int j = 0; j < target.length; j++) { var c1 = new JcaX509v3CertificateBuilder(
if (array[i + j] != target[j]) { holder_cert_1.getSubject(),
continue outer; holder_cert_1.getSerialNumber(),
} holder_cert_1.getNotBefore(),
holder_cert_1.getNotAfter(),
holder_cert_1.getSubject(),
EC_KEYPAIR.getPublic()
);
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()
);
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()
);
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;
}
private static ASN1Primitive getEncodableFromList(int tagNo) {
for (ASN1Encodable asn1Encodable : teeEnforcedAuthList) {
ASN1TaggedObject taggedObject = (ASN1TaggedObject) asn1Encodable;
if (taggedObject.getTagNo() == tagNo) {
return taggedObject.getBaseObject().toASN1Primitive();
} }
return i;
} }
return -1;
XposedBridge.log("Couldn't found " + tagNo + " object in TEE list");
for (ASN1Encodable asn1Encodable : swEnforcedAuthList) {
ASN1TaggedObject taggedObject = (ASN1TaggedObject) asn1Encodable;
if (taggedObject.getTagNo() == tagNo) {
return taggedObject.getBaseObject().toASN1Primitive();
}
}
XposedBridge.log("Couldn't found " + tagNo + " object in SW list");
return null;
} }
private static Certificate hackOtherCert(Certificate certificate) { private static Extension addHackedExtension(ASN1Sequence keyDescription) {
try { try {
X509CertificateHolder certificateHolder = new X509CertificateHolder(certificate.getEncoded()); swEnforcedAuthList = (ASN1Sequence) keyDescription.getObjectAt(6).toASN1Primitive();
teeEnforcedAuthList = (ASN1Sequence) keyDescription.getObjectAt(7).toASN1Primitive();
X509v3CertificateBuilder certBuilder = new JcaX509v3CertificateBuilder(certificateHolder.getSubject(), certificateHolder.getSerialNumber(), certificateHolder.getNotBefore(), certificateHolder.getNotAfter(), certificateHolder.getSubject(), keyPair.getPublic()); byte[] bytes1 = new byte[32];
byte[] bytes2 = new byte[32];
ContentSigner contentSigner = new JcaContentSignerBuilder("SHA256WithRSAEncryption").build(keyPair.getPrivate()); SecureRandom secureRandom = new SecureRandom();
X509CertificateHolder ch = certBuilder.build(contentSigner);
JcaX509CertificateConverter converter = new JcaX509CertificateConverter(); secureRandom.nextBytes(bytes1);
secureRandom.nextBytes(bytes2);
return converter.getCertificate(ch); ASN1Encodable[] rootOfTrustEncodables = {
new DEROctetString(bytes1),
ASN1Boolean.TRUE,
new ASN1Enumerated(0),
new DEROctetString(bytes2)
};
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);
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
};
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 uniqueId = new DEROctetString("".getBytes());
ASN1Sequence softwareEnforced = new DLSequence();
ASN1Sequence teeEnforced = new DLSequence(teeEnforcedEncodables);
ASN1Encodable[] keyDescriptionEncodables = {
attestationVersion,
attestationSecurityLevel,
keymasterVersion,
keymasterSecurityLevel,
attestationChallenge,
uniqueId,
softwareEnforced,
teeEnforced
};
ASN1Sequence keyDescriptionHackSeq = new DLSequence(keyDescriptionEncodables);
ASN1OctetString keyDescriptionOctetStr = new DEROctetString(keyDescriptionHackSeq);
return new Extension(new ASN1ObjectIdentifier("1.3.6.1.4.1.11129.2.1.17"), true, keyDescriptionOctetStr);
} catch (Exception e) { } catch (Exception e) {
XposedBridge.log("Error creating other cert: " + e); XposedBridge.log("error create extensions: " + e);
} }
return certificate; return null;
} }
private static Certificate hackLeafCert(Certificate certificate) { private static Certificate hackLeafCert(X509Certificate certificate) throws Throwable {
try { var holder = new X509CertificateHolder(certificate.getEncoded());
X509CertificateHolder certificateHolder = new X509CertificateHolder(certificate.getEncoded());
Extension extension = certificateHolder.getExtension(new ASN1ObjectIdentifier("1.3.6.1.4.1.11129.2.1.17")); var certBuilder = new JcaX509v3CertificateBuilder(
holder.getIssuer(),
holder.getSerialNumber(),
holder.getNotBefore(),
holder.getNotAfter(),
holder.getSubject(),
EC_KEYPAIR.getPublic()
);
ASN1Sequence keyDescription = ASN1Sequence.getInstance(extension.getExtnValue().getOctets()); for (Object extensionOID : holder.getExtensionOIDs()) {
ASN1Sequence swEnforcedAuthList = (ASN1Sequence) keyDescription.getObjectAt(6).toASN1Primitive(); ASN1ObjectIdentifier identifier = (ASN1ObjectIdentifier) extensionOID;
ASN1Sequence teeEnforcedAuthList = (ASN1Sequence) keyDescription.getObjectAt(7).toASN1Primitive(); if ("1.3.6.1.4.1.11129.2.1.17".equals(identifier.getId())) continue;
ASN1Sequence rootOfTrustAuthList = null; Extension e = holder.getExtension(identifier);
for (ASN1Encodable encodable : swEnforcedAuthList) { certBuilder.addExtension(e);
if (!(encodable instanceof ASN1TaggedObject asn1TaggedObject)) continue;
if (asn1TaggedObject.getTagNo() != 704) continue;
rootOfTrustAuthList = (ASN1Sequence) asn1TaggedObject.getBaseObject().toASN1Primitive();
hardwareAttesatation = false;
break;
}
for (ASN1Encodable encodable : teeEnforcedAuthList) {
if (!(encodable instanceof ASN1TaggedObject asn1TaggedObject)) continue;
if (asn1TaggedObject.getTagNo() != 704) continue;
rootOfTrustAuthList = (ASN1Sequence) asn1TaggedObject.getBaseObject().toASN1Primitive();
hardwareAttesatation = true;
break;
}
if (rootOfTrustAuthList == null) {
throw new CertificateException("ERROR, Root of Trust is null");
}
byte[] bytes = certificate.getEncoded();
int index = indexOf(bytes, rootOfTrustAuthList.getEncoded());
bytes[index + 38] = 1;
bytes[index + 41] = 0;
X509CertificateHolder modCert = new X509CertificateHolder(bytes);
if (hardwareAttesatation) {
JcaX509CertificateConverter converter = new JcaX509CertificateConverter();
return converter.getCertificate(modCert);
} else {
X509v3CertificateBuilder certBuilder = new JcaX509v3CertificateBuilder(certificateHolder.getSubject(), certificateHolder.getSerialNumber(), certificateHolder.getNotBefore(), certificateHolder.getNotAfter(), certificateHolder.getSubject(), keyPair.getPublic());
certBuilder.copyAndAddExtension(extension.getExtnId(), extension.isCritical(), modCert);
ContentSigner contentSigner = new JcaContentSignerBuilder("SHA256WithRSAEncryption").build(keyPair.getPrivate());
X509CertificateHolder certHolder = certBuilder.build(contentSigner);
return new JcaX509CertificateConverter().getCertificate(certHolder);
}
} catch (Exception e) {
XposedBridge.log("ERROR creating leaf certificate: " + e);
} }
return certificate; Extension extension = holder.getExtension(new ASN1ObjectIdentifier("1.3.6.1.4.1.11129.2.1.17"));
ASN1Sequence keyDescription = ASN1Sequence.getInstance(extension.getExtnValue().getOctets());
certBuilder.addExtension(addHackedExtension(keyDescription));
ContentSigner contentSigner = new JcaContentSignerBuilder("SHA256withECDSA").build(EC_KEYPAIR.getPrivate());
X509CertificateHolder certHolder = certBuilder.build(contentSigner);
return new JcaX509CertificateConverter().getCertificate(certHolder);
} }
@Override @Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) { public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) {
try { try {
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
KeyStoreSpi keyStoreSpi = (KeyStoreSpi) XposedHelpers.getObjectField(keyStore, "keyStoreSpi"); KeyStoreSpi keyStoreSpi = (KeyStoreSpi) XposedHelpers.getObjectField(keyStore, "keyStoreSpi");
XposedHelpers.findAndHookMethod(keyStoreSpi.getClass(), "engineGetCertificateChain", String.class, new XC_MethodHook() { XposedHelpers.findAndHookMethod(keyStoreSpi.getClass(), "engineGetCertificateChain", String.class, new XC_MethodHook() {
@Override @Override
protected void afterHookedMethod(MethodHookParam param) { protected void afterHookedMethod(MethodHookParam param) {
Certificate[] certificates = (Certificate[]) param.getResult(); try {
Certificate[] certificates = (Certificate[]) param.getResultOrThrowable();
certificates[0] = hackLeafCert(certificates[0]); Certificate leaf = certificates[0];
if (hardwareAttesatation) { if (!(leaf instanceof X509Certificate x509Certificate)) return;
for (Method method : certificates[0].getClass().getMethods()) {
if (method.getName().toLowerCase(Locale.ROOT).contains("verify")) { byte[] bytes = x509Certificate.getExtensionValue("1.3.6.1.4.1.11129.2.1.17");
XposedBridge.hookMethod(method, XC_MethodReplacement.DO_NOTHING);
} if (bytes == null || bytes.length == 0) {
} XposedBridge.log("Leaf certificate doesn't contain attestation extensions... Ignoring it.");
} else { return;
for (int i = 1; i < certificates.length; i++) {
certificates[i] = hackOtherCert(certificates[i]);
} }
List<Certificate> otherCerts = getOtherCertList();
Certificate[] hackCerts = new Certificate[4];
hackCerts[0] = hackLeafCert(x509Certificate);
hackCerts[1] = otherCerts.get(0);
hackCerts[2] = otherCerts.get(1);
hackCerts[3] = otherCerts.get(2);
param.setResult(hackCerts);
} catch (Throwable t) {
XposedBridge.log("ERROR: " + t);
} }
param.setResult(certificates);
} }
}); });
} catch (Throwable t) { } catch (Throwable t) {