From b41fa7920b6511220f52c1fa98ced1c871d33033 Mon Sep 17 00:00:00 2001 From: IcyClawz Date: Fri, 4 Oct 2024 11:22:42 +0300 Subject: [PATCH] new: support building with compact entries Pretty straightforward change. The motivation is to reproduce the original structure of the source APK. If it's built with compact resource entries - then rebuild with compact resource entries. --- .../src/main/java/brut/androlib/AaptInvoker.java | 4 ++++ .../src/main/java/brut/androlib/apk/ApkInfo.java | 6 ++++++ .../src/main/java/brut/androlib/res/data/ResTable.java | 7 +++++++ .../main/java/brut/androlib/res/decoder/ARSCDecoder.java | 6 ++++++ 4 files changed, 23 insertions(+) diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/AaptInvoker.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/AaptInvoker.java index a249869b1f..a31a3dcd50 100644 --- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/AaptInvoker.java +++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/AaptInvoker.java @@ -185,6 +185,10 @@ private void invokeAapt2(File apkFile, File manifest, File resDir, File rawDir, cmd.add("--enable-sparse-encoding"); } + if (mApkInfo.compactEntries) { + cmd.add("--enable-compact-entries"); + } + if (mApkInfo.isFrameworkApk) { cmd.add("-x"); } diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/apk/ApkInfo.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/apk/ApkInfo.java index 38a036d583..3bdd7a2e4d 100644 --- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/apk/ApkInfo.java +++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/apk/ApkInfo.java @@ -51,6 +51,7 @@ public class ApkInfo implements YamlSerializable { public Map featureFlags = new LinkedHashMap<>(); public boolean sharedLibrary; public boolean sparseResources; + public boolean compactEntries; public List doNotCompress = new ArrayList<>(); public ApkInfo() { @@ -266,6 +267,10 @@ public void readItem(YamlReader reader) throws AndrolibException { sparseResources = line.getValueBool(); break; } + case "compactEntries": { + compactEntries = line.getValueBool(); + break; + } case "doNotCompress": { doNotCompress.clear(); reader.readStringList(doNotCompress); @@ -288,6 +293,7 @@ public void write(YamlWriter writer) { } writer.writeBool("sharedLibrary", sharedLibrary); writer.writeBool("sparseResources", sparseResources); + writer.writeBool("compactEntries", compactEntries); if (!doNotCompress.isEmpty()) { writer.writeList("doNotCompress", doNotCompress); } diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResTable.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResTable.java index 24cc6c592d..190f517389 100644 --- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResTable.java +++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResTable.java @@ -266,6 +266,13 @@ public void setSparseResources(boolean flag) { mApkInfo.sparseResources = flag; } + public void setCompactEntries(boolean flag) { + if (mApkInfo.compactEntries != flag) { + LOGGER.info("Compactly packed resource entries detected."); + } + mApkInfo.compactEntries = flag; + } + public void clearSdkInfo() { mApkInfo.sdkInfo.clear(); } diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/decoder/ARSCDecoder.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/decoder/ARSCDecoder.java index 4b45591435..f1ecbd47c4 100644 --- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/decoder/ARSCDecoder.java +++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/decoder/ARSCDecoder.java @@ -370,6 +370,12 @@ private EntryData readEntryData() throws IOException, AndrolibException { return null; } + // Be sure we don't poison mResTable by marking the application as compact + // Only flag the ResTable as compact if the main package is not loaded. + if (isCompact && !mResTable.isMainPkgLoaded()) { + mResTable.setCompactEntries(true); + } + // #3366 - In a compactly packed entry, the key index is the size & type is higher 8 bits on flags. // We assume a size of 8 bytes for compact entries and the specNamesId is the data itself encoded. ResValue value;