├── version ├── jadx-core ├── lib │ └── dx-1.10.jar ├── clsp-data │ └── android-5.1.jar ├── src │ ├── main │ │ ├── java │ │ │ └── jadx │ │ │ │ ├── core │ │ │ │ ├── dex │ │ │ │ │ ├── regions │ │ │ │ │ │ ├── loops │ │ │ │ │ │ │ ├── LoopType.java │ │ │ │ │ │ │ ├── ForLoop.java │ │ │ │ │ │ │ └── ForEachLoop.java │ │ │ │ │ │ ├── AbstractRegion.java │ │ │ │ │ │ ├── conditions │ │ │ │ │ │ │ └── Compare.java │ │ │ │ │ │ └── SynchronizedRegion.java │ │ │ │ │ ├── attributes │ │ │ │ │ │ ├── IAttribute.java │ │ │ │ │ │ ├── nodes │ │ │ │ │ │ │ ├── LoopLabelAttr.java │ │ │ │ │ │ │ ├── SourceFileAttr.java │ │ │ │ │ │ │ ├── MethodInlineAttr.java │ │ │ │ │ │ │ ├── ForceReturnAttr.java │ │ │ │ │ │ │ ├── LineAttrNode.java │ │ │ │ │ │ │ ├── IgnoreEdgeAttr.java │ │ │ │ │ │ │ ├── PhiListAttr.java │ │ │ │ │ │ │ ├── DeclareVariablesAttr.java │ │ │ │ │ │ │ ├── JadxErrorAttr.java │ │ │ │ │ │ │ └── JumpInfo.java │ │ │ │ │ │ ├── AttrList.java │ │ │ │ │ │ ├── AFlag.java │ │ │ │ │ │ ├── annotations │ │ │ │ │ │ │ ├── MethodParameters.java │ │ │ │ │ │ │ └── Annotation.java │ │ │ │ │ │ └── IAttributeNode.java │ │ │ │ │ ├── nodes │ │ │ │ │ │ ├── IDexNode.java │ │ │ │ │ │ ├── ProcessState.java │ │ │ │ │ │ ├── IBlock.java │ │ │ │ │ │ ├── IContainer.java │ │ │ │ │ │ ├── IRegion.java │ │ │ │ │ │ ├── IBranchRegion.java │ │ │ │ │ │ ├── ILoadable.java │ │ │ │ │ │ ├── ResRefField.java │ │ │ │ │ │ ├── InsnContainer.java │ │ │ │ │ │ ├── parser │ │ │ │ │ │ │ └── StaticValuesParser.java │ │ │ │ │ │ └── Edge.java │ │ │ │ │ ├── instructions │ │ │ │ │ │ ├── args │ │ │ │ │ │ │ ├── Named.java │ │ │ │ │ │ │ ├── VarName.java │ │ │ │ │ │ │ ├── Typed.java │ │ │ │ │ │ │ ├── NamedArg.java │ │ │ │ │ │ │ └── PrimitiveType.java │ │ │ │ │ │ ├── InvokeType.java │ │ │ │ │ │ ├── ArithOp.java │ │ │ │ │ │ ├── GotoNode.java │ │ │ │ │ │ ├── IfOp.java │ │ │ │ │ │ ├── ConstStringNode.java │ │ │ │ │ │ ├── ConstClassNode.java │ │ │ │ │ │ ├── IndexInsnNode.java │ │ │ │ │ │ ├── FilledNewArrayNode.java │ │ │ │ │ │ ├── InsnType.java │ │ │ │ │ │ └── NewArrayNode.java │ │ │ │ │ ├── visitors │ │ │ │ │ │ ├── regions │ │ │ │ │ │ │ ├── IRegionIterativeVisitor.java │ │ │ │ │ │ │ ├── IRegionVisitor.java │ │ │ │ │ │ │ ├── AbstractRegionVisitor.java │ │ │ │ │ │ │ └── TracedRegionVisitor.java │ │ │ │ │ │ ├── AbstractVisitor.java │ │ │ │ │ │ ├── IDexTreeVisitor.java │ │ │ │ │ │ ├── typeinference │ │ │ │ │ │ │ ├── CheckTypeVisitor.java │ │ │ │ │ │ │ └── SelectTypeVisitor.java │ │ │ │ │ │ ├── JadxVisitor.java │ │ │ │ │ │ ├── SaveCode.java │ │ │ │ │ │ ├── blocksmaker │ │ │ │ │ │ │ └── helpers │ │ │ │ │ │ │ │ └── BlocksPair.java │ │ │ │ │ │ └── DepthTraversal.java │ │ │ │ │ └── trycatch │ │ │ │ │ │ ├── CatchAttr.java │ │ │ │ │ │ ├── SplitterBlockAttr.java │ │ │ │ │ │ └── ExcHandlerAttr.java │ │ │ │ ├── utils │ │ │ │ │ ├── exceptions │ │ │ │ │ │ ├── JadxOverflowException.java │ │ │ │ │ │ ├── JadxRuntimeException.java │ │ │ │ │ │ ├── DecodeException.java │ │ │ │ │ │ ├── JadxException.java │ │ │ │ │ │ └── CodegenException.java │ │ │ │ │ ├── AsmUtils.java │ │ │ │ │ └── files │ │ │ │ │ │ └── DexFile.java │ │ │ │ ├── xmlgen │ │ │ │ │ └── entry │ │ │ │ │ │ ├── RawValue.java │ │ │ │ │ │ ├── RawNamedValue.java │ │ │ │ │ │ └── EntryConfig.java │ │ │ │ ├── deobf │ │ │ │ │ └── OverridedMethodsNode.java │ │ │ │ ├── codegen │ │ │ │ │ └── CodeGen.java │ │ │ │ ├── clsp │ │ │ │ │ └── NClass.java │ │ │ │ └── Consts.java │ │ │ │ └── api │ │ │ │ ├── JavaNode.java │ │ │ │ ├── ResourceFileContent.java │ │ │ │ ├── IJadxArgs.java │ │ │ │ └── ResourceType.java │ │ └── resources │ │ │ └── export │ │ │ └── build.gradle.tmpl │ └── test │ │ ├── java │ │ └── jadx │ │ │ ├── api │ │ │ └── JadxInternalAccess.java │ │ │ └── tests │ │ │ ├── smali │ │ │ ├── TestN21.java │ │ │ ├── TestArithConst.java │ │ │ ├── TestInlineVarArg.java │ │ │ └── TestConstructor.java │ │ │ ├── api │ │ │ ├── compiler │ │ │ │ ├── CharSequenceJavaFileObject.java │ │ │ │ └── JavaClassObject.java │ │ │ └── utils │ │ │ │ ├── TestUtils.java │ │ │ │ ├── CountString.java │ │ │ │ └── JadxMatchers.java │ │ │ ├── integration │ │ │ ├── arrays │ │ │ │ ├── TestArrayFill.java │ │ │ │ ├── TestArrayFillConstReplace.java │ │ │ │ ├── TestArrays.java │ │ │ │ ├── TestArrays3.java │ │ │ │ ├── TestArrayFill2.java │ │ │ │ └── TestArrays2.java │ │ │ ├── TestStaticMethod.java │ │ │ ├── arith │ │ │ │ ├── TestArith.java │ │ │ │ ├── TestArith2.java │ │ │ │ ├── TestFieldIncrement2.java │ │ │ │ └── TestFieldIncrement.java │ │ │ ├── TestRedundantReturn.java │ │ │ ├── inner │ │ │ │ ├── TestInnerClass4.java │ │ │ │ ├── TestRFieldAccess.java │ │ │ │ ├── TestInnerClass.java │ │ │ │ ├── TestRFieldRestore2.java │ │ │ │ ├── TestInnerClass3.java │ │ │ │ ├── TestRFieldRestore.java │ │ │ │ ├── TestAnonymousClass6.java │ │ │ │ ├── TestAnonymousClass8.java │ │ │ │ └── TestAnonymousClass7.java │ │ │ ├── TestArgInline.java │ │ │ ├── variables │ │ │ │ ├── TestVariables2.java │ │ │ │ └── TestVariables3.java │ │ │ ├── conditions │ │ │ │ ├── TestConditions.java │ │ │ │ ├── TestCmpOp2.java │ │ │ │ ├── TestConditions7.java │ │ │ │ ├── TestConditions2.java │ │ │ │ ├── TestTernary2.java │ │ │ │ ├── TestConditions6.java │ │ │ │ ├── TestConditions4.java │ │ │ │ ├── TestSimpleConditions.java │ │ │ │ ├── TestConditions14.java │ │ │ │ ├── TestConditions11.java │ │ │ │ ├── TestTernaryInIf.java │ │ │ │ ├── TestTernary.java │ │ │ │ ├── TestConditions16.java │ │ │ │ └── TestConditions9.java │ │ │ ├── loops │ │ │ │ ├── TestDoWhileBreak.java │ │ │ │ ├── TestArrayForEach.java │ │ │ │ ├── TestLoopCondition2.java │ │ │ │ ├── TestIndexForLoop.java │ │ │ │ ├── TestIterableForEach.java │ │ │ │ ├── TestNestedLoops2.java │ │ │ │ ├── TestArrayForEach2.java │ │ │ │ ├── TestLoopDetection3.java │ │ │ │ ├── TestLoopCondition4.java │ │ │ │ ├── TestLoopDetection2.java │ │ │ │ ├── TestLoopCondition3.java │ │ │ │ ├── TestIfInLoop2.java │ │ │ │ ├── TestLoopDetection.java │ │ │ │ ├── TestIterableForEach3.java │ │ │ │ ├── TestBreakInLoop.java │ │ │ │ └── TestContinueInLoop.java │ │ │ ├── generics │ │ │ │ ├── TestGenerics4.java │ │ │ │ ├── TestGenerics.java │ │ │ │ └── TestGenerics6.java │ │ │ ├── types │ │ │ │ ├── TestTypeResolver2.java │ │ │ │ ├── TestTypeResolver.java │ │ │ │ └── TestTypeResolver3.java │ │ │ ├── inline │ │ │ │ ├── TestInline.java │ │ │ │ ├── TestInline6.java │ │ │ │ ├── TestInline2.java │ │ │ │ └── TestInline3.java │ │ │ ├── TestFloatValue.java │ │ │ ├── names │ │ │ │ └── TestSameMethodsNames.java │ │ │ ├── switches │ │ │ │ ├── TestSwitchNoDefault.java │ │ │ │ └── TestSwitchInLoop.java │ │ │ ├── trycatch │ │ │ │ ├── TestTryCatch.java │ │ │ │ ├── TestFinallyExtract.java │ │ │ │ ├── TestTryCatch2.java │ │ │ │ └── TestTryCatch7.java │ │ │ ├── synchronize │ │ │ │ ├── TestSynchronized2.java │ │ │ │ └── TestSynchronized3.java │ │ │ ├── invoke │ │ │ │ ├── TestSuperInvoke.java │ │ │ │ └── TestConstructorInvoke.java │ │ │ ├── fallback │ │ │ │ └── TestFallbackMode.java │ │ │ ├── enums │ │ │ │ ├── TestEnumsWithConsts.java │ │ │ │ └── TestSwitchOverEnum.java │ │ │ ├── usethis │ │ │ │ └── TestRedundantThis.java │ │ │ ├── others │ │ │ │ └── TestFieldInit2.java │ │ │ ├── TestStaticFieldsInit.java │ │ │ ├── TestClassGen.java │ │ │ └── TestStringBuilderElimination.java │ │ │ └── functional │ │ │ └── TemplateFileTest.java │ │ ├── smali │ │ ├── TestArithConst.smali │ │ ├── TestConstructor.smali │ │ └── TestInlineVarArg.smali │ │ ├── resources │ │ └── logback.xml │ │ └── groovy │ │ └── jadx │ │ └── tests │ │ ├── TestNameMapper.groovy │ │ └── TestStringUtils.groovy └── build.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── jadx-gui ├── libs │ └── jfontchooser-1.0.5.jar └── src │ ├── main │ ├── resources │ │ └── icons-16 │ │ │ ├── cross.png │ │ │ ├── sync.png │ │ │ ├── wand.png │ │ │ ├── arrow_up.png │ │ │ ├── cf_obj.png │ │ │ ├── enum_obj.png │ │ │ ├── error_co.png │ │ │ ├── file_obj.png │ │ │ ├── final_co.png │ │ │ ├── folder.png │ │ │ ├── int_obj.png │ │ │ ├── java_ovr.png │ │ │ ├── jcu_obj.png │ │ │ ├── report.png │ │ │ ├── synch_co.png │ │ │ ├── wrench.png │ │ │ ├── arrow_down.png │ │ │ ├── class_obj.png │ │ │ ├── constr_ovr.png │ │ │ ├── icon_back.png │ │ │ ├── lock_edit.png │ │ │ ├── magnifier.png │ │ │ ├── native_co.png │ │ │ ├── static_co.png │ │ │ ├── abstract_co.png │ │ │ ├── cross_grayed.png │ │ │ ├── database_save.png │ │ │ ├── disk_multiple.png │ │ │ ├── icon_forward.png │ │ │ ├── library_obj.png │ │ │ ├── methdef_obj.png │ │ │ ├── methpri_obj.png │ │ │ ├── methpro_obj.png │ │ │ ├── methpub_obj.png │ │ │ ├── package_obj.png │ │ │ ├── template_obj.png │ │ │ ├── transient_co.png │ │ │ ├── volatile_co.png │ │ │ ├── annotation_obj.png │ │ │ ├── empty_pack_obj.png │ │ │ ├── java_model_obj.png │ │ │ ├── class_default_obj.png │ │ │ ├── field_default_obj.png │ │ │ ├── field_private_obj.png │ │ │ ├── field_public_obj.png │ │ │ ├── packagefolder_obj.png │ │ │ ├── field_protected_obj.png │ │ │ ├── innerclass_private_obj.png │ │ │ ├── empty_logical_package_obj.png │ │ │ └── innerclass_protected_obj.png │ └── java │ │ └── jadx │ │ └── gui │ │ ├── utils │ │ ├── NLS.java │ │ ├── search │ │ │ ├── SearchIndex.java │ │ │ └── SimpleIndex.java │ │ ├── CodeLinesInfo.java │ │ └── Position.java │ │ ├── ui │ │ ├── ContentPanel.java │ │ └── ImagePanel.java │ │ ├── jobs │ │ └── DecompileJob.java │ │ ├── treemodel │ │ └── TextNode.java │ │ ├── settings │ │ └── WindowLocation.java │ │ ├── JadxGUI.java │ │ └── update │ │ └── data │ │ └── Release.java │ └── test │ ├── java │ └── jadx │ │ └── api │ │ └── Factory.java │ └── groovy │ └── jadx │ └── gui │ └── tests │ └── TestVersionsComparator.groovy ├── .gitmodules ├── jadx-samples └── src │ └── main │ └── java │ └── jadx │ └── samples │ ├── otherpkg │ ├── A.java │ ├── C.java │ └── D.java │ ├── TestDeadCode.java │ ├── TestImports.java │ ├── TestStringProcessing.java │ ├── TestInnerNames.java │ ├── TestImports2.java │ ├── TestCF4.java │ └── TestAnnotationsParser.java ├── settings.gradle ├── .gitignore ├── jadx-test-app └── README.md ├── jadx-cli ├── build.gradle └── src │ ├── main │ └── resources │ │ └── logback.xml │ └── test │ └── java │ └── jadx │ └── cli │ └── JadxCLIArgsTest.java └── .travis.yml /version: -------------------------------------------------------------------------------- 1 | 0.6.1 2 | -------------------------------------------------------------------------------- /jadx-core/lib/dx-1.10.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-core/lib/dx-1.10.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /jadx-core/clsp-data/android-5.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-core/clsp-data/android-5.1.jar -------------------------------------------------------------------------------- /jadx-gui/libs/jfontchooser-1.0.5.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-gui/libs/jfontchooser-1.0.5.jar -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "jadx-test-app/test-app"] 2 | path = jadx-test-app/test-app 3 | url = git://github.com/skylot/jadx-test-app.git 4 | -------------------------------------------------------------------------------- /jadx-gui/src/main/resources/icons-16/cross.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-gui/src/main/resources/icons-16/cross.png -------------------------------------------------------------------------------- /jadx-gui/src/main/resources/icons-16/sync.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-gui/src/main/resources/icons-16/sync.png -------------------------------------------------------------------------------- /jadx-gui/src/main/resources/icons-16/wand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-gui/src/main/resources/icons-16/wand.png -------------------------------------------------------------------------------- /jadx-gui/src/main/resources/icons-16/arrow_up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-gui/src/main/resources/icons-16/arrow_up.png -------------------------------------------------------------------------------- /jadx-gui/src/main/resources/icons-16/cf_obj.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-gui/src/main/resources/icons-16/cf_obj.png -------------------------------------------------------------------------------- /jadx-gui/src/main/resources/icons-16/enum_obj.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-gui/src/main/resources/icons-16/enum_obj.png -------------------------------------------------------------------------------- /jadx-gui/src/main/resources/icons-16/error_co.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-gui/src/main/resources/icons-16/error_co.png -------------------------------------------------------------------------------- /jadx-gui/src/main/resources/icons-16/file_obj.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-gui/src/main/resources/icons-16/file_obj.png -------------------------------------------------------------------------------- /jadx-gui/src/main/resources/icons-16/final_co.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-gui/src/main/resources/icons-16/final_co.png -------------------------------------------------------------------------------- /jadx-gui/src/main/resources/icons-16/folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-gui/src/main/resources/icons-16/folder.png -------------------------------------------------------------------------------- /jadx-gui/src/main/resources/icons-16/int_obj.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-gui/src/main/resources/icons-16/int_obj.png -------------------------------------------------------------------------------- /jadx-gui/src/main/resources/icons-16/java_ovr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-gui/src/main/resources/icons-16/java_ovr.png -------------------------------------------------------------------------------- /jadx-gui/src/main/resources/icons-16/jcu_obj.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-gui/src/main/resources/icons-16/jcu_obj.png -------------------------------------------------------------------------------- /jadx-gui/src/main/resources/icons-16/report.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-gui/src/main/resources/icons-16/report.png -------------------------------------------------------------------------------- /jadx-gui/src/main/resources/icons-16/synch_co.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-gui/src/main/resources/icons-16/synch_co.png -------------------------------------------------------------------------------- /jadx-gui/src/main/resources/icons-16/wrench.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-gui/src/main/resources/icons-16/wrench.png -------------------------------------------------------------------------------- /jadx-gui/src/main/resources/icons-16/arrow_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-gui/src/main/resources/icons-16/arrow_down.png -------------------------------------------------------------------------------- /jadx-gui/src/main/resources/icons-16/class_obj.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-gui/src/main/resources/icons-16/class_obj.png -------------------------------------------------------------------------------- /jadx-gui/src/main/resources/icons-16/constr_ovr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-gui/src/main/resources/icons-16/constr_ovr.png -------------------------------------------------------------------------------- /jadx-gui/src/main/resources/icons-16/icon_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-gui/src/main/resources/icons-16/icon_back.png -------------------------------------------------------------------------------- /jadx-gui/src/main/resources/icons-16/lock_edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-gui/src/main/resources/icons-16/lock_edit.png -------------------------------------------------------------------------------- /jadx-gui/src/main/resources/icons-16/magnifier.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-gui/src/main/resources/icons-16/magnifier.png -------------------------------------------------------------------------------- /jadx-gui/src/main/resources/icons-16/native_co.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-gui/src/main/resources/icons-16/native_co.png -------------------------------------------------------------------------------- /jadx-gui/src/main/resources/icons-16/static_co.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-gui/src/main/resources/icons-16/static_co.png -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/regions/loops/LoopType.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.regions.loops; 2 | 3 | public abstract class LoopType { 4 | } 5 | -------------------------------------------------------------------------------- /jadx-gui/src/main/resources/icons-16/abstract_co.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-gui/src/main/resources/icons-16/abstract_co.png -------------------------------------------------------------------------------- /jadx-gui/src/main/resources/icons-16/cross_grayed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-gui/src/main/resources/icons-16/cross_grayed.png -------------------------------------------------------------------------------- /jadx-gui/src/main/resources/icons-16/database_save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-gui/src/main/resources/icons-16/database_save.png -------------------------------------------------------------------------------- /jadx-gui/src/main/resources/icons-16/disk_multiple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-gui/src/main/resources/icons-16/disk_multiple.png -------------------------------------------------------------------------------- /jadx-gui/src/main/resources/icons-16/icon_forward.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-gui/src/main/resources/icons-16/icon_forward.png -------------------------------------------------------------------------------- /jadx-gui/src/main/resources/icons-16/library_obj.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-gui/src/main/resources/icons-16/library_obj.png -------------------------------------------------------------------------------- /jadx-gui/src/main/resources/icons-16/methdef_obj.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-gui/src/main/resources/icons-16/methdef_obj.png -------------------------------------------------------------------------------- /jadx-gui/src/main/resources/icons-16/methpri_obj.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-gui/src/main/resources/icons-16/methpri_obj.png -------------------------------------------------------------------------------- /jadx-gui/src/main/resources/icons-16/methpro_obj.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-gui/src/main/resources/icons-16/methpro_obj.png -------------------------------------------------------------------------------- /jadx-gui/src/main/resources/icons-16/methpub_obj.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-gui/src/main/resources/icons-16/methpub_obj.png -------------------------------------------------------------------------------- /jadx-gui/src/main/resources/icons-16/package_obj.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-gui/src/main/resources/icons-16/package_obj.png -------------------------------------------------------------------------------- /jadx-gui/src/main/resources/icons-16/template_obj.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-gui/src/main/resources/icons-16/template_obj.png -------------------------------------------------------------------------------- /jadx-gui/src/main/resources/icons-16/transient_co.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-gui/src/main/resources/icons-16/transient_co.png -------------------------------------------------------------------------------- /jadx-gui/src/main/resources/icons-16/volatile_co.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-gui/src/main/resources/icons-16/volatile_co.png -------------------------------------------------------------------------------- /jadx-gui/src/main/resources/icons-16/annotation_obj.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-gui/src/main/resources/icons-16/annotation_obj.png -------------------------------------------------------------------------------- /jadx-gui/src/main/resources/icons-16/empty_pack_obj.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-gui/src/main/resources/icons-16/empty_pack_obj.png -------------------------------------------------------------------------------- /jadx-gui/src/main/resources/icons-16/java_model_obj.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-gui/src/main/resources/icons-16/java_model_obj.png -------------------------------------------------------------------------------- /jadx-samples/src/main/java/jadx/samples/otherpkg/A.java: -------------------------------------------------------------------------------- 1 | package jadx.samples.otherpkg; 2 | 3 | public class A { 4 | protected class B { 5 | 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /jadx-samples/src/main/java/jadx/samples/otherpkg/C.java: -------------------------------------------------------------------------------- 1 | package jadx.samples.otherpkg; 2 | 3 | public class C { 4 | public static class E { 5 | 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /jadx-samples/src/main/java/jadx/samples/otherpkg/D.java: -------------------------------------------------------------------------------- 1 | package jadx.samples.otherpkg; 2 | 3 | public class D { 4 | public static class E { 5 | 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /jadx-gui/src/main/resources/icons-16/class_default_obj.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-gui/src/main/resources/icons-16/class_default_obj.png -------------------------------------------------------------------------------- /jadx-gui/src/main/resources/icons-16/field_default_obj.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-gui/src/main/resources/icons-16/field_default_obj.png -------------------------------------------------------------------------------- /jadx-gui/src/main/resources/icons-16/field_private_obj.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-gui/src/main/resources/icons-16/field_private_obj.png -------------------------------------------------------------------------------- /jadx-gui/src/main/resources/icons-16/field_public_obj.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-gui/src/main/resources/icons-16/field_public_obj.png -------------------------------------------------------------------------------- /jadx-gui/src/main/resources/icons-16/packagefolder_obj.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-gui/src/main/resources/icons-16/packagefolder_obj.png -------------------------------------------------------------------------------- /jadx-gui/src/main/resources/icons-16/field_protected_obj.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-gui/src/main/resources/icons-16/field_protected_obj.png -------------------------------------------------------------------------------- /jadx-gui/src/main/resources/icons-16/innerclass_private_obj.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-gui/src/main/resources/icons-16/innerclass_private_obj.png -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'jadx' 2 | 3 | include 'jadx-core' 4 | include 'jadx-cli' 5 | include 'jadx-gui' 6 | include 'jadx-samples' 7 | include 'jadx-test-app' 8 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/attributes/IAttribute.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.attributes; 2 | 3 | public interface IAttribute { 4 | 5 | AType getType(); 6 | 7 | } 8 | -------------------------------------------------------------------------------- /jadx-gui/src/main/resources/icons-16/empty_logical_package_obj.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-gui/src/main/resources/icons-16/empty_logical_package_obj.png -------------------------------------------------------------------------------- /jadx-gui/src/main/resources/icons-16/innerclass_protected_obj.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/jadx/master/jadx-gui/src/main/resources/icons-16/innerclass_protected_obj.png -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/nodes/IDexNode.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.nodes; 2 | 3 | public interface IDexNode { 4 | 5 | DexNode dex(); 6 | 7 | RootNode root(); 8 | } 9 | 10 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/instructions/args/Named.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.instructions.args; 2 | 3 | public interface Named { 4 | 5 | String getName(); 6 | 7 | void setName(String name); 8 | } 9 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/nodes/ProcessState.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.nodes; 2 | 3 | public enum ProcessState { 4 | NOT_LOADED, 5 | STARTED, 6 | PROCESSED, 7 | GENERATED, 8 | UNLOADED 9 | } 10 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/instructions/InvokeType.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.instructions; 2 | 3 | public enum InvokeType { 4 | STATIC, 5 | DIRECT, 6 | VIRTUAL, 7 | INTERFACE, 8 | SUPER, 9 | } 10 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/nodes/IBlock.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.nodes; 2 | 3 | import java.util.List; 4 | 5 | public interface IBlock extends IContainer { 6 | 7 | List getInstructions(); 8 | } 9 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.7-bin.zip 6 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/api/JadxInternalAccess.java: -------------------------------------------------------------------------------- 1 | package jadx.api; 2 | 3 | import jadx.core.dex.nodes.RootNode; 4 | 5 | public class JadxInternalAccess { 6 | 7 | public static RootNode getRoot(JadxDecompiler d) { 8 | return d.getRoot(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/api/JavaNode.java: -------------------------------------------------------------------------------- 1 | package jadx.api; 2 | 3 | public interface JavaNode { 4 | 5 | String getName(); 6 | 7 | String getFullName(); 8 | 9 | JavaClass getDeclaringClass(); 10 | 11 | JavaClass getTopParentClass(); 12 | 13 | int getDecompiledLine(); 14 | } 15 | -------------------------------------------------------------------------------- /jadx-core/src/test/smali/TestArithConst.smali: -------------------------------------------------------------------------------- 1 | .class public LTestArithConst; 2 | .super Ljava/lang/Object; 3 | 4 | .field public static final CONST_INT:I = 0xff 5 | 6 | .method private test(I)I 7 | .registers 2 8 | 9 | add-int/lit16 v0, p1, 0xff 10 | 11 | return v0 12 | .end method 13 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/nodes/IContainer.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.nodes; 2 | 3 | import jadx.core.dex.attributes.IAttributeNode; 4 | 5 | public interface IContainer extends IAttributeNode { 6 | 7 | /** 8 | * Unique id for use in 'toString()' method 9 | */ 10 | String baseString(); 11 | } 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Eclipse files 2 | .classpath 3 | .project 4 | .settings/ 5 | 6 | # IntelliJ Idea files 7 | .idea/ 8 | out/ 9 | *.iml 10 | *.ipr 11 | *.iws 12 | 13 | bin/ 14 | target/ 15 | build/ 16 | idea/ 17 | .gradle/ 18 | gradle.properties 19 | 20 | *-tmp/ 21 | 22 | *.dex 23 | *.class 24 | *.dump 25 | *.log 26 | *.cfg 27 | 28 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/nodes/IRegion.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.nodes; 2 | 3 | import java.util.List; 4 | 5 | public interface IRegion extends IContainer { 6 | 7 | IRegion getParent(); 8 | 9 | List getSubBlocks(); 10 | 11 | boolean replaceSubBlock(IContainer oldBlock, IContainer newBlock); 12 | } 13 | -------------------------------------------------------------------------------- /jadx-samples/src/main/java/jadx/samples/TestDeadCode.java: -------------------------------------------------------------------------------- 1 | package jadx.samples; 2 | 3 | public class TestDeadCode extends AbstractTest { 4 | 5 | private void test1(int i) { 6 | if (i == 0) { 7 | return; 8 | } 9 | return; 10 | } 11 | 12 | @Override 13 | public boolean testRun() throws Exception { 14 | return true; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/utils/exceptions/JadxOverflowException.java: -------------------------------------------------------------------------------- 1 | package jadx.core.utils.exceptions; 2 | 3 | public class JadxOverflowException extends JadxRuntimeException { 4 | 5 | private static final long serialVersionUID = 2568659798680154204L; 6 | 7 | public JadxOverflowException(String message) { 8 | super(message); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/nodes/IBranchRegion.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.nodes; 2 | 3 | import java.util.List; 4 | 5 | public interface IBranchRegion extends IRegion { 6 | 7 | /** 8 | * Return list of branches in this region. 9 | * NOTE: Contains 'null' elements for indicate empty branches. 10 | */ 11 | List getBranches(); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /jadx-core/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | %d{HH:mm:ss} %-5level - %msg%n 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/instructions/args/VarName.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.instructions.args; 2 | 3 | public class VarName { 4 | private String name; 5 | 6 | public String getName() { 7 | return name; 8 | } 9 | 10 | public void setName(String name) { 11 | this.name = name; 12 | } 13 | 14 | @Override 15 | public String toString() { 16 | return name; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/nodes/ILoadable.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.nodes; 2 | 3 | import jadx.core.utils.exceptions.DecodeException; 4 | 5 | public interface ILoadable { 6 | 7 | /** 8 | * On demand loading 9 | * 10 | * @throws DecodeException 11 | */ 12 | void load() throws DecodeException; 13 | 14 | /** 15 | * Free resources 16 | */ 17 | void unload(); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/visitors/regions/IRegionIterativeVisitor.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.visitors.regions; 2 | 3 | import jadx.core.dex.nodes.IRegion; 4 | import jadx.core.dex.nodes.MethodNode; 5 | 6 | public interface IRegionIterativeVisitor { 7 | 8 | /** 9 | * If return 'true' traversal will be restarted. 10 | */ 11 | boolean visitRegion(MethodNode mth, IRegion region); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/smali/TestN21.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.smali; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.SmaliTest; 5 | 6 | import org.junit.Test; 7 | 8 | public class TestN21 extends SmaliTest { 9 | 10 | @Test 11 | public void test() { 12 | ClassNode cls = getClassNodeFromSmali("TestN21"); 13 | String code = cls.getCode().toString(); 14 | System.out.println(code); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /jadx-test-app/README.md: -------------------------------------------------------------------------------- 1 | ### Run jadx on test android application 2 | 3 | This module contains build scripts for test recompilation of simple android app from: 4 | https://github.com/skylot/jadx-test-app 5 | 6 | For run tests type follow commands in jadx root directory: 7 | 8 | ```java 9 | git submodule init 10 | git submodule update 11 | ./gradlew testAppCheck 12 | ``` 13 | 14 | Note: You will need connected device or emulator for success 15 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/utils/exceptions/JadxRuntimeException.java: -------------------------------------------------------------------------------- 1 | package jadx.core.utils.exceptions; 2 | 3 | public class JadxRuntimeException extends RuntimeException { 4 | 5 | private static final long serialVersionUID = -7410848445429898248L; 6 | 7 | public JadxRuntimeException(String message) { 8 | super(message); 9 | } 10 | 11 | public JadxRuntimeException(String message, Throwable cause) { 12 | super(message, cause); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /jadx-gui/src/test/java/jadx/api/Factory.java: -------------------------------------------------------------------------------- 1 | package jadx.api; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | 5 | import java.util.List; 6 | 7 | public class Factory { 8 | 9 | public static JavaPackage newPackage(String name, List classes) { 10 | return new JavaPackage(name, classes); 11 | } 12 | 13 | public static JavaClass newClass(JadxDecompiler decompiler, ClassNode classNode) { 14 | return new JavaClass(classNode, decompiler); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /jadx-cli/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'application' 2 | 3 | mainClassName = 'jadx.cli.JadxCLI' 4 | applicationName = 'jadx' 5 | 6 | dependencies { 7 | compile(project(':jadx-core')) 8 | compile 'com.beust:jcommander:1.47' 9 | compile 'ch.qos.logback:logback-classic:1.1.2' 10 | } 11 | 12 | applicationDistribution.with { 13 | into('') { 14 | from '../.' 15 | include 'README.md' 16 | include 'NOTICE' 17 | include 'LICENSE' 18 | } 19 | } 20 | 21 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/instructions/ArithOp.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.instructions; 2 | 3 | public enum ArithOp { 4 | ADD("+"), 5 | SUB("-"), 6 | MUL("*"), 7 | DIV("/"), 8 | REM("%"), 9 | 10 | AND("&"), 11 | OR("|"), 12 | XOR("^"), 13 | 14 | SHL("<<"), 15 | SHR(">>"), 16 | USHR(">>>"); 17 | 18 | private final String symbol; 19 | 20 | ArithOp(String symbol) { 21 | this.symbol = symbol; 22 | } 23 | 24 | public String getSymbol() { 25 | return this.symbol; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /jadx-cli/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | INFO 6 | 7 | 8 | %d{HH:mm:ss} %-5level - %msg%n 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /jadx-samples/src/main/java/jadx/samples/TestImports.java: -------------------------------------------------------------------------------- 1 | package jadx.samples; 2 | 3 | import jadx.samples.otherpkg.A; 4 | 5 | /** 6 | * Tests: 7 | * - class B not imported 8 | */ 9 | public class TestImports extends AbstractTest { 10 | 11 | public class C extends A { 12 | public B getB() { 13 | return null; 14 | } 15 | } 16 | 17 | @Override 18 | public boolean testRun() { 19 | return true; 20 | } 21 | 22 | public static void main(String[] args) { 23 | new TestImports().testRun(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/nodes/ResRefField.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.nodes; 2 | 3 | import jadx.core.dex.info.FieldInfo; 4 | import jadx.core.dex.instructions.args.ArgType; 5 | 6 | import com.android.dx.rop.code.AccessFlags; 7 | 8 | public class ResRefField extends FieldNode { 9 | 10 | public ResRefField(DexNode dex, String str) { 11 | super(dex.root().getAppResClass(), 12 | FieldInfo.from(dex, dex.root().getAppResClass().getClassInfo(), str, ArgType.INT), 13 | AccessFlags.ACC_PUBLIC); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /jadx-gui/src/main/java/jadx/gui/utils/NLS.java: -------------------------------------------------------------------------------- 1 | package jadx.gui.utils; 2 | 3 | import java.util.Locale; 4 | import java.util.ResourceBundle; 5 | 6 | public class NLS { 7 | 8 | private static ResourceBundle messages; 9 | 10 | static { 11 | load(new Locale("en", "US")); 12 | } 13 | 14 | private NLS() { 15 | } 16 | 17 | private static void load(Locale locale) { 18 | messages = ResourceBundle.getBundle("i18n/Messages", locale); 19 | } 20 | 21 | public static String str(String key) { 22 | return messages.getString(key); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/api/ResourceFileContent.java: -------------------------------------------------------------------------------- 1 | package jadx.api; 2 | 3 | import jadx.core.codegen.CodeWriter; 4 | import jadx.core.xmlgen.ResContainer; 5 | 6 | public class ResourceFileContent extends ResourceFile { 7 | 8 | private final CodeWriter content; 9 | 10 | public ResourceFileContent(String name, ResourceType type, CodeWriter content) { 11 | super(null, name, type); 12 | this.content = content; 13 | } 14 | 15 | @Override 16 | public ResContainer loadContent() { 17 | return ResContainer.singleFile(getName(), content); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/visitors/regions/IRegionVisitor.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.visitors.regions; 2 | 3 | import jadx.core.dex.nodes.IBlock; 4 | import jadx.core.dex.nodes.IRegion; 5 | import jadx.core.dex.nodes.MethodNode; 6 | 7 | public interface IRegionVisitor { 8 | 9 | void processBlock(MethodNode mth, IBlock container); 10 | 11 | /** 12 | * @return true for traverse sub-blocks, false otherwise. 13 | */ 14 | boolean enterRegion(MethodNode mth, IRegion region); 15 | 16 | void leaveRegion(MethodNode mth, IRegion region); 17 | 18 | } 19 | -------------------------------------------------------------------------------- /jadx-gui/src/main/java/jadx/gui/utils/search/SearchIndex.java: -------------------------------------------------------------------------------- 1 | package jadx.gui.utils.search; 2 | 3 | import java.util.List; 4 | 5 | public abstract class SearchIndex { 6 | 7 | public abstract void put(String str, V value); 8 | 9 | public void put(StringRef str, V value) { 10 | throw new UnsupportedOperationException("StringRef put not supported"); 11 | } 12 | 13 | public boolean isStringRefSupported() { 14 | return false; 15 | } 16 | 17 | public abstract List getValuesForKeysContaining(String str); 18 | 19 | public abstract int size(); 20 | } 21 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/regions/loops/ForLoop.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.regions.loops; 2 | 3 | import jadx.core.dex.nodes.InsnNode; 4 | 5 | public final class ForLoop extends LoopType { 6 | 7 | private final InsnNode initInsn; 8 | private final InsnNode incrInsn; 9 | 10 | public ForLoop(InsnNode initInsn, InsnNode incrInsn) { 11 | this.initInsn = initInsn; 12 | this.incrInsn = incrInsn; 13 | } 14 | 15 | public InsnNode getInitInsn() { 16 | return initInsn; 17 | } 18 | 19 | public InsnNode getIncrInsn() { 20 | return incrInsn; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /jadx-gui/src/main/java/jadx/gui/ui/ContentPanel.java: -------------------------------------------------------------------------------- 1 | package jadx.gui.ui; 2 | 3 | import jadx.gui.treemodel.JNode; 4 | 5 | import javax.swing.JPanel; 6 | 7 | abstract class ContentPanel extends JPanel { 8 | 9 | protected final TabbedPane tabbedPane; 10 | protected final JNode node; 11 | 12 | ContentPanel(TabbedPane panel, JNode jnode) { 13 | tabbedPane = panel; 14 | node = jnode; 15 | } 16 | 17 | public abstract void loadSettings(); 18 | 19 | TabbedPane getTabbedPane() { 20 | return tabbedPane; 21 | } 22 | 23 | JNode getNode() { 24 | return node; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | jdk: 3 | - oraclejdk8 4 | - oraclejdk7 5 | - openjdk6 6 | 7 | before_install: 8 | - chmod +x gradlew 9 | 10 | script: 11 | - TERM=dumb ./gradlew clean build dist 12 | 13 | after_success: 14 | - TERM=dumb ./gradlew jacocoTestReport coveralls 15 | 16 | sudo: false 17 | 18 | cache: 19 | directories: 20 | - $HOME/.gradle/caches/ 21 | - $HOME/.gradle/wrapper/ 22 | 23 | before_cache: 24 | - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock 25 | 26 | notifications: 27 | email: 28 | - skylot@gmail.com 29 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/xmlgen/entry/RawValue.java: -------------------------------------------------------------------------------- 1 | package jadx.core.xmlgen.entry; 2 | 3 | public final class RawValue { 4 | private final int dataType; 5 | private final int data; 6 | 7 | public RawValue(int dataType, int data) { 8 | this.dataType = dataType; 9 | this.data = data; 10 | } 11 | 12 | public int getDataType() { 13 | return dataType; 14 | } 15 | 16 | public int getData() { 17 | return data; 18 | } 19 | 20 | @Override 21 | public String toString() { 22 | return "RawValue: type=0x" + Integer.toHexString(dataType) + ", value=" + data; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /jadx-core/src/test/smali/TestConstructor.smali: -------------------------------------------------------------------------------- 1 | .class public LTestConstructor; 2 | .super Ljava/lang/Object; 3 | 4 | .method private test(DDLSomeObject;)LSomeObject; 5 | .locals 22 6 | .param p1, "arg1" # D 7 | .param p3, "arg2" # D 8 | .param p5, "arg3" # LSomeObject; 9 | 10 | .prologue 11 | .line 54 12 | 13 | new-instance v17, LSomeObject; 14 | 15 | move-object/from16 v0, v17 16 | 17 | move-object/from16 v1, p5 18 | 19 | invoke-direct {v0, v1}, LSomeObject;->(LSomeObject;)V 20 | 21 | .line 59 22 | .local v17, "localSomeObject":LSomeObject; 23 | .end method 24 | -------------------------------------------------------------------------------- /jadx-samples/src/main/java/jadx/samples/TestStringProcessing.java: -------------------------------------------------------------------------------- 1 | package jadx.samples; 2 | 3 | public class TestStringProcessing extends AbstractTest { 4 | 5 | public void testStringEscape() { 6 | String str = "test\tstr\n"; 7 | assertTrue(str.length() == 9); 8 | 9 | str = "test\bunicode\u1234"; 10 | assertTrue(str.charAt(4) == '\b'); 11 | } 12 | 13 | public void testStringConcat() { 14 | String s = "1"; 15 | assertEquals("a" + s, "a1"); 16 | } 17 | 18 | @Override 19 | public boolean testRun() throws Exception { 20 | testStringEscape(); 21 | testStringConcat(); 22 | return true; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/deobf/OverridedMethodsNode.java: -------------------------------------------------------------------------------- 1 | package jadx.core.deobf; 2 | 3 | import jadx.core.dex.info.MethodInfo; 4 | 5 | import java.util.Set; 6 | 7 | /* package */ class OverridedMethodsNode { 8 | 9 | private Set methods; 10 | 11 | public OverridedMethodsNode(Set methodsSet) { 12 | methods = methodsSet; 13 | } 14 | 15 | public boolean contains(MethodInfo mth) { 16 | return methods.contains(mth); 17 | } 18 | 19 | public void add(MethodInfo mth) { 20 | methods.add(mth); 21 | } 22 | 23 | public Set getMethods() { 24 | return methods; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/xmlgen/entry/RawNamedValue.java: -------------------------------------------------------------------------------- 1 | package jadx.core.xmlgen.entry; 2 | 3 | public class RawNamedValue { 4 | private final int nameRef; 5 | private final RawValue rawValue; 6 | 7 | public RawNamedValue(int nameRef, RawValue rawValue) { 8 | this.nameRef = nameRef; 9 | this.rawValue = rawValue; 10 | } 11 | 12 | public int getNameRef() { 13 | return nameRef; 14 | } 15 | 16 | public RawValue getRawValue() { 17 | return rawValue; 18 | } 19 | 20 | @Override 21 | public String toString() { 22 | return "RawNamedValue{nameRef=" + nameRef + ", rawValue=" + rawValue + '}'; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/smali/TestArithConst.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.smali; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.SmaliTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static jadx.tests.api.utils.JadxMatchers.containsOne; 9 | import static org.junit.Assert.assertThat; 10 | 11 | public class TestArithConst extends SmaliTest { 12 | 13 | @Test 14 | public void test() { 15 | noDebugInfo(); 16 | ClassNode cls = getClassNodeFromSmali("TestArithConst"); 17 | String code = cls.getCode().toString(); 18 | 19 | assertThat(code, containsOne("return i + CONST_INT;")); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/visitors/regions/AbstractRegionVisitor.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.visitors.regions; 2 | 3 | import jadx.core.dex.nodes.IBlock; 4 | import jadx.core.dex.nodes.IRegion; 5 | import jadx.core.dex.nodes.MethodNode; 6 | 7 | public abstract class AbstractRegionVisitor implements IRegionVisitor { 8 | 9 | @Override 10 | public boolean enterRegion(MethodNode mth, IRegion region) { 11 | return true; 12 | } 13 | 14 | @Override 15 | public void processBlock(MethodNode mth, IBlock container) { 16 | } 17 | 18 | @Override 19 | public void leaveRegion(MethodNode mth, IRegion region) { 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/smali/TestInlineVarArg.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.smali; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.SmaliTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static jadx.tests.api.utils.JadxMatchers.containsOne; 9 | import static org.junit.Assert.assertThat; 10 | 11 | public class TestInlineVarArg extends SmaliTest { 12 | 13 | @Test 14 | public void test() { 15 | noDebugInfo(); 16 | ClassNode cls = getClassNodeFromSmali("TestInlineVarArg"); 17 | String code = cls.getCode().toString(); 18 | 19 | assertThat(code, containsOne("f(\"a\", \"b\", \"c\");")); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/visitors/AbstractVisitor.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.visitors; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.core.dex.nodes.MethodNode; 5 | import jadx.core.dex.nodes.RootNode; 6 | import jadx.core.utils.exceptions.JadxException; 7 | 8 | public class AbstractVisitor implements IDexTreeVisitor { 9 | 10 | @Override 11 | public void init(RootNode root) throws JadxException { 12 | } 13 | 14 | @Override 15 | public boolean visit(ClassNode cls) throws JadxException { 16 | return true; 17 | } 18 | 19 | @Override 20 | public void visit(MethodNode mth) throws JadxException { 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/regions/loops/ForEachLoop.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.regions.loops; 2 | 3 | import jadx.core.dex.instructions.args.InsnArg; 4 | import jadx.core.dex.instructions.args.RegisterArg; 5 | 6 | public final class ForEachLoop extends LoopType { 7 | private final RegisterArg varArg; 8 | private final InsnArg iterableArg; 9 | 10 | public ForEachLoop(RegisterArg varArg, InsnArg iterableArg) { 11 | this.varArg = varArg; 12 | this.iterableArg = iterableArg; 13 | } 14 | 15 | public RegisterArg getVarArg() { 16 | return varArg; 17 | } 18 | 19 | public InsnArg getIterableArg() { 20 | return iterableArg; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/attributes/nodes/LoopLabelAttr.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.attributes.nodes; 2 | 3 | import jadx.core.dex.attributes.AType; 4 | import jadx.core.dex.attributes.IAttribute; 5 | 6 | public class LoopLabelAttr implements IAttribute { 7 | 8 | private final LoopInfo loop; 9 | 10 | public LoopLabelAttr(LoopInfo loop) { 11 | this.loop = loop; 12 | } 13 | 14 | public LoopInfo getLoop() { 15 | return loop; 16 | } 17 | 18 | @Override 19 | public AType getType() { 20 | return AType.LOOP_LABEL; 21 | } 22 | 23 | @Override 24 | public String toString() { 25 | return "LOOP_LABEL: " + loop; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/api/compiler/CharSequenceJavaFileObject.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.api.compiler; 2 | 3 | import javax.tools.SimpleJavaFileObject; 4 | import java.net.URI; 5 | 6 | public class CharSequenceJavaFileObject extends SimpleJavaFileObject { 7 | 8 | private CharSequence content; 9 | 10 | public CharSequenceJavaFileObject(String className, CharSequence content) { 11 | super(URI.create("string:///" + className.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE); 12 | this.content = content; 13 | } 14 | 15 | @Override 16 | public CharSequence getCharContent(boolean ignoreEncodingErrors) { 17 | return content; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/trycatch/CatchAttr.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.trycatch; 2 | 3 | import jadx.core.dex.attributes.AType; 4 | import jadx.core.dex.attributes.IAttribute; 5 | 6 | public class CatchAttr implements IAttribute { 7 | 8 | private final TryCatchBlock tryBlock; 9 | 10 | public CatchAttr(TryCatchBlock block) { 11 | this.tryBlock = block; 12 | } 13 | 14 | @Override 15 | public AType getType() { 16 | return AType.CATCH_BLOCK; 17 | } 18 | 19 | public TryCatchBlock getTryBlock() { 20 | return tryBlock; 21 | } 22 | 23 | @Override 24 | public String toString() { 25 | return tryBlock.toString(); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /jadx-gui/src/main/java/jadx/gui/jobs/DecompileJob.java: -------------------------------------------------------------------------------- 1 | package jadx.gui.jobs; 2 | 3 | import jadx.api.JavaClass; 4 | import jadx.gui.JadxWrapper; 5 | 6 | public class DecompileJob extends BackgroundJob { 7 | 8 | public DecompileJob(JadxWrapper wrapper, int threadsCount) { 9 | super(wrapper, threadsCount); 10 | } 11 | 12 | protected void runJob() { 13 | for (final JavaClass cls : wrapper.getClasses()) { 14 | addTask(new Runnable() { 15 | @Override 16 | public void run() { 17 | cls.decompile(); 18 | } 19 | }); 20 | } 21 | } 22 | 23 | @Override 24 | public String getInfoString() { 25 | return "Decompiling: "; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /jadx-gui/src/main/java/jadx/gui/treemodel/TextNode.java: -------------------------------------------------------------------------------- 1 | package jadx.gui.treemodel; 2 | 3 | import javax.swing.Icon; 4 | 5 | public class TextNode extends JNode { 6 | 7 | private static final long serialVersionUID = 2342749142368352232L; 8 | 9 | private final String label; 10 | 11 | public TextNode(String str) { 12 | this.label = str; 13 | } 14 | 15 | @Override 16 | public JClass getJParent() { 17 | return null; 18 | } 19 | 20 | @Override 21 | public int getLine() { 22 | return 0; 23 | } 24 | 25 | @Override 26 | public Icon getIcon() { 27 | return null; 28 | } 29 | 30 | @Override 31 | public String makeString() { 32 | return label; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /jadx-cli/src/test/java/jadx/cli/JadxCLIArgsTest.java: -------------------------------------------------------------------------------- 1 | package jadx.cli; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.hamcrest.Matchers.is; 6 | import static org.junit.Assert.assertThat; 7 | 8 | public class JadxCLIArgsTest { 9 | 10 | @Test 11 | public void testInvertedBooleanOption() throws Exception { 12 | assertThat(parse("--no-replace-consts").isReplaceConsts(), is(false)); 13 | assertThat(parse("").isReplaceConsts(), is(true)); 14 | } 15 | 16 | private JadxCLIArgs parse(String... args) { 17 | JadxCLIArgs jadxArgs = new JadxCLIArgs(); 18 | boolean res = jadxArgs.processArgs(args); 19 | assertThat(res, is(true)); 20 | return jadxArgs; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/attributes/nodes/SourceFileAttr.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.attributes.nodes; 2 | 3 | import jadx.core.dex.attributes.AType; 4 | import jadx.core.dex.attributes.IAttribute; 5 | 6 | public class SourceFileAttr implements IAttribute { 7 | 8 | private final String fileName; 9 | 10 | public SourceFileAttr(String fileName) { 11 | this.fileName = fileName; 12 | } 13 | 14 | public String getFileName() { 15 | return fileName; 16 | } 17 | 18 | @Override 19 | public AType getType() { 20 | return AType.SOURCE_FILE; 21 | } 22 | 23 | @Override 24 | public String toString() { 25 | return "SOURCE:" + fileName; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/instructions/GotoNode.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.instructions; 2 | 3 | import jadx.core.dex.nodes.InsnNode; 4 | import jadx.core.utils.InsnUtils; 5 | 6 | public class GotoNode extends InsnNode { 7 | 8 | protected int target; 9 | 10 | public GotoNode(int target) { 11 | this(InsnType.GOTO, target, 0); 12 | } 13 | 14 | protected GotoNode(InsnType type, int target, int argsCount) { 15 | super(type, argsCount); 16 | this.target = target; 17 | } 18 | 19 | public int getTarget() { 20 | return target; 21 | } 22 | 23 | @Override 24 | public String toString() { 25 | return super.toString() + "-> " + InsnUtils.formatOffset(target); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/nodes/InsnContainer.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.nodes; 2 | 3 | import jadx.core.dex.attributes.AttrNode; 4 | 5 | import java.util.List; 6 | 7 | public class InsnContainer extends AttrNode implements IBlock { 8 | 9 | private final List insns; 10 | 11 | public InsnContainer(List insns) { 12 | this.insns = insns; 13 | } 14 | 15 | @Override 16 | public List getInstructions() { 17 | return insns; 18 | } 19 | 20 | @Override 21 | public String baseString() { 22 | return Integer.toString(insns.size()); 23 | } 24 | 25 | @Override 26 | public String toString() { 27 | return "InsnContainer:" + insns.size(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/utils/exceptions/DecodeException.java: -------------------------------------------------------------------------------- 1 | package jadx.core.utils.exceptions; 2 | 3 | import jadx.core.dex.nodes.MethodNode; 4 | 5 | public class DecodeException extends JadxException { 6 | 7 | private static final long serialVersionUID = -6611189094923499636L; 8 | 9 | public DecodeException(String message) { 10 | super(message); 11 | } 12 | 13 | public DecodeException(String message, Throwable cause) { 14 | super(message, cause); 15 | } 16 | 17 | public DecodeException(MethodNode mth, String msg) { 18 | super(mth, msg, null); 19 | } 20 | 21 | public DecodeException(MethodNode mth, String msg, Throwable th) { 22 | super(mth, msg, th); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/attributes/AttrList.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.attributes; 2 | 3 | import jadx.core.utils.Utils; 4 | 5 | import java.util.LinkedList; 6 | import java.util.List; 7 | 8 | public class AttrList implements IAttribute { 9 | 10 | private final AType> type; 11 | private final List list = new LinkedList(); 12 | 13 | public AttrList(AType> type) { 14 | this.type = type; 15 | } 16 | 17 | public List getList() { 18 | return list; 19 | } 20 | 21 | @Override 22 | public AType> getType() { 23 | return type; 24 | } 25 | 26 | @Override 27 | public String toString() { 28 | return Utils.listToString(list); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/codegen/CodeGen.java: -------------------------------------------------------------------------------- 1 | package jadx.core.codegen; 2 | 3 | import jadx.api.IJadxArgs; 4 | import jadx.core.dex.nodes.ClassNode; 5 | import jadx.core.dex.visitors.AbstractVisitor; 6 | import jadx.core.utils.exceptions.CodegenException; 7 | 8 | public class CodeGen extends AbstractVisitor { 9 | 10 | private final IJadxArgs args; 11 | 12 | public CodeGen(IJadxArgs args) { 13 | this.args = args; 14 | } 15 | 16 | @Override 17 | public boolean visit(ClassNode cls) throws CodegenException { 18 | ClassGen clsGen = new ClassGen(cls, args); 19 | CodeWriter clsCode = clsGen.makeClass(); 20 | clsCode.finish(); 21 | cls.setCode(clsCode); 22 | return false; 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/attributes/nodes/MethodInlineAttr.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.attributes.nodes; 2 | 3 | import jadx.core.dex.attributes.AType; 4 | import jadx.core.dex.attributes.IAttribute; 5 | import jadx.core.dex.nodes.InsnNode; 6 | 7 | public class MethodInlineAttr implements IAttribute { 8 | 9 | private final InsnNode insn; 10 | 11 | public MethodInlineAttr(InsnNode insn) { 12 | this.insn = insn; 13 | } 14 | 15 | public InsnNode getInsn() { 16 | return insn; 17 | } 18 | 19 | @Override 20 | public AType getType() { 21 | return AType.METHOD_INLINE; 22 | } 23 | 24 | @Override 25 | public String toString() { 26 | return "INLINE: " + insn; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/trycatch/SplitterBlockAttr.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.trycatch; 2 | 3 | import jadx.core.dex.attributes.AType; 4 | import jadx.core.dex.attributes.IAttribute; 5 | import jadx.core.dex.nodes.BlockNode; 6 | 7 | public class SplitterBlockAttr implements IAttribute { 8 | 9 | private final BlockNode block; 10 | 11 | public SplitterBlockAttr(BlockNode block) { 12 | this.block = block; 13 | } 14 | 15 | public BlockNode getBlock() { 16 | return block; 17 | } 18 | 19 | @Override 20 | public AType getType() { 21 | return AType.SPLITTER_BLOCK; 22 | } 23 | 24 | @Override 25 | public String toString() { 26 | return "Splitter: " + block; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/api/utils/TestUtils.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.api.utils; 2 | 3 | import jadx.core.codegen.CodeWriter; 4 | 5 | public class TestUtils { 6 | 7 | public static String indent(int indent) { 8 | if (indent == 1) { 9 | return CodeWriter.INDENT; 10 | } 11 | StringBuilder sb = new StringBuilder(indent * CodeWriter.INDENT.length()); 12 | for (int i = 0; i < indent; i++) { 13 | sb.append(CodeWriter.INDENT); 14 | } 15 | return sb.toString(); 16 | } 17 | 18 | public static int count(String string, String substring) { 19 | int count = 0; 20 | int idx = 0; 21 | while ((idx = string.indexOf(substring, idx)) != -1) { 22 | idx++; 23 | count++; 24 | } 25 | return count; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/utils/AsmUtils.java: -------------------------------------------------------------------------------- 1 | package jadx.core.utils; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.IOException; 6 | 7 | import org.objectweb.asm.ClassReader; 8 | 9 | import static jadx.core.utils.files.FileUtils.close; 10 | 11 | public class AsmUtils { 12 | 13 | private AsmUtils() { 14 | } 15 | 16 | public static String getNameFromClassFile(File file) throws IOException { 17 | String className = null; 18 | FileInputStream in = null; 19 | try { 20 | in = new FileInputStream(file); 21 | ClassReader classReader = new ClassReader(in); 22 | className = classReader.getClassName(); 23 | } finally { 24 | close(in); 25 | } 26 | return className; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/attributes/AFlag.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.attributes; 2 | 3 | public enum AFlag { 4 | TRY_ENTER, 5 | TRY_LEAVE, 6 | 7 | LOOP_START, 8 | LOOP_END, 9 | 10 | SYNTHETIC, 11 | FINAL, // SSAVar attribute for make var final 12 | 13 | RETURN, // block contains only return instruction 14 | ORIG_RETURN, 15 | 16 | DECLARE_VAR, 17 | DONT_WRAP, 18 | 19 | DONT_SHRINK, 20 | DONT_INLINE, 21 | DONT_GENERATE, 22 | SKIP, 23 | REMOVE, 24 | 25 | SKIP_FIRST_ARG, 26 | SKIP_ARG, // skip argument in invoke call 27 | ANONYMOUS_CONSTRUCTOR, 28 | ANONYMOUS_CLASS, 29 | 30 | ELSE_IF_CHAIN, 31 | 32 | WRAPPED, 33 | ARITH_ONEARG, 34 | 35 | FALL_THROUGH, 36 | 37 | INCONSISTENT_CODE, // warning about incorrect decompilation 38 | } 39 | -------------------------------------------------------------------------------- /jadx-core/build.gradle: -------------------------------------------------------------------------------- 1 | ext.jadxClasspath = 'clsp-data/android-5.1.jar' 2 | 3 | apply plugin: "info.solidsoft.pitest" 4 | 5 | dependencies { 6 | runtime files(jadxClasspath) 7 | 8 | compile files('lib/dx-1.10.jar') 9 | compile 'commons-io:commons-io:2.4' 10 | compile 'org.ow2.asm:asm:5.0.3' 11 | compile 'com.intellij:annotations:12.0' 12 | compile 'uk.com.robust-it:cloning:1.9.2' 13 | 14 | testCompile 'org.smali:smali:2.0.3' 15 | } 16 | 17 | task packTests(type: Jar) { 18 | classifier = 'tests' 19 | from sourceSets.test.output 20 | } 21 | 22 | pitest { 23 | excludedMethods = ['toString'] 24 | threads = 4 25 | enableDefaultIncrementalAnalysis = true 26 | outputFormats = ['XML', 'HTML'] 27 | jvmArgs = ['-Xmx12G'] 28 | } 29 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/utils/files/DexFile.java: -------------------------------------------------------------------------------- 1 | package jadx.core.utils.files; 2 | 3 | import com.android.dex.Dex; 4 | 5 | public class DexFile { 6 | private final InputFile inputFile; 7 | private final String name; 8 | private final Dex dexBuf; 9 | 10 | public DexFile(InputFile inputFile, String name, Dex dexBuf) { 11 | this.inputFile = inputFile; 12 | this.name = name; 13 | this.dexBuf = dexBuf; 14 | } 15 | 16 | public String getName() { 17 | return name; 18 | } 19 | 20 | public Dex getDexBuf() { 21 | return dexBuf; 22 | } 23 | 24 | public InputFile getInputFile() { 25 | return inputFile; 26 | } 27 | 28 | @Override 29 | public String toString() { 30 | return inputFile.toString() + (name.isEmpty() ? "" : ":" + name); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /jadx-gui/src/main/java/jadx/gui/ui/ImagePanel.java: -------------------------------------------------------------------------------- 1 | package jadx.gui.ui; 2 | 3 | import hu.kazocsaba.imageviewer.ImageViewer; 4 | import jadx.api.ResourceFile; 5 | import jadx.gui.treemodel.JResource; 6 | 7 | import java.awt.BorderLayout; 8 | import java.awt.image.BufferedImage; 9 | 10 | public class ImagePanel extends ContentPanel { 11 | 12 | ImagePanel(TabbedPane panel, JResource res) { 13 | super(panel, res); 14 | 15 | ResourceFile resFile = res.getResFile(); 16 | BufferedImage img = resFile.loadContent().getImage(); 17 | ImageViewer imageViewer = new ImageViewer(img); 18 | imageViewer.setZoomFactor(2.); 19 | 20 | setLayout(new BorderLayout()); 21 | add(imageViewer.getComponent()); 22 | } 23 | 24 | @Override 25 | public void loadSettings() { 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /jadx-samples/src/main/java/jadx/samples/TestInnerNames.java: -------------------------------------------------------------------------------- 1 | package jadx.samples; 2 | 3 | public class TestInnerNames extends AbstractTest { 4 | 5 | public int D; 6 | 7 | public class A extends TestInner.MyThread { 8 | public A(String name) { 9 | super(name); 10 | } 11 | } 12 | 13 | public class B extends A { 14 | public B(String name) { 15 | super(name); 16 | } 17 | 18 | public class C extends TestInner2.B { 19 | } 20 | } 21 | 22 | public class C extends TestInner2.B { 23 | } 24 | 25 | public class D extends TestInner2.D { 26 | } 27 | 28 | @Override 29 | public boolean testRun() throws Exception { 30 | return true; 31 | } 32 | 33 | public static void main(String[] args) throws Exception { 34 | new TestInnerNames().testRun(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/api/compiler/JavaClassObject.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.api.compiler; 2 | 3 | import javax.tools.SimpleJavaFileObject; 4 | import java.io.ByteArrayOutputStream; 5 | import java.io.IOException; 6 | import java.io.OutputStream; 7 | import java.net.URI; 8 | 9 | public class JavaClassObject extends SimpleJavaFileObject { 10 | 11 | protected final ByteArrayOutputStream bos = new ByteArrayOutputStream(); 12 | 13 | public JavaClassObject(String name, Kind kind) { 14 | super(URI.create("string:///" + name.replace('.', '/') + kind.extension), kind); 15 | } 16 | 17 | public byte[] getBytes() { 18 | return bos.toByteArray(); 19 | } 20 | 21 | @Override 22 | public OutputStream openOutputStream() throws IOException { 23 | return bos; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/arrays/TestArrayFill.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.arrays; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.hamcrest.CoreMatchers.containsString; 9 | import static org.junit.Assert.assertThat; 10 | 11 | public class TestArrayFill extends IntegrationTest { 12 | 13 | public static class TestCls { 14 | 15 | public String[] method() { 16 | return new String[]{"1", "2", "3"}; 17 | } 18 | } 19 | 20 | @Test 21 | public void test() { 22 | ClassNode cls = getClassNode(TestCls.class); 23 | String code = cls.getCode().toString(); 24 | 25 | assertThat(code, containsString("return new String[]{\"1\", \"2\", \"3\"};")); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /jadx-core/src/main/resources/export/build.gradle.tmpl: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | jcenter() 4 | } 5 | dependencies { 6 | classpath 'com.android.tools.build:gradle:1.5.0' 7 | } 8 | } 9 | apply plugin: 'com.android.application' 10 | 11 | repositories { 12 | mavenCentral() 13 | jcenter() 14 | } 15 | 16 | android { 17 | compileSdkVersion 23 18 | buildToolsVersion '23.0.1' 19 | 20 | defaultConfig { 21 | applicationId '{{applicationId}}' 22 | minSdkVersion {{minSdkVersion}} 23 | targetSdkVersion {{targetSdkVersion}} 24 | versionCode 1 25 | versionName "1.0" 26 | } 27 | 28 | lintOptions { 29 | abortOnError false 30 | } 31 | } 32 | 33 | dependencies { 34 | // some dependencies 35 | } 36 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/functional/TemplateFileTest.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.functional; 2 | 3 | import jadx.core.export.TemplateFile; 4 | 5 | import org.junit.Test; 6 | 7 | import static org.hamcrest.Matchers.containsString; 8 | import static org.junit.Assert.assertThat; 9 | 10 | public class TemplateFileTest { 11 | 12 | @Test 13 | public void testBuildGradle() throws Exception { 14 | TemplateFile tmpl = TemplateFile.fromResources("/export/build.gradle.tmpl"); 15 | tmpl.add("applicationId", "SOME_ID"); 16 | tmpl.add("minSdkVersion", 1); 17 | tmpl.add("targetSdkVersion", 2); 18 | String res = tmpl.build(); 19 | System.out.println(res); 20 | 21 | assertThat(res, containsString("applicationId 'SOME_ID'")); 22 | assertThat(res, containsString("targetSdkVersion 2")); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/smali/TestConstructor.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.smali; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.SmaliTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static jadx.tests.api.utils.JadxMatchers.containsOne; 9 | import static org.hamcrest.CoreMatchers.containsString; 10 | import static org.hamcrest.CoreMatchers.not; 11 | import static org.junit.Assert.assertThat; 12 | 13 | public class TestConstructor extends SmaliTest { 14 | 15 | @Test 16 | public void test() { 17 | disableCompilation(); 18 | ClassNode cls = getClassNodeFromSmali("TestConstructor"); 19 | String code = cls.getCode().toString(); 20 | 21 | assertThat(code, containsOne("new SomeObject(arg3);")); 22 | assertThat(code, not(containsString("= someObject"))); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/TestStaticMethod.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.hamcrest.CoreMatchers.containsString; 9 | import static org.junit.Assert.assertThat; 10 | 11 | public class TestStaticMethod extends IntegrationTest { 12 | 13 | public static class TestCls { 14 | static { 15 | f(); 16 | } 17 | 18 | private static void f() { 19 | } 20 | } 21 | 22 | @Test 23 | public void test() { 24 | ClassNode cls = getClassNode(TestCls.class); 25 | String code = cls.getCode().toString(); 26 | 27 | assertThat(code, containsString("static {")); 28 | assertThat(code, containsString("private static void f() {")); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/attributes/nodes/ForceReturnAttr.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.attributes.nodes; 2 | 3 | import jadx.core.dex.attributes.AType; 4 | import jadx.core.dex.attributes.IAttribute; 5 | import jadx.core.dex.nodes.InsnNode; 6 | import jadx.core.utils.Utils; 7 | 8 | public class ForceReturnAttr implements IAttribute { 9 | 10 | private final InsnNode returnInsn; 11 | 12 | public ForceReturnAttr(InsnNode retInsn) { 13 | this.returnInsn = retInsn; 14 | } 15 | 16 | public InsnNode getReturnInsn() { 17 | return returnInsn; 18 | } 19 | 20 | @Override 21 | public AType getType() { 22 | return AType.FORCE_RETURN; 23 | } 24 | 25 | @Override 26 | public String toString() { 27 | return "FORCE_RETURN " + Utils.listToString(returnInsn.getArguments()); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /jadx-samples/src/main/java/jadx/samples/TestImports2.java: -------------------------------------------------------------------------------- 1 | package jadx.samples; 2 | 3 | import jadx.samples.otherpkg.C.E; 4 | import jadx.samples.otherpkg.D; 5 | 6 | public class TestImports2 extends AbstractTest { 7 | 8 | public Object f1() { 9 | return new E() { 10 | @Override 11 | public String toString() { 12 | return "C.E"; 13 | } 14 | }; 15 | } 16 | 17 | public Object f2() { 18 | return new D.E() { 19 | @Override 20 | public String toString() { 21 | return "D.E"; 22 | } 23 | }; 24 | } 25 | 26 | public static class X1 extends E { 27 | } 28 | 29 | public static class X2 extends D.E { 30 | } 31 | 32 | @Override 33 | public boolean testRun() { 34 | return true; 35 | } 36 | 37 | public static void main(String[] args) { 38 | new TestImports2().testRun(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/arith/TestArith.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.arith; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.hamcrest.CoreMatchers.containsString; 9 | import static org.junit.Assert.assertThat; 10 | 11 | public class TestArith extends IntegrationTest { 12 | 13 | public static class TestCls { 14 | 15 | public void method(int a) { 16 | a += 2; 17 | } 18 | 19 | public void method2(int a) { 20 | a++; 21 | } 22 | } 23 | 24 | @Test 25 | public void test() { 26 | ClassNode cls = getClassNode(TestCls.class); 27 | String code = cls.getCode().toString(); 28 | 29 | assertThat(code, containsString("a += 2;")); 30 | assertThat(code, containsString("a++;")); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/utils/exceptions/JadxException.java: -------------------------------------------------------------------------------- 1 | package jadx.core.utils.exceptions; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.core.dex.nodes.MethodNode; 5 | import jadx.core.utils.ErrorsCounter; 6 | 7 | public class JadxException extends Exception { 8 | 9 | private static final long serialVersionUID = 3577449089978463557L; 10 | 11 | public JadxException(String message) { 12 | super(message); 13 | } 14 | 15 | public JadxException(String message, Throwable cause) { 16 | super(message, cause); 17 | } 18 | 19 | public JadxException(ClassNode cls, String msg, Throwable th) { 20 | super(ErrorsCounter.formatErrorMsg(cls, msg), th); 21 | } 22 | 23 | public JadxException(MethodNode mth, String msg, Throwable th) { 24 | super(ErrorsCounter.formatErrorMsg(mth, msg), th); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/attributes/nodes/LineAttrNode.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.attributes.nodes; 2 | 3 | import jadx.core.dex.attributes.AttrNode; 4 | 5 | public abstract class LineAttrNode extends AttrNode { 6 | 7 | private int sourceLine; 8 | 9 | private int decompiledLine; 10 | 11 | public int getSourceLine() { 12 | return sourceLine; 13 | } 14 | 15 | public void setSourceLine(int sourceLine) { 16 | this.sourceLine = sourceLine; 17 | } 18 | 19 | public int getDecompiledLine() { 20 | return decompiledLine; 21 | } 22 | 23 | public void setDecompiledLine(int decompiledLine) { 24 | this.decompiledLine = decompiledLine; 25 | } 26 | 27 | public void copyLines(LineAttrNode lineAttrNode) { 28 | setSourceLine(lineAttrNode.getSourceLine()); 29 | setDecompiledLine(lineAttrNode.getDecompiledLine()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/instructions/args/Typed.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.instructions.args; 2 | 3 | import jadx.core.dex.attributes.AttrNode; 4 | import jadx.core.dex.nodes.DexNode; 5 | 6 | public abstract class Typed extends AttrNode { 7 | 8 | protected ArgType type; 9 | 10 | public ArgType getType() { 11 | return type; 12 | } 13 | 14 | public void setType(ArgType type) { 15 | this.type = type; 16 | } 17 | 18 | public boolean isTypeImmutable() { 19 | return false; 20 | } 21 | 22 | public boolean merge(DexNode dex, ArgType newType) { 23 | ArgType m = ArgType.merge(dex, type, newType); 24 | if (m != null && !m.equals(type)) { 25 | setType(m); 26 | return true; 27 | } 28 | return false; 29 | } 30 | 31 | public boolean merge(DexNode dex, InsnArg arg) { 32 | return merge(dex, arg.getType()); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/TestRedundantReturn.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.hamcrest.CoreMatchers.containsString; 9 | import static org.hamcrest.CoreMatchers.not; 10 | import static org.junit.Assert.assertThat; 11 | import static org.junit.Assert.fail; 12 | 13 | public class TestRedundantReturn extends IntegrationTest { 14 | 15 | public static class TestCls { 16 | public void test(int num) { 17 | if (num == 4) { 18 | fail(); 19 | } 20 | } 21 | } 22 | 23 | @Test 24 | public void test() { 25 | ClassNode cls = getClassNode(TestCls.class); 26 | String code = cls.getCode().toString(); 27 | 28 | assertThat(code, not(containsString("return;"))); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /jadx-core/src/test/smali/TestInlineVarArg.smali: -------------------------------------------------------------------------------- 1 | .class public LTestInlineVarArg; 2 | .super Ljava/lang/Object; 3 | 4 | .method public static varargs f([Ljava/lang/String;)V 5 | .registers 1 6 | return-void 7 | .end method 8 | 9 | .method public test()V 10 | .registers 5 11 | 12 | const/4 v2, 0x3 13 | 14 | new-array v1, v2, [Ljava/lang/String; 15 | 16 | move-object v0, v1 17 | 18 | const/4 v2, 0x0 19 | 20 | const-string v3, "a" 21 | 22 | aput-object v3, v0, v2 23 | 24 | const/4 v2, 0x1 25 | 26 | const-string v3, "b" 27 | 28 | aput-object v3, v0, v2 29 | 30 | const/4 v2, 0x2 31 | 32 | const-string v3, "c" 33 | 34 | aput-object v3, v0, v2 35 | 36 | move-object v1, v0 37 | 38 | invoke-static {v1}, LTestInlineVarArg;->f([Ljava/lang/String;)V 39 | 40 | return-void 41 | .end method 42 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/arrays/TestArrayFillConstReplace.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.arrays; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static jadx.tests.api.utils.JadxMatchers.containsOne; 9 | import static org.junit.Assert.assertThat; 10 | 11 | public class TestArrayFillConstReplace extends IntegrationTest { 12 | 13 | public static class TestCls { 14 | public static final int CONST_INT = 0xffff; 15 | 16 | public int[] test() { 17 | return new int[]{127, 129, CONST_INT}; 18 | } 19 | } 20 | 21 | @Test 22 | public void test() { 23 | ClassNode cls = getClassNode(TestCls.class); 24 | String code = cls.getCode().toString(); 25 | 26 | assertThat(code, containsOne("return new int[]{127, 129, CONST_INT};")); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/instructions/IfOp.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.instructions; 2 | 3 | import jadx.core.utils.exceptions.JadxRuntimeException; 4 | 5 | public enum IfOp { 6 | EQ("=="), 7 | NE("!="), 8 | LT("<"), 9 | LE("<="), 10 | GT(">"), 11 | GE(">="); 12 | 13 | private final String symbol; 14 | 15 | IfOp(String symbol) { 16 | this.symbol = symbol; 17 | } 18 | 19 | public String getSymbol() { 20 | return symbol; 21 | } 22 | 23 | public IfOp invert() { 24 | switch (this) { 25 | case EQ: 26 | return NE; 27 | case NE: 28 | return EQ; 29 | 30 | case LT: 31 | return GE; 32 | case LE: 33 | return GT; 34 | 35 | case GT: 36 | return LE; 37 | case GE: 38 | return LT; 39 | 40 | default: 41 | throw new JadxRuntimeException("Unknown if operations type: " + this); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/inner/TestInnerClass4.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.inner; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static jadx.tests.api.utils.JadxMatchers.containsOne; 9 | import static org.junit.Assert.assertThat; 10 | 11 | public class TestInnerClass4 extends IntegrationTest { 12 | 13 | public static class TestCls { 14 | public class C { 15 | public String c; 16 | 17 | private C() { 18 | this.c = "c"; 19 | } 20 | } 21 | 22 | private String test() { 23 | return new C().c; 24 | } 25 | } 26 | 27 | @Test 28 | public void test() { 29 | ClassNode cls = getClassNode(TestCls.class); 30 | String code = cls.getCode().toString(); 31 | 32 | assertThat(code, containsOne("return new C().c;")); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/nodes/parser/StaticValuesParser.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.nodes.parser; 2 | 3 | import jadx.core.dex.nodes.DexNode; 4 | import jadx.core.dex.nodes.FieldNode; 5 | import jadx.core.utils.exceptions.DecodeException; 6 | 7 | import java.util.List; 8 | 9 | import com.android.dex.Dex.Section; 10 | import com.android.dex.Leb128; 11 | 12 | public class StaticValuesParser extends EncValueParser { 13 | 14 | public StaticValuesParser(DexNode dex, Section in) { 15 | super(dex, in); 16 | } 17 | 18 | public int processFields(List fields) throws DecodeException { 19 | int count = Leb128.readUnsignedLeb128(in); 20 | for (int i = 0; i < count; i++) { 21 | Object value = parseValue(); 22 | if (i < fields.size()) { 23 | fields.get(i).addAttr(FieldInitAttr.constValue(value)); 24 | } 25 | } 26 | return count; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/attributes/annotations/MethodParameters.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.attributes.annotations; 2 | 3 | import jadx.core.dex.attributes.AType; 4 | import jadx.core.dex.attributes.IAttribute; 5 | import jadx.core.utils.Utils; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | public class MethodParameters implements IAttribute { 11 | 12 | private final List paramList; 13 | 14 | public MethodParameters(int paramCount) { 15 | paramList = new ArrayList(paramCount); 16 | } 17 | 18 | public List getParamList() { 19 | return paramList; 20 | } 21 | 22 | @Override 23 | public AType getType() { 24 | return AType.ANNOTATION_MTH_PARAMETERS; 25 | } 26 | 27 | @Override 28 | public String toString() { 29 | return Utils.listToString(paramList); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/attributes/nodes/IgnoreEdgeAttr.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.attributes.nodes; 2 | 3 | import jadx.core.dex.attributes.AType; 4 | import jadx.core.dex.attributes.IAttribute; 5 | import jadx.core.dex.nodes.BlockNode; 6 | import jadx.core.utils.Utils; 7 | 8 | import java.util.HashSet; 9 | import java.util.Set; 10 | 11 | public class IgnoreEdgeAttr implements IAttribute { 12 | 13 | private final Set blocks = new HashSet(3); 14 | 15 | public Set getBlocks() { 16 | return blocks; 17 | } 18 | 19 | public boolean contains(BlockNode block) { 20 | return blocks.contains(block); 21 | } 22 | 23 | @Override 24 | public AType getType() { 25 | return AType.IGNORE_EDGE; 26 | } 27 | 28 | @Override 29 | public String toString() { 30 | return "IGNORE_EDGES: " + Utils.listToString(blocks); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/visitors/IDexTreeVisitor.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.visitors; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.core.dex.nodes.MethodNode; 5 | import jadx.core.dex.nodes.RootNode; 6 | import jadx.core.utils.exceptions.JadxException; 7 | 8 | /** 9 | * Visitor interface for traverse dex tree 10 | */ 11 | public interface IDexTreeVisitor { 12 | 13 | /** 14 | * Called after loading dex tree, but before visitor traversal. 15 | */ 16 | void init(RootNode root) throws JadxException; 17 | 18 | /** 19 | * Visit class 20 | * 21 | * @return false for disable child methods and inner classes traversal 22 | * @throws JadxException 23 | */ 24 | boolean visit(ClassNode cls) throws JadxException; 25 | 26 | /** 27 | * Visit method 28 | * 29 | * @throws JadxException 30 | */ 31 | void visit(MethodNode mth) throws JadxException; 32 | } 33 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/TestArgInline.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.hamcrest.CoreMatchers.containsString; 9 | import static org.hamcrest.CoreMatchers.not; 10 | import static org.junit.Assert.assertThat; 11 | 12 | public class TestArgInline extends IntegrationTest { 13 | 14 | public static class TestCls { 15 | 16 | public void test(int a) { 17 | while (a < 10) { 18 | int b = a + 1; 19 | a = b; 20 | } 21 | } 22 | } 23 | 24 | @Test 25 | public void test() { 26 | noDebugInfo(); 27 | ClassNode cls = getClassNode(TestCls.class); 28 | String code = cls.getCode().toString(); 29 | 30 | assertThat(code, containsString("i++;")); 31 | assertThat(code, not(containsString("i = i + 1;"))); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/inner/TestRFieldAccess.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.inner; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static jadx.tests.api.utils.JadxMatchers.countString; 9 | import static org.junit.Assert.assertThat; 10 | 11 | public class TestRFieldAccess extends IntegrationTest { 12 | 13 | public static class R { 14 | public static final class id { 15 | public static final int Button01 = 2131230730; 16 | } 17 | } 18 | 19 | public static class TestR { 20 | public int test() { 21 | return R.id.Button01; 22 | } 23 | } 24 | 25 | @Test 26 | public void test() { 27 | ClassNode cls = getClassNode(TestRFieldAccess.class); 28 | String code = cls.getCode().toString(); 29 | assertThat(code, countString(2, "return R.id.Button01;")); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/variables/TestVariables2.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.variables; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.hamcrest.CoreMatchers.containsString; 9 | import static org.junit.Assert.assertThat; 10 | 11 | public class TestVariables2 extends IntegrationTest { 12 | 13 | public static class TestCls { 14 | Object test(Object s) { 15 | Object store = s != null ? s : null; 16 | if (store == null) { 17 | store = new Object(); 18 | s = store; 19 | } 20 | return store; 21 | } 22 | } 23 | 24 | @Test 25 | public void test() { 26 | ClassNode cls = getClassNode(TestCls.class); 27 | String code = cls.getCode().toString(); 28 | 29 | assertThat(code, containsString("Object store = s != null ? s : null;")); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/conditions/TestConditions.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.conditions; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.hamcrest.CoreMatchers.containsString; 9 | import static org.hamcrest.CoreMatchers.not; 10 | import static org.junit.Assert.assertThat; 11 | 12 | public class TestConditions extends IntegrationTest { 13 | 14 | public static class TestCls { 15 | private boolean test(boolean a, boolean b, boolean c) { 16 | return (a && b) || c; 17 | } 18 | } 19 | 20 | @Test 21 | public void test() { 22 | ClassNode cls = getClassNode(TestCls.class); 23 | String code = cls.getCode().toString(); 24 | 25 | assertThat(code, not(containsString("(!a || !b) && !c"))); 26 | assertThat(code, containsString("return (a && b) || c;")); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/loops/TestDoWhileBreak.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.loops; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static jadx.tests.api.utils.JadxMatchers.containsOne; 9 | import static org.junit.Assert.assertThat; 10 | 11 | public class TestDoWhileBreak extends IntegrationTest { 12 | 13 | public static class TestCls { 14 | 15 | public int test(int k) throws InterruptedException { 16 | int i = 3; 17 | do { 18 | if (k > 9) { 19 | i = 0; 20 | break; 21 | } 22 | i++; 23 | } while (i < 5); 24 | 25 | return i; 26 | } 27 | } 28 | 29 | @Test 30 | public void test() { 31 | ClassNode cls = getClassNode(TestCls.class); 32 | String code = cls.getCode().toString(); 33 | 34 | assertThat(code, containsOne("while (")); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/conditions/TestCmpOp2.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.conditions; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.hamcrest.CoreMatchers.containsString; 9 | import static org.junit.Assert.assertThat; 10 | 11 | public class TestCmpOp2 extends IntegrationTest { 12 | 13 | public static class TestCls { 14 | public boolean testGT(float a, float b) { 15 | return a > b; 16 | } 17 | 18 | public boolean testLT(float c, double d) { 19 | return c < d; 20 | } 21 | } 22 | 23 | @Test 24 | public void test() { 25 | ClassNode cls = getClassNode(TestCls.class); 26 | String code = cls.getCode().toString(); 27 | 28 | assertThat(code, containsString("return a > b;")); 29 | assertThat(code, containsString("return ((double) c) < d;")); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/attributes/nodes/PhiListAttr.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.attributes.nodes; 2 | 3 | import jadx.core.dex.attributes.AType; 4 | import jadx.core.dex.attributes.IAttribute; 5 | import jadx.core.dex.instructions.PhiInsn; 6 | 7 | import java.util.LinkedList; 8 | import java.util.List; 9 | 10 | public class PhiListAttr implements IAttribute { 11 | 12 | private final List list = new LinkedList(); 13 | 14 | @Override 15 | public AType getType() { 16 | return AType.PHI_LIST; 17 | } 18 | 19 | public List getList() { 20 | return list; 21 | } 22 | 23 | @Override 24 | public String toString() { 25 | StringBuilder sb = new StringBuilder(); 26 | sb.append("PHI: "); 27 | for (PhiInsn phiInsn : list) { 28 | sb.append('r').append(phiInsn.getResult().getRegNum()).append(" "); 29 | } 30 | return sb.toString(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/CheckTypeVisitor.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.visitors.typeinference; 2 | 3 | import jadx.core.dex.instructions.args.InsnArg; 4 | import jadx.core.dex.nodes.InsnNode; 5 | import jadx.core.dex.nodes.MethodNode; 6 | import jadx.core.utils.ErrorsCounter; 7 | 8 | public class CheckTypeVisitor { 9 | 10 | public static void visit(MethodNode mth, InsnNode insn) { 11 | if (insn.getResult() != null 12 | && !insn.getResult().getType().isTypeKnown()) { 13 | error("Wrong return type", mth, insn); 14 | return; 15 | } 16 | 17 | for (InsnArg arg : insn.getArguments()) { 18 | if (!arg.getType().isTypeKnown()) { 19 | error("Wrong type", mth, insn); 20 | return; 21 | } 22 | } 23 | } 24 | 25 | private static void error(String msg, MethodNode mth, InsnNode insn) { 26 | ErrorsCounter.methodError(mth, msg + ": " + insn); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/conditions/TestConditions7.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.conditions; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.hamcrest.CoreMatchers.containsString; 9 | import static org.hamcrest.CoreMatchers.not; 10 | import static org.junit.Assert.assertThat; 11 | 12 | public class TestConditions7 extends IntegrationTest { 13 | 14 | public static class TestCls { 15 | public void test(int[] a, int i) { 16 | if (i >= 0 && i < a.length) { 17 | a[i]++; 18 | } 19 | } 20 | } 21 | 22 | @Test 23 | public void test() { 24 | ClassNode cls = getClassNode(TestCls.class); 25 | String code = cls.getCode().toString(); 26 | 27 | assertThat(code, containsString("if (i >= 0 && i < a.length) {")); 28 | assertThat(code, not(containsString("||"))); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/generics/TestGenerics4.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.generics; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.hamcrest.CoreMatchers.containsString; 9 | import static org.hamcrest.CoreMatchers.not; 10 | import static org.junit.Assert.assertThat; 11 | 12 | public class TestGenerics4 extends IntegrationTest { 13 | 14 | public static class TestCls { 15 | 16 | public static Class method(int i) { 17 | Class[] a = new Class[0]; 18 | return a[a.length - i]; 19 | } 20 | } 21 | 22 | @Test 23 | public void test() { 24 | ClassNode cls = getClassNode(TestCls.class); 25 | String code = cls.getCode().toString(); 26 | 27 | assertThat(code, containsString("Class[] a =")); 28 | assertThat(code, not(containsString("Class[] a ="))); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/arrays/TestArrays.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.arrays; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static jadx.tests.api.utils.JadxMatchers.containsOne; 9 | import static org.junit.Assert.assertThat; 10 | 11 | public class TestArrays extends IntegrationTest { 12 | public static class TestCls { 13 | 14 | public int test1(int i) { 15 | int[] a = new int[]{1, 2, 3, 5}; 16 | return a[i]; 17 | } 18 | 19 | public int test2(int i) { 20 | int[][] a = new int[i][i + 1]; 21 | return a.length; 22 | } 23 | } 24 | 25 | @Test 26 | public void test() { 27 | noDebugInfo(); 28 | ClassNode cls = getClassNode(TestCls.class); 29 | String code = cls.getCode().toString(); 30 | 31 | assertThat(code, containsOne("return new int[]{1, 2, 3, 5}[i];")); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/types/TestTypeResolver2.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.types; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import java.io.IOException; 7 | 8 | import org.junit.Test; 9 | 10 | import static jadx.tests.api.utils.JadxMatchers.containsOne; 11 | import static org.junit.Assert.assertThat; 12 | 13 | public class TestTypeResolver2 extends IntegrationTest { 14 | 15 | public static class TestCls { 16 | 17 | private static boolean test(Object obj) throws IOException { 18 | if (obj != null) { 19 | return true; 20 | } 21 | throw new IOException(); 22 | } 23 | } 24 | 25 | @Test 26 | public void test() { 27 | noDebugInfo(); 28 | 29 | ClassNode cls = getClassNode(TestCls.class); 30 | String code = cls.getCode().toString(); 31 | 32 | assertThat(code, containsOne("if (obj != null) {")); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/inline/TestInline.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.inline; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.hamcrest.CoreMatchers.containsString; 9 | import static org.junit.Assert.assertThat; 10 | 11 | public class TestInline extends IntegrationTest { 12 | 13 | public static class TestCls { 14 | public static void main(String[] args) throws Exception { 15 | System.out.println("Test: " + new TestCls().testRun()); 16 | } 17 | 18 | private boolean testRun() { 19 | return false; 20 | } 21 | } 22 | 23 | @Test 24 | public void test() { 25 | ClassNode cls = getClassNode(TestCls.class); 26 | String code = cls.getCode().toString(); 27 | 28 | assertThat(code, containsString("System.out.println(\"Test: \" + new TestInline$TestCls().testRun());")); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/TestFloatValue.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.hamcrest.CoreMatchers.containsString; 9 | import static org.hamcrest.CoreMatchers.not; 10 | import static org.junit.Assert.assertThat; 11 | 12 | public class TestFloatValue extends IntegrationTest { 13 | 14 | public static class TestCls { 15 | public float[] method() { 16 | float[] fa = {0.55f}; 17 | fa[0] /= 2; 18 | return fa; 19 | } 20 | } 21 | 22 | @Test 23 | public void test() { 24 | ClassNode cls = getClassNode(TestCls.class); 25 | String code = cls.getCode().toString(); 26 | 27 | assertThat(code, not(containsString("1073741824"))); 28 | assertThat(code, containsString("0.55f")); 29 | assertThat(code, containsString("fa[0] = fa[0] / 2.0f;")); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/conditions/TestConditions2.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.conditions; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | public class TestConditions2 extends IntegrationTest { 9 | 10 | public static class TestCls { 11 | int c; 12 | String d; 13 | String f; 14 | 15 | public void testComplexIf(String a, int b) { 16 | if (d == null || (c == 0 && b != -1 && d.length() == 0)) { 17 | c = a.codePointAt(c); 18 | } else { 19 | if (a.hashCode() != 0xCDE) { 20 | c = f.compareTo(a); 21 | } 22 | } 23 | } 24 | } 25 | 26 | @Test 27 | public void test() { 28 | ClassNode cls = getClassNode(TestCls.class); 29 | String code = cls.getCode().toString(); 30 | 31 | // assertThat(code, containsString("return;")); 32 | // assertThat(code, not(containsString("else"))); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/api/IJadxArgs.java: -------------------------------------------------------------------------------- 1 | package jadx.api; 2 | 3 | import java.io.File; 4 | 5 | public interface IJadxArgs { 6 | File getOutDir(); 7 | 8 | int getThreadsCount(); 9 | 10 | boolean isCFGOutput(); 11 | 12 | boolean isRawCFGOutput(); 13 | 14 | boolean isFallbackMode(); 15 | 16 | boolean isShowInconsistentCode(); 17 | 18 | boolean isVerbose(); 19 | 20 | boolean isSkipResources(); 21 | 22 | boolean isSkipSources(); 23 | 24 | boolean isDeobfuscationOn(); 25 | 26 | int getDeobfuscationMinLength(); 27 | 28 | int getDeobfuscationMaxLength(); 29 | 30 | boolean isDeobfuscationForceSave(); 31 | 32 | boolean useSourceNameAsClassAlias(); 33 | 34 | boolean escapeUnicode(); 35 | 36 | /** 37 | * Replace constant values with static final fields with same value 38 | */ 39 | boolean isReplaceConsts(); 40 | 41 | /** 42 | * Save as gradle project 43 | */ 44 | boolean isExportAsGradleProject(); 45 | } 46 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/conditions/TestTernary2.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.conditions; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.junit.Assert.assertEquals; 9 | import static org.junit.Assert.assertTrue; 10 | 11 | public class TestTernary2 extends IntegrationTest { 12 | 13 | public static class TestCls { 14 | 15 | public void test() { 16 | assertTrue(f(1, 0) == 0); 17 | } 18 | 19 | private int f(int a, int b) { 20 | return a + b; 21 | } 22 | } 23 | 24 | @Test 25 | public void test() { 26 | ClassNode cls = getClassNode(TestCls.class); 27 | String code = cls.getCode().toString(); 28 | 29 | assertEquals(1, count(code, "assertTrue")); 30 | assertEquals(1, count(code, "f(1, 0)")); 31 | // TODO: 32 | // assertThat(code, containsString("assertTrue(f(1, 0) == 0);")); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/loops/TestArrayForEach.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.loops; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static jadx.tests.api.utils.JadxMatchers.containsLines; 9 | import static org.junit.Assert.assertThat; 10 | 11 | public class TestArrayForEach extends IntegrationTest { 12 | 13 | public static class TestCls { 14 | 15 | private int test(int[] a) { 16 | int sum = 0; 17 | for (int n : a) { 18 | sum += n; 19 | } 20 | return sum; 21 | } 22 | } 23 | 24 | @Test 25 | public void test() { 26 | ClassNode cls = getClassNode(TestCls.class); 27 | String code = cls.getCode().toString(); 28 | 29 | assertThat(code, containsLines(2, 30 | "int sum = 0;", 31 | "for (int n : a) {", 32 | indent(1) + "sum += n;", 33 | "}", 34 | "return sum;" 35 | )); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/visitors/JadxVisitor.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.visitors; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * Annotation for describe dependencies of jadx visitors 10 | */ 11 | @Retention(RetentionPolicy.RUNTIME) 12 | @Target(ElementType.TYPE) 13 | public @interface JadxVisitor { 14 | /** 15 | * Visitor short name (identifier) 16 | */ 17 | String name(); 18 | 19 | /** 20 | * Detailed visitor description 21 | */ 22 | String desc() default ""; 23 | 24 | /** 25 | * This visitor must be run after listed visitors 26 | */ 27 | Class[] runAfter() default {}; 28 | 29 | /** 30 | * This visitor must be run before listed visitors 31 | */ 32 | Class[] runBefore() default {}; 33 | } 34 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/api/utils/CountString.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.api.utils; 2 | 3 | import org.hamcrest.Description; 4 | import org.hamcrest.core.SubstringMatcher; 5 | 6 | public class CountString extends SubstringMatcher { 7 | 8 | private final int count; 9 | 10 | public CountString(int count, String substring) { 11 | super(substring); 12 | this.count = count; 13 | } 14 | 15 | @Override 16 | protected boolean evalSubstringOf(String string) { 17 | return this.count == count(string); 18 | } 19 | 20 | @Override 21 | protected String relationship() { 22 | return "containing <" + count + "> occurrence of"; 23 | } 24 | 25 | @Override 26 | public void describeMismatchSafely(String item, Description mismatchDescription) { 27 | mismatchDescription.appendText("found ").appendValue(count(item)); 28 | } 29 | 30 | private int count(String string) { 31 | return TestUtils.count(string, substring); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/arrays/TestArrays3.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.arrays; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static jadx.tests.api.utils.JadxMatchers.containsOne; 9 | import static org.hamcrest.CoreMatchers.instanceOf; 10 | import static org.junit.Assert.assertThat; 11 | 12 | public class TestArrays3 extends IntegrationTest { 13 | public static class TestCls { 14 | 15 | private Object test(byte[] bArr) { 16 | return new Object[]{bArr}; 17 | } 18 | 19 | public void check() { 20 | assertThat(test(new byte[]{1, 2}), instanceOf(Object[].class)); 21 | } 22 | } 23 | 24 | @Test 25 | public void test() { 26 | noDebugInfo(); 27 | ClassNode cls = getClassNode(TestCls.class); 28 | String code = cls.getCode().toString(); 29 | 30 | assertThat(code, containsOne("return new Object[]{bArr};")); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/names/TestSameMethodsNames.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.names; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static jadx.tests.api.utils.JadxMatchers.containsOne; 9 | import static org.junit.Assert.assertThat; 10 | 11 | public class TestSameMethodsNames extends IntegrationTest { 12 | 13 | public static class TestCls { 14 | 15 | public static void test() { 16 | new Bug().Bug(); 17 | } 18 | 19 | public static class Bug { 20 | public Bug() { 21 | System.out.println("constructor"); 22 | } 23 | 24 | void Bug() { 25 | System.out.println("Bug"); 26 | } 27 | } 28 | } 29 | 30 | @Test 31 | public void test() { 32 | ClassNode cls = getClassNode(TestCls.class); 33 | String code = cls.getCode().toString(); 34 | 35 | assertThat(code, containsOne("new Bug().Bug();")); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/SelectTypeVisitor.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.visitors.typeinference; 2 | 3 | import jadx.core.dex.instructions.args.ArgType; 4 | import jadx.core.dex.instructions.args.InsnArg; 5 | import jadx.core.dex.nodes.DexNode; 6 | import jadx.core.dex.nodes.InsnNode; 7 | 8 | public class SelectTypeVisitor { 9 | 10 | private SelectTypeVisitor() { 11 | } 12 | 13 | public static void visit(DexNode dex, InsnNode insn) { 14 | InsnArg res = insn.getResult(); 15 | if (res != null && !res.getType().isTypeKnown()) { 16 | selectType(dex, res); 17 | } 18 | for (InsnArg arg : insn.getArguments()) { 19 | if (!arg.getType().isTypeKnown()) { 20 | selectType(dex, arg); 21 | } 22 | } 23 | } 24 | 25 | private static void selectType(DexNode dex, InsnArg arg) { 26 | ArgType t = arg.getType(); 27 | ArgType newType = ArgType.merge(dex, t, t.selectFirst()); 28 | arg.setType(newType); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/utils/exceptions/CodegenException.java: -------------------------------------------------------------------------------- 1 | package jadx.core.utils.exceptions; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.core.dex.nodes.MethodNode; 5 | 6 | public class CodegenException extends JadxException { 7 | 8 | private static final long serialVersionUID = 39344288912966824L; 9 | 10 | public CodegenException(String message) { 11 | super(message); 12 | } 13 | 14 | public CodegenException(String message, Throwable cause) { 15 | super(message, cause); 16 | } 17 | 18 | public CodegenException(ClassNode mth, String msg) { 19 | super(mth, msg, null); 20 | } 21 | 22 | public CodegenException(ClassNode mth, String msg, Throwable th) { 23 | super(mth, msg, th); 24 | } 25 | 26 | public CodegenException(MethodNode mth, String msg) { 27 | super(mth, msg, null); 28 | } 29 | 30 | public CodegenException(MethodNode mth, String msg, Throwable th) { 31 | super(mth, msg, th); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/attributes/IAttributeNode.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.attributes; 2 | 3 | import jadx.core.dex.attributes.annotations.Annotation; 4 | 5 | import java.util.List; 6 | 7 | public interface IAttributeNode { 8 | 9 | void add(AFlag flag); 10 | 11 | void addAttr(IAttribute attr); 12 | 13 | void addAttr(AType> type, T obj); 14 | 15 | void copyAttributesFrom(AttrNode attrNode); 16 | 17 | boolean contains(AFlag flag); 18 | 19 | boolean contains(AType type); 20 | 21 | T get(AType type); 22 | 23 | Annotation getAnnotation(String cls); 24 | 25 | List getAll(AType> type); 26 | 27 | void remove(AFlag flag); 28 | 29 | void remove(AType type); 30 | 31 | void removeAttr(IAttribute attr); 32 | 33 | void clearAttributes(); 34 | 35 | List getAttributesStringsList(); 36 | 37 | String getAttributesString(); 38 | } 39 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/loops/TestLoopCondition2.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.loops; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static jadx.tests.api.utils.JadxMatchers.containsOne; 9 | import static org.junit.Assert.assertThat; 10 | 11 | public class TestLoopCondition2 extends IntegrationTest { 12 | 13 | public static class TestCls { 14 | 15 | public int test(boolean a) { 16 | int i = 0; 17 | while (a && i < 10) { 18 | i++; 19 | } 20 | return i; 21 | } 22 | } 23 | 24 | @Test 25 | public void test() { 26 | ClassNode cls = getClassNode(TestCls.class); 27 | String code = cls.getCode().toString(); 28 | 29 | assertThat(code, containsOne("int i = 0;")); 30 | assertThat(code, containsOne("while (a && i < 10) {")); 31 | assertThat(code, containsOne("i++;")); 32 | assertThat(code, containsOne("return i;")); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/instructions/ConstStringNode.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.instructions; 2 | 3 | import jadx.core.dex.nodes.InsnNode; 4 | 5 | public final class ConstStringNode extends InsnNode { 6 | 7 | private final String str; 8 | 9 | public ConstStringNode(String str) { 10 | super(InsnType.CONST_STR, 0); 11 | this.str = str; 12 | } 13 | 14 | public String getString() { 15 | return str; 16 | } 17 | 18 | @Override 19 | public InsnNode copy() { 20 | return copyCommonParams(new ConstStringNode(str)); 21 | } 22 | 23 | @Override 24 | public boolean isSame(InsnNode obj) { 25 | if (this == obj) { 26 | return true; 27 | } 28 | if (!(obj instanceof ConstStringNode) || !super.isSame(obj)) { 29 | return false; 30 | } 31 | ConstStringNode other = (ConstStringNode) obj; 32 | return str.equals(other.str); 33 | } 34 | 35 | @Override 36 | public String toString() { 37 | return super.toString() + " \"" + str + "\""; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/regions/AbstractRegion.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.regions; 2 | 3 | import jadx.core.dex.attributes.AttrNode; 4 | import jadx.core.dex.nodes.IContainer; 5 | import jadx.core.dex.nodes.IRegion; 6 | 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | public abstract class AbstractRegion extends AttrNode implements IRegion { 11 | private static final Logger LOG = LoggerFactory.getLogger(AbstractRegion.class); 12 | 13 | private IRegion parent; 14 | 15 | public AbstractRegion(IRegion parent) { 16 | this.parent = parent; 17 | } 18 | 19 | @Override 20 | public IRegion getParent() { 21 | return parent; 22 | } 23 | 24 | public void setParent(IRegion parent) { 25 | this.parent = parent; 26 | } 27 | 28 | @Override 29 | public boolean replaceSubBlock(IContainer oldBlock, IContainer newBlock) { 30 | LOG.warn("Replace sub block not supported for class \"{}\"", this.getClass()); 31 | return false; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/visitors/SaveCode.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.visitors; 2 | 3 | import jadx.api.IJadxArgs; 4 | import jadx.core.codegen.CodeWriter; 5 | import jadx.core.dex.nodes.ClassNode; 6 | import jadx.core.utils.exceptions.CodegenException; 7 | 8 | import java.io.File; 9 | 10 | public class SaveCode extends AbstractVisitor { 11 | private final File dir; 12 | private final IJadxArgs args; 13 | 14 | public SaveCode(File dir, IJadxArgs args) { 15 | this.args = args; 16 | this.dir = dir; 17 | } 18 | 19 | @Override 20 | public boolean visit(ClassNode cls) throws CodegenException { 21 | save(dir, args, cls); 22 | return false; 23 | } 24 | 25 | public static void save(File dir, IJadxArgs args, ClassNode cls) { 26 | CodeWriter clsCode = cls.getCode(); 27 | String fileName = cls.getClassInfo().getFullPath() + ".java"; 28 | if (args.isFallbackMode()) { 29 | fileName += ".jadx"; 30 | } 31 | clsCode.save(dir, fileName); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/loops/TestIndexForLoop.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.loops; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static jadx.tests.api.utils.JadxMatchers.containsLines; 9 | import static org.junit.Assert.assertThat; 10 | 11 | public class TestIndexForLoop extends IntegrationTest { 12 | 13 | public static class TestCls { 14 | 15 | private int test(int[] a, int b) { 16 | int sum = 0; 17 | for (int i = 0; i < b; i++) { 18 | sum += a[i]; 19 | } 20 | return sum; 21 | } 22 | } 23 | 24 | @Test 25 | public void test() { 26 | ClassNode cls = getClassNode(TestCls.class); 27 | String code = cls.getCode().toString(); 28 | 29 | assertThat(code, containsLines(2, 30 | "int sum = 0;", 31 | "for (int i = 0; i < b; i++) {", 32 | indent(1) + "sum += a[i];", 33 | "}", 34 | "return sum;" 35 | )); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/arrays/TestArrayFill2.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.arrays; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.hamcrest.CoreMatchers.containsString; 9 | import static org.junit.Assert.assertThat; 10 | 11 | public class TestArrayFill2 extends IntegrationTest { 12 | 13 | public static class TestCls { 14 | 15 | public int[] test(int a) { 16 | return new int[]{1, a + 1, 2}; 17 | } 18 | 19 | // TODO 20 | // public int[] test2(int a) { 21 | // return new int[]{1, a++, a * 2}; 22 | // } 23 | } 24 | 25 | @Test 26 | public void test() { 27 | ClassNode cls = getClassNode(TestCls.class); 28 | String code = cls.getCode().toString(); 29 | 30 | assertThat(code, containsString("return new int[]{1, a + 1, 2};")); 31 | 32 | // TODO 33 | // assertThat(code, containsString("return new int[]{1, a++, a * 2};")); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/conditions/TestConditions6.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.conditions; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import java.util.List; 7 | 8 | import org.junit.Test; 9 | 10 | import static org.hamcrest.CoreMatchers.containsString; 11 | import static org.hamcrest.CoreMatchers.not; 12 | import static org.junit.Assert.assertThat; 13 | 14 | public class TestConditions6 extends IntegrationTest { 15 | 16 | public static class TestCls { 17 | public boolean test(List l1, List l2) { 18 | if (l2.size() > 0) { 19 | l1.clear(); 20 | } 21 | return l1.size() == 0; 22 | } 23 | } 24 | 25 | @Test 26 | public void test() { 27 | ClassNode cls = getClassNode(TestCls.class); 28 | String code = cls.getCode().toString(); 29 | 30 | assertThat(code, containsString("return l1.size() == 0;")); 31 | assertThat(code, not(containsString("else"))); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/attributes/nodes/DeclareVariablesAttr.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.attributes.nodes; 2 | 3 | import jadx.core.dex.attributes.AType; 4 | import jadx.core.dex.attributes.IAttribute; 5 | import jadx.core.dex.instructions.args.RegisterArg; 6 | import jadx.core.utils.Utils; 7 | 8 | import java.util.LinkedList; 9 | import java.util.List; 10 | 11 | /** 12 | * List of variables to be declared at region start. 13 | */ 14 | public class DeclareVariablesAttr implements IAttribute { 15 | 16 | private final List vars = new LinkedList(); 17 | 18 | public Iterable getVars() { 19 | return vars; 20 | } 21 | 22 | public void addVar(RegisterArg arg) { 23 | vars.add(arg); 24 | } 25 | 26 | @Override 27 | public AType getType() { 28 | return AType.DECLARE_VARIABLES; 29 | } 30 | 31 | @Override 32 | public String toString() { 33 | return "DECL_VAR: " + Utils.listToString(vars); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/nodes/Edge.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.nodes; 2 | 3 | public class Edge { 4 | private final BlockNode source; 5 | private final BlockNode target; 6 | 7 | public Edge(BlockNode source, BlockNode target) { 8 | this.source = source; 9 | this.target = target; 10 | } 11 | 12 | public BlockNode getSource() { 13 | return source; 14 | } 15 | 16 | public BlockNode getTarget() { 17 | return target; 18 | } 19 | 20 | @Override 21 | public boolean equals(Object o) { 22 | if (this == o) { 23 | return true; 24 | } 25 | if (o == null || getClass() != o.getClass()) { 26 | return false; 27 | } 28 | Edge edge = (Edge) o; 29 | return source.equals(edge.source) && target.equals(edge.target); 30 | 31 | } 32 | 33 | @Override 34 | public int hashCode() { 35 | return source.hashCode() + 31 * target.hashCode(); 36 | } 37 | 38 | @Override 39 | public String toString() { 40 | return "Edge: " + source + " -> " + target; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/trycatch/ExcHandlerAttr.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.trycatch; 2 | 3 | import jadx.core.dex.attributes.AType; 4 | import jadx.core.dex.attributes.IAttribute; 5 | 6 | public class ExcHandlerAttr implements IAttribute { 7 | 8 | private final TryCatchBlock tryBlock; 9 | private final ExceptionHandler handler; 10 | 11 | public ExcHandlerAttr(TryCatchBlock block, ExceptionHandler handler) { 12 | this.tryBlock = block; 13 | this.handler = handler; 14 | } 15 | 16 | @Override 17 | public AType getType() { 18 | return AType.EXC_HANDLER; 19 | } 20 | 21 | public TryCatchBlock getTryBlock() { 22 | return tryBlock; 23 | } 24 | 25 | public ExceptionHandler getHandler() { 26 | return handler; 27 | } 28 | 29 | @Override 30 | public String toString() { 31 | return "ExcHandler: " + (handler.isFinally() 32 | ? " FINALLY" 33 | : (handler.isCatchAll() ? "all" : handler.getCatchType()) + " " + handler.getArg()); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /jadx-gui/src/main/java/jadx/gui/utils/search/SimpleIndex.java: -------------------------------------------------------------------------------- 1 | package jadx.gui.utils.search; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import java.util.List; 6 | 7 | public class SimpleIndex extends SearchIndex { 8 | 9 | private final List keys = new ArrayList(); 10 | private final List values = new ArrayList(); 11 | 12 | @Override 13 | public void put(String str, T value) { 14 | keys.add(str); 15 | values.add(value); 16 | } 17 | 18 | @Override 19 | public List getValuesForKeysContaining(String str) { 20 | int size = size(); 21 | if (size == 0) { 22 | return Collections.emptyList(); 23 | } 24 | List results = new ArrayList(); 25 | for (int i = 0; i < size; i++) { 26 | String key = keys.get(i); 27 | if (key.contains(str)) { 28 | results.add(values.get(i)); 29 | } 30 | } 31 | return results; 32 | } 33 | 34 | @Override 35 | public int size() { 36 | return keys.size(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/conditions/TestConditions4.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.conditions; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.hamcrest.CoreMatchers.containsString; 9 | import static org.hamcrest.CoreMatchers.not; 10 | import static org.junit.Assert.assertThat; 11 | 12 | public class TestConditions4 extends IntegrationTest { 13 | 14 | public static class TestCls { 15 | public int test(int num) { 16 | boolean inRange = (num >= 59 && num <= 66); 17 | return inRange ? num + 1 : num; 18 | } 19 | } 20 | 21 | @Test 22 | public void test() { 23 | ClassNode cls = getClassNode(TestCls.class); 24 | String code = cls.getCode().toString(); 25 | 26 | assertThat(code, containsString("num >= 59 && num <= 66")); 27 | assertThat(code, containsString("return inRange ? num + 1 : num;")); 28 | assertThat(code, not(containsString("else"))); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/conditions/TestSimpleConditions.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.conditions; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.hamcrest.CoreMatchers.containsString; 9 | import static org.junit.Assert.assertThat; 10 | 11 | public class TestSimpleConditions extends IntegrationTest { 12 | 13 | public static class TestCls { 14 | public boolean test1(boolean[] a) { 15 | return (a[0] && a[1] && a[2]) || (a[3] && a[4]); 16 | } 17 | 18 | public boolean test2(boolean[] a) { 19 | return a[0] || a[1] || a[2] || a[3]; 20 | } 21 | } 22 | 23 | @Test 24 | public void test() { 25 | ClassNode cls = getClassNode(TestCls.class); 26 | String code = cls.getCode().toString(); 27 | 28 | assertThat(code, containsString("return (a[0] && a[1] && a[2]) || (a[3] && a[4]);")); 29 | assertThat(code, containsString("return a[0] || a[1] || a[2] || a[3];")); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/switches/TestSwitchNoDefault.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.switches; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.junit.Assert.assertEquals; 9 | 10 | public class TestSwitchNoDefault extends IntegrationTest { 11 | 12 | public static class TestCls { 13 | public void test(int a) { 14 | String s = null; 15 | switch (a) { 16 | case 1: 17 | s = "1"; 18 | break; 19 | case 2: 20 | s = "2"; 21 | break; 22 | case 3: 23 | s = "3"; 24 | break; 25 | case 4: 26 | s = "4"; 27 | break; 28 | } 29 | System.out.println(s); 30 | } 31 | } 32 | 33 | @Test 34 | public void test() { 35 | ClassNode cls = getClassNode(TestCls.class); 36 | String code = cls.getCode().toString(); 37 | 38 | assertEquals(4, count(code, "break;")); 39 | assertEquals(1, count(code, "System.out.println(s);")); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/types/TestTypeResolver.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.types; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.hamcrest.CoreMatchers.containsString; 9 | import static org.hamcrest.CoreMatchers.not; 10 | import static org.junit.Assert.assertThat; 11 | 12 | public class TestTypeResolver extends IntegrationTest { 13 | 14 | public static class TestCls { 15 | public TestCls(int b1, int b2) { 16 | // test 'this' move and constructor invocation on moved register 17 | this(b1, b2, 0, 0, 0); 18 | } 19 | 20 | public TestCls(int a1, int a2, int a3, int a4, int a5) { 21 | } 22 | } 23 | 24 | @Test 25 | public void test() { 26 | ClassNode cls = getClassNode(TestCls.class); 27 | String code = cls.getCode().toString(); 28 | 29 | assertThat(code, containsString("this(b1, b2, 0, 0, 0);")); 30 | assertThat(code, not(containsString("= this;"))); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/attributes/nodes/JadxErrorAttr.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.attributes.nodes; 2 | 3 | import jadx.core.dex.attributes.AType; 4 | import jadx.core.dex.attributes.IAttribute; 5 | import jadx.core.utils.Utils; 6 | 7 | public class JadxErrorAttr implements IAttribute { 8 | 9 | private final Throwable cause; 10 | 11 | public JadxErrorAttr(Throwable cause) { 12 | this.cause = cause; 13 | } 14 | 15 | public Throwable getCause() { 16 | return cause; 17 | } 18 | 19 | @Override 20 | public AType getType() { 21 | return AType.JADX_ERROR; 22 | } 23 | 24 | @Override 25 | public String toString() { 26 | StringBuilder str = new StringBuilder(); 27 | str.append("JadxError: "); 28 | if (cause == null) { 29 | str.append("null"); 30 | } else { 31 | str.append(cause.getClass()); 32 | str.append(":"); 33 | str.append(cause.getMessage()); 34 | str.append("\n"); 35 | str.append(Utils.getStackTrace(cause)); 36 | } 37 | return str.toString(); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/arith/TestArith2.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.arith; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import static org.hamcrest.CoreMatchers.containsString; 7 | import static org.hamcrest.CoreMatchers.not; 8 | import static org.junit.Assert.assertThat; 9 | 10 | public class TestArith2 extends IntegrationTest { 11 | 12 | public static class TestCls { 13 | 14 | public int test1(int a) { 15 | return (a + 2) * 3; 16 | } 17 | 18 | public int test2(int a, int b, int c) { 19 | return a + b + c; 20 | } 21 | } 22 | 23 | // @Test 24 | public void test() { 25 | ClassNode cls = getClassNode(TestCls.class); 26 | String code = cls.getCode().toString(); 27 | 28 | assertThat(code, containsString("return (a + 2) * 3;")); 29 | assertThat(code, not(containsString("a + 2 * 3"))); 30 | 31 | assertThat(code, containsString("return a + b + c;")); 32 | assertThat(code, not(containsString("return (a + b) + c;"))); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /jadx-gui/src/test/groovy/jadx/gui/tests/TestVersionsComparator.groovy: -------------------------------------------------------------------------------- 1 | package jadx.gui.tests 2 | 3 | import jadx.gui.update.VersionComparator 4 | import spock.lang.Specification 5 | 6 | class TestVersionsComparator extends Specification { 7 | 8 | def "test"() { 9 | expect: 10 | VersionComparator.compare(s1, s2) == expected 11 | VersionComparator.compare(s2, s1) == -expected 12 | 13 | where: 14 | s1 | s2 | expected 15 | "" | "" | 0 16 | "1" | "1" | 0 17 | "1" | "2" | -1 18 | "1.1" | "1.1" | 0 19 | "0.5" | "0.5" | 0 20 | "0.5" | "0.5.0" | 0 21 | "0.5" | "0.5.00" | 0 22 | "0.5" | "0.5.0.0" | 0 23 | "0.5" | "0.5.0.1" | -1 24 | "0.5.0" | "0.5.0" | 0 25 | "0.5.0" | "0.5.1" | -1 26 | "0.5" | "0.5.1" | -1 27 | "0.4.8" | "0.5" | -1 28 | "0.4.8" | "0.5.0" | -1 29 | "0.4.8" | "0.6" | -1 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/visitors/regions/TracedRegionVisitor.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.visitors.regions; 2 | 3 | import jadx.core.dex.nodes.IBlock; 4 | import jadx.core.dex.nodes.IRegion; 5 | import jadx.core.dex.nodes.MethodNode; 6 | 7 | import java.util.ArrayDeque; 8 | import java.util.Deque; 9 | 10 | public abstract class TracedRegionVisitor implements IRegionVisitor { 11 | 12 | protected final Deque regionStack = new ArrayDeque(); 13 | 14 | @Override 15 | public boolean enterRegion(MethodNode mth, IRegion region) { 16 | regionStack.push(region); 17 | return true; 18 | } 19 | 20 | @Override 21 | public void processBlock(MethodNode mth, IBlock container) { 22 | IRegion curRegion = regionStack.peek(); 23 | processBlockTraced(mth, container, curRegion); 24 | } 25 | 26 | public abstract void processBlockTraced(MethodNode mth, IBlock container, IRegion currentRegion); 27 | 28 | @Override 29 | public void leaveRegion(MethodNode mth, IRegion region) { 30 | regionStack.pop(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/xmlgen/entry/EntryConfig.java: -------------------------------------------------------------------------------- 1 | package jadx.core.xmlgen.entry; 2 | 3 | public class EntryConfig { 4 | private String language; 5 | private String country; 6 | 7 | public void setLanguage(String language) { 8 | this.language = language; 9 | } 10 | 11 | public String getLanguage() { 12 | return language; 13 | } 14 | 15 | public void setCountry(String country) { 16 | this.country = country; 17 | } 18 | 19 | public String getCountry() { 20 | return country; 21 | } 22 | 23 | public String getLocale() { 24 | StringBuilder sb = new StringBuilder(); 25 | if (language != null) { 26 | sb.append(language); 27 | } 28 | if (country != null) { 29 | sb.append("-r").append(country); 30 | } 31 | return sb.toString(); 32 | } 33 | 34 | @Override 35 | public String toString() { 36 | StringBuilder sb = new StringBuilder(); 37 | sb.append(getLocale()); 38 | if (sb.length() != 0) { 39 | sb.insert(0, " ["); 40 | sb.append(']'); 41 | } 42 | return sb.toString(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/arith/TestFieldIncrement2.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.arith; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.hamcrest.CoreMatchers.containsString; 9 | import static org.junit.Assert.assertThat; 10 | 11 | public class TestFieldIncrement2 extends IntegrationTest { 12 | 13 | public static class TestCls { 14 | private static class A { 15 | int f = 5; 16 | } 17 | 18 | public A a; 19 | 20 | public void test1(int n) { 21 | this.a.f = this.a.f + n; 22 | } 23 | 24 | public void test2(int n) { 25 | this.a.f *= n; 26 | } 27 | } 28 | 29 | @Test 30 | public void test() { 31 | ClassNode cls = getClassNode(TestCls.class); 32 | String code = cls.getCode().toString(); 33 | 34 | assertThat(code, containsString("this.a.f += n;")); 35 | assertThat(code, containsString("a.f *= n;")); 36 | // TODO 37 | // assertThat(code, containsString("this.a.f *= n;")); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/inner/TestInnerClass.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.inner; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.hamcrest.CoreMatchers.containsString; 9 | import static org.hamcrest.CoreMatchers.not; 10 | import static org.junit.Assert.assertThat; 11 | 12 | public class TestInnerClass extends IntegrationTest { 13 | 14 | public static class TestCls { 15 | public class Inner { 16 | public class Inner2 extends Thread { 17 | } 18 | } 19 | } 20 | 21 | @Test 22 | public void test() { 23 | ClassNode cls = getClassNode(TestCls.class); 24 | String code = cls.getCode().toString(); 25 | 26 | assertThat(code, containsString("Inner {")); 27 | assertThat(code, containsString("Inner2 extends Thread {")); 28 | assertThat(code, not(containsString("super();"))); 29 | assertThat(code, not(containsString("this$"))); 30 | assertThat(code, not(containsString("/* synthetic */"))); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/loops/TestIterableForEach.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.loops; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static jadx.tests.api.utils.JadxMatchers.containsLines; 9 | import static org.junit.Assert.assertThat; 10 | 11 | public class TestIterableForEach extends IntegrationTest { 12 | 13 | public static class TestCls { 14 | private String test(Iterable a) { 15 | StringBuilder sb = new StringBuilder(); 16 | for (String s : a) { 17 | sb.append(s); 18 | } 19 | return sb.toString(); 20 | } 21 | } 22 | 23 | @Test 24 | public void test() { 25 | ClassNode cls = getClassNode(TestCls.class); 26 | String code = cls.getCode().toString(); 27 | 28 | assertThat(code, containsLines(2, 29 | "StringBuilder sb = new StringBuilder();", 30 | "for (String s : a) {", 31 | indent(1) + "sb.append(s);", 32 | "}", 33 | "return sb.toString();" 34 | )); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /jadx-core/src/test/groovy/jadx/tests/TestNameMapper.groovy: -------------------------------------------------------------------------------- 1 | package jadx.tests 2 | 3 | import spock.lang.Specification 4 | 5 | import static jadx.core.deobf.NameMapper.isValidFullIdentifier 6 | 7 | class TestNameMapper extends Specification { 8 | 9 | def "test is Valid Full Identifier"() { 10 | expect: 11 | isValidFullIdentifier(valid) 12 | where: 13 | valid << [ 14 | 'C', 15 | 'Cc', 16 | 'b.C', 17 | 'b.Cc', 18 | 'aAa.b.Cc', 19 | 'a.b.Cc', 20 | 'a.b.C_c', 21 | 'a.b.C$c', 22 | 'a.b.C9' 23 | ] 24 | } 25 | 26 | def "test is not Valid Full Identifier"() { 27 | expect: 28 | !isValidFullIdentifier(invalid) 29 | where: 30 | invalid << [ 31 | '', 32 | '5', 33 | '7A', 34 | '.C', 35 | 'b.9C', 36 | 'b..C', 37 | ] 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/inline/TestInline6.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.inline; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.hamcrest.CoreMatchers.containsString; 9 | import static org.hamcrest.CoreMatchers.not; 10 | import static org.junit.Assert.assertThat; 11 | 12 | public class TestInline6 extends IntegrationTest { 13 | 14 | public static class TestCls { 15 | public void f() { 16 | } 17 | 18 | public void test(int a, int b) { 19 | long start = System.nanoTime(); 20 | f(); 21 | System.out.println(System.nanoTime() - start); 22 | } 23 | } 24 | 25 | @Test 26 | public void test() { 27 | ClassNode cls = getClassNode(TestCls.class); 28 | String code = cls.getCode().toString(); 29 | 30 | assertThat(code, containsString("System.out.println(System.nanoTime() - start);")); 31 | assertThat(code, not(containsString("System.out.println(System.nanoTime() - System.nanoTime());"))); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/inner/TestRFieldRestore2.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.inner; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | 9 | import org.junit.Test; 10 | 11 | import static jadx.tests.api.utils.JadxMatchers.containsOne; 12 | import static org.junit.Assert.assertThat; 13 | 14 | public class TestRFieldRestore2 extends IntegrationTest { 15 | 16 | public static class TestCls { 17 | 18 | public static class R { 19 | } 20 | 21 | public int test() { 22 | return 2131230730; 23 | } 24 | } 25 | 26 | @Test 27 | public void test() { 28 | // unknown id.Button 29 | disableCompilation(); 30 | 31 | Map map = new HashMap(); 32 | map.put(2131230730, "id.Button"); 33 | setResMap(map); 34 | 35 | ClassNode cls = getClassNode(TestCls.class); 36 | String code = cls.getCode().toString(); 37 | assertThat(code, containsOne("return R.id.Button;")); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/trycatch/TestTryCatch.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.trycatch; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.hamcrest.CoreMatchers.containsString; 9 | import static org.hamcrest.CoreMatchers.not; 10 | import static org.junit.Assert.assertThat; 11 | 12 | public class TestTryCatch extends IntegrationTest { 13 | 14 | public static class TestCls { 15 | private void f() { 16 | try { 17 | Thread.sleep(50); 18 | } catch (InterruptedException e) { 19 | // ignore 20 | } 21 | } 22 | } 23 | 24 | @Test 25 | public void test() { 26 | ClassNode cls = getClassNode(TestCls.class); 27 | String code = cls.getCode().toString(); 28 | 29 | assertThat(code, containsString("try {")); 30 | assertThat(code, containsString("Thread.sleep(50);")); 31 | assertThat(code, containsString("} catch (InterruptedException e) {")); 32 | assertThat(code, not(containsString("return"))); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /jadx-gui/src/main/java/jadx/gui/utils/CodeLinesInfo.java: -------------------------------------------------------------------------------- 1 | package jadx.gui.utils; 2 | 3 | import jadx.api.JavaClass; 4 | import jadx.api.JavaMethod; 5 | import jadx.api.JavaNode; 6 | 7 | import java.util.Map; 8 | import java.util.NavigableMap; 9 | import java.util.TreeMap; 10 | 11 | public class CodeLinesInfo { 12 | private NavigableMap map = new TreeMap(); 13 | 14 | public CodeLinesInfo(JavaClass cls) { 15 | addClass(cls); 16 | } 17 | 18 | public void addClass(JavaClass cls) { 19 | map.put(cls.getDecompiledLine(), cls); 20 | for (JavaClass innerCls : cls.getInnerClasses()) { 21 | map.put(innerCls.getDecompiledLine(), innerCls); 22 | addClass(innerCls); 23 | } 24 | for (JavaMethod mth : cls.getMethods()) { 25 | map.put(mth.getDecompiledLine(), mth); 26 | } 27 | } 28 | 29 | public JavaNode getJavaNodeByLine(int line) { 30 | Map.Entry entry = map.floorEntry(line); 31 | if (entry == null) { 32 | return null; 33 | } 34 | return entry.getValue(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/instructions/ConstClassNode.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.instructions; 2 | 3 | import jadx.core.dex.instructions.args.ArgType; 4 | import jadx.core.dex.nodes.InsnNode; 5 | 6 | public final class ConstClassNode extends InsnNode { 7 | 8 | private final ArgType clsType; 9 | 10 | public ConstClassNode(ArgType clsType) { 11 | super(InsnType.CONST_CLASS, 0); 12 | this.clsType = clsType; 13 | } 14 | 15 | public ArgType getClsType() { 16 | return clsType; 17 | } 18 | 19 | @Override 20 | public InsnNode copy() { 21 | return copyCommonParams(new ConstClassNode(clsType)); 22 | } 23 | 24 | @Override 25 | public boolean isSame(InsnNode obj) { 26 | if (this == obj) { 27 | return true; 28 | } 29 | if (!(obj instanceof ConstClassNode) || !super.isSame(obj)) { 30 | return false; 31 | } 32 | ConstClassNode other = (ConstClassNode) obj; 33 | return clsType.equals(other.clsType); 34 | } 35 | 36 | @Override 37 | public String toString() { 38 | return super.toString() + " " + clsType; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/synchronize/TestSynchronized2.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.synchronize; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.hamcrest.CoreMatchers.containsString; 9 | import static org.junit.Assert.assertThat; 10 | 11 | public class TestSynchronized2 extends IntegrationTest { 12 | 13 | public static class TestCls { 14 | private static synchronized boolean test(Object obj) { 15 | return obj.toString() != null; 16 | } 17 | } 18 | 19 | @Test 20 | public void test() { 21 | ClassNode cls = getClassNode(TestCls.class); 22 | String code = cls.getCode().toString(); 23 | 24 | assertThat(code, containsString("private static synchronized boolean test(Object obj) {")); 25 | assertThat(code, containsString("obj.toString() != null;")); 26 | // TODO 27 | // assertThat(code, containsString("return obj.toString() != null;")); 28 | // assertThat(code, not(containsString("synchronized ("))); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /jadx-samples/src/main/java/jadx/samples/TestCF4.java: -------------------------------------------------------------------------------- 1 | package jadx.samples; 2 | 3 | public class TestCF4 extends AbstractTest { 4 | 5 | int c; 6 | String d; 7 | String f; 8 | 9 | public void testComplexIf(String a, int b) { 10 | if (d == null || (c == 0 && b != -1 && d.length() == 0)) { 11 | c = a.codePointAt(c); 12 | } else { 13 | if (a.length() != 2) { 14 | c = f.compareTo(a); 15 | } 16 | } 17 | } 18 | 19 | public void checkComplexIf() { 20 | d = null; 21 | f = null; 22 | c = 2; 23 | testComplexIf("abcdef", 0); 24 | assertEquals(c, (int) 'c'); 25 | 26 | d = ""; 27 | f = null; 28 | c = 0; 29 | testComplexIf("abcdef", 0); 30 | assertEquals(c, (int) 'a'); 31 | 32 | d = ""; 33 | f = "1"; 34 | c = 777; 35 | testComplexIf("ab", -1); 36 | assertEquals(c, 777); 37 | } 38 | 39 | @Override 40 | public boolean testRun() throws Exception { 41 | checkComplexIf(); 42 | return true; 43 | } 44 | 45 | public static void main(String[] args) throws Exception { 46 | new TestCF4().testRun(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/attributes/nodes/JumpInfo.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.attributes.nodes; 2 | 3 | import jadx.core.utils.InsnUtils; 4 | 5 | public class JumpInfo { 6 | 7 | private final int src; 8 | private final int dest; 9 | 10 | public JumpInfo(int src, int dest) { 11 | this.src = src; 12 | this.dest = dest; 13 | } 14 | 15 | public int getSrc() { 16 | return src; 17 | } 18 | 19 | public int getDest() { 20 | return dest; 21 | } 22 | 23 | @Override 24 | public int hashCode() { 25 | return 31 * dest + src; 26 | } 27 | 28 | @Override 29 | public boolean equals(Object obj) { 30 | if (this == obj) { 31 | return true; 32 | } 33 | if (obj == null) { 34 | return false; 35 | } 36 | if (getClass() != obj.getClass()) { 37 | return false; 38 | } 39 | JumpInfo other = (JumpInfo) obj; 40 | return dest == other.dest && src == other.src; 41 | } 42 | 43 | @Override 44 | public String toString() { 45 | return "JUMP: " + InsnUtils.formatOffset(src) + " -> " + InsnUtils.formatOffset(dest); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/invoke/TestSuperInvoke.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.invoke; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static jadx.tests.api.utils.JadxMatchers.countString; 9 | import static org.junit.Assert.assertEquals; 10 | import static org.junit.Assert.assertThat; 11 | 12 | public class TestSuperInvoke extends IntegrationTest { 13 | 14 | public class A { 15 | public int a() { 16 | return 1; 17 | } 18 | } 19 | 20 | public class B extends A { 21 | @Override 22 | public int a() { 23 | return super.a() + 2; 24 | } 25 | 26 | public int test() { 27 | return a(); 28 | } 29 | } 30 | 31 | public void check() { 32 | assertEquals(3, new B().test()); 33 | } 34 | 35 | @Test 36 | public void test() { 37 | noDebugInfo(); 38 | ClassNode cls = getClassNode(TestSuperInvoke.class); 39 | String code = cls.getCode().toString(); 40 | 41 | assertThat(code, countString(2, "return super.a() + 2;")); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/conditions/TestConditions14.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.conditions; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static jadx.tests.api.utils.JadxMatchers.containsOne; 9 | import static org.junit.Assert.assertThat; 10 | 11 | public class TestConditions14 extends IntegrationTest { 12 | 13 | public static class TestCls { 14 | 15 | public static boolean test(Object a, Object b) { 16 | boolean r = a == null ? b != null : !a.equals(b); 17 | if (r) { 18 | return false; 19 | } 20 | System.out.println("1"); 21 | return true; 22 | } 23 | } 24 | 25 | @Test 26 | public void test() { 27 | ClassNode cls = getClassNode(TestCls.class); 28 | String code = cls.getCode().toString(); 29 | 30 | assertThat(code, containsOne("boolean r = a == null ? b != null : !a.equals(b);")); 31 | assertThat(code, containsOne("if (r) {")); 32 | assertThat(code, containsOne("System.out.println(\"1\");")); 33 | 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/loops/TestNestedLoops2.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.loops; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import java.util.List; 7 | 8 | import org.junit.Test; 9 | 10 | import static jadx.tests.api.utils.JadxMatchers.containsOne; 11 | import static org.junit.Assert.assertThat; 12 | 13 | public class TestNestedLoops2 extends IntegrationTest { 14 | 15 | public static class TestCls { 16 | 17 | private boolean test(List list) { 18 | int j = 0; 19 | for (int i = 0; i < list.size(); i++) { 20 | String s = list.get(i); 21 | while (j < s.length()) { 22 | j++; 23 | } 24 | } 25 | return j > 10; 26 | } 27 | } 28 | 29 | @Test 30 | public void test() { 31 | ClassNode cls = getClassNode(TestCls.class); 32 | String code = cls.getCode().toString(); 33 | 34 | assertThat(code, containsOne("for (int i = 0; i < list.size(); i++) {")); 35 | assertThat(code, containsOne("while (j < ((String) list.get(i)).length()) {")); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/synchronize/TestSynchronized3.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.synchronize; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static jadx.tests.api.utils.JadxMatchers.containsLines; 9 | import static org.junit.Assert.assertThat; 10 | 11 | public class TestSynchronized3 extends IntegrationTest { 12 | 13 | public static class TestCls { 14 | private int x; 15 | 16 | public void f() { 17 | } 18 | 19 | public void test() { 20 | while (true) { 21 | synchronized (this) { 22 | if (x == 0) { 23 | throw new IllegalStateException("bad luck"); 24 | } 25 | x++; 26 | if (x == 10) { 27 | break; 28 | } 29 | } 30 | this.x++; 31 | f(); 32 | } 33 | } 34 | } 35 | 36 | @Test 37 | public void test() { 38 | ClassNode cls = getClassNode(TestCls.class); 39 | String code = cls.getCode().toString(); 40 | 41 | assertThat(code, containsLines(3, "}", "this.x++;", "f();")); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/variables/TestVariables3.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.variables; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.hamcrest.CoreMatchers.containsString; 9 | import static org.junit.Assert.assertThat; 10 | 11 | public class TestVariables3 extends IntegrationTest { 12 | 13 | public static class TestCls { 14 | String test(Object s) { 15 | int i; 16 | if (s == null) { 17 | i = 2; 18 | } else { 19 | i = 3; 20 | s = null; 21 | } 22 | return s + " " + i; 23 | } 24 | } 25 | 26 | @Test 27 | public void test() { 28 | ClassNode cls = getClassNode(TestCls.class); 29 | String code = cls.getCode().toString(); 30 | 31 | assertThat(code, containsString("int i;")); 32 | assertThat(code, containsString("i = 2;")); 33 | assertThat(code, containsString("i = 3;")); 34 | assertThat(code, containsString("s = null;")); 35 | assertThat(code, containsString("return s + \" \" + i;")); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /jadx-gui/src/main/java/jadx/gui/settings/WindowLocation.java: -------------------------------------------------------------------------------- 1 | package jadx.gui.settings; 2 | 3 | public class WindowLocation { 4 | 5 | private final String windowId; 6 | 7 | private final int x; 8 | private final int y; 9 | private final int width; 10 | private final int height; 11 | 12 | public WindowLocation(String windowId, int x, int y, int width, int height) { 13 | this.windowId = windowId; 14 | this.x = x; 15 | this.y = y; 16 | this.width = width; 17 | this.height = height; 18 | } 19 | 20 | public String getWindowId() { 21 | return windowId; 22 | } 23 | 24 | public int getX() { 25 | return x; 26 | } 27 | 28 | public int getY() { 29 | return y; 30 | } 31 | 32 | public int getWidth() { 33 | return width; 34 | } 35 | 36 | public int getHeight() { 37 | return height; 38 | } 39 | 40 | @Override 41 | public String toString() { 42 | return "WindowLocation{" + 43 | "id='" + windowId + '\'' + 44 | ", x=" + x + 45 | ", y=" + y + 46 | ", width=" + width + 47 | ", height=" + height + 48 | '}'; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/visitors/blocksmaker/helpers/BlocksPair.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.visitors.blocksmaker.helpers; 2 | 3 | import jadx.core.dex.nodes.BlockNode; 4 | 5 | public final class BlocksPair { 6 | private final BlockNode first; 7 | private final BlockNode second; 8 | 9 | public BlocksPair(BlockNode first, BlockNode second) { 10 | this.first = first; 11 | this.second = second; 12 | } 13 | 14 | public BlockNode getFirst() { 15 | return first; 16 | } 17 | 18 | public BlockNode getSecond() { 19 | return second; 20 | } 21 | 22 | @Override 23 | public int hashCode() { 24 | return 31 * first.hashCode() + second.hashCode(); 25 | } 26 | 27 | @Override 28 | public boolean equals(Object o) { 29 | if (this == o) { 30 | return true; 31 | } 32 | if (!(o instanceof BlocksPair)) { 33 | return false; 34 | } 35 | BlocksPair other = (BlocksPair) o; 36 | return first.equals(other.first) && second.equals(other.second); 37 | } 38 | 39 | @Override 40 | public String toString() { 41 | return "(" + first + ", " + second + ")"; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/inner/TestInnerClass3.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.inner; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.hamcrest.CoreMatchers.containsString; 9 | import static org.hamcrest.CoreMatchers.not; 10 | import static org.junit.Assert.assertThat; 11 | 12 | public class TestInnerClass3 extends IntegrationTest { 13 | 14 | public static class TestCls { 15 | private String c; 16 | 17 | private void setC(String c) { 18 | this.c = c; 19 | } 20 | 21 | public class C { 22 | public String c() { 23 | setC("c"); 24 | return c; 25 | } 26 | } 27 | } 28 | 29 | @Test 30 | public void test() { 31 | ClassNode cls = getClassNode(TestCls.class); 32 | String code = cls.getCode().toString(); 33 | 34 | assertThat(code, not(containsString("synthetic"))); 35 | assertThat(code, not(containsString("access$"))); 36 | assertThat(code, not(containsString("x0"))); 37 | assertThat(code, containsString("setC(\"c\");")); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/invoke/TestConstructorInvoke.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.invoke; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.hamcrest.Matchers.containsString; 9 | import static org.junit.Assert.assertThat; 10 | 11 | public class TestConstructorInvoke extends IntegrationTest { 12 | 13 | public class TestCls { 14 | void test(String root, String name) { 15 | ViewHolder viewHolder = new ViewHolder(root, name); 16 | } 17 | 18 | private final class ViewHolder { 19 | private int mElements = 0; 20 | private final String mRoot; 21 | private String mName; 22 | 23 | private ViewHolder(String root, String name) { 24 | this.mRoot = root; 25 | this.mName = name; 26 | } 27 | } 28 | } 29 | 30 | @Test 31 | public void test() { 32 | ClassNode cls = getClassNode(TestConstructorInvoke.class); 33 | String code = cls.getCode().toString(); 34 | 35 | assertThat(code, containsString("new ViewHolder(root, name);")); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/instructions/args/NamedArg.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.instructions.args; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | public final class NamedArg extends InsnArg implements Named { 6 | 7 | @NotNull 8 | private String name; 9 | 10 | public NamedArg(@NotNull String name, @NotNull ArgType type) { 11 | this.name = name; 12 | this.type = type; 13 | } 14 | 15 | @NotNull 16 | public String getName() { 17 | return name; 18 | } 19 | 20 | @Override 21 | public boolean isNamed() { 22 | return true; 23 | } 24 | 25 | public void setName(@NotNull String name) { 26 | this.name = name; 27 | } 28 | 29 | @Override 30 | public boolean equals(Object o) { 31 | if (this == o) { 32 | return true; 33 | } 34 | if (!(o instanceof NamedArg)) { 35 | return false; 36 | } 37 | return name.equals(((NamedArg) o).name); 38 | 39 | } 40 | 41 | @Override 42 | public int hashCode() { 43 | return name.hashCode(); 44 | } 45 | 46 | @Override 47 | public String toString() { 48 | return "(" + name + " " + type + ")"; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/fallback/TestFallbackMode.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.fallback; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.hamcrest.CoreMatchers.containsString; 9 | import static org.hamcrest.CoreMatchers.not; 10 | import static org.junit.Assert.assertThat; 11 | 12 | public class TestFallbackMode extends IntegrationTest { 13 | 14 | public static class TestCls { 15 | 16 | public int test(int a) { 17 | while (a < 10) { 18 | a++; 19 | } 20 | return a; 21 | } 22 | } 23 | 24 | @Test 25 | public void test() { 26 | setFallback(); 27 | disableCompilation(); 28 | 29 | ClassNode cls = getClassNode(TestCls.class); 30 | String code = cls.getCode().toString(); 31 | 32 | assertThat(code, containsString("public int test(int r2) {")); 33 | assertThat(code, containsString("r1 = this;")); 34 | assertThat(code, containsString("L_0x0004:")); 35 | assertThat(code, not(containsString("throw new UnsupportedOperationException"))); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/loops/TestArrayForEach2.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.loops; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static jadx.tests.api.utils.JadxMatchers.containsLines; 9 | import static org.junit.Assert.assertThat; 10 | 11 | public class TestArrayForEach2 extends IntegrationTest { 12 | 13 | public static class TestCls { 14 | private void test(String str) { 15 | for (String s : str.split("\n")) { 16 | String t = s.trim(); 17 | if (t.length() > 0) { 18 | System.out.println(t); 19 | } 20 | } 21 | } 22 | } 23 | 24 | @Test 25 | public void test() { 26 | ClassNode cls = getClassNode(TestCls.class); 27 | String code = cls.getCode().toString(); 28 | 29 | assertThat(code, containsLines(2, 30 | "for (String s : str.split(\"\\n\")) {", 31 | indent(1) + "String t = s.trim();", 32 | indent(1) + "if (t.length() > 0) {", 33 | indent(2) + "System.out.println(t);", 34 | indent(1) + "}", 35 | "}" 36 | )); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/conditions/TestConditions11.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.conditions; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static jadx.tests.api.utils.JadxMatchers.containsOne; 9 | import static org.hamcrest.CoreMatchers.containsString; 10 | import static org.hamcrest.CoreMatchers.not; 11 | import static org.junit.Assert.assertThat; 12 | 13 | public class TestConditions11 extends IntegrationTest { 14 | 15 | public static class TestCls { 16 | 17 | public void test(boolean a, int b) { 18 | if (a || b > 2) { 19 | f(); 20 | } 21 | } 22 | 23 | private void f() { 24 | } 25 | } 26 | 27 | @Test 28 | public void test() { 29 | ClassNode cls = getClassNode(TestCls.class); 30 | String code = cls.getCode().toString(); 31 | 32 | assertThat(code, containsOne("if (a || b > 2) {")); 33 | assertThat(code, containsOne("f();")); 34 | assertThat(code, not(containsString("return"))); 35 | assertThat(code, not(containsString("else"))); 36 | 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/enums/TestEnumsWithConsts.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.enums; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static jadx.tests.api.utils.JadxMatchers.containsLines; 9 | import static org.junit.Assert.assertThat; 10 | 11 | public class TestEnumsWithConsts extends IntegrationTest { 12 | 13 | public static class TestCls { 14 | 15 | public static final int C1 = 1; 16 | public static final int C2 = 2; 17 | public static final int C4 = 4; 18 | 19 | public static final String S = "NORTH"; 20 | 21 | public enum Direction { 22 | NORTH, 23 | SOUTH, 24 | EAST, 25 | WEST 26 | } 27 | } 28 | 29 | @Test 30 | public void test() { 31 | ClassNode cls = getClassNode(TestCls.class); 32 | String code = cls.getCode().toString(); 33 | 34 | assertThat(code, containsLines(1, "public enum Direction {", 35 | indent(1) + "NORTH,", 36 | indent(1) + "SOUTH,", 37 | indent(1) + "EAST,", 38 | indent(1) + "WEST", 39 | "}")); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/types/TestTypeResolver3.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.types; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static jadx.tests.api.utils.JadxMatchers.containsOne; 9 | import static org.junit.Assert.assertThat; 10 | 11 | public class TestTypeResolver3 extends IntegrationTest { 12 | 13 | public static class TestCls { 14 | 15 | public int test(String s1, String s2) { 16 | int cmp = s2.compareTo(s1); 17 | if (cmp != 0) { 18 | return cmp; 19 | } 20 | return s1.length() == s2.length() ? 0 : s1.length() < s2.length() ? -1 : 1; 21 | } 22 | } 23 | 24 | @Test 25 | public void test() { 26 | ClassNode cls = getClassNode(TestCls.class); 27 | String code = cls.getCode().toString(); 28 | 29 | // TODO inline into return 30 | assertThat(code, containsOne("s1.length() == s2.length() ? 0 : s1.length() < s2.length() ? -1 : 1;")); 31 | } 32 | 33 | @Test 34 | public void test2() { 35 | noDebugInfo(); 36 | getClassNode(TestCls.class); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/api/ResourceType.java: -------------------------------------------------------------------------------- 1 | package jadx.api; 2 | 3 | public enum ResourceType { 4 | CODE(".dex", ".jar", ".class"), 5 | MANIFEST("AndroidManifest.xml"), 6 | XML(".xml"), 7 | ARSC(".arsc"), 8 | FONT(".ttf"), 9 | IMG(".png", ".gif", ".jpg"), 10 | LIB(".so"), 11 | UNKNOWN; 12 | 13 | private final String[] exts; 14 | 15 | ResourceType(String... exts) { 16 | this.exts = exts; 17 | } 18 | 19 | public String[] getExts() { 20 | return exts; 21 | } 22 | 23 | public static ResourceType getFileType(String fileName) { 24 | for (ResourceType type : ResourceType.values()) { 25 | for (String ext : type.getExts()) { 26 | if (fileName.endsWith(ext)) { 27 | return type; 28 | } 29 | } 30 | } 31 | return UNKNOWN; 32 | } 33 | 34 | public static boolean isSupportedForUnpack(ResourceType type) { 35 | switch (type) { 36 | case CODE: 37 | case LIB: 38 | case FONT: 39 | case UNKNOWN: 40 | return false; 41 | 42 | case MANIFEST: 43 | case XML: 44 | case ARSC: 45 | case IMG: 46 | return true; 47 | } 48 | return false; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/generics/TestGenerics.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.generics; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import java.util.List; 7 | 8 | import org.junit.Test; 9 | 10 | import static org.hamcrest.CoreMatchers.containsString; 11 | import static org.junit.Assert.assertThat; 12 | 13 | public class TestGenerics extends IntegrationTest { 14 | 15 | public static class TestCls { 16 | class A { 17 | } 18 | 19 | public static void mthWildcard(List list) { 20 | } 21 | 22 | public static void mthExtends(List list) { 23 | } 24 | 25 | public static void mthSuper(List list) { 26 | } 27 | } 28 | 29 | @Test 30 | public void test() { 31 | ClassNode cls = getClassNode(TestCls.class); 32 | String code = cls.getCode().toString(); 33 | 34 | assertThat(code, containsString("mthWildcard(List list)")); 35 | assertThat(code, containsString("mthExtends(List list)")); 36 | assertThat(code, containsString("mthSuper(List list)")); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/instructions/IndexInsnNode.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.instructions; 2 | 3 | import jadx.core.dex.nodes.InsnNode; 4 | import jadx.core.utils.InsnUtils; 5 | 6 | public class IndexInsnNode extends InsnNode { 7 | 8 | private final Object index; 9 | 10 | public IndexInsnNode(InsnType type, Object index, int argCount) { 11 | super(type, argCount); 12 | this.index = index; 13 | } 14 | 15 | public Object getIndex() { 16 | return index; 17 | } 18 | 19 | @Override 20 | public IndexInsnNode copy() { 21 | return copyCommonParams(new IndexInsnNode(insnType, index, getArgsCount())); 22 | } 23 | 24 | @Override 25 | public boolean isSame(InsnNode obj) { 26 | if (this == obj) { 27 | return true; 28 | } 29 | if (!(obj instanceof IndexInsnNode) || !super.isSame(obj)) { 30 | return false; 31 | } 32 | IndexInsnNode other = (IndexInsnNode) obj; 33 | return index == null ? other.index == null : index.equals(other.index); 34 | } 35 | 36 | @Override 37 | public String toString() { 38 | return super.toString() + " " + InsnUtils.indexToString(index); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/usethis/TestRedundantThis.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.usethis; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import static org.hamcrest.CoreMatchers.containsString; 7 | import static org.hamcrest.CoreMatchers.not; 8 | import static org.junit.Assert.assertThat; 9 | 10 | public class TestRedundantThis extends IntegrationTest { 11 | 12 | public static class TestCls { 13 | public int field1 = 1; 14 | public int field2 = 2; 15 | 16 | public boolean f1() { 17 | return false; 18 | } 19 | 20 | public int method() { 21 | f1(); 22 | return field1; 23 | } 24 | 25 | public void method2(int field2) { 26 | this.field2 = field2; 27 | } 28 | } 29 | 30 | // @Test 31 | public void test() { 32 | ClassNode cls = getClassNode(TestCls.class); 33 | String code = cls.getCode().toString(); 34 | 35 | assertThat(code, not(containsString("this.f1();"))); 36 | assertThat(code, not(containsString("return this.field1;"))); 37 | 38 | assertThat(code, containsString("this.field2 = field2;")); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/inline/TestInline2.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.inline; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static jadx.tests.api.utils.JadxMatchers.containsOne; 9 | import static org.junit.Assert.assertThat; 10 | 11 | public class TestInline2 extends IntegrationTest { 12 | 13 | public static class TestCls { 14 | public int test() throws InterruptedException { 15 | int[] a = new int[]{1, 2, 4, 6, 8}; 16 | int b = 0; 17 | for (int i = 0; i < a.length; i += 2) { 18 | b += a[i]; 19 | } 20 | for (long i = b; i > 0; i--) { 21 | b += i; 22 | } 23 | return b; 24 | } 25 | } 26 | 27 | @Test 28 | public void test() { 29 | ClassNode cls = getClassNode(TestCls.class); 30 | String code = cls.getCode().toString(); 31 | 32 | assertThat(code, containsOne("int[] a = new int[]{1, 2, 4, 6, 8};")); 33 | assertThat(code, containsOne("for (int i = 0; i < a.length; i += 2) {")); 34 | assertThat(code, containsOne("for (long i2 = (long) b; i2 > 0; i2--) {")); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/loops/TestLoopDetection3.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.loops; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.hamcrest.CoreMatchers.containsString; 9 | import static org.junit.Assert.assertThat; 10 | 11 | public class TestLoopDetection3 extends IntegrationTest { 12 | 13 | public static class TestCls { 14 | 15 | private void test(TestCls parent, int pos) { 16 | Object item; 17 | while (--pos >= 0) { 18 | item = parent.get(pos); 19 | if (item instanceof String) { 20 | func((String) item); 21 | return; 22 | } 23 | } 24 | } 25 | 26 | private Object get(int pos) { 27 | return null; 28 | } 29 | 30 | private void func(String item) { 31 | } 32 | } 33 | 34 | @Test 35 | public void test() { 36 | ClassNode cls = getClassNode(TestCls.class); 37 | String code = cls.getCode().toString(); 38 | 39 | assertThat(code, containsString("while")); 40 | // TODO 41 | // assertThat(code, containsString("while (--pos >= 0) {")); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/instructions/FilledNewArrayNode.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.instructions; 2 | 3 | import jadx.core.dex.instructions.args.ArgType; 4 | import jadx.core.dex.nodes.InsnNode; 5 | 6 | import org.jetbrains.annotations.NotNull; 7 | 8 | public class FilledNewArrayNode extends InsnNode { 9 | 10 | private final ArgType elemType; 11 | 12 | public FilledNewArrayNode(@NotNull ArgType elemType, int size) { 13 | super(InsnType.FILLED_NEW_ARRAY, size); 14 | this.elemType = elemType; 15 | } 16 | 17 | public ArgType getElemType() { 18 | return elemType; 19 | } 20 | 21 | public ArgType getArrayType() { 22 | return ArgType.array(elemType); 23 | } 24 | 25 | @Override 26 | public boolean isSame(InsnNode obj) { 27 | if (this == obj) { 28 | return true; 29 | } 30 | if (!(obj instanceof FilledNewArrayNode) || !super.isSame(obj)) { 31 | return false; 32 | } 33 | FilledNewArrayNode other = (FilledNewArrayNode) obj; 34 | return elemType == other.elemType; 35 | } 36 | 37 | @Override 38 | public String toString() { 39 | return super.toString() + " elemType: " + elemType; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/arith/TestFieldIncrement.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.arith; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.hamcrest.CoreMatchers.containsString; 9 | import static org.junit.Assert.assertThat; 10 | 11 | public class TestFieldIncrement extends IntegrationTest { 12 | 13 | public static class TestCls { 14 | public int instanceField = 1; 15 | public static int staticField = 1; 16 | public static String result = ""; 17 | 18 | public void method() { 19 | instanceField++; 20 | } 21 | 22 | public void method2() { 23 | staticField--; 24 | } 25 | 26 | public void method3(String s) { 27 | result += s + '_'; 28 | } 29 | } 30 | 31 | @Test 32 | public void test() { 33 | ClassNode cls = getClassNode(TestCls.class); 34 | String code = cls.getCode().toString(); 35 | 36 | assertThat(code, containsString("instanceField++;")); 37 | assertThat(code, containsString("staticField--;")); 38 | assertThat(code, containsString("result += s + '_';")); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/instructions/InsnType.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.instructions; 2 | 3 | public enum InsnType { 4 | 5 | CONST, 6 | CONST_STR, 7 | CONST_CLASS, 8 | 9 | ARITH, 10 | NEG, 11 | 12 | MOVE, 13 | CAST, 14 | 15 | RETURN, 16 | GOTO, 17 | 18 | THROW, 19 | MOVE_EXCEPTION, 20 | 21 | CMP_L, 22 | CMP_G, 23 | IF, 24 | SWITCH, 25 | 26 | MONITOR_ENTER, 27 | MONITOR_EXIT, 28 | 29 | CHECK_CAST, 30 | INSTANCE_OF, 31 | 32 | ARRAY_LENGTH, 33 | FILL_ARRAY, 34 | FILLED_NEW_ARRAY, 35 | 36 | AGET, 37 | APUT, 38 | 39 | NEW_ARRAY, 40 | NEW_INSTANCE, 41 | 42 | IGET, 43 | IPUT, 44 | 45 | SGET, 46 | SPUT, 47 | 48 | INVOKE, 49 | 50 | // *** Additional instructions *** 51 | 52 | // replacement for removed instructions 53 | NOP, 54 | 55 | TERNARY, 56 | CONSTRUCTOR, 57 | 58 | BREAK, 59 | CONTINUE, 60 | 61 | // strings concatenation 62 | STR_CONCAT, 63 | 64 | // just generate one argument 65 | ONE_ARG, 66 | PHI, 67 | 68 | // merge all arguments in one 69 | MERGE, 70 | 71 | // TODO: now multidimensional arrays created using Array.newInstance function 72 | NEW_MULTIDIM_ARRAY 73 | } 74 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/loops/TestLoopCondition4.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.loops; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static jadx.tests.api.utils.JadxMatchers.containsOne; 9 | import static org.junit.Assert.assertThat; 10 | 11 | public class TestLoopCondition4 extends IntegrationTest { 12 | 13 | public static class TestCls { 14 | public static void test() { 15 | int n = -1; 16 | while (n < 0) { 17 | n += 12; 18 | } 19 | while (n > 11) { 20 | n -= 12; 21 | } 22 | System.out.println(n); 23 | } 24 | } 25 | 26 | @Test 27 | public void test() { 28 | ClassNode cls = getClassNode(TestCls.class); 29 | String code = cls.getCode().toString(); 30 | 31 | assertThat(code, containsOne("int n = -1;")); 32 | assertThat(code, containsOne("while (n < 0) {")); 33 | assertThat(code, containsOne("n += 12;")); 34 | assertThat(code, containsOne("while (n > 11) {")); 35 | assertThat(code, containsOne("n -= 12;")); 36 | assertThat(code, containsOne("System.out.println(n);")); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/api/utils/JadxMatchers.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.api.utils; 2 | 3 | import jadx.core.codegen.CodeWriter; 4 | 5 | import org.hamcrest.Matcher; 6 | 7 | public class JadxMatchers { 8 | 9 | public static Matcher countString(int count, String substring) { 10 | return new CountString(count, substring); 11 | } 12 | 13 | public static Matcher containsOne(String substring) { 14 | return countString(1, substring); 15 | } 16 | 17 | public static Matcher containsLines(String... lines) { 18 | StringBuilder sb = new StringBuilder(); 19 | for (String line : lines) { 20 | sb.append(line).append(CodeWriter.NL); 21 | } 22 | return countString(1, sb.toString()); 23 | } 24 | 25 | public static Matcher containsLines(int commonIndent, String... lines) { 26 | String indent = TestUtils.indent(commonIndent); 27 | StringBuilder sb = new StringBuilder(); 28 | for (String line : lines) { 29 | if (!line.isEmpty()) { 30 | sb.append(indent); 31 | sb.append(line); 32 | } 33 | sb.append(CodeWriter.NL); 34 | } 35 | return countString(1, sb.toString()); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/loops/TestLoopDetection2.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.loops; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static jadx.tests.api.utils.JadxMatchers.containsOne; 9 | import static org.hamcrest.CoreMatchers.containsString; 10 | import static org.hamcrest.CoreMatchers.not; 11 | import static org.junit.Assert.assertThat; 12 | 13 | public class TestLoopDetection2 extends IntegrationTest { 14 | 15 | public static class TestCls { 16 | 17 | public int test(int a, int b) { 18 | int c = a + b; 19 | for (int i = a; i < b; i++) { 20 | if (i == 7) { 21 | c += 2; 22 | } else { 23 | c *= 2; 24 | } 25 | } 26 | c--; 27 | return c; 28 | } 29 | } 30 | 31 | @Test 32 | public void test() { 33 | ClassNode cls = getClassNode(TestCls.class); 34 | String code = cls.getCode().toString(); 35 | 36 | assertThat(code, containsOne("int c = a + b;")); 37 | assertThat(code, containsOne("for (int i = a; i < b; i++) {")); 38 | assertThat(code, not(containsString("c_2"))); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/clsp/NClass.java: -------------------------------------------------------------------------------- 1 | package jadx.core.clsp; 2 | 3 | /** 4 | * Class node in classpath graph 5 | */ 6 | public class NClass { 7 | 8 | private final String name; 9 | private NClass[] parents; 10 | private int id; 11 | 12 | public NClass(String name, int id) { 13 | this.name = name; 14 | this.id = id; 15 | } 16 | 17 | public String getName() { 18 | return name; 19 | } 20 | 21 | public int getId() { 22 | return id; 23 | } 24 | 25 | public void setId(int id) { 26 | this.id = id; 27 | } 28 | 29 | public NClass[] getParents() { 30 | return parents; 31 | } 32 | 33 | public void setParents(NClass[] parents) { 34 | this.parents = parents; 35 | } 36 | 37 | @Override 38 | public int hashCode() { 39 | return name.hashCode(); 40 | } 41 | 42 | @Override 43 | public boolean equals(Object o) { 44 | if (this == o) { 45 | return true; 46 | } 47 | if (o == null || getClass() != o.getClass()) { 48 | return false; 49 | } 50 | NClass nClass = (NClass) o; 51 | return name.equals(nClass.name); 52 | } 53 | 54 | @Override 55 | public String toString() { 56 | return name; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/inner/TestRFieldRestore.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.inner; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | 9 | import org.junit.Test; 10 | 11 | import static jadx.tests.api.utils.JadxMatchers.containsOne; 12 | import static org.hamcrest.Matchers.containsString; 13 | import static org.hamcrest.Matchers.not; 14 | import static org.junit.Assert.assertThat; 15 | 16 | public class TestRFieldRestore extends IntegrationTest { 17 | 18 | public static class TestCls { 19 | public int test() { 20 | return 2131230730; 21 | } 22 | } 23 | 24 | @Test 25 | public void test() { 26 | // unknown R class 27 | disableCompilation(); 28 | 29 | Map map = new HashMap(); 30 | map.put(2131230730, "id.Button"); 31 | setResMap(map); 32 | 33 | ClassNode cls = getClassNode(TestCls.class); 34 | String code = cls.getCode().toString(); 35 | assertThat(code, containsOne("return R.id.Button;")); 36 | assertThat(code, not(containsString("import R;"))); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/loops/TestLoopCondition3.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.loops; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static jadx.tests.api.utils.JadxMatchers.containsOne; 9 | import static org.junit.Assert.assertThat; 10 | 11 | public class TestLoopCondition3 extends IntegrationTest { 12 | 13 | public static class TestCls { 14 | 15 | public static void test(int a, int b, int c) { 16 | while (a < 12) { 17 | if (b + a < 9 && b < 8) { 18 | if (b >= 2 && a > -1 && b < 6) { 19 | System.out.println("OK"); 20 | c = b + 1; 21 | } 22 | b = a; 23 | } 24 | c = b; 25 | b++; 26 | b = c; 27 | a++; 28 | } 29 | } 30 | } 31 | 32 | @Test 33 | public void test() { 34 | ClassNode cls = getClassNode(TestCls.class); 35 | String code = cls.getCode().toString(); 36 | 37 | assertThat(code, containsOne("while (a < 12) {")); 38 | assertThat(code, containsOne("if (b + a < 9 && b < 8) {")); 39 | assertThat(code, containsOne("if (b >= 2 && a > -1 && b < 6) {")); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/loops/TestIfInLoop2.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.loops; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.hamcrest.CoreMatchers.containsString; 9 | import static org.hamcrest.CoreMatchers.not; 10 | import static org.junit.Assert.assertThat; 11 | 12 | public class TestIfInLoop2 extends IntegrationTest { 13 | 14 | public static class TestCls { 15 | public static void test(String str) { 16 | int len = str.length(); 17 | int at = 0; 18 | while (at < len) { 19 | char c = str.charAt(at); 20 | int endAt = at + 1; 21 | if (c == 'A') { 22 | while (endAt < len) { 23 | c = str.charAt(endAt); 24 | if (c == 'B') { 25 | break; 26 | } 27 | endAt++; 28 | } 29 | } 30 | at = endAt; 31 | } 32 | } 33 | } 34 | 35 | @Test 36 | public void test() { 37 | ClassNode cls = getClassNode(TestCls.class); 38 | String code = cls.getCode().toString(); 39 | 40 | assertThat(code, not(containsString("for (int at = 0; at < len; at = endAt) {"))); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/instructions/NewArrayNode.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.instructions; 2 | 3 | import jadx.core.dex.instructions.args.ArgType; 4 | import jadx.core.dex.instructions.args.InsnArg; 5 | import jadx.core.dex.instructions.args.RegisterArg; 6 | import jadx.core.dex.nodes.InsnNode; 7 | 8 | import org.jetbrains.annotations.NotNull; 9 | 10 | public class NewArrayNode extends InsnNode { 11 | 12 | private final ArgType arrType; 13 | 14 | public NewArrayNode(@NotNull ArgType arrType, RegisterArg res, InsnArg size) { 15 | super(InsnType.NEW_ARRAY, 1); 16 | this.arrType = arrType; 17 | setResult(res); 18 | addArg(size); 19 | } 20 | 21 | public ArgType getArrayType() { 22 | return arrType; 23 | } 24 | 25 | @Override 26 | public boolean isSame(InsnNode obj) { 27 | if (this == obj) { 28 | return true; 29 | } 30 | if (!(obj instanceof NewArrayNode) || !super.isSame(obj)) { 31 | return false; 32 | } 33 | NewArrayNode other = (NewArrayNode) obj; 34 | return arrType == other.arrType; 35 | } 36 | 37 | @Override 38 | public String toString() { 39 | return super.toString() + " type: " + arrType; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/conditions/TestTernaryInIf.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.conditions; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static jadx.tests.api.utils.JadxMatchers.containsOne; 9 | import static org.hamcrest.CoreMatchers.containsString; 10 | import static org.hamcrest.CoreMatchers.not; 11 | import static org.junit.Assert.assertThat; 12 | 13 | public class TestTernaryInIf extends IntegrationTest { 14 | 15 | public static class TestCls { 16 | public boolean test1(boolean a, boolean b, boolean c) { 17 | return a ? b : c; 18 | } 19 | 20 | public int test2(boolean a, boolean b, boolean c) { 21 | return (a ? b : c) ? 1 : 2; 22 | } 23 | } 24 | 25 | @Test 26 | public void test() { 27 | ClassNode cls = getClassNode(TestCls.class); 28 | String code = cls.getCode().toString(); 29 | 30 | assertThat(code, containsOne("return a ? b : c;")); 31 | assertThat(code, containsOne("return (a ? b : c) ? 1 : 2;")); 32 | assertThat(code, not(containsString("if"))); 33 | assertThat(code, not(containsString("else"))); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /jadx-gui/src/main/java/jadx/gui/utils/Position.java: -------------------------------------------------------------------------------- 1 | package jadx.gui.utils; 2 | 3 | import jadx.api.CodePosition; 4 | import jadx.gui.treemodel.JClass; 5 | import jadx.gui.treemodel.JNode; 6 | 7 | public class Position { 8 | private final JNode node; 9 | private final int line; 10 | 11 | public Position(CodePosition pos) { 12 | this.node = new JClass(pos.getJavaClass()); 13 | this.line = pos.getLine(); 14 | } 15 | 16 | public Position(JNode node, int line) { 17 | this.node = node; 18 | this.line = line; 19 | } 20 | 21 | public JNode getNode() { 22 | return node; 23 | } 24 | 25 | public int getLine() { 26 | return line; 27 | } 28 | 29 | @Override 30 | public boolean equals(Object obj) { 31 | if (this == obj) { 32 | return true; 33 | } 34 | if (!(obj instanceof Position)) { 35 | return false; 36 | } 37 | Position position = (Position) obj; 38 | return line == position.line && node.equals(position.node); 39 | } 40 | 41 | @Override 42 | public int hashCode() { 43 | return 31 * node.hashCode() + line; 44 | } 45 | 46 | @Override 47 | public String toString() { 48 | return "Position: " + node + " : " + line; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /jadx-gui/src/main/java/jadx/gui/JadxGUI.java: -------------------------------------------------------------------------------- 1 | package jadx.gui; 2 | 3 | import jadx.gui.settings.JadxSettings; 4 | import jadx.gui.settings.JadxSettingsAdapter; 5 | import jadx.gui.ui.MainWindow; 6 | import jadx.gui.utils.LogCollector; 7 | 8 | import javax.swing.SwingUtilities; 9 | import javax.swing.UIManager; 10 | 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | 14 | public class JadxGUI { 15 | private static final Logger LOG = LoggerFactory.getLogger(JadxGUI.class); 16 | 17 | public static void main(String[] args) { 18 | try { 19 | LogCollector.register(); 20 | final JadxSettings jadxArgs = JadxSettingsAdapter.load(); 21 | // overwrite loaded settings by command line arguments 22 | if (!jadxArgs.processArgs(args)) { 23 | return; 24 | } 25 | UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 26 | SwingUtilities.invokeLater(new Runnable() { 27 | public void run() { 28 | MainWindow window = new MainWindow(jadxArgs); 29 | window.open(); 30 | } 31 | }); 32 | } catch (Throwable e) { 33 | LOG.error("Error: {}", e.getMessage(), e); 34 | System.exit(1); 35 | } 36 | } 37 | } 38 | 39 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/visitors/DepthTraversal.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.visitors; 2 | 3 | import jadx.core.dex.attributes.AType; 4 | import jadx.core.dex.nodes.ClassNode; 5 | import jadx.core.dex.nodes.MethodNode; 6 | import jadx.core.utils.ErrorsCounter; 7 | 8 | public class DepthTraversal { 9 | 10 | public static void visit(IDexTreeVisitor visitor, ClassNode cls) { 11 | try { 12 | if (visitor.visit(cls)) { 13 | for (ClassNode inCls : cls.getInnerClasses()) { 14 | visit(visitor, inCls); 15 | } 16 | for (MethodNode mth : cls.getMethods()) { 17 | visit(visitor, mth); 18 | } 19 | } 20 | } catch (Throwable e) { 21 | ErrorsCounter.classError(cls, 22 | e.getClass().getSimpleName() + " in pass: " + visitor.getClass().getSimpleName(), e); 23 | } 24 | } 25 | 26 | public static void visit(IDexTreeVisitor visitor, MethodNode mth) { 27 | if (mth.contains(AType.JADX_ERROR)) { 28 | return; 29 | } 30 | try { 31 | visitor.visit(mth); 32 | } catch (Throwable e) { 33 | ErrorsCounter.methodError(mth, 34 | e.getClass().getSimpleName() + " in pass: " + visitor.getClass().getSimpleName(), e); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/attributes/annotations/Annotation.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.attributes.annotations; 2 | 3 | import jadx.core.dex.instructions.args.ArgType; 4 | 5 | import java.util.Map; 6 | 7 | public class Annotation { 8 | 9 | public enum Visibility { 10 | BUILD, RUNTIME, SYSTEM 11 | } 12 | 13 | private final Visibility visibility; 14 | private final ArgType atype; 15 | private final Map values; 16 | 17 | public Annotation(Visibility visibility, ArgType type, Map values) { 18 | this.visibility = visibility; 19 | this.atype = type; 20 | this.values = values; 21 | } 22 | 23 | public Visibility getVisibility() { 24 | return visibility; 25 | } 26 | 27 | public ArgType getType() { 28 | return atype; 29 | } 30 | 31 | public String getAnnotationClass() { 32 | return atype.getObject(); 33 | } 34 | 35 | public Map getValues() { 36 | return values; 37 | } 38 | 39 | public Object getDefaultValue() { 40 | return values.get("value"); 41 | } 42 | 43 | @Override 44 | public String toString() { 45 | return "Annotation[" + visibility + ", " + atype + ", " + values + "]"; 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/conditions/TestTernary.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.conditions; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.hamcrest.CoreMatchers.containsString; 9 | import static org.hamcrest.CoreMatchers.not; 10 | import static org.junit.Assert.assertThat; 11 | import static org.junit.Assert.assertTrue; 12 | 13 | public class TestTernary extends IntegrationTest { 14 | 15 | public static class TestCls { 16 | public boolean test1(int a) { 17 | return a != 2; 18 | } 19 | 20 | public void test2(int a) { 21 | assertTrue(a == 3); 22 | } 23 | 24 | public int test3(int a) { 25 | return a > 0 ? 1 : (a + 2) * 3; 26 | } 27 | } 28 | 29 | @Test 30 | public void test() { 31 | ClassNode cls = getClassNode(TestCls.class); 32 | String code = cls.getCode().toString(); 33 | 34 | assertThat(code, not(containsString("else"))); 35 | assertThat(code, containsString("return a != 2;")); 36 | assertThat(code, containsString("assertTrue(a == 3)")); 37 | assertThat(code, containsString("return a > 0 ? 1 : (a + 2) * 3;")); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/loops/TestLoopDetection.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.loops; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.hamcrest.CoreMatchers.containsString; 9 | import static org.hamcrest.CoreMatchers.not; 10 | import static org.junit.Assert.assertThat; 11 | 12 | public class TestLoopDetection extends IntegrationTest { 13 | 14 | public static class TestCls { 15 | 16 | private void test(int[] a, int b) { 17 | int i = 0; 18 | while (i < a.length && i < b) { 19 | a[i]++; 20 | i++; 21 | } 22 | while (i < a.length) { 23 | a[i]--; 24 | i++; 25 | } 26 | } 27 | } 28 | 29 | @Test 30 | public void test() { 31 | ClassNode cls = getClassNode(TestCls.class); 32 | String code = cls.getCode().toString(); 33 | 34 | assertThat(code, containsString("while (i < a.length && i < b) {")); 35 | assertThat(code, containsString("while (i < a.length) {")); 36 | 37 | assertThat(code, containsString("int i = 0;")); 38 | assertThat(code, not(containsString("i_2"))); 39 | assertThat(code, containsString("i++;")); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/arrays/TestArrays2.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.arrays; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static jadx.tests.api.utils.JadxMatchers.containsOne; 9 | import static org.hamcrest.CoreMatchers.instanceOf; 10 | import static org.junit.Assert.assertThat; 11 | 12 | public class TestArrays2 extends IntegrationTest { 13 | public static class TestCls { 14 | 15 | private static Object test4(int type) { 16 | if (type == 1) { 17 | return new int[]{1, 2}; 18 | } else if (type == 2) { 19 | return new float[]{1, 2}; 20 | } else if (type == 3) { 21 | return new short[]{1, 2}; 22 | } else if (type == 4) { 23 | return new byte[]{1, 2}; 24 | } else { 25 | return null; 26 | } 27 | } 28 | 29 | public void check() { 30 | assertThat(test4(4), instanceOf(byte[].class)); 31 | } 32 | } 33 | 34 | @Test 35 | public void test() { 36 | noDebugInfo(); 37 | ClassNode cls = getClassNode(TestCls.class); 38 | String code = cls.getCode().toString(); 39 | 40 | assertThat(code, containsOne("new int[]{1, 2}")); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/conditions/TestConditions16.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.conditions; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static jadx.tests.api.utils.JadxMatchers.containsOne; 9 | import static org.junit.Assert.assertFalse; 10 | import static org.junit.Assert.assertThat; 11 | import static org.junit.Assert.assertTrue; 12 | 13 | public class TestConditions16 extends IntegrationTest { 14 | 15 | public static class TestCls { 16 | private static boolean test(int a, int b) { 17 | return a < 0 || b % 2 != 0 && a > 28 || b < 0; 18 | } 19 | 20 | public void check() { 21 | assertTrue(test(-1, 1)); 22 | assertTrue(test(1, -1)); 23 | assertTrue(test(29, 3)); 24 | assertFalse(test(2, 2)); 25 | } 26 | } 27 | 28 | @Test 29 | public void test() { 30 | ClassNode cls = getClassNode(TestCls.class); 31 | String code = cls.getCode().toString(); 32 | 33 | // assertThat(code, containsOne("return a < 0 || (b % 2 != 0 && a > 28) || b < 0;")); 34 | assertThat(code, containsOne("return a < 0 || ((b % 2 != 0 && a > 28) || b < 0);")); 35 | 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/enums/TestSwitchOverEnum.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.enums; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static jadx.tests.api.utils.JadxMatchers.countString; 9 | import static org.junit.Assert.assertEquals; 10 | import static org.junit.Assert.assertThat; 11 | 12 | public class TestSwitchOverEnum extends IntegrationTest { 13 | 14 | public enum Count { 15 | ONE, TWO, THREE 16 | } 17 | 18 | public int testEnum(Count c) { 19 | switch (c) { 20 | case ONE: 21 | return 1; 22 | case TWO: 23 | return 2; 24 | } 25 | return 0; 26 | } 27 | 28 | public void check() { 29 | assertEquals(1, testEnum(Count.ONE)); 30 | assertEquals(2, testEnum(Count.TWO)); 31 | assertEquals(0, testEnum(Count.THREE)); 32 | } 33 | 34 | @Test 35 | public void test() { 36 | ClassNode cls = getClassNode(TestSwitchOverEnum.class); 37 | String code = cls.getCode().toString(); 38 | 39 | assertThat(code, countString(1, "synthetic")); 40 | assertThat(code, countString(2, "switch (c) {")); 41 | assertThat(code, countString(2, "case ONE:")); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/inline/TestInline3.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.inline; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.hamcrest.CoreMatchers.containsString; 9 | import static org.hamcrest.CoreMatchers.not; 10 | import static org.junit.Assert.assertThat; 11 | 12 | public class TestInline3 extends IntegrationTest { 13 | 14 | public static class TestCls { 15 | public TestCls(int b1, int b2) { 16 | this(b1, b2, 0, 0, 0); 17 | } 18 | 19 | public TestCls(int a1, int a2, int a3, int a4, int a5) { 20 | } 21 | 22 | public class A extends TestCls { 23 | public A(int a) { 24 | super(a, a); 25 | } 26 | } 27 | } 28 | 29 | @Test 30 | public void test() { 31 | ClassNode cls = getClassNode(TestCls.class); 32 | String code = cls.getCode().toString(); 33 | 34 | assertThat(code, containsString("this(b1, b2, 0, 0, 0);")); 35 | assertThat(code, containsString("super(a, a);")); 36 | assertThat(code, not(containsString("super(a, a).this$0"))); 37 | 38 | assertThat(code, containsString("public class A extends TestInline3$TestCls {")); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/loops/TestIterableForEach3.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.loops; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import java.util.Set; 7 | 8 | import org.junit.Test; 9 | 10 | import static jadx.tests.api.utils.JadxMatchers.containsOne; 11 | import static org.junit.Assert.assertThat; 12 | 13 | public class TestIterableForEach3 extends IntegrationTest { 14 | 15 | public static class TestCls { 16 | private Set a; 17 | private Set b; 18 | 19 | private void test(T str) { 20 | Set set = str.length() == 1 ? a : b; 21 | for (T s : set) { 22 | if (s.length() == str.length()) { 23 | if (str.length() == 0) { 24 | set.remove(s); 25 | } else { 26 | set.add(str); 27 | } 28 | return; 29 | } 30 | } 31 | } 32 | } 33 | 34 | @Test 35 | public void test() { 36 | ClassNode cls = getClassNode(TestCls.class); 37 | String code = cls.getCode().toString(); 38 | 39 | assertThat(code, containsOne("for (T s : set) {")); 40 | assertThat(code, containsOne("if (str.length() == 0) {")); 41 | // TODO move return outside 'if' 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/trycatch/TestFinallyExtract.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.trycatch; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import java.io.IOException; 7 | 8 | import org.junit.Test; 9 | 10 | import static jadx.tests.api.utils.JadxMatchers.containsOne; 11 | import static org.junit.Assert.assertThat; 12 | 13 | public class TestFinallyExtract extends IntegrationTest { 14 | 15 | public static class TestCls { 16 | 17 | public String test() throws IOException { 18 | boolean success = false; 19 | try { 20 | String value = test(); 21 | success = true; 22 | return value; 23 | } finally { 24 | if (!success) { 25 | test(); 26 | } 27 | } 28 | } 29 | } 30 | 31 | @Test 32 | public void test() { 33 | ClassNode cls = getClassNode(TestCls.class); 34 | String code = cls.getCode().toString(); 35 | 36 | assertThat(code, containsOne("success = true;")); 37 | assertThat(code, containsOne("return value;")); 38 | assertThat(code, containsOne("try {")); 39 | assertThat(code, containsOne("} finally {")); 40 | assertThat(code, containsOne("if (!success) {")); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /jadx-samples/src/main/java/jadx/samples/TestAnnotationsParser.java: -------------------------------------------------------------------------------- 1 | package jadx.samples; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | public class TestAnnotationsParser extends AbstractTest { 9 | 10 | @Target({ElementType.TYPE}) 11 | @Retention(RetentionPolicy.RUNTIME) 12 | public static @interface A { 13 | int i(); 14 | 15 | float f(); 16 | } 17 | 18 | @A(i = -1, f = C1.FLOAT_CONST) 19 | public static class C1 { 20 | public static final float FLOAT_CONST = 3.14f; 21 | } 22 | 23 | @A(i = -1025, f = C2.FLOAT_CONST) 24 | public static class C2 { 25 | public static final float FLOAT_CONST = 0xFF0000; 26 | } 27 | 28 | public boolean testRun() { 29 | A c1 = C1.class.getAnnotation(A.class); 30 | assertEquals(c1.i(), -1); 31 | assertEquals(c1.f(), C1.FLOAT_CONST); 32 | 33 | A c2 = C2.class.getAnnotation(A.class); 34 | assertEquals(c2.i(), -1025); 35 | assertEquals(c2.f(), C2.FLOAT_CONST); 36 | return true; 37 | } 38 | 39 | public static void main(String[] args) throws Exception { 40 | new TestAnnotationsParser().testRun(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/inner/TestAnonymousClass6.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.inner; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static jadx.tests.api.utils.JadxMatchers.containsOne; 9 | import static org.hamcrest.Matchers.containsString; 10 | import static org.hamcrest.Matchers.not; 11 | import static org.junit.Assert.assertThat; 12 | 13 | public class TestAnonymousClass6 extends IntegrationTest { 14 | 15 | public static class TestCls { 16 | public Runnable test(final double d) { 17 | return new Runnable() { 18 | public void run() { 19 | System.out.println(d); 20 | } 21 | }; 22 | } 23 | } 24 | 25 | @Test 26 | public void test() { 27 | ClassNode cls = getClassNode(TestCls.class); 28 | String code = cls.getCode().toString(); 29 | 30 | assertThat(code, containsOne("public Runnable test(final double d) {")); 31 | assertThat(code, containsOne("return new Runnable() {")); 32 | assertThat(code, containsOne("public void run() {")); 33 | assertThat(code, containsOne("System.out.println(d);")); 34 | assertThat(code, not(containsString("synthetic"))); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/regions/conditions/Compare.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.regions.conditions; 2 | 3 | import jadx.core.dex.instructions.IfNode; 4 | import jadx.core.dex.instructions.IfOp; 5 | import jadx.core.dex.instructions.args.InsnArg; 6 | import jadx.core.dex.instructions.args.LiteralArg; 7 | 8 | public final class Compare { 9 | private final IfNode insn; 10 | 11 | public Compare(IfNode insn) { 12 | this.insn = insn; 13 | } 14 | 15 | public IfOp getOp() { 16 | return insn.getOp(); 17 | } 18 | 19 | public InsnArg getA() { 20 | return insn.getArg(0); 21 | } 22 | 23 | public InsnArg getB() { 24 | return insn.getArg(1); 25 | } 26 | 27 | public IfNode getInsn() { 28 | return insn; 29 | } 30 | 31 | public Compare invert() { 32 | insn.invertCondition(); 33 | return this; 34 | } 35 | 36 | /** 37 | * Change 'a != false' to 'a == true' 38 | */ 39 | public void normalize() { 40 | if (getOp() == IfOp.NE && getB().isLiteral() && getB().equals(LiteralArg.FALSE)) { 41 | insn.changeCondition(IfOp.EQ, getA(), LiteralArg.TRUE); 42 | } 43 | } 44 | 45 | @Override 46 | public String toString() { 47 | return getA() + " " + getOp().getSymbol() + " " + getB(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/generics/TestGenerics6.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.generics; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import java.util.Collection; 7 | 8 | import org.junit.Test; 9 | 10 | import static jadx.tests.api.utils.JadxMatchers.containsOne; 11 | import static org.junit.Assert.assertThat; 12 | 13 | public class TestGenerics6 extends IntegrationTest { 14 | 15 | public static class TestCls { 16 | public void test1(Collection as) { 17 | for (A a : as) { 18 | a.f(); 19 | } 20 | } 21 | 22 | public void test2(Collection is) { 23 | for (I i : is) { 24 | i.f(); 25 | } 26 | } 27 | 28 | private interface I { 29 | void f(); 30 | } 31 | 32 | private class A implements I { 33 | public void f() { 34 | } 35 | } 36 | } 37 | 38 | @Test 39 | public void test() { 40 | ClassNode cls = getClassNode(TestCls.class); 41 | String code = cls.getCode().toString(); 42 | 43 | assertThat(code, containsOne("for (A a : as) {")); 44 | // TODO: fix iterable arg type (unexpected cast to A in bytecode) 45 | // assertThat(code, containsOne("for (I i : is) {")); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/loops/TestBreakInLoop.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.loops; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static jadx.tests.api.utils.JadxMatchers.containsOne; 9 | import static jadx.tests.api.utils.JadxMatchers.countString; 10 | import static org.junit.Assert.assertThat; 11 | 12 | public class TestBreakInLoop extends IntegrationTest { 13 | 14 | public static class TestCls { 15 | private int f; 16 | 17 | private void test(int[] a, int b) { 18 | for (int i = 0; i < a.length; i++) { 19 | a[i]++; 20 | if (i < b) { 21 | break; 22 | } 23 | } 24 | this.f++; 25 | } 26 | } 27 | 28 | @Test 29 | public void test() { 30 | ClassNode cls = getClassNode(TestCls.class); 31 | String code = cls.getCode().toString(); 32 | 33 | assertThat(code, containsOne("for (int i = 0; i < a.length; i++) {")); 34 | // assertThat(code, containsOne("a[i]++;")); 35 | assertThat(code, containsOne("if (i < b) {")); 36 | assertThat(code, containsOne("break;")); 37 | assertThat(code, containsOne("this.f++;")); 38 | 39 | assertThat(code, countString(0, "else")); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/others/TestFieldInit2.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.others; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static jadx.tests.api.utils.JadxMatchers.containsLines; 9 | import static jadx.tests.api.utils.JadxMatchers.containsOne; 10 | import static org.junit.Assert.assertThat; 11 | 12 | public class TestFieldInit2 extends IntegrationTest { 13 | 14 | public static class TestCls { 15 | 16 | public interface BasicAbstract { 17 | void doSomething(); 18 | } 19 | 20 | private BasicAbstract x = new BasicAbstract() { 21 | @Override 22 | public void doSomething() { 23 | y = 1; 24 | } 25 | }; 26 | private int y = 0; 27 | 28 | public TestCls() { 29 | } 30 | 31 | public TestCls(int z) { 32 | } 33 | } 34 | 35 | @Test 36 | public void test() { 37 | ClassNode cls = getClassNode(TestCls.class); 38 | String code = cls.getCode().toString(); 39 | 40 | assertThat(code, containsOne("x = new BasicAbstract() {")); 41 | assertThat(code, containsOne("y = 0;")); 42 | assertThat(code, containsLines(1, "public TestFieldInit2$TestCls(int z) {", "}")); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/Consts.java: -------------------------------------------------------------------------------- 1 | package jadx.core; 2 | 3 | public class Consts { 4 | public static final boolean DEBUG = false; 5 | 6 | public static final String CLASS_OBJECT = "java.lang.Object"; 7 | public static final String CLASS_STRING = "java.lang.String"; 8 | public static final String CLASS_CLASS = "java.lang.Class"; 9 | public static final String CLASS_THROWABLE = "java.lang.Throwable"; 10 | public static final String CLASS_ENUM = "java.lang.Enum"; 11 | 12 | public static final String CLASS_STRING_BUILDER = "java.lang.StringBuilder"; 13 | 14 | public static final String DALVIK_ANNOTATION_PKG = "dalvik.annotation."; 15 | public static final String DALVIK_SIGNATURE = "dalvik.annotation.Signature"; 16 | public static final String DALVIK_INNER_CLASS = "dalvik.annotation.InnerClass"; 17 | public static final String DALVIK_THROWS = "dalvik.annotation.Throws"; 18 | public static final String DALVIK_ANNOTATION_DEFAULT = "dalvik.annotation.AnnotationDefault"; 19 | 20 | public static final String DEFAULT_PACKAGE_NAME = "defpackage"; 21 | public static final String ANONYMOUS_CLASS_PREFIX = "AnonymousClass"; 22 | 23 | public static final String MTH_TOSTRING_SIGNATURE = "toString()Ljava/lang/String;"; 24 | } 25 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/TestStaticFieldsInit.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.hamcrest.CoreMatchers.containsString; 9 | import static org.hamcrest.CoreMatchers.not; 10 | import static org.junit.Assert.assertThat; 11 | 12 | public class TestStaticFieldsInit extends IntegrationTest { 13 | 14 | public static class TestCls { 15 | public static final String s1 = "1"; 16 | public static final String s2 = "12".substring(1); 17 | public static final String s3 = null; 18 | public static final String s4; 19 | public static final String s5 = "5"; 20 | public static String s6 = "6"; 21 | 22 | static { 23 | if (s5.equals("?")) { 24 | s4 = "?"; 25 | } else { 26 | s4 = "4"; 27 | } 28 | } 29 | } 30 | 31 | @Test 32 | public void test() { 33 | ClassNode cls = getClassNode(TestCls.class); 34 | String code = cls.getCode().toString(); 35 | 36 | assertThat(code, not(containsString("public static final String s2 = null;"))); 37 | // TODO: 38 | // assertThat(code, containsString("public static final String s3 = null;")); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/inner/TestAnonymousClass8.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.inner; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static jadx.tests.api.utils.JadxMatchers.containsOne; 9 | import static org.hamcrest.Matchers.containsString; 10 | import static org.hamcrest.Matchers.not; 11 | import static org.junit.Assert.assertThat; 12 | 13 | public class TestAnonymousClass8 extends IntegrationTest { 14 | 15 | public static class TestCls { 16 | 17 | public final double d = Math.abs(4); 18 | 19 | public Runnable test() { 20 | return new Runnable() { 21 | public void run() { 22 | System.out.println(d); 23 | } 24 | }; 25 | } 26 | } 27 | 28 | @Test 29 | public void test() { 30 | ClassNode cls = getClassNode(TestCls.class); 31 | String code = cls.getCode().toString(); 32 | 33 | assertThat(code, containsOne("public Runnable test() {")); 34 | assertThat(code, containsOne("return new Runnable() {")); 35 | assertThat(code, containsOne("public void run() {")); 36 | assertThat(code, containsOne("this.d);")); 37 | assertThat(code, not(containsString("synthetic"))); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /jadx-core/src/test/groovy/jadx/tests/TestStringUtils.groovy: -------------------------------------------------------------------------------- 1 | package jadx.tests 2 | 3 | import jadx.api.JadxArgs 4 | import jadx.core.utils.StringUtils 5 | import spock.lang.Specification 6 | 7 | class TestStringUtils extends Specification { 8 | 9 | def "unescape string"() { 10 | def args = new JadxArgs() 11 | args.setEscapeUnicode(true) 12 | def stringUtils = new StringUtils(args) 13 | expect: 14 | stringUtils.unescapeString(input) == "\"$expected\"" 15 | 16 | where: 17 | input | expected 18 | "" | "" 19 | "'" | "'" 20 | "a" | "a" 21 | "\n" | "\\n" 22 | "\t" | "\\t" 23 | "\r" | "\\r" 24 | "\b" | "\\b" 25 | "\f" | "\\f" 26 | "\\" | "\\\\" 27 | "\"" | "\\\"" 28 | "\u1234" | "\\u1234" 29 | } 30 | 31 | def "unescape char"() { 32 | expect: 33 | new StringUtils(new JadxArgs()).unescapeChar(input as char) == "'$expected'" 34 | 35 | where: 36 | input | expected 37 | 'a' | "a" 38 | ' ' | " " 39 | '\n' | "\\n" 40 | '\'' | "\\\'" 41 | '\0' | "\\u0000" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/inner/TestAnonymousClass7.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.inner; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static jadx.tests.api.utils.JadxMatchers.containsOne; 9 | import static org.hamcrest.Matchers.containsString; 10 | import static org.hamcrest.Matchers.not; 11 | import static org.junit.Assert.assertThat; 12 | 13 | public class TestAnonymousClass7 extends IntegrationTest { 14 | 15 | public static class TestCls { 16 | public static Runnable test(final double d) { 17 | return new Runnable() { 18 | public void run() { 19 | System.out.println(d); 20 | } 21 | }; 22 | } 23 | 24 | } 25 | 26 | @Test 27 | public void test() { 28 | ClassNode cls = getClassNode(TestCls.class); 29 | String code = cls.getCode().toString(); 30 | 31 | assertThat(code, containsOne("public static Runnable test(final double d) {")); 32 | assertThat(code, containsOne("return new Runnable() {")); 33 | assertThat(code, containsOne("public void run() {")); 34 | assertThat(code, containsOne("System.out.println(d);")); 35 | assertThat(code, not(containsString("synthetic"))); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/regions/SynchronizedRegion.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.regions; 2 | 3 | import jadx.core.dex.nodes.IContainer; 4 | import jadx.core.dex.nodes.IRegion; 5 | import jadx.core.dex.nodes.InsnNode; 6 | 7 | import java.util.LinkedList; 8 | import java.util.List; 9 | 10 | public final class SynchronizedRegion extends AbstractRegion { 11 | 12 | private final InsnNode enterInsn; 13 | private final List exitInsns = new LinkedList(); 14 | private final Region region; 15 | 16 | public SynchronizedRegion(IRegion parent, InsnNode insn) { 17 | super(parent); 18 | this.enterInsn = insn; 19 | this.region = new Region(this); 20 | } 21 | 22 | public InsnNode getEnterInsn() { 23 | return enterInsn; 24 | } 25 | 26 | public List getExitInsns() { 27 | return exitInsns; 28 | } 29 | 30 | public Region getRegion() { 31 | return region; 32 | } 33 | 34 | @Override 35 | public List getSubBlocks() { 36 | return region.getSubBlocks(); 37 | } 38 | 39 | @Override 40 | public String baseString() { 41 | return Integer.toHexString(enterInsn.getOffset()); 42 | } 43 | 44 | @Override 45 | public String toString() { 46 | return "Synchronized:" + region; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/conditions/TestConditions9.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.conditions; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static jadx.tests.api.utils.JadxMatchers.containsOne; 9 | import static org.hamcrest.CoreMatchers.containsString; 10 | import static org.hamcrest.CoreMatchers.not; 11 | import static org.junit.Assert.assertThat; 12 | 13 | public class TestConditions9 extends IntegrationTest { 14 | 15 | public static class TestCls { 16 | public void test(boolean a, int b) throws Exception { 17 | if (!a || (b >= 0 && b <= 11)) { 18 | System.out.println('1'); 19 | } else { 20 | System.out.println('2'); 21 | } 22 | } 23 | } 24 | 25 | @Test 26 | public void test() { 27 | ClassNode cls = getClassNode(TestCls.class); 28 | String code = cls.getCode().toString(); 29 | 30 | assertThat(code, containsOne("if (!a || (b >= 0 && b <= 11)) {")); 31 | assertThat(code, containsOne("System.out.println('1');")); 32 | assertThat(code, containsOne("} else {")); 33 | assertThat(code, containsOne("System.out.println('2');")); 34 | assertThat(code, not(containsString("return;"))); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /jadx-gui/src/main/java/jadx/gui/update/data/Release.java: -------------------------------------------------------------------------------- 1 | package jadx.gui.update.data; 2 | 3 | import java.util.List; 4 | 5 | import com.google.gson.annotations.SerializedName; 6 | 7 | public class Release { 8 | private int id; 9 | private String name; 10 | 11 | @SerializedName("prerelease") 12 | private boolean preRelease; 13 | 14 | private List assets; 15 | 16 | public String getName() { 17 | return name; 18 | } 19 | 20 | public void setName(String name) { 21 | this.name = name; 22 | } 23 | 24 | public int getId() { 25 | return id; 26 | } 27 | 28 | public void setId(int id) { 29 | this.id = id; 30 | } 31 | 32 | public boolean isPreRelease() { 33 | return preRelease; 34 | } 35 | 36 | public void setPreRelease(boolean preRelease) { 37 | this.preRelease = preRelease; 38 | } 39 | 40 | public List getAssets() { 41 | return assets; 42 | } 43 | 44 | public void setAssets(List assets) { 45 | this.assets = assets; 46 | } 47 | 48 | @Override 49 | public String toString() { 50 | StringBuilder sb = new StringBuilder(); 51 | sb.append(name); 52 | for (Asset asset : getAssets()) { 53 | sb.append("\n "); 54 | sb.append(asset); 55 | } 56 | return sb.toString(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/TestClassGen.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.hamcrest.CoreMatchers.containsString; 9 | import static org.hamcrest.CoreMatchers.not; 10 | import static org.junit.Assert.assertThat; 11 | 12 | public class TestClassGen extends IntegrationTest { 13 | 14 | public static class TestCls { 15 | public interface I { 16 | int test(); 17 | 18 | public int test3(); 19 | } 20 | 21 | public static abstract class A { 22 | public abstract int test2(); 23 | } 24 | } 25 | 26 | @Test 27 | public void test() { 28 | ClassNode cls = getClassNode(TestCls.class); 29 | String code = cls.getCode().toString(); 30 | 31 | assertThat(code, containsString("public interface I {")); 32 | assertThat(code, containsString(indent(2) + "int test();")); 33 | assertThat(code, not(containsString("public int test();"))); 34 | assertThat(code, containsString(indent(2) + "int test3();")); 35 | 36 | assertThat(code, containsString("public static abstract class A {")); 37 | assertThat(code, containsString(indent(2) + "public abstract int test2();")); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/trycatch/TestTryCatch2.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.trycatch; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.hamcrest.CoreMatchers.containsString; 9 | import static org.junit.Assert.assertThat; 10 | 11 | public class TestTryCatch2 extends IntegrationTest { 12 | 13 | public static class TestCls { 14 | private final static Object obj = new Object(); 15 | 16 | private static boolean test() { 17 | try { 18 | synchronized (obj) { 19 | obj.wait(5); 20 | } 21 | return true; 22 | } catch (InterruptedException e) { 23 | return false; 24 | } 25 | } 26 | } 27 | 28 | @Test 29 | public void test() { 30 | ClassNode cls = getClassNode(TestCls.class); 31 | String code = cls.getCode().toString(); 32 | 33 | assertThat(code, containsString("try {")); 34 | assertThat(code, containsString("synchronized (obj) {")); 35 | assertThat(code, containsString("obj.wait(5);")); 36 | assertThat(code, containsString("return true;")); 37 | assertThat(code, containsString("} catch (InterruptedException e) {")); 38 | assertThat(code, containsString("return false;")); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/TestStringBuilderElimination.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.hamcrest.CoreMatchers.containsString; 9 | import static org.hamcrest.CoreMatchers.not; 10 | import static org.junit.Assert.assertThat; 11 | 12 | public class TestStringBuilderElimination extends IntegrationTest { 13 | 14 | public static class MyException extends Exception { 15 | private static final long serialVersionUID = 4245254480662372757L; 16 | 17 | public MyException(String str, Exception e) { 18 | super("msg:" + str, e); 19 | } 20 | 21 | public void method(int k) { 22 | System.out.println("k=" + k); 23 | } 24 | } 25 | 26 | @Test 27 | public void test() { 28 | ClassNode cls = getClassNode(MyException.class); 29 | String code = cls.getCode().toString(); 30 | 31 | assertThat(code, containsString("MyException(String str, Exception e) {")); 32 | assertThat(code, containsString("super(\"msg:\" + str, e);")); 33 | 34 | assertThat(code, not(containsString("new StringBuilder"))); 35 | assertThat(code, containsString("System.out.println(\"k=\" + k);")); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/loops/TestContinueInLoop.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.loops; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static jadx.tests.api.utils.JadxMatchers.containsOne; 9 | import static org.junit.Assert.assertThat; 10 | 11 | public class TestContinueInLoop extends IntegrationTest { 12 | 13 | public static class TestCls { 14 | private int f; 15 | 16 | private void test(int[] a, int b) { 17 | for (int i = 0; i < a.length; i++) { 18 | int v = a[i]; 19 | if (v < b) { 20 | a[i]++; 21 | } else if (v > b) { 22 | a[i]--; 23 | } else { 24 | continue; 25 | } 26 | if (i < b) { 27 | break; 28 | } 29 | } 30 | this.f++; 31 | } 32 | } 33 | 34 | @Test 35 | public void test() { 36 | ClassNode cls = getClassNode(TestCls.class); 37 | String code = cls.getCode().toString(); 38 | 39 | assertThat(code, containsOne("for (int i = 0; i < a.length; i++) {")); 40 | assertThat(code, containsOne("if (i < b) {")); 41 | assertThat(code, containsOne("continue;")); 42 | assertThat(code, containsOne("break;")); 43 | assertThat(code, containsOne("this.f++;")); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/switches/TestSwitchInLoop.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.switches; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static jadx.tests.api.utils.JadxMatchers.containsOne; 9 | import static org.junit.Assert.assertEquals; 10 | import static org.junit.Assert.assertThat; 11 | 12 | public class TestSwitchInLoop extends IntegrationTest { 13 | public static class TestCls { 14 | public int test(int k) { 15 | int a = 0; 16 | while (true) { 17 | switch (k) { 18 | case 0: 19 | return a; 20 | default: 21 | a++; 22 | k >>= 1; 23 | } 24 | } 25 | } 26 | 27 | public void check() { 28 | assertEquals(1, test(1)); 29 | } 30 | } 31 | 32 | @Test 33 | public void test() { 34 | ClassNode cls = getClassNode(TestCls.class); 35 | String code = cls.getCode().toString(); 36 | 37 | assertThat(code, containsOne("switch (k) {")); 38 | assertThat(code, containsOne("case 0:")); 39 | assertThat(code, containsOne("return a;")); 40 | assertThat(code, containsOne("default:")); 41 | assertThat(code, containsOne("a++;")); 42 | assertThat(code, containsOne("k >>= 1;")); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /jadx-core/src/test/java/jadx/tests/integration/trycatch/TestTryCatch7.java: -------------------------------------------------------------------------------- 1 | package jadx.tests.integration.trycatch; 2 | 3 | import jadx.core.dex.nodes.ClassNode; 4 | import jadx.tests.api.IntegrationTest; 5 | 6 | import org.junit.Test; 7 | 8 | import static jadx.tests.api.utils.JadxMatchers.containsOne; 9 | import static org.junit.Assert.assertThat; 10 | 11 | public class TestTryCatch7 extends IntegrationTest { 12 | 13 | public static class TestCls { 14 | private Exception test() { 15 | Exception e = new Exception(); 16 | try { 17 | Thread.sleep(50); 18 | } catch (Exception ex) { 19 | e = ex; 20 | } 21 | e.printStackTrace(); 22 | return e; 23 | } 24 | } 25 | 26 | @Test 27 | public void test() { 28 | noDebugInfo(); 29 | ClassNode cls = getClassNode(TestCls.class); 30 | String code = cls.getCode().toString(); 31 | 32 | String excVarName = "exception"; 33 | assertThat(code, containsOne("Exception " + excVarName + " = new Exception();")); 34 | assertThat(code, containsOne("} catch (Exception e) {")); 35 | assertThat(code, containsOne(excVarName + " = e;")); 36 | assertThat(code, containsOne(excVarName + ".printStackTrace();")); 37 | assertThat(code, containsOne("return " + excVarName + ";")); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /jadx-core/src/main/java/jadx/core/dex/instructions/args/PrimitiveType.java: -------------------------------------------------------------------------------- 1 | package jadx.core.dex.instructions.args; 2 | 3 | public enum PrimitiveType { 4 | BOOLEAN("Z", "boolean"), 5 | CHAR("C", "char"), 6 | BYTE("B", "byte"), 7 | SHORT("S", "short"), 8 | INT("I", "int"), 9 | FLOAT("F", "float"), 10 | LONG("J", "long"), 11 | DOUBLE("D", "double"), 12 | OBJECT("L", "OBJECT"), 13 | ARRAY("[", "ARRAY"), 14 | VOID("V", "void"); 15 | 16 | private final String shortName; 17 | private final String longName; 18 | 19 | PrimitiveType(String shortName, String longName) { 20 | this.shortName = shortName; 21 | this.longName = longName; 22 | } 23 | 24 | public String getShortName() { 25 | return shortName; 26 | } 27 | 28 | public String getLongName() { 29 | return longName; 30 | } 31 | 32 | public static PrimitiveType getWidest(PrimitiveType a, PrimitiveType b) { 33 | if (a.ordinal() > b.ordinal()) { 34 | return a; 35 | } else { 36 | return b; 37 | } 38 | } 39 | 40 | public static PrimitiveType getSmaller(PrimitiveType a, PrimitiveType b) { 41 | if (a.ordinal() < b.ordinal()) { 42 | return a; 43 | } else { 44 | return b; 45 | } 46 | } 47 | 48 | @Override 49 | public String toString() { 50 | return longName; 51 | } 52 | } 53 | --------------------------------------------------------------------------------