Skip to content

Commit

Permalink
Build dynamic stub resource APK at runtime
Browse files Browse the repository at this point in the history
Close topjohnwu#6013

Co-authored-by: vvb2060 <[email protected]>
  • Loading branch information
topjohnwu and vvb2060 committed Jun 22, 2022
1 parent a2495fb commit 0b26882
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 29 deletions.
28 changes: 10 additions & 18 deletions buildSrc/src/main/java/Setup.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.PrintStream
import java.nio.file.Files
import java.security.KeyStore
import java.security.cert.X509Certificate
import java.util.*
Expand Down Expand Up @@ -270,27 +269,20 @@ fun Project.setupStub() {
commandLine(aapt, "optimize", "-o", apkTmp, "--collapse-resource-names", apk)
}

val buffer = ByteArrayOutputStream()
apkTmp.inputStream().use {
object : GZIPOutputStream(buffer) {
init {
def.setLevel(Deflater.BEST_COMPRESSION)
}
}.use { o ->
it.transferTo(o)
val bos = ByteArrayOutputStream()
ZipFile(apkTmp).use { src ->
ZipOutputStream(apk.outputStream()).use {
it.setLevel(Deflater.BEST_COMPRESSION)
it.putNextEntry(ZipEntry("AndroidManifest.xml"))
src.getInputStream(src.getEntry("AndroidManifest.xml")).transferTo(it)
it.closeEntry()
}
}
ZipFile(apkTmp).use { o ->
ZipOutputStream(apk.outputStream()).use { n ->
n.setLevel(Deflater.BEST_COMPRESSION)
n.putNextEntry(ZipEntry("AndroidManifest.xml"))
o.getInputStream(o.getEntry("AndroidManifest.xml")).transferTo(n)
n.closeEntry()
n.finish()
DeflaterOutputStream(bos, Deflater(Deflater.BEST_COMPRESSION)).use {
src.getInputStream(src.getEntry("resources.arsc")).transferTo(it)
}
}
apkTmp.delete()
genEncryptedResources(ByteArrayInputStream(buffer.toByteArray()), outSrcDir)
genEncryptedResources(ByteArrayInputStream(bos.toByteArray()), outSrcDir)
}
}
registerJavaGeneratingTask(genSrcTask, outSrcDir)
Expand Down
39 changes: 28 additions & 11 deletions stub/src/main/java/com/topjohnwu/magisk/DownloadActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.zip.GZIPInputStream;
import java.util.zip.InflaterInputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
Expand Down Expand Up @@ -76,7 +79,9 @@ protected void onCreate(Bundle savedInstanceState) {
// Inject resources
try {
loadResources();
} catch (Exception ignored) {}
} catch (Exception e) {
error(e);
}

ProviderInstaller.install(this);

Expand All @@ -103,7 +108,7 @@ public void finish() {
}

private void error(Throwable e) {
Log.e(getClass().getSimpleName(), "", e);
Log.e(getClass().getSimpleName(), Log.getStackTraceString(e));
finish();
}

Expand Down Expand Up @@ -157,14 +162,26 @@ private void dlAPK() {
}

private void decryptResources(OutputStream out) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKey key = new SecretKeySpec(Bytes.key(), "AES");
IvParameterSpec iv = new IvParameterSpec(Bytes.iv());
cipher.init(Cipher.DECRYPT_MODE, key, iv);
var is = new GZIPInputStream(new CipherInputStream(
new ByteArrayInputStream(Bytes.res()), cipher));
try (is; out) {
APKInstall.transfer(is, out);
try (var zip = new ZipOutputStream(out)) {
zip.putNextEntry(new ZipEntry("resources.arsc"));
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKey key = new SecretKeySpec(Bytes.key(), "AES");
IvParameterSpec iv = new IvParameterSpec(Bytes.iv());
cipher.init(Cipher.DECRYPT_MODE, key, iv);
var is = new InflaterInputStream(new CipherInputStream(
new ByteArrayInputStream(Bytes.res()), cipher));
try (is) {
APKInstall.transfer(is, zip);
}
zip.closeEntry();

zip.putNextEntry(new ZipEntry("AndroidManifest.xml"));
var apk = new ZipFile(getPackageResourcePath());
var xml = apk.getInputStream(apk.getEntry("AndroidManifest.xml"));
try (apk; xml) {
APKInstall.transfer(xml, zip);
}
zip.closeEntry();
}
}

Expand Down

0 comments on commit 0b26882

Please sign in to comment.