JEB is much more than just a Dalvik decompiler and disassembler. The interactivity and flexibility it provides are equally important for reverse engineers. However, you will be interested to see how JEB's decompiler output compares to that of the current standard tools.
This page shows how our decompiler performs versus the two most common combination of tools: dex2jar+JD-GUI and dex2jar+JAD.
Note: JD and JAD being Java class files decompilers, a prerequisite step to show you their output is to convert the Java bytecode to Dalvik bytecode. This step can be destructive, both for bytecode data and metadata. It is also extremely easy to write Dalvik bytecode that will crash dex2jar. One such example of obfuscated code is presented later in this page.
This document is divided into three parts:
In all four cases below, JEB gives almost perfect source code. JD-GUI and JAD, particularly the latter, produce incorrect, overly complex and difficult to read decompiled code.
RC4 encryption
A ubiquitous, standard stream cipher. Algorithmically, nothing fancy: three loops and a couple of bit-wise arithmetic operations.
Quicksort
The most famous divide-and-conquer sorting algorithm. The presence of nested loops and recursion calls makes it algorithmically more complex than RC4.
Eratosthenes sieve
One of the most basic way to generate prime numbers. A standard implementation is based on loops, nested loops, conditionals, arrays and so on.
LZSS decompression
Improved upon LZ77, this Lempel-Ziv compression scheme is the basis of many more compression algorithms. Algorithmically, it is at par with the prime number generator presented above.
Here, we show the decompiled output for android.support.v4.app.BackStackRecord, one of the big classes of the
Android Support framework.
As you can see, the code produced by JD and JAD does not appear as unreadable as for the examples above. Still, many routines are incorrectly or poorly rendered by those tools, especially when they contain nested complex loops.
As previously shown, JEB is doing very well. For an example of that, see the method popFromBackStack().
(For enhanced clarity, here are the individual output files : JEB / JD-GUI / JAD)
Obfuscated code and/or modified+repackaged apps are likely to break DEX-to-JAR converters. It is the case here:
$ dex2jar obfuscated.dex
dex2jar obfuscated.dex -> obfuscated-dex2jar.jar
com.googlecode.dex2jar.DexException: while accept method:[LA;.f(I)I]
at com.googlecode.dex2jar.reader.DexFileReader.acceptMethod(DexFileReader.java:699)
at com.googlecode.dex2jar.reader.DexFileReader.acceptClass(DexFileReader.java:446)
at com.googlecode.dex2jar.reader.DexFileReader.accept(DexFileReader.java:328)
at com.googlecode.dex2jar.v3.Dex2jar.doTranslate(Dex2jar.java:84)
at com.googlecode.dex2jar.v3.Dex2jar.to(Dex2jar.java:239)
at com.googlecode.dex2jar.v3.Dex2jar.to(Dex2jar.java:230)
at com.googlecode.dex2jar.tools.Dex2jarCmd.doCommandLine(Dex2jarCmd.java:107)
at com.googlecode.dex2jar.tools.BaseCmd.doMain(BaseCmd.java:168)
at com.googlecode.dex2jar.tools.Dex2jarCmd.main(Dex2jarCmd.java:34)
Caused by: com.googlecode.dex2jar.DexException: while accept code in method:[LA;.f(I)I]
at com.googlecode.dex2jar.reader.DexFileReader.acceptMethod(DexFileReader.java:689)
... 8 more
Caused by: java.lang.ArrayIndexOutOfBoundsException: 15
at com.googlecode.dex2jar.v3.V3CodeAdapter.visitConstStmt(V3CodeAdapter.java:326)
at com.googlecode.dex2jar.reader.DexOpcodeAdapter.x1n(DexOpcodeAdapter.java:262)
at com.googlecode.dex2jar.reader.DexCodeReader.acceptInsn(DexCodeReader.java:411)
at com.googlecode.dex2jar.reader.DexCodeReader.accept(DexCodeReader.java:330)
at com.googlecode.dex2jar.reader.DexFileReader.acceptMethod(DexFileReader.java:686)
... 8 more
For this reason, we can only present JEB's output.
This example is a very simple piece of code that was run through a flow obfuscator and junk insertion program.
JEB reconstructs the flow and removes junk code, giving simplified Java source.
.method public f(I)I
const/4 v15, 0x7
move/from16 v6, v15
move v7, v15
and-int/lit8 v6, v15, 0x4
move/from16 v9, v7
const v14, 0x5
add-int v9, v9, v15
mul-int/2addr v7, v9
const v7, 0x5
sub-int/2addr v9, v6
move v11, v7
move/16 v13, v6
goto/16 :180
:30
return v0
:36
goto :38
:38
const v7, 0x6
move v15, v7
const/4 v8, 0x3
move v0, v2
const v15, 0x2
const v3, 0x1
div-int/lit8 v3, v8, 0x3
mul-int/lit8 v8, v3, 0x2
div-int/lit8 v8, v3, 0x2
div-int/2addr v7, v8
const/4 v5, 0x2
and-int v8, v8, v5
const v5, 0x6
goto :6C
:6C
const v9, 0x1
const/16 v6, 0x2
add-int/lit8 v9, v6, 0x2
move/from16 v10, v9
move/from16 v14, v10
move/16 v5, v6
const/16 v3, 0x0
move/from16 v6, v9
add-int v6, v6, v14
add-int/lit8 v0, v0, 0x1
const v14, 0x6
rem-int v5, v5, v6
const/4 v10, 0x6
shr-int/lit8 v10, v14, 0x5
goto/16 :1EC
:AC
const v13, 0x2
const/4 v9, 0x7
const/4 v15, 0x1
const/4 v10, 0x2
rem-int/lit16 v9, v13, 0x7
move/from16 v4, v15
ushr-int/2addr v15, v10
const v5, 0x6
shl-int v5, v5, v13
div-int/lit8 v4, v5, 0x1
const v14, 0x6
xor-int v15, v15, v14
const v7, 0x6
move v15, v5
if-ltz v15, :12E
:E6
const/16 v7, 0x4
const/16 v4, 0x7
move/16 v14, v5
xor-int/lit16 v7, v14, 0x2
move/from16 v9, v15
div-int v4, v4, v10
move v8, v15
and-int v9, v9, v4
const/16 v4, 0x0
move/from16 v14, v9
const v12, 0x1
move/16 v4, v12
mul-int/lit16 v14, v10, 0x0
move v7, v10
div-int v10, v10, v7
or-int/lit16 v4, v8, 0x6
mul-int v5, v5, v15
goto :12E
:12E
const v3, 0x7
move/16 v10, v3
ushr-int/lit8 v10, v3, 0x0
and-int/lit8 v10, v3, 0x0
const/4 v4, 0x4
xor-int/lit16 v3, v4, 0x3
move/from16 v6, v4
xor-int/lit8 v3, v6, 0x3
sub-int v10, v10, v4
goto :156
:156
const v4, 0x2
const v6, 0x4
add-int/lit16 v6, v4, 0x6
move v11, v4
const v6, 0x5
move/from16 v10, v11
move/from16 v3, v4
and-int v10, v10, v4
shr-int v4, v4, v6
goto :1E2
:180
const v13, 0x0
move/from16 v7, v13
add-int/lit8 v13, v7, 0x1
const/16 v11, 0x3
div-int v7, v7, v11
xor-int v13, v13, v11
if-ge v7, v13, :36
:19E
xor-int/2addr v7, v13
move v10, v13
and-int/lit16 v11, v13, 0x6
const v7, 0x5
const/16 v8, 0x6
rsub-int v10, v11, 0x6
const v13, 0x5
const v5, 0x0
const v5, 0x1
and-int v10, v10, v5
rem-int/lit16 v11, v8, 0x7
move/16 v4, v10
move v10, v13
or-int/2addr v7, v13
rem-int/lit16 v5, v13, 0x0
div-int/2addr v10, v11
goto/16 :36
:1E2
const v11, 0x1
goto/16 :30
:1EC
const v8, 0x0
move v9, v8
move/from16 v8, v9
goto/16 :AC
.end method
This Dalvik listing appears unnaturally complex. JEB's deobfuscator chimes in and decompiles it to a simple:
// Decompiled by JEB v0.9.0 alpha
public int f(int arg2) {
int v0 = arg2 + 1;
return v0;
}
Try JEB for yourself, download a demo version.