skylot / jadx

Dex to Java decompiler
Apache License 2.0
41.96k stars 4.9k forks source link

[core] Caused by: java.util.zip.ZipException: invalid CEN header (bad compression method: 7261) #2171

Closed ohyeah521 closed 1 month ago

ohyeah521 commented 7 months ago

Issue details

The malware exploits the Android system's failure to verify zip flag tampering, causing an exception to be thrown when parsing the apk.

Relevant log output or stacktrace

jadx.core.utils.exceptions.JadxRuntimeException: Failed to process zip file: C:\Users\test\Desktop\test.apk
        at jadx.api.plugins.utils.ZipSecurity.visitZipEntries(ZipSecurity.java:148)
        at jadx.api.plugins.utils.ZipSecurity.readZipEntries(ZipSecurity.java:154)
        at jadx.plugins.input.java.JavaInputLoader.collectFromZip(JavaInputLoader.java:91)
        at jadx.plugins.input.java.JavaInputLoader.loadReader(JavaInputLoader.java:71)
        at jadx.plugins.input.java.JavaInputLoader.loadFromFile(JavaInputLoader.java:50)
        at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
        at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
        at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1655)
        at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
        at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
        at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913)
        at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
        at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578)
        at jadx.plugins.input.java.JavaInputLoader.collectFiles(JavaInputLoader.java:37)
        at jadx.plugins.input.java.JavaInputPlugin.loadClassFiles(JavaInputPlugin.java:36)
        at jadx.plugins.input.java.JavaInputPlugin.loadClassFiles(JavaInputPlugin.java:32)
        at jadx.api.JadxDecompiler.loadInputFiles(JadxDecompiler.java:153)
        at jadx.api.JadxDecompiler.load(JadxDecompiler.java:119)
        at jadx.cli.JadxCLI.processAndSave(JadxCLI.java:51)
        at jadx.cli.JadxCLI.execute(JadxCLI.java:38)
        at jadx.cli.JadxCLI.main(JadxCLI.java:22)
Caused by: java.util.zip.ZipException: invalid CEN header (bad compression method: 7261)
        at java.base/java.util.zip.ZipFile$Source.zerror(ZipFile.java:1597)
        at java.base/java.util.zip.ZipFile$Source.initCEN(ZipFile.java:1557)
        at java.base/java.util.zip.ZipFile$Source.<init>(ZipFile.java:1299)
        at java.base/java.util.zip.ZipFile$Source.get(ZipFile.java:1262)
        at java.base/java.util.zip.ZipFile$CleanableResource.<init>(ZipFile.java:733)
        at java.base/java.util.zip.ZipFile$CleanableResource.get(ZipFile.java:842)
        at java.base/java.util.zip.ZipFile.<init>(ZipFile.java:248)
        at java.base/java.util.zip.ZipFile.<init>(ZipFile.java:177)
        at java.base/java.util.zip.ZipFile.<init>(ZipFile.java:191)
        at jadx.api.plugins.utils.ZipSecurity.visitZipEntries(ZipSecurity.java:130)
        ... 20 common frames omitted

Provide sample and class/method full name

test.zip

Jadx version

1.5.0

jpstotz commented 7 months ago

It is a known problem that ZIP implementation of Java does not support archives with unknown compression methods. As you can see from the stack trace this happens when creating the ZipFile instance, thus there is no way to ignore or skip this error.

The only way to solve this problem would be using a completely different ZIP implementation.

ohyeah521 commented 7 months ago

You are right. Maybe we can analyze the source code by referring to the zip of the source code and ignore some of the verification fields that throw exceptions.

jpstotz commented 7 months ago

To my knowledge there is no option or other possibility to skip this check. initCEN is always executed when opening a new ZIP file

See https://github.com/AdoptOpenJDK/openjdk-jdk11/blob/master/src/java.base/share/classes/java/util/zip/ZipFile.java

ohyeah521 commented 7 months ago

It is true that Java is very difficult to implement. Perhaps introducing an external decompression tool is a better choice. Instead of calling the system library directly, it can be made into a configuration option. When encountering confusion, users can choose the decompression tool themselves. In this way, decompilation can continue. I think this implementation is better than exiting directly.

jpstotz commented 7 months ago

You have the sample file. Feel free to test other libraries but to my knowledge there are not many like ZIP libraries that have an own implementation. Just two candidates come to my mind: apache-commons-compress and zip4j.

skylot commented 7 months ago

@jpstotz I tried zip4j, but it also not support fake compression method :cry:

Caused by: net.lingala.zip4j.exception.ZipException: Unknown compression method
    at net.lingala.zip4j.model.enums.CompressionMethod.getCompressionMethodFromCode(CompressionMethod.java:52)
    at net.lingala.zip4j.headers.HeaderReader.readLocalFileHeader(HeaderReader.java:543)
    at net.lingala.zip4j.io.inputstream.ZipInputStream.getNextEntry(ZipInputStream.java:115)
    at net.lingala.zip4j.io.inputstream.ZipInputStream.getNextEntry(ZipInputStream.java:105)
    at jadx.api.plugins.utils.ZipSecurity.visitZipEntries(ZipSecurity.java:135)

Will try other lib :confused:

skylot commented 7 months ago

Apache Commons Compress also doesn't support fake compression method:

Caused by: org.apache.commons.compress.archivers.zip.UnsupportedZipFeatureException: Unsupported feature compression method used in entry AndroidManifest.xml
    at org.apache.commons.compress.archivers.zip.ZipUtil.checkRequestedFeatures(ZipUtil.java:145)
    at org.apache.commons.compress.archivers.zip.ZipArchiveInputStream.read(ZipArchiveInputStream.java:915)

Looks like the only way to fight such tampering is to write own zip reader implementation :rofl:

jackwpa commented 7 months ago

Looks like the only way to fight such tampering is to write own zip reader implementation

It must be what JEB has done (link to JEB API). It's working fine for me with JEB 5.12:

image

skylot commented 6 months ago

I actually implemented my own zip parser, and it is working fine :rofl: But looks like this sample use some tricks to prevent parsing AndroidManifest.xml (maybe related to #2182), so I will keep working on this issue.

skylot commented 1 month ago

Fixed in PR #2298 by @qfalconer :tada:

ohyeah521 commented 1 month ago

Well done, I provide another idea: I first check whether the apk file has modified the zip file format through a third-party tool. If so, use it to decompress, and then use jadx to analyze the dex file. Since this implementation requires the use of third-party tools, I did not provide a PR

drego85 commented 1 week ago

Hi @ohyeah521, can I ask you which third-party tool do you use? Thanks

drego85 commented 1 week ago

I created this Python script based on the initial work of @qfalconer: https://gist.github.com/drego85/f3fa845b2f14b29e926417d697131134

Any other tools or information is definitely appreciated!

ohyeah521 commented 1 week ago

@drego85 https://github.com/mins4416/apk_cure

ohyeah521 commented 1 week ago

I created this Python script based on the initial work of @qfalconer: https://gist.github.com/drego85/f3fa845b2f14b29e926417d697131134

Any other tools or information is definitely appreciated!

Maybe you can integrate these 2 projects together. https://github.com/mins4416/apk_cure