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" } maven { url "https://jitpack.io" }
} }
dependencies { 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" 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.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
import java.security.KeyStore; import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@ -142,8 +143,6 @@ public class LSPatch {
throw new PatchError(outputPath + " exists. Use --force to overwrite"); throw new PatchError(outputPath + " exists. Use --force to overwrite");
System.out.println("Processing " + srcApkFile + " -> " + outputFile); System.out.println("Processing " + srcApkFile + " -> " + outputFile);
if (v1) System.err.println("\nWarning: Sign with v1 signature may cause installation failure\n");
patch(srcApkFile, outputFile); patch(srcApkFile, outputFile);
} }
} }
@ -265,7 +264,27 @@ public class LSPatch {
if (verbose) if (verbose)
System.out.println("Creating nested apk link..."); 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); StoredEntry originalZipEntry = dstZFile.get(ORIGINAL_APK_ASSET_PATH);
NestedZip nestedZip = new NestedZip(srcZFile, originalZipEntry); NestedZip nestedZip = new NestedZip(srcZFile, originalZipEntry);
for (StoredEntry entry : srcZFile.entries()) { for (StoredEntry entry : srcZFile.entries()) {
@ -291,25 +310,10 @@ public class LSPatch {
nestedZipLink.nestedZips.add(nestedZip); nestedZipLink.nestedZips.add(nestedZip);
} }
dstZFile.addZFileExtension(nestedZipLink);
// sign apk
System.out.println("Signing apk...");
try { try {
var keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); nestedZipLink.register();
try (var is = getClass().getClassLoader().getResourceAsStream("assets/keystore")) { } catch (NoSuchAlgorithmException e) {
keyStore.load(is, "123456".toCharArray()); throw new PatchError("Failed to create link: " + e);
}
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);
} }
System.out.println("Done. Output APK: " + outputFile.getAbsolutePath()); System.out.println("Done. Output APK: " + outputFile.getAbsolutePath());

View File

@ -1,6 +1,8 @@
package org.lsposed.patch.util; package org.lsposed.patch.util;
import com.android.apksig.ApkSignerEngine;
import com.android.apksig.internal.util.Pair; 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.utils.IOExceptionRunnable;
import com.android.tools.build.apkzlib.zip.CentralDirectoryHeader; import com.android.tools.build.apkzlib.zip.CentralDirectoryHeader;
import com.android.tools.build.apkzlib.zip.EncodeUtils; 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.ZFile;
import com.android.tools.build.apkzlib.zip.ZFileExtension; import com.android.tools.build.apkzlib.zip.ZFileExtension;
import java.io.BufferedInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.security.NoSuchAlgorithmException;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -38,14 +43,38 @@ public class NestedZipLink extends ZFileExtension {
private boolean written; private boolean written;
public NestedZipLink(ZFile zFile) { public final SigningExtension signingExtension;
public NestedZipLink(ZFile zFile, SigningExtension signingExtension) {
this.zFile = zFile; this.zFile = zFile;
this.signingExtension = signingExtension;
} }
@Override @Override
public IOExceptionRunnable beforeUpdate() { public IOExceptionRunnable beforeUpdate() {
written = false; return () -> {
return null; 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 @Override
@ -93,7 +122,8 @@ public class NestedZipLink extends ZFileExtension {
long nestedZipOffset = nestedZip.entry.getCentralDirectoryHeader().getOffset(); long nestedZipOffset = nestedZip.entry.getCentralDirectoryHeader().getOffset();
for (var link : nestedZip.links) { for (var link : nestedZip.links) {
var entry = nestedZip.zip.get(link.getFirst()); 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(); CentralDirectoryHeader cdh = entry.getCentralDirectoryHeader();
field_entry_file.set(entry, zFile); field_entry_file.set(entry, zFile);
field_cdh_file.set(cdh, zFile); field_cdh_file.set(cdh, zFile);
@ -107,6 +137,21 @@ public class NestedZipLink extends ZFileExtension {
computeEocd.invoke(zFile); 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 { private byte[] encodeFileName(String name) throws Exception {
Class<?> GPFlags = Class.forName("com.android.tools.build.apkzlib.zip.GPFlags"); Class<?> GPFlags = Class.forName("com.android.tools.build.apkzlib.zip.GPFlags");
Method make = GPFlags.getDeclaredMethod("make", boolean.class); Method make = GPFlags.getDeclaredMethod("make", boolean.class);
@ -117,4 +162,9 @@ public class NestedZipLink extends ZFileExtension {
var flags = make.invoke(null, encodeWithUtf8); var flags = make.invoke(null, encodeWithUtf8);
return (byte[]) encode.invoke(null, name, flags); return (byte[]) encode.invoke(null, name, flags);
} }
}
public void register() throws NoSuchAlgorithmException, IOException {
zFile.addZFileExtension(this);
signingExtension.register(zFile);
}
}