From be9fc8d990501c74a4a34d3a06f70841da3096cf Mon Sep 17 00:00:00 2001 From: Alexander Fink Date: Sat, 11 Apr 2020 14:50:20 +0200 Subject: [PATCH] Add support for optimized dex-files --- .../java/comm/android/dx/dex/code/Dops.java | 68 ++++++++ .../java/comm/android/dx/io/OpcodeInfo.java | 103 +++++++++++ src/main/java/comm/android/dx/io/Opcodes.java | 26 +++ .../dx/io/instructions/InstructionCodec.java | 11 ++ .../saarland/cispa/dexterous/Dexterous.java | 160 +++++++++++------- 5 files changed, 305 insertions(+), 63 deletions(-) diff --git a/src/main/java/comm/android/dx/dex/code/Dops.java b/src/main/java/comm/android/dx/dex/code/Dops.java index 818e4eb..96bec07 100644 --- a/src/main/java/comm/android/dx/dex/code/Dops.java +++ b/src/main/java/comm/android/dx/dex/code/Dops.java @@ -502,6 +502,10 @@ public final class Dops { new Dop(Opcodes.INVOKE_INTERFACE, Opcodes.INVOKE_INTERFACE, Opcodes.INVOKE_INTERFACE_RANGE, Form35c.THE_ONE, false); + public static final Dop RETURN_VOID_NO_BARRIER = + new Dop(Opcodes.RETURN_VOID_NO_BARRIER, Opcodes.RETURN_VOID_NO_BARRIER, + Opcodes.NO_NEXT, Form10x.THE_ONE, false); + public static final Dop INVOKE_VIRTUAL_RANGE = new Dop(Opcodes.INVOKE_VIRTUAL_RANGE, Opcodes.INVOKE_VIRTUAL, Opcodes.NO_NEXT, Form3rc.THE_ONE, false); @@ -937,6 +941,52 @@ public final class Dops { public static final Dop USHR_INT_LIT8 = new Dop(Opcodes.USHR_INT_LIT8, Opcodes.USHR_INT, Opcodes.NO_NEXT, Form22b.THE_ONE, true); + public static final Dop IGET_QUICK = + new Dop(Opcodes.IGET_QUICK, Opcodes.IGET_QUICK, Opcodes.NO_NEXT, Form22c.THE_ONE, true); + public static final Dop IGET_WIDE_QUICK = + new Dop(Opcodes.IGET_WIDE_QUICK, Opcodes.IGET_WIDE_QUICK, Opcodes.NO_NEXT, Form22c.THE_ONE, true); + public static final Dop IGET_OBJECT_QUICK = + new Dop(Opcodes.IGET_OBJECT_QUICK, Opcodes.IGET_OBJECT_QUICK, Opcodes.NO_NEXT, Form22c.THE_ONE, true); + public static final Dop IPUT_QUICK = + new Dop(Opcodes.IPUT_QUICK, Opcodes.IPUT_QUICK, Opcodes.NO_NEXT, Form22c.THE_ONE, false); + public static final Dop IPUT_WIDE_QUICK = + new Dop(Opcodes.IPUT_WIDE_QUICK, Opcodes.IPUT_WIDE_QUICK, Opcodes.NO_NEXT, Form22c.THE_ONE, false); + public static final Dop IPUT_OBJECT_QUICK = + new Dop(Opcodes.IPUT_OBJECT_QUICK, Opcodes.IPUT_OBJECT_QUICK, Opcodes.NO_NEXT, Form22c.THE_ONE, false); + public static final Dop INVOKE_VIRTUAL_QUICK = + new Dop(Opcodes.INVOKE_VIRTUAL_QUICK, Opcodes.INVOKE_VIRTUAL_QUICK, Opcodes.NO_NEXT, Form35c.THE_ONE, false); + public static final Dop INVOKE_VIRTUAL_RANGE_QUICK = + new Dop(Opcodes.INVOKE_VIRTUAL_RANGE_QUICK, Opcodes.INVOKE_VIRTUAL_RANGE_QUICK, Opcodes.NO_NEXT, Form3rc.THE_ONE, false); + public static final Dop IPUT_BOOLEAN_QUICK = + new Dop(Opcodes.IPUT_BOOLEAN_QUICK, Opcodes.IPUT_BOOLEAN_QUICK, Opcodes.NO_NEXT, Form22c.THE_ONE, false); + public static final Dop IPUT_BYTE_QUICK = + new Dop(Opcodes.IPUT_BYTE_QUICK, Opcodes.IPUT_BYTE_QUICK, Opcodes.NO_NEXT, Form22c.THE_ONE, false); + public static final Dop IPUT_CHAR_QUICK = + new Dop(Opcodes.IPUT_CHAR_QUICK, Opcodes.IPUT_CHAR_QUICK, Opcodes.NO_NEXT, Form22c.THE_ONE, false); + public static final Dop IPUT_SHORT_QUICK = + new Dop(Opcodes.IPUT_SHORT_QUICK, Opcodes.IPUT_SHORT_QUICK, Opcodes.NO_NEXT, Form22c.THE_ONE, false); + public static final Dop IGET_BOOLEAN_QUICK = + new Dop(Opcodes.IGET_BOOLEAN_QUICK, Opcodes.IGET_BOOLEAN_QUICK, Opcodes.NO_NEXT, Form22c.THE_ONE, true); + public static final Dop IGET_BYTE_QUICK = + new Dop(Opcodes.IGET_BYTE_QUICK, Opcodes.IGET_BYTE_QUICK, Opcodes.NO_NEXT, Form22c.THE_ONE, true); + public static final Dop IGET_CHAR_QUICK = + new Dop(Opcodes.IGET_CHAR_QUICK, Opcodes.IGET_CHAR_QUICK, Opcodes.NO_NEXT, Form22c.THE_ONE, true); + public static final Dop IGET_SHORT_QUICK = + new Dop(Opcodes.IGET_SHORT_QUICK, Opcodes.IGET_SHORT_QUICK, Opcodes.NO_NEXT, Form22c.THE_ONE, true); + //public static final Dop INVOKE_LAMBDA = + // new Dop(Opcodes.INVOKE_LAMBDA, Opcodes.INVOKE_LAMBDA, Opcodes.NO_NEXT, Form25x.THE_ONE, false); + public static final Dop UNUSED_F4 = + new Dop(Opcodes.UNUSED_F4, Opcodes.UNUSED_F4, Opcodes.NO_NEXT, Form10x.THE_ONE, false); + public static final Dop CAPTURE_VARIABLE = + new Dop(Opcodes.CAPTURE_VARIABLE, Opcodes.CAPTURE_VARIABLE, Opcodes.NO_NEXT, Form21c.THE_ONE, false); + public static final Dop CREATE_LAMBDA = + new Dop(Opcodes.CREATE_LAMBDA, Opcodes.CREATE_LAMBDA, Opcodes.NO_NEXT, Form21c.THE_ONE, false); + public static final Dop LIBERATE_VARIABLE = + new Dop(Opcodes.LIBERATE_VARIABLE, Opcodes.LIBERATE_VARIABLE, Opcodes.NO_NEXT, Form22c.THE_ONE, false); + public static final Dop BOX_LAMBDA = + new Dop(Opcodes.BOX_LAMBDA, Opcodes.BOX_LAMBDA, Opcodes.NO_NEXT, Form22x.THE_ONE, true); + public static final Dop UNBOX_LAMBDA = + new Dop(Opcodes.UNBOX_LAMBDA, Opcodes.UNBOX_LAMBDA, Opcodes.NO_NEXT, Form22c.THE_ONE, true); public static final Dop INVOKE_POLYMORPHIC = new Dop(Opcodes.INVOKE_POLYMORPHIC, Opcodes.INVOKE_POLYMORPHIC, @@ -1072,6 +1122,7 @@ public final class Dops { set(INVOKE_DIRECT); set(INVOKE_STATIC); set(INVOKE_INTERFACE); + set(RETURN_VOID_NO_BARRIER); set(INVOKE_VIRTUAL_RANGE); set(INVOKE_SUPER_RANGE); set(INVOKE_DIRECT_RANGE); @@ -1181,6 +1232,23 @@ public final class Dops { set(SHL_INT_LIT8); set(SHR_INT_LIT8); set(USHR_INT_LIT8); + set(IGET_QUICK); + set(IGET_WIDE_QUICK); + set(IGET_OBJECT_QUICK); + set(IPUT_QUICK); + set(IPUT_WIDE_QUICK); + set(IPUT_OBJECT_QUICK); + set(INVOKE_VIRTUAL_QUICK); + set(INVOKE_VIRTUAL_RANGE_QUICK); + set(IPUT_BOOLEAN_QUICK); + set(IPUT_BYTE_QUICK); + set(IPUT_CHAR_QUICK); + set(IPUT_SHORT_QUICK); + set(IGET_BOOLEAN_QUICK); + set(IGET_BYTE_QUICK); + set(IGET_CHAR_QUICK); + set(IGET_SHORT_QUICK); + set(INVOKE_POLYMORPHIC); set(INVOKE_POLYMORPHIC_RANGE); set(INVOKE_CUSTOM); diff --git a/src/main/java/comm/android/dx/io/OpcodeInfo.java b/src/main/java/comm/android/dx/io/OpcodeInfo.java index e4c8642..7c7bed7 100644 --- a/src/main/java/comm/android/dx/io/OpcodeInfo.java +++ b/src/main/java/comm/android/dx/io/OpcodeInfo.java @@ -16,6 +16,8 @@ package comm.android.dx.io; +import android.util.Log; + import comm.android.dx.io.instructions.InstructionCodec; import comm.android.dx.util.Hex; import comm.android.dx.util.Hex; @@ -496,6 +498,10 @@ public final class OpcodeInfo { new Info(Opcodes.INVOKE_INTERFACE, "invoke-interface", InstructionCodec.FORMAT_35C, IndexType.METHOD_REF); + public static final Info RETURN_VOID_NO_BARRIER = + new Info(Opcodes.RETURN_VOID_NO_BARRIER, "return-void-no-barrier", + InstructionCodec.FORMAT_10X, IndexType.NONE); + public static final Info INVOKE_VIRTUAL_RANGE = new Info(Opcodes.INVOKE_VIRTUAL_RANGE, "invoke-virtual/range", InstructionCodec.FORMAT_3RC, IndexType.METHOD_REF); @@ -932,6 +938,78 @@ public final class OpcodeInfo { new Info(Opcodes.USHR_INT_LIT8, "ushr-int/lit8", InstructionCodec.FORMAT_22B, IndexType.NONE); + + public static final Info IGET_QUICK = + new Info(Opcodes.IGET_QUICK, "iget-quick", + InstructionCodec.FORMAT_22C, IndexType.FIELD_OFFSET); + public static final Info IGET_WIDE_QUICK = + new Info(Opcodes.IGET_WIDE_QUICK, "iget-wide-quick", + InstructionCodec.FORMAT_22C, IndexType.FIELD_OFFSET); + public static final Info IGET_OBJECT_QUICK = + new Info(Opcodes.IGET_OBJECT_QUICK, "iget-object-quick", + InstructionCodec.FORMAT_22C, IndexType.FIELD_OFFSET); + public static final Info IPUT_QUICK = + new Info(Opcodes.IPUT_QUICK, "iput-quick", + InstructionCodec.FORMAT_22C, IndexType.FIELD_OFFSET); + public static final Info IPUT_WIDE_QUICK = + new Info(Opcodes.IPUT_WIDE_QUICK, "iput-wide-quick", + InstructionCodec.FORMAT_22C, IndexType.FIELD_OFFSET); + public static final Info IPUT_OBJECT_QUICK = + new Info(Opcodes.IPUT_OBJECT_QUICK, "iput-object-quick", + InstructionCodec.FORMAT_22C, IndexType.FIELD_OFFSET); + public static final Info INVOKE_VIRTUAL_QUICK = + new Info(Opcodes.INVOKE_VIRTUAL_QUICK, "invoke-virtual-quick", + InstructionCodec.FORMAT_35C, IndexType.VTABLE_OFFSET); + public static final Info INVOKE_VIRTUAL_RANGE_QUICK = + new Info(Opcodes.INVOKE_VIRTUAL_RANGE_QUICK, "invoke-virtual/range-quick", + InstructionCodec.FORMAT_3RC, IndexType.VTABLE_OFFSET); + public static final Info IPUT_BOOLEAN_QUICK = + new Info(Opcodes.IPUT_BOOLEAN_QUICK, "iput-boolean-quick", + InstructionCodec.FORMAT_22C, IndexType.FIELD_OFFSET); + public static final Info IPUT_BYTE_QUICK = + new Info(Opcodes.IPUT_BYTE_QUICK, "iput-byte-quick", + InstructionCodec.FORMAT_22C, IndexType.FIELD_OFFSET); + public static final Info IPUT_CHAR_QUICK = + new Info(Opcodes.IPUT_CHAR_QUICK, "iput-char-quick", + InstructionCodec.FORMAT_22C, IndexType.FIELD_OFFSET); + public static final Info IPUT_SHORT_QUICK = + new Info(Opcodes.IPUT_SHORT_QUICK, "iput-short-quick", + InstructionCodec.FORMAT_22C, IndexType.FIELD_OFFSET); + public static final Info IGET_BOOLEAN_QUICK = + new Info(Opcodes.IGET_BOOLEAN_QUICK, "iget-boolean-quick", + InstructionCodec.FORMAT_22C, IndexType.FIELD_OFFSET); + public static final Info IGET_BYTE_QUICK = + new Info(Opcodes.IGET_BYTE_QUICK, "iget-byte-quick", + InstructionCodec.FORMAT_22C, IndexType.FIELD_OFFSET); + public static final Info IGET_CHAR_QUICK = + new Info(Opcodes.IGET_CHAR_QUICK, "iget-char-quick", + InstructionCodec.FORMAT_22C, IndexType.FIELD_OFFSET); + public static final Info IGET_SHORT_QUICK = + new Info(Opcodes.IGET_SHORT_QUICK, "iget-short-quick", + InstructionCodec.FORMAT_22C, IndexType.FIELD_OFFSET); + public static final Info INVOKE_LAMBDA = + new Info(Opcodes.INVOKE_LAMBDA, "invoke-lambda", + InstructionCodec.FORMAT_25X, IndexType.NONE); + public static final Info UNUSED_F4 = + new Info(Opcodes.UNUSED_F4, "unused-f4", + InstructionCodec.FORMAT_10X, IndexType.UNKNOWN); + public static final Info CAPTURE_VARIABLE = + new Info(Opcodes.CAPTURE_VARIABLE, "capture-variable", + InstructionCodec.FORMAT_21C, IndexType.STRING_REF); + public static final Info CREATE_LAMBDA = + new Info(Opcodes.CREATE_LAMBDA, "create-lambda", + InstructionCodec.FORMAT_21C, IndexType.METHOD_REF); + public static final Info LIBERATE_VARIABLE = + new Info(Opcodes.LIBERATE_VARIABLE, "liberate-variable", + InstructionCodec.FORMAT_22C, IndexType.STRING_REF); + public static final Info BOX_LAMBDA = + new Info(Opcodes.BOX_LAMBDA, "box-lambda", + InstructionCodec.FORMAT_22X, IndexType.NONE); + public static final Info UNBOX_LAMBDA = + new Info(Opcodes.UNBOX_LAMBDA, "unbox-lambda", + InstructionCodec.FORMAT_22C, IndexType.TYPE_REF); + + public static final Info INVOKE_POLYMORPHIC = new Info(Opcodes.INVOKE_POLYMORPHIC, "invoke-polymorphic", InstructionCodec.FORMAT_45CC, IndexType.METHOD_AND_PROTO_REF); @@ -1072,6 +1150,7 @@ public final class OpcodeInfo { set(INVOKE_DIRECT); set(INVOKE_STATIC); set(INVOKE_INTERFACE); + set(RETURN_VOID_NO_BARRIER); set(INVOKE_VIRTUAL_RANGE); set(INVOKE_SUPER_RANGE); set(INVOKE_DIRECT_RANGE); @@ -1181,6 +1260,30 @@ public final class OpcodeInfo { set(SHL_INT_LIT8); set(SHR_INT_LIT8); set(USHR_INT_LIT8); + set(IGET_QUICK); + set(IGET_WIDE_QUICK); + set(IGET_OBJECT_QUICK); + set(IPUT_QUICK); + set(IPUT_WIDE_QUICK); + set(IPUT_OBJECT_QUICK); + set(INVOKE_VIRTUAL_QUICK); + set(INVOKE_VIRTUAL_RANGE_QUICK); + set(IPUT_BOOLEAN_QUICK); + set(IPUT_BYTE_QUICK); + set(IPUT_CHAR_QUICK); + set(IPUT_SHORT_QUICK); + set(IGET_BOOLEAN_QUICK); + set(IGET_BYTE_QUICK); + set(IGET_CHAR_QUICK); + set(IGET_SHORT_QUICK); + set(INVOKE_LAMBDA); + set(UNUSED_F4); + set(CAPTURE_VARIABLE); + set(CREATE_LAMBDA); + set(LIBERATE_VARIABLE); + set(BOX_LAMBDA); + set(UNBOX_LAMBDA); + set(INVOKE_POLYMORPHIC); set(INVOKE_POLYMORPHIC_RANGE); set(INVOKE_CUSTOM); diff --git a/src/main/java/comm/android/dx/io/Opcodes.java b/src/main/java/comm/android/dx/io/Opcodes.java index 28d6f28..08e4ed9 100644 --- a/src/main/java/comm/android/dx/io/Opcodes.java +++ b/src/main/java/comm/android/dx/io/Opcodes.java @@ -150,6 +150,7 @@ public final class Opcodes { public static final int INVOKE_DIRECT = 0x70; public static final int INVOKE_STATIC = 0x71; public static final int INVOKE_INTERFACE = 0x72; + public static final int RETURN_VOID_NO_BARRIER = 0x73; public static final int INVOKE_VIRTUAL_RANGE = 0x74; public static final int INVOKE_SUPER_RANGE = 0x75; public static final int INVOKE_DIRECT_RANGE = 0x76; @@ -259,6 +260,31 @@ public final class Opcodes { public static final int SHL_INT_LIT8 = 0xe0; public static final int SHR_INT_LIT8 = 0xe1; public static final int USHR_INT_LIT8 = 0xe2; + + public static final int IGET_QUICK = 0xE3; + public static final int IGET_WIDE_QUICK = 0xE4; + public static final int IGET_OBJECT_QUICK = 0xE5; + public static final int IPUT_QUICK = 0xE6; + public static final int IPUT_WIDE_QUICK = 0xE7; + public static final int IPUT_OBJECT_QUICK = 0xE8; + public static final int INVOKE_VIRTUAL_QUICK = 0xE9; + public static final int INVOKE_VIRTUAL_RANGE_QUICK = 0xEA; + public static final int IPUT_BOOLEAN_QUICK = 0xEB; + public static final int IPUT_BYTE_QUICK = 0xEC; + public static final int IPUT_CHAR_QUICK = 0xED; + public static final int IPUT_SHORT_QUICK = 0xEE; + public static final int IGET_BOOLEAN_QUICK = 0xEF; + public static final int IGET_BYTE_QUICK = 0xF0; + public static final int IGET_CHAR_QUICK = 0xF1; + public static final int IGET_SHORT_QUICK = 0xF2; + public static final int INVOKE_LAMBDA = 0xF3; + public static final int UNUSED_F4 = 0xF4; + public static final int CAPTURE_VARIABLE = 0xF5; + public static final int CREATE_LAMBDA = 0xF6; + public static final int LIBERATE_VARIABLE = 0xF7; + public static final int BOX_LAMBDA = 0xF8; + public static final int UNBOX_LAMBDA = 0xF9; + public static final int INVOKE_POLYMORPHIC = 0xfa; public static final int INVOKE_POLYMORPHIC_RANGE = 0xfb; public static final int INVOKE_CUSTOM = 0xfc; diff --git a/src/main/java/comm/android/dx/io/instructions/InstructionCodec.java b/src/main/java/comm/android/dx/io/instructions/InstructionCodec.java index bf15088..3233eef 100644 --- a/src/main/java/comm/android/dx/io/instructions/InstructionCodec.java +++ b/src/main/java/comm/android/dx/io/instructions/InstructionCodec.java @@ -404,6 +404,17 @@ public enum InstructionCodec { } }, + FORMAT_25X() { + @Override public DecodedInstruction decode(int opcodeUnit, + CodeInput in) throws EOFException { + return decodeRegisterList(this, opcodeUnit, in); + } + + @Override public void encode(DecodedInstruction insn, CodeOutput out) { + encodeRegisterList(insn, out); + } + }, + FORMAT_30T() { @Override public DecodedInstruction decode(int opcodeUnit, CodeInput in) throws EOFException { diff --git a/src/main/java/saarland/cispa/dexterous/Dexterous.java b/src/main/java/saarland/cispa/dexterous/Dexterous.java index 2bd1506..dec1f3b 100644 --- a/src/main/java/saarland/cispa/dexterous/Dexterous.java +++ b/src/main/java/saarland/cispa/dexterous/Dexterous.java @@ -140,79 +140,113 @@ public String buildApk() { } catch (final FileNotFoundException e) { Log.e(TAG, "", e); } - try ( - ZipInputStream zipInput = - new ZipInputStream(new BufferedInputStream(apk_original), Charset.forName("ISO-8859-1")); - ZipOutputStream zipOutput = - new ZipOutputStream(new BufferedOutputStream(apk_injected), Charset.forName("ISO-8859-1")); - ) { - ZipEntry apkContent; - int classes_dex_counter = 1; - - while ((apkContent = zipInput.getNextEntry()) != null) { + int classes_dex_counter = 1; + if (config.apkPath.endsWith(".dex")){ + try( + ZipOutputStream zipOutput = + new ZipOutputStream(new BufferedOutputStream(apk_injected), Charset.forName("ISO-8859-1")); + ) { + for (final Dex classesDex : this.dexBuffers.values()) { + final String classes_dex_name; + + if (classes_dex_counter == 1) { + classes_dex_name = "classes.dex"; + } else { + classes_dex_name = String.format(Locale.getDefault(), "classes%d.dex", classes_dex_counter); + } + Log.i(TAG, "> APK - Writing: " + classes_dex_name); + + ZipEntry newClassesEntry = new ZipEntry(classes_dex_name); + + try { + zipOutput.putNextEntry(newClassesEntry); + zipOutput.write(classesDex.getBytes(), 0, classesDex.getLength()); + zipOutput.closeEntry(); + } catch (final IOException e) { + Log.e(TAG, e.getMessage()); + } + ++classes_dex_counter; + } + return config.mergedApkPath; + } catch (final IOException e) { + Log.e(TAG, "", e); + return ""; + } + } + else { + try ( + ZipInputStream zipInput = + new ZipInputStream(new BufferedInputStream(apk_original), Charset.forName("ISO-8859-1")); + ZipOutputStream zipOutput = + new ZipOutputStream(new BufferedOutputStream(apk_injected), Charset.forName("ISO-8859-1")); + ) { + ZipEntry apkContent; + + while ((apkContent = zipInput.getNextEntry()) != null) { // Log.d(TAG, "> zipInput: " + apkContent.getName()); - if (apkContent.getName().endsWith(".dex") && classes_dex_counter == 1) { - for (final Dex classesDex : this.dexBuffers.values()) { - final String classes_dex_name; - - if (classes_dex_counter == 1) { - classes_dex_name = "classes.dex"; - } else { - classes_dex_name = String.format(Locale.getDefault(), "classes%d.dex", classes_dex_counter); - } - Log.i(TAG, "> APK - Writing: " + classes_dex_name); + if (apkContent.getName().endsWith(".dex") && classes_dex_counter == 1) { + for (final Dex classesDex : this.dexBuffers.values()) { + final String classes_dex_name; - ZipEntry newClassesEntry = new ZipEntry(classes_dex_name); + if (classes_dex_counter == 1) { + classes_dex_name = "classes.dex"; + } else { + classes_dex_name = String.format(Locale.getDefault(), "classes%d.dex", classes_dex_counter); + } + Log.i(TAG, "> APK - Writing: " + classes_dex_name); + + ZipEntry newClassesEntry = new ZipEntry(classes_dex_name); + try { + zipOutput.putNextEntry(newClassesEntry); + zipOutput.write(classesDex.getBytes(), 0, classesDex.getLength()); + zipOutput.closeEntry(); + } catch (final IOException e) { + Log.e(TAG, e.getMessage()); + } + ++classes_dex_counter; + } + } else if (!apkContent.getName().endsWith(".dex")) { + byte[] buffer = new byte[1024]; + int count; try { - zipOutput.putNextEntry(newClassesEntry); - zipOutput.write(classesDex.getBytes(), 0, classesDex.getLength()); + // Reusing zipInput ZipEntry can leads to error: + // java.util.zip.ZipException: invalid entry compressed size + // (expected 5088 but got 5171 bytes) + final String fileName = apkContent.getName(); + final String fileExtension = ("." + FilenameUtils.getExtension(fileName)); + final ZipEntry zipEntry = new ZipEntry(fileName); + if (Config.NO_COMPRESS_EXTENSIONS.contains(fileExtension)) { + Log.v(TAG, String.format(Locale.getDefault(), "> No Compression: %s " + + "[Method: %d] Size: %d Compressed: %d", + fileName, + apkContent.getMethod(), + apkContent.getSize(), + apkContent.getCompressedSize())); + long size = apkContent.getSize(); + long crc = apkContent.getCrc(); + if (size != -1 && crc != -1) { + zipEntry.setMethod(ZipEntry.STORED); + zipEntry.setSize(size); + // zipEntry.setCompressedSize(apkContent.getCompressedSize()); + zipEntry.setCrc(crc); + } + } + zipOutput.putNextEntry(zipEntry); + while ((count = zipInput.read(buffer)) != -1) { + zipOutput.write(buffer, 0, count); + } zipOutput.closeEntry(); } catch (final IOException e) { - Log.e(TAG, e.getMessage()); - } - ++classes_dex_counter; - } - } else if (!apkContent.getName().endsWith(".dex")){ - byte[] buffer = new byte[1024]; - int count; - try { - // Reusing zipInput ZipEntry can leads to error: - // java.util.zip.ZipException: invalid entry compressed size - // (expected 5088 but got 5171 bytes) - final String fileName = apkContent.getName(); - final String fileExtension = ("." + FilenameUtils.getExtension(fileName)); - final ZipEntry zipEntry = new ZipEntry(fileName); - if (Config.NO_COMPRESS_EXTENSIONS.contains(fileExtension)) { - Log.v(TAG, String.format(Locale.getDefault(), "> No Compression: %s " + - "[Method: %d] Size: %d Compressed: %d", - fileName, - apkContent.getMethod(), - apkContent.getSize(), - apkContent.getCompressedSize())); - long size = apkContent.getSize(); - long crc = apkContent.getCrc(); - if (size != -1 && crc != -1) { - zipEntry.setMethod(ZipEntry.STORED); - zipEntry.setSize(size); - // zipEntry.setCompressedSize(apkContent.getCompressedSize()); - zipEntry.setCrc(crc); - } + Log.e(TAG, e.getMessage(), e); } - zipOutput.putNextEntry(zipEntry); - while ((count = zipInput.read(buffer)) != -1) { - zipOutput.write(buffer, 0, count); - } - zipOutput.closeEntry(); - } catch (final IOException e) { - Log.e(TAG, e.getMessage(), e); } } + return config.mergedApkPath; + } catch (final IOException e) { + Log.e(TAG, "", e); + return ""; } - return config.mergedApkPath; - } catch (final IOException e) { - Log.e(TAG, "", e); - return ""; } }