diff --git a/jadx-cli/src/main/java/jadx/cli/JadxCLIArgs.java b/jadx-cli/src/main/java/jadx/cli/JadxCLIArgs.java index 708582a299debe70e61083ed408e892c71d1130a..806c7280ed276a9837ecdb31067ad994c4d06a16 100644 --- a/jadx-cli/src/main/java/jadx/cli/JadxCLIArgs.java +++ b/jadx-cli/src/main/java/jadx/cli/JadxCLIArgs.java @@ -53,6 +53,9 @@ public class JadxCLIArgs { @Parameter(names = {"--escape-unicode"}, description = "escape non latin characters in strings (with \\u)") protected boolean escapeUnicode = false; + @Parameter(names = {"--respect-bytecode-access-modifiers"}, description = "don't change original access modifiers") + protected boolean respectBytecodeAccessModifiers = false; + @Parameter(names = {"--deobf"}, description = "activate deobfuscation") protected boolean deobfuscationOn = false; @@ -154,6 +157,7 @@ public class JadxCLIArgs { args.setDeobfuscationMaxLength(deobfuscationMaxLength); args.setUseSourceNameAsClassAlias(deobfuscationUseSourceNameAsAlias); args.setEscapeUnicode(escapeUnicode); + args.setRespectBytecodeAccModifiers(respectBytecodeAccessModifiers); args.setExportAsGradleProject(exportAsGradleProject); args.setUseImports(useImports); return args; @@ -239,6 +243,10 @@ public class JadxCLIArgs { return replaceConsts; } + public boolean isRespectBytecodeAccessModifiers() { + return respectBytecodeAccessModifiers; + } + public boolean isExportAsGradleProject() { return exportAsGradleProject; } diff --git a/jadx-core/src/main/java/jadx/api/JadxArgs.java b/jadx-core/src/main/java/jadx/api/JadxArgs.java index bd6f12548ece31b0391f0e98e16d6a6fb1b1e312..d9c226ea58f1852bddaefb01099f0f723a007e73 100644 --- a/jadx-core/src/main/java/jadx/api/JadxArgs.java +++ b/jadx-core/src/main/java/jadx/api/JadxArgs.java @@ -40,6 +40,7 @@ public class JadxArgs { private boolean escapeUnicode = false; private boolean replaceConsts = true; + private boolean respectBytecodeAccModifiers = false; private boolean exportAsGradleProject = false; public JadxArgs() { @@ -204,6 +205,14 @@ public class JadxArgs { this.replaceConsts = replaceConsts; } + public boolean isRespectBytecodeAccModifiers() { + return respectBytecodeAccModifiers; + } + + public void setRespectBytecodeAccModifiers(boolean respectBytecodeAccModifiers) { + this.respectBytecodeAccModifiers = respectBytecodeAccModifiers; + } + public boolean isExportAsGradleProject() { return exportAsGradleProject; } @@ -234,8 +243,10 @@ public class JadxArgs { sb.append(", deobfuscationMaxLength=").append(deobfuscationMaxLength); sb.append(", escapeUnicode=").append(escapeUnicode); sb.append(", replaceConsts=").append(replaceConsts); + sb.append(", respectBytecodeAccModifiers=").append(respectBytecodeAccModifiers); sb.append(", exportAsGradleProject=").append(exportAsGradleProject); sb.append('}'); return sb.toString(); } + } diff --git a/jadx-core/src/main/java/jadx/core/Jadx.java b/jadx-core/src/main/java/jadx/core/Jadx.java index 37d27f9fe16f955aad9f80cf186e95b78700ff3c..7527a8e0944c78a3d692b7b21215ccd524bc72cb 100644 --- a/jadx-core/src/main/java/jadx/core/Jadx.java +++ b/jadx-core/src/main/java/jadx/core/Jadx.java @@ -19,6 +19,7 @@ import jadx.core.dex.visitors.DotGraphVisitor; import jadx.core.dex.visitors.EnumVisitor; import jadx.core.dex.visitors.ExtractFieldInit; import jadx.core.dex.visitors.FallbackModeVisitor; +import jadx.core.dex.visitors.FixAccessModifiers; import jadx.core.dex.visitors.IDexTreeVisitor; import jadx.core.dex.visitors.MethodInlineVisitor; import jadx.core.dex.visitors.ModVisitor; @@ -96,6 +97,7 @@ public class Jadx { passes.add(new MethodInlineVisitor()); passes.add(new ExtractFieldInit()); + passes.add(new FixAccessModifiers()); passes.add(new ClassModifier()); passes.add(new EnumVisitor()); passes.add(new PrepareForCodeGen()); diff --git a/jadx-core/src/main/java/jadx/core/dex/info/AccessInfo.java b/jadx-core/src/main/java/jadx/core/dex/info/AccessInfo.java index 11a13f49f584558758f67c4f08f3140067bb7b14..0c511a336b5544000789d47b296def97c726e69b 100644 --- a/jadx-core/src/main/java/jadx/core/dex/info/AccessInfo.java +++ b/jadx-core/src/main/java/jadx/core/dex/info/AccessInfo.java @@ -6,6 +6,7 @@ import jadx.core.Consts; public class AccessInfo { + public static final int VISIBILITY_FLAGS = AccessFlags.ACC_PUBLIC | AccessFlags.ACC_PROTECTED | AccessFlags.ACC_PRIVATE; private final int accFlags; public enum AFType { @@ -30,11 +31,24 @@ public class AccessInfo { return this; } + public AccessInfo add(int flag) { + if (!containsFlag(flag)) { + return new AccessInfo(accFlags | flag, type); + } + return this; + } + + public AccessInfo changeVisibility(int flag) { + int currentVisFlags = accFlags & VISIBILITY_FLAGS; + if (currentVisFlags == flag) { + return this; + } + int unsetAllVisFlags = accFlags & ~VISIBILITY_FLAGS; + return new AccessInfo(unsetAllVisFlags | flag, type); + } + public AccessInfo getVisibility() { - int f = accFlags & AccessFlags.ACC_PUBLIC - | accFlags & AccessFlags.ACC_PROTECTED - | accFlags & AccessFlags.ACC_PRIVATE; - return new AccessInfo(f, type); + return new AccessInfo(accFlags & VISIBILITY_FLAGS, type); } public boolean isPublic() { diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/MethodNode.java b/jadx-core/src/main/java/jadx/core/dex/nodes/MethodNode.java index d1d291e31cdcf51ddef5e42b416fb86eef44e4fa..15ac0c92c3c07921f501181aadc0d2e9c172cb27 100644 --- a/jadx-core/src/main/java/jadx/core/dex/nodes/MethodNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/nodes/MethodNode.java @@ -51,7 +51,7 @@ public class MethodNode extends LineAttrNode implements ILoadable, IDexNode { private final MethodInfo mthInfo; private final ClassNode parentClass; - private final AccessInfo accFlags; + private AccessInfo accFlags; private final Method methodData; private int regsCount; @@ -599,6 +599,10 @@ public class MethodNode extends LineAttrNode implements ILoadable, IDexNode { return accFlags; } + public void setAccFlags(AccessInfo accFlags) { + this.accFlags = accFlags; + } + public Region getRegion() { return region; } diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/FixAccessModifiers.java b/jadx-core/src/main/java/jadx/core/dex/visitors/FixAccessModifiers.java new file mode 100644 index 0000000000000000000000000000000000000000..d62143945fd926f0fdc7c651e02b8e4897e6c3e2 --- /dev/null +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/FixAccessModifiers.java @@ -0,0 +1,57 @@ +package jadx.core.dex.visitors; + +import com.android.dx.rop.code.AccessFlags; + +import jadx.core.dex.attributes.AType; +import jadx.core.dex.info.AccessInfo; +import jadx.core.dex.nodes.MethodNode; +import jadx.core.dex.nodes.RootNode; + +@JadxVisitor( + name = "FixAccessModifiers", + desc = "Change class and method access modifiers if needed", + runAfter = ModVisitor.class +) +public class FixAccessModifiers extends AbstractVisitor { + + private boolean respectAccessModifiers; + + @Override + public void init(RootNode root) { + this.respectAccessModifiers = root.getArgs().isRespectBytecodeAccModifiers(); + } + + @Override + public void visit(MethodNode mth) { + if (respectAccessModifiers) { + return; + } + AccessInfo accessFlags = mth.getAccessFlags(); + int newVisFlag = fixVisibility(mth, accessFlags); + if (newVisFlag != 0) { + AccessInfo newAccFlags = accessFlags.changeVisibility(newVisFlag); + if (newAccFlags != accessFlags) { + mth.setAccFlags(newAccFlags); + mth.addAttr(AType.COMMENTS, "Access modifiers changed, original: " + accessFlags.rawString()); + } + } + } + + private int fixVisibility(MethodNode mth, AccessInfo accessFlags) { + if (mth.isVirtual()) { + // make virtual methods public + return AccessFlags.ACC_PUBLIC; + } else { + if (accessFlags.isAbstract()) { + // make abstract methods public + return AccessFlags.ACC_PUBLIC; + } + if (accessFlags.isConstructor() || accessFlags.isStatic()) { + // TODO: make public if used outside + return 0; + } + // make other direct methods private + return AccessFlags.ACC_PRIVATE; + } + } +} diff --git a/jadx-core/src/test/java/jadx/core/dex/info/AccessInfoTest.java b/jadx-core/src/test/java/jadx/core/dex/info/AccessInfoTest.java new file mode 100644 index 0000000000000000000000000000000000000000..7fd7acc876fb20c1cc98e75907684586296c1e6b --- /dev/null +++ b/jadx-core/src/test/java/jadx/core/dex/info/AccessInfoTest.java @@ -0,0 +1,32 @@ +package jadx.core.dex.info; + +import com.android.dx.rop.code.AccessFlags; +import org.junit.Test; + +import jadx.core.dex.info.AccessInfo.AFType; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertThat; + +public class AccessInfoTest { + + @Test + public void changeVisibility() { + AccessInfo accessInfo = new AccessInfo(AccessFlags.ACC_PROTECTED | AccessFlags.ACC_STATIC, AFType.METHOD); + AccessInfo result = accessInfo.changeVisibility(AccessFlags.ACC_PUBLIC); + + assertThat(result.isPublic(), is(true)); + assertThat(result.isPrivate(), is(false)); + assertThat(result.isProtected(), is(false)); + + assertThat(result.isStatic(), is(true)); + } + + @Test + public void changeVisibilityNoOp() { + AccessInfo accessInfo = new AccessInfo(AccessFlags.ACC_PUBLIC, AFType.METHOD); + AccessInfo result = accessInfo.changeVisibility(AccessFlags.ACC_PUBLIC); + assertSame(accessInfo, result); + } +} diff --git a/jadx-core/src/test/java/jadx/tests/api/SmaliTest.java b/jadx-core/src/test/java/jadx/tests/api/SmaliTest.java index e77e80b5164419d85cc230dc4f398f65864721e7..49658e4e0a508d402c9ad3cb02ad97958fe8be9a 100644 --- a/jadx-core/src/test/java/jadx/tests/api/SmaliTest.java +++ b/jadx-core/src/test/java/jadx/tests/api/SmaliTest.java @@ -1,6 +1,10 @@ package jadx.tests.api; import java.io.File; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; import org.jf.smali.Smali; import org.jf.smali.SmaliOptions; @@ -16,7 +20,7 @@ public abstract class SmaliTest extends IntegrationTest { protected ClassNode getClassNodeFromSmali(String file, String clsName) { File smaliFile = getSmaliFile(file); File outDex = createTempFile(".dex"); - compileSmali(smaliFile, outDex); + compileSmali(outDex, Collections.singletonList(smaliFile)); return getClassNodeFromFile(outDex, clsName); } @@ -28,27 +32,37 @@ public abstract class SmaliTest extends IntegrationTest { return getClassNodeFromSmali(pkg + File.separatorChar + clsName, pkg + '.' + clsName); } + protected ClassNode getClassNodeFromSmaliFiles(String pkg, String testName, String clsName, String... smaliFileNames) { + File outDex = createTempFile(".dex"); + List smaliFiles = Arrays.stream(smaliFileNames) + .map(file -> getSmaliFile(pkg + File.separatorChar + testName + File.separatorChar + file)) + .collect(Collectors.toList()); + compileSmali(outDex, smaliFiles); + return getClassNodeFromFile(outDex, pkg + "." + clsName); + } + protected ClassNode getClassNodeFromSmali(String clsName) { return getClassNodeFromSmali(clsName, clsName); } - private static File getSmaliFile(String clsName) { - File smaliFile = new File(SMALI_TESTS_DIR, clsName + SMALI_TESTS_EXT); + private static File getSmaliFile(String baseName) { + File smaliFile = new File(SMALI_TESTS_DIR, baseName + SMALI_TESTS_EXT); if (smaliFile.exists()) { return smaliFile; } - smaliFile = new File(SMALI_TESTS_PROJECT, smaliFile.getPath()); - if (smaliFile.exists()) { - return smaliFile; + File pathFromRoot = new File(SMALI_TESTS_PROJECT, smaliFile.getPath()); + if (pathFromRoot.exists()) { + return pathFromRoot; } - throw new AssertionError("Smali file not found: " + smaliFile.getAbsolutePath()); + throw new AssertionError("Smali file not found: " + smaliFile.getPath()); } - private static boolean compileSmali(File input, File output) { + private static boolean compileSmali(File output, List inputFiles) { try { SmaliOptions params = new SmaliOptions(); params.outputDexFile = output.getAbsolutePath(); - Smali.assemble(params, input.getAbsolutePath()); + List inputFileNames = inputFiles.stream().map(File::getAbsolutePath).collect(Collectors.toList()); + Smali.assemble(params, inputFileNames); } catch (Exception e) { throw new AssertionError("Smali assemble error", e); } diff --git a/jadx-core/src/test/java/jadx/tests/integration/debuginfo/TestLineNumbers2.java b/jadx-core/src/test/java/jadx/tests/integration/debuginfo/TestLineNumbers2.java index 31e47b56f4cd9f7d5e3847910303c55e84f133f5..aad9ad13c60dc44d2aad48a40c3002f60d19f015 100644 --- a/jadx-core/src/test/java/jadx/tests/integration/debuginfo/TestLineNumbers2.java +++ b/jadx-core/src/test/java/jadx/tests/integration/debuginfo/TestLineNumbers2.java @@ -19,7 +19,7 @@ public class TestLineNumbers2 extends IntegrationTest { public TestCls(TestCls s) { } - TestCls test(TestCls s) { + public TestCls test(TestCls s) { TestCls store = f != null ? f.get() : null; if (store == null) { store = new TestCls(s); diff --git a/jadx-core/src/test/java/jadx/tests/integration/enums/TestEnums2.java b/jadx-core/src/test/java/jadx/tests/integration/enums/TestEnums2.java index 80638a151a299b52978df9d5d525dd5cb18786db..2a3eee3266aa95497a42285a0537e1931eccbbce 100644 --- a/jadx-core/src/test/java/jadx/tests/integration/enums/TestEnums2.java +++ b/jadx-core/src/test/java/jadx/tests/integration/enums/TestEnums2.java @@ -14,17 +14,17 @@ public class TestEnums2 extends IntegrationTest { public enum Operation { PLUS { - int apply(int x, int y) { + public int apply(int x, int y) { return x + y; } }, MINUS { - int apply(int x, int y) { + public int apply(int x, int y) { return x - y; } }; - abstract int apply(int x, int y); + public abstract int apply(int x, int y); } } @@ -36,17 +36,17 @@ public class TestEnums2 extends IntegrationTest { assertThat(code, JadxMatchers.containsLines(1, "public enum Operation {", indent(1) + "PLUS {", - indent(2) + "int apply(int x, int y) {", + indent(2) + "public int apply(int x, int y) {", indent(3) + "return x + y;", indent(2) + "}", indent(1) + "},", indent(1) + "MINUS {", - indent(2) + "int apply(int x, int y) {", + indent(2) + "public int apply(int x, int y) {", indent(3) + "return x - y;", indent(2) + "}", indent(1) + "};", "", - indent(1) + "abstract int apply(int i, int i2);", + indent(1) + "public abstract int apply(int i, int i2);", "}" )); } diff --git a/jadx-core/src/test/java/jadx/tests/integration/inner/TestInnerClassSyntheticRename.java b/jadx-core/src/test/java/jadx/tests/integration/inner/TestInnerClassSyntheticRename.java index 6a2068a200a9076d9d3a189740389436417ff6aa..2404735676bc2054a19e69878c776b507dd46743 100644 --- a/jadx-core/src/test/java/jadx/tests/integration/inner/TestInnerClassSyntheticRename.java +++ b/jadx-core/src/test/java/jadx/tests/integration/inner/TestInnerClassSyntheticRename.java @@ -34,8 +34,8 @@ public class TestInnerClassSyntheticRename extends SmaliTest { ClassNode cls = getClassNodeFromSmali("inner/TestInnerClassSyntheticRename", "com.github.skylot.testasync.MyAsync"); String code = cls.getCode().toString(); - assertThat(code, containsOne("protected List doInBackground(Uri... uriArr) {")); - assertThat(code, containsOne("protected void onPostExecute(List list) {")); + assertThat(code, containsOne("List doInBackground(Uri... uriArr) {")); + assertThat(code, containsOne("void onPostExecute(List list) {")); assertThat(code, not(containsString("synthetic"))); } } diff --git a/jadx-core/src/test/java/jadx/tests/integration/others/TestBadMethodAccessModifiers.java b/jadx-core/src/test/java/jadx/tests/integration/others/TestBadMethodAccessModifiers.java new file mode 100644 index 0000000000000000000000000000000000000000..f267d5eb9111b01fd51e4c729fe231416360a03a --- /dev/null +++ b/jadx-core/src/test/java/jadx/tests/integration/others/TestBadMethodAccessModifiers.java @@ -0,0 +1,36 @@ +package jadx.tests.integration.others; + +import org.junit.Test; + +import jadx.core.dex.nodes.ClassNode; +import jadx.tests.api.SmaliTest; + +import static jadx.tests.api.utils.JadxMatchers.containsOne; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.not; +import static org.junit.Assert.assertThat; + +public class TestBadMethodAccessModifiers extends SmaliTest { + /* + public static class TestCls { + + public abstract class A { + public abstract void test(); + } + + public class B extends A { + protected void test() { + } + } + } + */ + @Test + public void test() { + ClassNode cls = getClassNodeFromSmaliFiles("others", "TestBadMethodAccessModifiers", "TestCls", + "TestCls$A", "TestCls$B", "TestCls"); + String code = cls.getCode().toString(); + + assertThat(code, not(containsString("protected void test() {"))); + assertThat(code, containsOne("public void test() {")); + } +} diff --git a/jadx-core/src/test/smali/others/TestBadMethodAccessModifiers/TestCls$A.smali b/jadx-core/src/test/smali/others/TestBadMethodAccessModifiers/TestCls$A.smali new file mode 100644 index 0000000000000000000000000000000000000000..e1a89583af2204754169609201aa4268f75f2cb0 --- /dev/null +++ b/jadx-core/src/test/smali/others/TestBadMethodAccessModifiers/TestCls$A.smali @@ -0,0 +1,38 @@ +.class public abstract Lothers/TestCls$A; +.super Ljava/lang/Object; +.source "TestCls.java" + + +# annotations +.annotation system Ldalvik/annotation/EnclosingClass; + value = Lothers/TestCls; +.end annotation + +.annotation system Ldalvik/annotation/InnerClass; + accessFlags = 0x401 + name = "A" +.end annotation + + +# instance fields +.field final synthetic this$0:Lothers/TestCls; + + +# direct methods +.method public constructor (Lothers/TestCls;)V + .registers 2 + .param p1, "this$0" # Lothers/TestCls; + + .prologue + .line 5 + iput-object p1, p0, Lothers/TestCls$A;->this$0:Lothers/TestCls; + + invoke-direct {p0}, Ljava/lang/Object;->()V + + return-void +.end method + + +# virtual methods +.method public abstract test()V +.end method diff --git a/jadx-core/src/test/smali/others/TestBadMethodAccessModifiers/TestCls$B.smali b/jadx-core/src/test/smali/others/TestBadMethodAccessModifiers/TestCls$B.smali new file mode 100644 index 0000000000000000000000000000000000000000..d12c79e6384821057fe7be8d5496c1e47519993c --- /dev/null +++ b/jadx-core/src/test/smali/others/TestBadMethodAccessModifiers/TestCls$B.smali @@ -0,0 +1,43 @@ +.class public Lothers/TestCls$B; +.super Lothers/TestCls$A; +.source "TestCls.java" + + +# annotations +.annotation system Ldalvik/annotation/EnclosingClass; + value = Lothers/TestCls; +.end annotation + +.annotation system Ldalvik/annotation/InnerClass; + accessFlags = 0x1 + name = "B" +.end annotation + + +# instance fields +.field final synthetic this$0:Lothers/TestCls; + + +# direct methods +.method public constructor (Lothers/TestCls;)V + .registers 2 + .param p1, "this$0" # Lothers/TestCls; + + .prologue + .line 9 + iput-object p1, p0, Lothers/TestCls$B;->this$0:Lothers/TestCls; + + invoke-direct {p0, p1}, Lothers/TestCls$A;->(Lothers/TestCls;)V + + return-void +.end method + + +# virtual methods +.method protected test()V + .registers 1 + + .prologue + .line 11 + return-void +.end method diff --git a/jadx-core/src/test/smali/others/TestBadMethodAccessModifiers/TestCls.smali b/jadx-core/src/test/smali/others/TestBadMethodAccessModifiers/TestCls.smali new file mode 100644 index 0000000000000000000000000000000000000000..150536a63b4afe10483c9b4b0549104dec85abaa --- /dev/null +++ b/jadx-core/src/test/smali/others/TestBadMethodAccessModifiers/TestCls.smali @@ -0,0 +1,24 @@ +.class public Lothers/TestCls; +.super Ljava/lang/Object; +.source "TestCls.java" + + +# annotations +.annotation system Ldalvik/annotation/MemberClasses; + value = { + Lothers/TestCls$B;, + Lothers/TestCls$A; + } +.end annotation + + +# direct methods +.method public constructor ()V + .registers 1 + + .prologue + .line 3 + invoke-direct {p0}, Ljava/lang/Object;->()V + + return-void +.end method diff --git a/jadx-gui/src/main/java/jadx/gui/settings/JadxSettings.java b/jadx-gui/src/main/java/jadx/gui/settings/JadxSettings.java index 4c134d0bcbcfe9b7bde177f368bb4bd4de638022..6b6fd126780f1b60e194859b9805d55d6f55d310 100644 --- a/jadx-gui/src/main/java/jadx/gui/settings/JadxSettings.java +++ b/jadx-gui/src/main/java/jadx/gui/settings/JadxSettings.java @@ -26,7 +26,7 @@ public class JadxSettings extends JadxCLIArgs { private static final String USER_HOME = System.getProperty("user.home"); private static final int RECENT_FILES_COUNT = 15; - private static final int CURRENT_SETTINGS_VERSION = 5; + private static final int CURRENT_SETTINGS_VERSION = 6; private static final Font DEFAULT_FONT = FONT_HACK != null ? FONT_HACK : new RSyntaxTextArea().getFont(); @@ -235,6 +235,10 @@ public class JadxSettings extends JadxCLIArgs { this.replaceConsts = replaceConsts; } + public void setRespectBytecodeAccessModifiers(boolean respectBytecodeAccessModifiers) { + this.respectBytecodeAccessModifiers = respectBytecodeAccessModifiers; + } + public void setUseImports(boolean useImports) { this.useImports = useImports; } @@ -311,6 +315,10 @@ public class JadxSettings extends JadxCLIArgs { } if (fromVersion == 4) { setUseImports(true); + fromVersion++; + } + if (fromVersion == 5) { + setRespectBytecodeAccessModifiers(false); } settingsVersion = CURRENT_SETTINGS_VERSION; sync(); diff --git a/jadx-gui/src/main/java/jadx/gui/settings/JadxSettingsWindow.java b/jadx-gui/src/main/java/jadx/gui/settings/JadxSettingsWindow.java index 0ada8165b038916b6915a788fdecbc2b67064a78..5bcbf535100d7d8520fc5c25f04138a7cb3bdd30 100644 --- a/jadx-gui/src/main/java/jadx/gui/settings/JadxSettingsWindow.java +++ b/jadx-gui/src/main/java/jadx/gui/settings/JadxSettingsWindow.java @@ -259,6 +259,13 @@ public class JadxSettingsWindow extends JDialog { needReload(); }); + JCheckBox respectBytecodeAccessModifiers = new JCheckBox(); + respectBytecodeAccessModifiers.setSelected(settings.isRespectBytecodeAccessModifiers()); + respectBytecodeAccessModifiers.addItemListener(e -> { + settings.setRespectBytecodeAccessModifiers(e.getStateChange() == ItemEvent.SELECTED); + needReload(); + }); + JCheckBox useImports = new JCheckBox(); useImports.setSelected(settings.isUseImports()); useImports.addItemListener(e -> { @@ -274,6 +281,7 @@ public class JadxSettingsWindow extends JDialog { other.addRow(NLS.str("preferences.showInconsistentCode"), showInconsistentCode); other.addRow(NLS.str("preferences.escapeUnicode"), escapeUnicode); other.addRow(NLS.str("preferences.replaceConsts"), replaceConsts); + other.addRow(NLS.str("preferences.respectBytecodeAccessModifiers"), respectBytecodeAccessModifiers); other.addRow(NLS.str("preferences.useImports"), useImports); other.addRow(NLS.str("preferences.fallback"), fallback); other.addRow(NLS.str("preferences.skipResourcesDecode"), resourceDecode); diff --git a/jadx-gui/src/main/resources/i18n/Messages_en_US.properties b/jadx-gui/src/main/resources/i18n/Messages_en_US.properties index ad43b2ff48f3e08397d5e9bc4bad0e63b85c78c8..fe5504adff43f4cd86f9e1e4bcb2802d635de963 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_en_US.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_en_US.properties @@ -86,6 +86,7 @@ preferences.fallback=Fallback mode (simple dump) preferences.showInconsistentCode=Show inconsistent code preferences.escapeUnicode=Escape unicode preferences.replaceConsts=Replace constants +preferences.respectBytecodeAccessModifiers=Respect bytecode access modifiers preferences.useImports=Use import statements preferences.skipResourcesDecode=Don't decode resources preferences.threads=Processing threads count