Skip to content

Commit

Permalink
Drop TEE reprogramming requeriment + fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
chiteroman committed Apr 29, 2024
1 parent 646b0fe commit 1e328de
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 49 deletions.
33 changes: 21 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
Modify framework.jar to build a valid certificate chain.

## Requirements
- TEE must be reprogrammed with a valid keybox.
- Intermediate Windows and Linux knowledge.
- Intermediate Java and Smali knowledge.
- WSL (only in Windows).
Expand All @@ -16,6 +15,14 @@ sudo apt full-upgrade -y
sudo apt install -y default-jdk zipalign
```

## SystemRW
To make system rw you can use @lebigmac scripts: https://systemrw.com/download.php

For my vayu, I used this: https://mega.nz/file/TQ42WApL#ky3OzPwEKQeKrFGJYygqEr07zsidEqYAd7lSu9-ceEM

FLASH IN CUSTOM RECOVERY.
AFTER FLASHING; REBOOT TO RECOVERY AGAIN TO START MODIFYING SYSTEM.

## Tutorial
First, cd to a working (and clean) directory.

Expand Down Expand Up @@ -61,32 +68,34 @@ After .dex files are decompiled, you must search in folders for this files and m

Search for method "engineGetCertificateChain" and near the end should be a line like this:
```
aput-object v0, v2, v3
return-object v2
const/4 v4, 0x0
aput-object v2, v3, v4
return-object v3
```

In this example:

v0 -> leaf cert.
v2 -> certificate chain.
v3 -> 0, the position to insert the certificate in certificate chain.
v2 -> leaf cert.
v3 -> certificate chain.
v4 -> 0, the position to insert the leaf cert in certificate chain.

It may be different in your .smali file. Do not copy and paste...

Before aput operation, you must add this:
After aput operation, you must add this:
```
invoke-static {XX}, Lcom/android/internal/util/framework/Android;->modifyCertificate(Ljava/security/cert/Certificate;)Ljava/security/cert/Certificate;
invoke-static {XX}, Lcom/android/internal/util/framework/Android;->modifyCertificates([Ljava/security/cert/Certificate;)[Ljava/security/cert/Certificate;
move-result-object XX
```

Replace XX with the leaf certificate register.

So the final code (in this example) should be this:
```
invoke-static {v0}, Lcom/android/internal/util/framework/Android;->modifyCertificate(Ljava/security/cert/Certificate;)Ljava/security/cert/Certificate;
move-result-object v0
aput-object v0, v2, v3
return-object v2
const/4 v4, 0x0
aput-object v2, v3, v4
invoke-static {v3}, Lcom/android/internal/util/framework/Android;->modifyCertificates([Ljava/security/cert/Certificate;)[Ljava/security/cert/Certificate;
move-result-object v3
return-object v3
```

- Instrumentation.smali:
Expand Down
107 changes: 71 additions & 36 deletions app/src/main/java/com/android/internal/util/framework/Android.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import android.app.Application;
import android.content.Context;
import android.os.Build;
import android.security.keystore.KeyProperties;
import android.util.Log;

import org.bouncycastle.asn1.ASN1Boolean;
Expand All @@ -17,6 +18,7 @@
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.DERTaggedObject;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.KeyUsage;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
Expand All @@ -25,27 +27,28 @@
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader;
import org.lsposed.lsparanoid.Obfuscate;

import java.io.IOException;
import java.io.StringReader;
import java.lang.reflect.Field;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;

@Obfuscate
public final class Android {
private static final String TAG = "chiteroman";
private static final PrivateKey EC, RSA;
private static final PEMKeyPair EC, RSA;
private static final ASN1ObjectIdentifier OID = new ASN1ObjectIdentifier("1.3.6.1.4.1.11129.2.1.17");
private static final HashMap<String, String> map = new HashMap<>();
private static final String EC_PRIVATE_KEY = """
""";
private static final String RSA_PRIVATE_KEY = """
""";
private static final List<Certificate> EC_CERTS = new ArrayList<>();
private static final List<Certificate> RSA_CERTS = new ArrayList<>();

static {
map.put("MANUFACTURER", "");
Expand All @@ -55,31 +58,57 @@ public final class Android {
map.put("MODEL", "");
map.put("FINGERPRINT", "");

try (PEMParser parser = new PEMParser(new StringReader(EC_PRIVATE_KEY))) {
PEMKeyPair pemKeyPair = (PEMKeyPair) parser.readObject();
EC = new JcaPEMKeyConverter().getPrivateKey(pemKeyPair.getPrivateKeyInfo());
} catch (IOException e) {
Log.e(TAG, e.toString());
throw new RuntimeException(e);
try {

EC = parseKeyPair(Keybox.EC.PRIVATE_KEY);

EC_CERTS.add(parseCert(Keybox.EC.CERTIFICATE_0));
EC_CERTS.add(parseCert(Keybox.EC.CERTIFICATE_1));
EC_CERTS.add(parseCert(Keybox.EC.CERTIFICATE_2));

RSA = parseKeyPair(Keybox.RSA.PRIVATE_KEY);

RSA_CERTS.add(parseCert(Keybox.RSA.CERTIFICATE_0));
RSA_CERTS.add(parseCert(Keybox.RSA.CERTIFICATE_1));
RSA_CERTS.add(parseCert(Keybox.RSA.CERTIFICATE_2));

} catch (Throwable t) {
Log.e(TAG, t.toString());
throw new RuntimeException(t);
}
}

private static PEMKeyPair parseKeyPair(String key) throws Throwable {
try (PEMParser parser = new PEMParser(new StringReader(key))) {
return (PEMKeyPair) parser.readObject();
}
}

try (PEMParser parser = new PEMParser(new StringReader(RSA_PRIVATE_KEY))) {
PEMKeyPair pemKeyPair = (PEMKeyPair) parser.readObject();
RSA = new JcaPEMKeyConverter().getPrivateKey(pemKeyPair.getPrivateKeyInfo());
} catch (IOException e) {
Log.e(TAG, e.toString());
throw new RuntimeException(e);
private static Certificate parseCert(String cert) throws Throwable {
PemObject pemObject;
try (PemReader reader = new PemReader(new StringReader(cert))) {
pemObject = reader.readPemObject();
}
return new JcaX509CertificateConverter().getCertificate(new X509CertificateHolder(pemObject.getContent()));
}

public static Certificate modifyCertificate(Certificate certificate) {
if (certificate == null) return null;
// TODO: create fake leaf cert for devices with broken TEE
private static Certificate createLeafCertificate() {
return null;
}

public static Certificate[] modifyCertificates(Certificate[] certificates) {
if (certificates == null || certificates.length < 2) return certificates;
if (!(certificates[0] instanceof X509Certificate leaf)) return certificates;
try {
X509CertificateHolder holder = new X509CertificateHolder(certificate.getEncoded());
// You can force this to false if your keybox doesn't have EC keys
boolean isEC = KeyProperties.KEY_ALGORITHM_EC.equals(leaf.getPublicKey().getAlgorithm());

X509CertificateHolder holder = new X509CertificateHolder(leaf.getEncoded());

Extension ext = holder.getExtension(OID);

if (ext == null) return certificate;
if (ext == null) return certificates;

ASN1Sequence sequence = ASN1Sequence.getInstance(ext.getExtnValue().getOctets());

Expand Down Expand Up @@ -120,31 +149,37 @@ public static Certificate modifyCertificate(Certificate certificate) {

Extension hackedExt = new Extension(OID, false, hackedSeqOctets);

X509v3CertificateBuilder builder = new X509v3CertificateBuilder(holder).replaceExtension(hackedExt);

X509Certificate x509Certificate = new JcaX509CertificateConverter().getCertificate(holder);

JcaContentSignerBuilder signerBuilder = new JcaContentSignerBuilder(x509Certificate.getSigAlgName());

X509v3CertificateBuilder builder;
ContentSigner signer;

if (x509Certificate.getSigAlgName().contains("ECDSA")) {
signer = signerBuilder.build(EC);
LinkedList<Certificate> hackedCerts;

if (isEC) {
hackedCerts = new LinkedList<>(EC_CERTS);
builder = new X509v3CertificateBuilder(new X509CertificateHolder(EC_CERTS.get(0).getEncoded()).getSubject(), holder.getSerialNumber(), holder.getNotBefore(), holder.getNotAfter(), holder.getSubject(), EC.getPublicKeyInfo());
signer = new JcaContentSignerBuilder("SHA256withECDSA").build(new JcaPEMKeyConverter().getPrivateKey(EC.getPrivateKeyInfo()));
} else {
signer = signerBuilder.build(RSA);
hackedCerts = new LinkedList<>(RSA_CERTS);
builder = new X509v3CertificateBuilder(new X509CertificateHolder(RSA_CERTS.get(0).getEncoded()).getSubject(), holder.getSerialNumber(), holder.getNotBefore(), holder.getNotAfter(), holder.getSubject(), RSA.getPublicKeyInfo());
signer = new JcaContentSignerBuilder("SHA256withRSA").build(new JcaPEMKeyConverter().getPrivateKey(RSA.getPrivateKeyInfo()));
}

X509CertificateHolder hackedCert = builder.build(signer);
KeyUsage keyUsage = new KeyUsage(KeyUsage.keyCertSign);

builder.addExtension(Extension.keyUsage, true, keyUsage);

builder.addExtension(hackedExt);

return new JcaX509CertificateConverter().getCertificate(hackedCert);
hackedCerts.addFirst(new JcaX509CertificateConverter().getCertificate(builder.build(signer)));

return hackedCerts.toArray(new Certificate[0]);

} catch (Throwable t) {
Log.e(TAG, t.toString());
}
return certificate;
return certificates;
}


private static Field getFieldByName(String name) {

Field field;
Expand Down
41 changes: 41 additions & 0 deletions app/src/main/java/com/android/internal/util/framework/Keybox.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.android.internal.util.framework;

public final class Keybox {
public static final class EC {
public static final String PRIVATE_KEY = """
-----BEGIN EC PRIVATE KEY-----
-----END EC PRIVATE KEY-----
""";
public static final String CERTIFICATE_0 = """
-----BEGIN CERTIFICATE-----
-----END CERTIFICATE-----
""";
public static final String CERTIFICATE_1 = """
-----BEGIN CERTIFICATE-----
-----END CERTIFICATE-----
""";
public static final String CERTIFICATE_2 = """
-----BEGIN CERTIFICATE-----
-----END CERTIFICATE-----
""";
}

public static final class RSA {
public static final String PRIVATE_KEY = """
-----BEGIN RSA PRIVATE KEY-----
-----END RSA PRIVATE KEY-----
""";
public static final String CERTIFICATE_0 = """
-----BEGIN CERTIFICATE-----
-----END CERTIFICATE-----
""";
public static final String CERTIFICATE_1 = """
-----BEGIN CERTIFICATE-----
-----END CERTIFICATE-----
""";
public static final String CERTIFICATE_2 = """
-----BEGIN CERTIFICATE-----
-----END CERTIFICATE-----
""";
}
}
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id("com.android.application") version "8.3.1" apply false
id("com.android.application") version "8.3.2" apply false
}

0 comments on commit 1e328de

Please sign in to comment.