Skip to content

Commit

Permalink
feat: add 'simple' decompilation mode
Browse files Browse the repository at this point in the history
  • Loading branch information
skylot committed Mar 23, 2022
1 parent 909cf0a commit d8306cb
Show file tree
Hide file tree
Showing 32 changed files with 686 additions and 150 deletions.
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@ options:
--output-format - can be 'java' or 'json', default: java
-e, --export-gradle - save as android gradle project
-j, --threads-count - processing threads count, default: 4
-m, --decompilation-mode - code output mode:
'auto' - trying best options (default)
'restructure' - restore code structure (normal java code)
'simple' - simplified instructions (linear, with goto's)
'fallback' - raw instructions without modifications
--show-bad-code - show inconsistent code (incorrectly decompiled)
--no-imports - disable use of imports, always write entire package name
--no-debug-info - disable debug info
Expand Down Expand Up @@ -115,7 +120,7 @@ options:
--fs-case-sensitive - treat filesystem as case sensitive, false by default
--cfg - save methods control flow graph to dot file
--raw-cfg - save methods control flow graph (use raw instructions)
-f, --fallback - make simple dump (using goto instead of 'if', 'for', etc)
-f, --fallback - set '--decompilation-mode' to 'fallback' (deprecated)
--use-dx - use dx/d8 to convert java bytecode
--comments-level - set code comments level, values: error, warn, info, debug, user-only, none, default: info
--log-level - set log level, values: quiet, progress, error, warn, info, debug, default: progress
Expand Down
37 changes: 35 additions & 2 deletions jadx-cli/src/main/java/jadx/cli/JadxCLIArgs.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import com.beust.jcommander.Parameter;

import jadx.api.CommentsLevel;
import jadx.api.DecompilationMode;
import jadx.api.JadxArgs;
import jadx.api.JadxArgs.RenameEnum;
import jadx.api.JadxArgs.UseKotlinMethodsForVarNames;
Expand Down Expand Up @@ -58,6 +59,17 @@ public class JadxCLIArgs {
@Parameter(names = { "-j", "--threads-count" }, description = "processing threads count")
protected int threadsCount = JadxArgs.DEFAULT_THREADS_COUNT;

@Parameter(
names = { "-m", "--decompilation-mode" },
description = "code output mode:"
+ "\n 'auto' - trying best options (default)"
+ "\n 'restructure' - restore code structure (normal java code)"
+ "\n 'simple' - simplified instructions (linear, with goto's)"
+ "\n 'fallback' - raw instructions without modifications",
converter = RenameConverter.class
)
protected DecompilationMode decompilationMode = DecompilationMode.AUTO;

@Parameter(names = { "--show-bad-code" }, description = "show inconsistent code (incorrectly decompiled)")
protected boolean showInconsistentCode = false;

Expand Down Expand Up @@ -148,7 +160,7 @@ public class JadxCLIArgs {
@Parameter(names = { "--raw-cfg" }, description = "save methods control flow graph (use raw instructions)")
protected boolean rawCfgOutput = false;

@Parameter(names = { "-f", "--fallback" }, description = "make simple dump (using goto instead of 'if', 'for', etc)")
@Parameter(names = { "-f", "--fallback" }, description = "set '--decompilation-mode' to 'fallback' (deprecated)")
protected boolean fallbackMode = false;

@Parameter(names = { "--use-dx" }, description = "use dx/d8 to convert java bytecode")
Expand Down Expand Up @@ -236,7 +248,11 @@ public JadxArgs toJadxArgs() {
args.setThreadsCount(threadsCount);
args.setSkipSources(skipSources);
args.setSkipResources(skipResources);
args.setFallbackMode(fallbackMode);
if (fallbackMode) {
args.setDecompilationMode(DecompilationMode.FALLBACK);
} else {
args.setDecompilationMode(decompilationMode);
}
args.setShowInconsistentCode(showInconsistentCode);
args.setCfgOutput(cfgOutput);
args.setRawCFGOutput(rawCfgOutput);
Expand Down Expand Up @@ -313,6 +329,10 @@ public boolean isUseDx() {
return useDx;
}

public DecompilationMode getDecompilationMode() {
return decompilationMode;
}

public boolean isShowInconsistentCode() {
return showInconsistentCode;
}
Expand Down Expand Up @@ -493,6 +513,19 @@ public DeobfuscationMapFileMode convert(String value) {
}
}

public static class DecompilationModeConverter implements IStringConverter<DecompilationMode> {
@Override
public DecompilationMode convert(String value) {
try {
return DecompilationMode.valueOf(value.toUpperCase());
} catch (Exception e) {
throw new IllegalArgumentException(
'\'' + value + "' is unknown, possible values are: "
+ JadxCLIArgs.enumValuesString(DecompilationMode.values()));
}
}
}

public static String enumValuesString(Enum<?>[] values) {
return Stream.of(values)
.map(v -> v.name().replace('_', '-').toLowerCase(Locale.ROOT))
Expand Down
23 changes: 23 additions & 0 deletions jadx-core/src/main/java/jadx/api/DecompilationMode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package jadx.api;

public enum DecompilationMode {
/**
* Trying best options (default)
*/
AUTO,

/**
* Restore code structure (normal java code)
*/
RESTRUCTURE,

/**
* Simplified instructions (linear with goto's)
*/
SIMPLE,

/**
* Raw instructions without modifications
*/
FALLBACK
}
27 changes: 21 additions & 6 deletions jadx-core/src/main/java/jadx/api/JadxArgs.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ public class JadxArgs {
private boolean cfgOutput = false;
private boolean rawCFGOutput = false;

private boolean fallbackMode = false;
private boolean showInconsistentCode = false;

private boolean useImports = true;
Expand Down Expand Up @@ -85,6 +84,8 @@ public enum OutputFormatEnum {

private OutputFormatEnum outputFormat = OutputFormatEnum.JAVA;

private DecompilationMode decompilationMode = DecompilationMode.AUTO;

private ICodeData codeData;

private CommentsLevel commentsLevel = CommentsLevel.INFO;
Expand Down Expand Up @@ -175,11 +176,17 @@ public void setRawCFGOutput(boolean rawCFGOutput) {
}

public boolean isFallbackMode() {
return fallbackMode;
return decompilationMode == DecompilationMode.FALLBACK;
}

/**
* Deprecated: use 'decompilation mode' property
*/
@Deprecated
public void setFallbackMode(boolean fallbackMode) {
this.fallbackMode = fallbackMode;
if (fallbackMode) {
this.decompilationMode = DecompilationMode.FALLBACK;
}
}

public boolean isShowInconsistentCode() {
Expand Down Expand Up @@ -422,6 +429,14 @@ public void setOutputFormat(OutputFormatEnum outputFormat) {
this.outputFormat = outputFormat;
}

public DecompilationMode getDecompilationMode() {
return decompilationMode;
}

public void setDecompilationMode(DecompilationMode decompilationMode) {
this.decompilationMode = decompilationMode;
}

public ICodeCache getCodeCache() {
return codeCache;
}
Expand Down Expand Up @@ -493,9 +508,7 @@ public String toString() {
+ ", outDirSrc=" + outDirSrc
+ ", outDirRes=" + outDirRes
+ ", threadsCount=" + threadsCount
+ ", cfgOutput=" + cfgOutput
+ ", rawCFGOutput=" + rawCFGOutput
+ ", fallbackMode=" + fallbackMode
+ ", decompilationMode=" + decompilationMode
+ ", showInconsistentCode=" + showInconsistentCode
+ ", useImports=" + useImports
+ ", skipResources=" + skipResources
Expand All @@ -520,6 +533,8 @@ public String toString() {
+ ", codeWriter=" + codeWriterProvider.apply(this).getClass().getSimpleName()
+ ", useDxInput=" + useDxInput
+ ", pluginOptions=" + pluginOptions
+ ", cfgOutput=" + cfgOutput
+ ", rawCFGOutput=" + rawCFGOutput
+ '}';
}
}
86 changes: 69 additions & 17 deletions jadx-core/src/main/java/jadx/core/Jadx.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

import jadx.api.CommentsLevel;
import jadx.api.JadxArgs;
import jadx.core.dex.attributes.AFlag;
import jadx.core.dex.visitors.AnonymousClassVisitor;
import jadx.core.dex.visitors.AttachCommentsVisitor;
import jadx.core.dex.visitors.AttachMethodDetails;
Expand All @@ -32,6 +33,7 @@
import jadx.core.dex.visitors.InlineMethods;
import jadx.core.dex.visitors.MarkMethodsForInline;
import jadx.core.dex.visitors.MethodInvokeVisitor;
import jadx.core.dex.visitors.MethodVisitor;
import jadx.core.dex.visitors.ModVisitor;
import jadx.core.dex.visitors.MoveInlineVisitor;
import jadx.core.dex.visitors.OverrideMethodVisitor;
Expand Down Expand Up @@ -62,28 +64,28 @@
import jadx.core.dex.visitors.ssa.SSATransform;
import jadx.core.dex.visitors.typeinference.TypeInferenceVisitor;
import jadx.core.dex.visitors.usage.UsageInfoVisitor;
import jadx.core.utils.exceptions.JadxRuntimeException;

public class Jadx {
private static final Logger LOG = LoggerFactory.getLogger(Jadx.class);

private Jadx() {
}

static {
if (Consts.DEBUG) {
LOG.info("debug enabled");
public static List<IDexTreeVisitor> getPassesList(JadxArgs args) {
switch (args.getDecompilationMode()) {
case AUTO:
case RESTRUCTURE:
return getRegionsModePasses(args);
case SIMPLE:
return getSimpleModePasses(args);
case FALLBACK:
return getFallbackPassesList();
default:
throw new JadxRuntimeException("Unknown decompilation mode: " + args.getDecompilationMode());
}
}

public static List<IDexTreeVisitor> getFallbackPassesList() {
List<IDexTreeVisitor> passes = new ArrayList<>();
passes.add(new AttachTryCatchVisitor());
passes.add(new AttachCommentsVisitor());
passes.add(new ProcessInstructionsVisitor());
passes.add(new FallbackModeVisitor());
return passes;
}

public static List<IDexTreeVisitor> getPreDecompilePassesList() {
List<IDexTreeVisitor> passes = new ArrayList<>();
passes.add(new SignatureProcessor());
Expand All @@ -95,12 +97,8 @@ public static List<IDexTreeVisitor> getPreDecompilePassesList() {
return passes;
}

public static List<IDexTreeVisitor> getPassesList(JadxArgs args) {
if (args.isFallbackMode()) {
return getFallbackPassesList();
}
public static List<IDexTreeVisitor> getRegionsModePasses(JadxArgs args) {
List<IDexTreeVisitor> passes = new ArrayList<>();

// instructions IR
passes.add(new CheckCode());
if (args.isDebugInfo()) {
Expand Down Expand Up @@ -178,6 +176,60 @@ public static List<IDexTreeVisitor> getPassesList(JadxArgs args) {
return passes;
}

public static List<IDexTreeVisitor> getSimpleModePasses(JadxArgs args) {
List<IDexTreeVisitor> passes = new ArrayList<>();
if (args.isDebugInfo()) {
passes.add(new DebugInfoAttachVisitor());
}
passes.add(new AttachTryCatchVisitor());
if (args.getCommentsLevel() != CommentsLevel.NONE) {
passes.add(new AttachCommentsVisitor());
}
passes.add(new AttachMethodDetails());
passes.add(new ProcessInstructionsVisitor());

passes.add(new BlockSplitter());
passes.add(new MethodVisitor(mth -> mth.add(AFlag.DISABLE_BLOCKS_LOCK)));
if (args.isRawCFGOutput()) {
passes.add(DotGraphVisitor.dumpRaw());
}
passes.add(new MethodVisitor(mth -> mth.add(AFlag.DISABLE_BLOCKS_LOCK)));
passes.add(new BlockProcessor());
passes.add(new SSATransform());
passes.add(new MoveInlineVisitor());
passes.add(new ConstructorVisitor());
passes.add(new InitCodeVariables());
passes.add(new ConstInlineVisitor());
passes.add(new TypeInferenceVisitor());
if (args.isDebugInfo()) {
passes.add(new DebugInfoApplyVisitor());
}
passes.add(new CodeRenameVisitor());
passes.add(new DeboxingVisitor());
passes.add(new ModVisitor());
passes.add(new CodeShrinkVisitor());
passes.add(new ReSugarCode());
passes.add(new CodeShrinkVisitor());
passes.add(new SimplifyVisitor());
passes.add(new MethodVisitor(mth -> mth.remove(AFlag.DONT_GENERATE)));
if (args.isRawCFGOutput()) {
passes.add(DotGraphVisitor.dumpRaw());
}
if (args.isCfgOutput()) {
passes.add(DotGraphVisitor.dump());
}
return passes;
}

public static List<IDexTreeVisitor> getFallbackPassesList() {
List<IDexTreeVisitor> passes = new ArrayList<>();
passes.add(new AttachTryCatchVisitor());
passes.add(new AttachCommentsVisitor());
passes.add(new ProcessInstructionsVisitor());
passes.add(new FallbackModeVisitor());
return passes;
}

public static final String VERSION_DEV = "dev";

private static String version;
Expand Down
Loading

0 comments on commit d8306cb

Please sign in to comment.