skylot / jadx

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

Fail to build secure XML DocumentBuilderFactory #2291

Closed Lohita9 closed 1 month ago

Lohita9 commented 1 month ago

Issue details

This issue occurs when I decompile an APK using Jadx on my Android device.

Relevant log output or stacktrace

---StackTrace---
java.lang.ExceptionInInitializerError
    at jadx.core.xmlgen.XmlSecurity.verifyAppPackage(XmlSecurity.java:26)
    at jadx.core.xmlgen.ResourceStorage.setAppPackage(ResourceStorage.java:79)
    at jadx.core.xmlgen.ResTableBinaryParser.parsePackage(ResTableBinaryParser.java:161)
    at jadx.core.xmlgen.ResTableBinaryParser.decodeTableChunk(ResTableBinaryParser.java:118)
    at jadx.core.xmlgen.ResTableBinaryParser.decode(ResTableBinaryParser.java:91)
    at jadx.api.ResourcesLoader.decodeTable(ResourcesLoader.java:173)
    at jadx.core.dex.nodes.RootNode.lambda$loadResources$7(RootNode.java:210)
    at jadx.core.dex.nodes.RootNode$$ExternalSyntheticLambda16.decode(D8$$SyntheticClass:0)
    at jadx.api.ResourcesLoader.decodeStream(ResourcesLoader.java:113)
    at jadx.core.dex.nodes.RootNode.loadResources(RootNode.java:210)
    at jadx.api.JadxDecompiler.load(JadxDecompiler.java:126)
    at com.lohita.miss.MainActivity$1.onClick(MainActivity.java:41)
    at android.view.View.performClick(View.java:7507)
    at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:1218)
    at android.view.View.performClickInternal(View.java:7484)
    at android.view.View.access$3600(View.java:839)
    at android.view.View$PerformClick.run(View.java:28689)
    at android.os.Handler.handleCallback(Handler.java:938)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:236)
    at android.app.ActivityThread.main(ActivityThread.java:8057)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:656)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:967)
Caused by: java.lang.RuntimeException: Fail to build secure XML DocumentBuilderFactory
    at jadx.core.xmlgen.XmlSecurity.buildDBF(XmlSecurity.java:51)
    at jadx.core.xmlgen.XmlSecurity.<clinit>(XmlSecurity.java:16)
    ... 24 more
Caused by: javax.xml.parsers.ParserConfigurationException: http://apache.org/xml/features/disallow-doctype-decl
    at org.apache.harmony.xml.parsers.DocumentBuilderFactoryImpl.setFeature(DocumentBuilderFactoryImpl.java:101)
    at jadx.core.xmlgen.XmlSecurity.buildDBF(XmlSecurity.java:42)
    ... 25 more

Provide sample and class/method full name

my-debug.zip

Jadx version

latest unstable version

Lohita9 commented 1 month ago

https://github.com/user-attachments/assets/00f05d0d-dbda-40f7-954e-bfc0cde81628

@skylot provide some sample code in Java for Android that implements the current decompilation process using JADX. The code should display the class being decompiled inside a dialog box.

jpstotz commented 1 month ago

As there is no Android version of Jadx you seem to use Jadx as library. However the version "latest unstable version" does not really match the stack trace you have posted.

Especially the stack trace element at jadx.core.xmlgen.XmlSecurity.verifyAppPackage(XmlSecurity.java:26) does not point to a function call in latest unstable version. The code before line 26 in that file has not been modified since April 2024, thus you seem to use an older version, may be version 1.5.0'of jadx-core library?

The exception is caused by Android XML parser. It seems like it doesn't support all the features of a regular J2SE XML parser. Which Android version do you use?

Lohita9 commented 1 month ago

Android 11 Screenshot_2024-10-03-15-52-35-747_com.github.android.jpg

jpstotz commented 1 month ago

@Lohita9 Please never post code like gradle config as screenshot, especially not as truncated screenshot.

Edit: There is a related question in Stackoverflow on DocumentBuilderFactory on Android: https://stackoverflow.com/questions/67605248/how-to-prevent-xxe-attacks-on-android-when-documentbuilderfactory-doesnt-allow

As the DocumentBuilderFactory configuration we use in Jadx is not supported on Android the only way would be to make this function overridable so that you could modify it on Android.

The getSecureDbf() function had been added in 2017, we should also check if it is still necessary as we have changed our JDK requirement since that time.

Lohita9 commented 1 month ago

Ok, I am currently running jdk 21.

jpstotz commented 1 month ago

I just noticed that there is already a setting that allows to disable XML security checks which causes the problems on Android.

The problem is that jadx currently expects you to set JADX_DISABLE_XML_SECURITY environment variable. I am not sure if this is possible at all to set environment variables on Android for your own process/app.

