From 980c7bba4b9e4c6dcb2b1da34b603f17cb603602 Mon Sep 17 00:00:00 2001 From: LoveSy Date: Fri, 27 Aug 2021 11:28:16 +0800 Subject: [PATCH] Fix v1 signing --- build.gradle | 2 +- .../main/java/org/lsposed/patch/LSPatch.java | 46 +++++++------- .../org/lsposed/patch/util/NestedZipLink.java | 60 +++++++++++++++++-- 3 files changed, 81 insertions(+), 27 deletions(-) diff --git a/build.gradle b/build.gradle index 0773507..429e879 100644 --- a/build.gradle +++ b/build.gradle @@ -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" } } diff --git a/patch/src/main/java/org/lsposed/patch/LSPatch.java b/patch/src/main/java/org/lsposed/patch/LSPatch.java index f10f0a5..4d2f7e9 100644 --- a/patch/src/main/java/org/lsposed/patch/LSPatch.java +++ b/patch/src/main/java/org/lsposed/patch/LSPatch.java @@ -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()); diff --git a/patch/src/main/java/org/lsposed/patch/util/NestedZipLink.java b/patch/src/main/java/org/lsposed/patch/util/NestedZipLink.java index 278db88..82cf572 100644 --- a/patch/src/main/java/org/lsposed/patch/util/NestedZipLink.java +++ b/patch/src/main/java/org/lsposed/patch/util/NestedZipLink.java @@ -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); } -} \ No newline at end of file + + public void register() throws NoSuchAlgorithmException, IOException { + zFile.addZFileExtension(this); + signingExtension.register(zFile); + } +}