Fix v1 signing

This commit is contained in:
LoveSy 2021-08-27 11:28:16 +08:00
parent 1ced48aa49
commit 980c7bba4b
3 changed files with 81 additions and 27 deletions

View File

@ -8,7 +8,7 @@ buildscript {
maven { url "https://jitpack.io" }
}
dependencies {
classpath 'com.android.tools.build:gradle:7.1.0-alpha09'
classpath 'com.android.tools.build:gradle:7.1.0-alpha10'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.21"
}
}

View File

@ -31,6 +31,7 @@ import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
@ -142,8 +143,6 @@ public class LSPatch {
throw new PatchError(outputPath + " exists. Use --force to overwrite");
System.out.println("Processing " + srcApkFile + " -> " + outputFile);
if (v1) System.err.println("\nWarning: Sign with v1 signature may cause installation failure\n");
patch(srcApkFile, outputFile);
}
}
@ -265,7 +264,27 @@ public class LSPatch {
if (verbose)
System.out.println("Creating nested apk link...");
NestedZipLink nestedZipLink = new NestedZipLink(dstZFile);
SigningExtension signingExtension = null;
// sign apk
System.out.println("Signing apk...");
try {
var keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
try (var is = getClass().getClassLoader().getResourceAsStream("assets/keystore")) {
keyStore.load(is, "123456".toCharArray());
}
var entry = (KeyStore.PrivateKeyEntry) keyStore.getEntry("key0", new KeyStore.PasswordProtection("123456".toCharArray()));
signingExtension = new SigningExtension(SigningOptions.builder()
.setMinSdkVersion(27)
.setV1SigningEnabled(v1)
.setV2SigningEnabled(v2)
.setCertificates((X509Certificate[]) entry.getCertificateChain())
.setKey(entry.getPrivateKey())
.build());
} catch (Exception e) {
throw new PatchError("Failed to create signer: " + e);
}
NestedZipLink nestedZipLink = new NestedZipLink(dstZFile, signingExtension);
StoredEntry originalZipEntry = dstZFile.get(ORIGINAL_APK_ASSET_PATH);
NestedZip nestedZip = new NestedZip(srcZFile, originalZipEntry);
for (StoredEntry entry : srcZFile.entries()) {
@ -291,25 +310,10 @@ public class LSPatch {
nestedZipLink.nestedZips.add(nestedZip);
}
dstZFile.addZFileExtension(nestedZipLink);
// sign apk
System.out.println("Signing apk...");
try {
var keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
try (var is = getClass().getClassLoader().getResourceAsStream("assets/keystore")) {
keyStore.load(is, "123456".toCharArray());
}
var entry = (KeyStore.PrivateKeyEntry) keyStore.getEntry("key0", new KeyStore.PasswordProtection("123456".toCharArray()));
new SigningExtension(SigningOptions.builder()
.setMinSdkVersion(27)
.setV1SigningEnabled(v1)
.setV2SigningEnabled(v2)
.setCertificates((X509Certificate[]) entry.getCertificateChain())
.setKey(entry.getPrivateKey())
.build()).register(dstZFile);
} catch (Exception e) {
throw new PatchError("Failed to sign apk: " + e);
nestedZipLink.register();
} catch (NoSuchAlgorithmException e) {
throw new PatchError("Failed to create link: " + e);
}
System.out.println("Done. Output APK: " + outputFile.getAbsolutePath());

View File

@ -1,6 +1,8 @@
package org.lsposed.patch.util;
import com.android.apksig.ApkSignerEngine;
import com.android.apksig.internal.util.Pair;
import com.android.tools.build.apkzlib.sign.SigningExtension;
import com.android.tools.build.apkzlib.utils.IOExceptionRunnable;
import com.android.tools.build.apkzlib.zip.CentralDirectoryHeader;
import com.android.tools.build.apkzlib.zip.EncodeUtils;
@ -8,9 +10,12 @@ import com.android.tools.build.apkzlib.zip.StoredEntry;
import com.android.tools.build.apkzlib.zip.ZFile;
import com.android.tools.build.apkzlib.zip.ZFileExtension;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.security.NoSuchAlgorithmException;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
@ -38,14 +43,38 @@ public class NestedZipLink extends ZFileExtension {
private boolean written;
public NestedZipLink(ZFile zFile) {
public final SigningExtension signingExtension;
public NestedZipLink(ZFile zFile, SigningExtension signingExtension) {
this.zFile = zFile;
this.signingExtension = signingExtension;
}
@Override
public IOExceptionRunnable beforeUpdate() {
written = false;
return null;
return () -> {
written = false;
try {
var signerField = SigningExtension.class.getDeclaredField("signer");
signerField.setAccessible(true);
var signer = (ApkSignerEngine) signerField.get(signingExtension);
for (var nestedZip : nestedZips) {
for (var link : nestedZip.links) {
var entry = nestedZip.zip.get(link.getFirst());
if (entry == null)
throw new IOException("Entry " + link + " does not exist in nested zip");
notifySigner(signer, link.getFirst(), entry);
}
}
} catch (Exception e) {
var ex = new IOException("Error when writing link entries");
ex.addSuppressed(e);
throw ex;
}
};
}
@Override
@ -93,7 +122,8 @@ public class NestedZipLink extends ZFileExtension {
long nestedZipOffset = nestedZip.entry.getCentralDirectoryHeader().getOffset();
for (var link : nestedZip.links) {
var entry = nestedZip.zip.get(link.getFirst());
if (entry == null) throw new IOException("Entry " + link + " does not exist in nested zip");
if (entry == null)
throw new IOException("Entry " + link + " does not exist in nested zip");
CentralDirectoryHeader cdh = entry.getCentralDirectoryHeader();
field_entry_file.set(entry, zFile);
field_cdh_file.set(cdh, zFile);
@ -107,6 +137,21 @@ public class NestedZipLink extends ZFileExtension {
computeEocd.invoke(zFile);
}
private void notifySigner(ApkSignerEngine signer, String entryName, StoredEntry entry) throws IOException {
ApkSignerEngine.InspectJarEntryRequest inspectEntryRequest = signer.outputJarEntry(entryName);
if (inspectEntryRequest != null) {
try (InputStream inputStream = new BufferedInputStream(entry.open())) {
int bytesRead;
byte[] buffer = new byte[65536];
var dataSink = inspectEntryRequest.getDataSink();
while ((bytesRead = inputStream.read(buffer)) > 0) {
dataSink.consume(buffer, 0, bytesRead);
}
}
inspectEntryRequest.done();
}
}
private byte[] encodeFileName(String name) throws Exception {
Class<?> GPFlags = Class.forName("com.android.tools.build.apkzlib.zip.GPFlags");
Method make = GPFlags.getDeclaredMethod("make", boolean.class);
@ -117,4 +162,9 @@ public class NestedZipLink extends ZFileExtension {
var flags = make.invoke(null, encodeWithUtf8);
return (byte[]) encode.invoke(null, name, flags);
}
public void register() throws NoSuchAlgorithmException, IOException {
zFile.addZFileExtension(this);
signingExtension.register(zFile);
}
}