I assume this configuration settings via ENV variable were introduced mainly for jad-core command-line users. For jadx library users using ENV variables doesn't make much sense. May be on a long term perspective we ,may need a configuration system that is a little bit more flexible. @skylot What do you think?

@Lohita9 I just checked the code in jadx-code library in https://s01.oss.sonatype.org/content/repositories/snapshots/ repo. It points to https://github.com/skylot/jadx/blob/b26abdc851c63e9503b3c02f5f1ce062da7590ad/jadx-core/src/main/java/jadx/core/xmlgen/XmlSecurity.java#L25-L27 thus to the line if (DISABLE_CHECKS) {.

Therefore the version you use is not the latest unstable version - gradle doesn't seem to recognize that there is a newer snapshot available. I would recommend to delete the cached jadx library dependencies somewhere below ~/.gradle/caches or execute your Android app gradle build task with --refresh-dependencies option to force dependency update.

Lohita9 commented 1 month ago

Not working. Here is the crash log after refresh dependencies same error occurred

---StackTrace---
java.lang.ExceptionInInitializerError
    at jadx.core.xmlgen.XmlSecurity.verifyAppPackage(XmlSecurity.java:26)
    at jadx.core.xmlgen.ResourceStorage.setAppPackage(ResourceStorage.java:79)
    at jadx.core.xmlgen.ResTableBinaryParser.parsePackage(ResTableBinaryParser.java:161)
    at jadx.core.xmlgen.ResTableBinaryParser.decodeTableChunk(ResTableBinaryParser.java:118)
    at jadx.core.xmlgen.ResTableBinaryParser.decode(ResTableBinaryParser.java:91)
    at jadx.api.ResourcesLoader.decodeTable(ResourcesLoader.java:173)
    at jadx.core.dex.nodes.RootNode.lambda$loadResources$7(RootNode.java:210)
    at jadx.core.dex.nodes.RootNode$$ExternalSyntheticLambda16.decode(D8$$SyntheticClass:0)
    at jadx.api.ResourcesLoader.decodeStream(ResourcesLoader.java:113)
    at jadx.core.dex.nodes.RootNode.loadResources(RootNode.java:210)
    at jadx.api.JadxDecompiler.load(JadxDecompiler.java:126)
    at com.lohita.miss.MainActivity$1.onClick(MainActivity.java:41)
    at android.view.View.performClick(View.java:7507)
    at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:1218)
    at android.view.View.performClickInternal(View.java:7484)
    at android.view.View.access$3600(View.java:839)
    at android.view.View$PerformClick.run(View.java:28689)
    at android.os.Handler.handleCallback(Handler.java:938)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:236)
    at android.app.ActivityThread.main(ActivityThread.java:8057)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:656)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:967)
Caused by: java.lang.RuntimeException: Fail to build secure XML DocumentBuilderFactory
    at jadx.core.xmlgen.XmlSecurity.buildDBF(XmlSecurity.java:51)
    at jadx.core.xmlgen.XmlSecurity.<clinit>(XmlSecurity.java:16)
    ... 24 more
Caused by: javax.xml.parsers.ParserConfigurationException: http://apache.org/xml/features/disallow-doctype-decl
    at org.apache.harmony.xml.parsers.DocumentBuilderFactoryImpl.setFeature(DocumentBuilderFactoryImpl.java:101)
    at jadx.core.xmlgen.XmlSecurity.buildDBF(XmlSecurity.java:42)
    ... 25 more
skylot commented 1 month ago

may need a configuration system that is a little bit more flexible

@jpstotz looks like the only way is to allow completely replace implementation. This can be done by extracting interface from xml security (for parsing xml and validate package) and set default implementation to new property in JadxArgs and replacing all usage by it. Not sure how to correctly implement this on Android through. But providing implementation without any security checks should be fine for now.

And sure, any jadx env variable shouldn't be needed in 'jadx as a library' usage. I recently done similar thing for 'various files' properties in b26abdc851c63e9503b3c02f5f1ce062da7590ad, such changes also useful for jadx plugins. And there are a lot of things needs to be extracted in similar way :cry:

skylot commented 1 month ago

I commit fix allowing disable or completely replace xml security checks.

Set<JadxSecurityFlag> flags = JadxSecurityFlag.all();
jadxArgs.setSecurity(new JadxSecurity(flags));

Here flags set can be updated and not needed checks disabled/removed.

@Lohita9 also I created an example Android app with jadx lib usage, check https://github.com/jadx-decompiler/jadx-lib-android-example repo. Main jadx usage code can be found here. Hope this will help :slightly_smiling_face: