Category Archives: Decompilation

Ethereum Smart Contract Decompiler

Update: December 6:
– The full EVM decompiler will ship with JEB 3.0-beta.8
– Download a sample JEB Python script showing how to use the API
Update: November 20:
– The demo build JEB 3.0-beta.6.20181120 ships with important EVM decompiler updates – download/update here.
– We uploaded the decompiled code of an interested contract, the second part of the PolySwarm challenge (a good write-up can be found here)

We’re excited to announce that the pre-release of our Ethereum smart contract decompiler is available. We hope that it will become a tool of choice for security auditors, vulnerability researchers, and reverse engineers examining opaque smart contracts running on Ethereum platforms.

TL;DR: Download the demo build and start reversing contracts

Keep on reading to learn about the current features of the decompiler; how to use it and understand its output; its current limitations, and planned additions.

This opaque multisig wallet is holding more than USD $22 million as of 10/26/2018 (on mainnet, address 0x3DBB3E8A5B1E9DF522A441FFB8464F57798714B1)

Overall decompiler features

The decompiler modules provide the following specific capabilities:

    • The EVM decompiler takes compiled smart contract EVM 1 code as input, and decompiles them to Solidity-like source code.
    • The initial EVM code analysis passes determine contract’s public and private methods, including implementations of public methods synthetically generated by compilers.
    • Code analysis attempts to determine method and event names and prototypes, without access to an ABI.
  • The decompiler also attempts to recover various high-level constructs, including:
      • Implementations of well-known interfaces, such as ERC20 for standard tokens, ERC721 for non-fungible tokens, MultiSigWallet contracts, etc.
      • Storage variables and types
    • High-level Solidity artifacts and idioms, including:
        • Function mutability attributes
      • Function payability state
      • Event emission, including event name
      • Invocations of address.send() or address.transfer()
      • Precompiled contracts invocations

On top of the above, the JEB back-end and client platform provide the following standard functionality:

    • The decompiler uses JEB’s optimizations pipeline to produce high-level clean code.
    • It uses JEB code analysis core features, and therefore permits: code refactoring (eg, consistently renaming methods or fields), commenting and annotating, navigating (eg, cross references), typing, graphing, etc.
    • Users have access to the intermediate-level IR representation as well as high-level AST representations though the JEB API.
  • More generally, the API allows power-users to write extensions, ranging from simple scripts in Python to complex plugins in Java.

Our Ethereum modules were tested on thousands of smart contracts active on Ethereum mainnet and testnets.

Basic usage

Open a contract via the “File, Open smart contract…” menu entry.

You will be offered two options:

  • Open a binary file already stored on disk
  • Download 2 and open a contract from one of the principal Ethereum networks: mainnet, rinkeby, ropsten, or kovan:
    • Select the network
    • Provide the contract 20-byte address
    • Click Download and select a file destination
Open a contract via the File, Open smart contract menu entry

Note that to be recognized as EVM code, a file must:

  • either have a “.evm-bytecode” extension: in this case, the file may contain binary or hex-encoded code;
  • or have be a “.runtime” or “.bin-runtime” extension (as generated by the solc Solidity compiler), and contain hex-encoded Solidity generated code.

If you are opening raw files, we recommend you append the “.evm-extension” to them in order to guarantee that they will be processed as EVM contract code.

Contract Processing

JEB will process your contract file and generate a DecompiledContract class item to represent it:

The Assembly view on the right panel shows the processed code.

To switch to the decompiled view, select the “Decompiled Contract” node in the Hierarchy view, and press TAB (or right-click, Decompile).

Right-click on items to bring up context menus showing the principal commands and shortcuts.
The decompiled view of a contract.

The decompiled contract is rendered in Solidity-like code: it is mostly Solidity code, but not entirely; constructs that are illegal in Solidity are used throughout the code to represent instructions that the decompiler could not represent otherwise. Examples include: low-level statements representing some low-level EVM instructions, memory accesses, or very rarely, goto statements. Do not expect a DecompiledContract to be easily recompiled.

Code views

You may adjust the View panels to have side-by-side views if you wish to navigate the assembly and high-level code at the same time.

  • In the assembly view, within a routine, press Space to visualize its control flow graph.
  • To navigate from assembly to source, and back, press the TAB key. The caret will be positioned on the closest matching instruction.
Side by side views: assembly and source

Contract information

In the Project Explorer panel, double click the contract node (the node with the official Ethereum Foundation logo), and then select the Description tab in the opened view to see interesting information about the processed contract, such as:

  • The detected compiler and/or its version (currently supported are variants of Solidity and Vyper compilers).
  • The list of detected routines (private and public, with their hashes).
  • The Swarm hash of the metadata file, if any.
The contract was identified as being compiled with Solidity <= 0.4.21

Commands

The usual commands can be used to refactor and annotate the assembly or decompiled code. You will find the exhaustive list in the Action and Native menus. Here are basic commands:

  • Rename items (methods, variables, globals, …) using the N key
  • Navigate the code by examining cross-references, using the X key (eg, find all callers of a method and jump to one of them)
  • Comment using the Slash key
  • As said earlier, the TAB key is useful to navigate back and forth from the low-level EVM code to high-level decompiled code

We recommend you to browser the general user manual to get up to speed on how to use JEB.

Rename an item (eg, a variable) by pressing the N key

Remember that you can change immediate number bases and rendering by using the B key. In the example below, you can see a couple of strings present in the bad Fomo3D contract, initially rendered in Hex:

All immediates are rendered as hex-strings by default.
Use the B key to cycle through base (10, 16, etc.) and rendering (number, ascii)

Understanding decompiled contracts

This section highlights idioms you will encounter throughout decompiled pseudo-Solidity code. The examples below show the JEB UI Client with an assembly on the left side, and high level decompiled code on the right side. The contracts used as examples are live contracts currently active Ethereum mainnet.

We also highlight current limitations and planned additions.

Dispatcher and public functions

The entry-point function of a contract, at address 0, is generally its dispatcher. It is named start() by JEB, and in most cases will consist in an if-statement comparing the input calldata hash (the first 4 bytes) to pre-calculated hashes, to determine which routine is to be executed.

  • JEB attempts to determine public method names by using a hash dictionary (currently containing more than 140,000 entries).
  • Contracts compiled by Solidity generally use synthetic (compiler generated) methods as bridges between public routines, that use the public Ethereum ABI, and internal routines, using a compiler-specific ABI. Those routines are identified as well and, if their corresponding public method was named, will be assigned a similar name __impl_{PUBLIC_NAME}.

NOTE/PLANNED ADDITION: currently, JEB does not attempt to process input data of public routines and massage it back into an explicit prototype with regular variables. Therefore, you will see low-level access to CALLDATA bytes within public methods.

A dispatcher.

Below, see the public method collectToken(), which is retrieving its first parameter – a 20 byte address – from the calldata.

A public method reading its arguments from CALLDATA bytes.

Interface discovery

At the time of writing, implementation of the following interfaces can be detected: ERC20, ERC165, ERC721, ERC721TokenReceiver, ERC721Metadata, ERC721Enumerable, ERC820, ERC223, ERC777, TokenFallback used by ERC223/ERC777 interfaces, as well as the common MultiSigWallet interface.

Eg, the contract below was identified as an ERC20 token implementation:

This contract implements all methods specified by the ERC20 interface.

Function attributes

JEB does its best to retrieve:

  • low-level state mutability attributes (pure, read-only, read-write)
  • the high-level Solidity ‘payable’ attribute, reserved for public methods

Explicitly non-payable functions have lower-level synthetic stubs that verify that no Ether is being received. They REVERT if it is is the case. If JEB decides to remove this stub, the function will always have an inline comment /* non payable */ to avoid any ambiguity.

The contract below shows two public methods, one has a default mutability state (non-payable); the other one is payable. (Note that the hash 0xFF03AD56 was not resolved, therefore the name of the method is unknown and was set to sub_AF; you may also see a call to the collect()’s bridge function __impl_collect(), as was mentioned in the previous section).

Two public methods, one is payable, the other is not and will revert if it receives Ether.

Storage variables

The pre-release decompiler ships with a limited storage reconstructor module.

  • Accesses to primitives (int8 to int256, uint8 to uint256) is reconstructed in most cases
  • Packed small primitives in storage words are extracted (eg, a 256-bit storage word containing 2x uint8 and 1x int32, and accessed as such throughout the code, will yield 3 contract variables, as one would expect to see in a Solidity contract
Four primitive storage variables were reconstructed.

However, currently, accesses to complex storage variables, such as mappings, mappings of mappings, mappings of structures, etc. are not simplified. This limitation will be addressed in the full release.

When a storage variable is not resolved, you will see simple “storage[…]” assignments, such as:

Unresolved storage assignment, here, to a mapping.

Due to how storage on Ethereum is designed (a key-value store of uint256 to uint256), Solidity internally uses a two-or-more indirection level for computing actual storage keys. Those low-level storage keys depend on the position of the high level storage variables. The KECCAK256 opcode is used to calculate intermediate and final keys. We will detail this mechanism in detail in a future blog post.

Precompiled contracts

Ethereum defines four pre-compiled contracts at addresses 1, 2, 3, 4. (Other addresses (5-8) are being reserved for additional pre-compiled contracts, but this is still at the ERC stage.)

JEB identifies CALLs that will eventually lead to pre-compiled code execution, and marks them as such in decompiled code: call_{specific}.

The example below shows the __impl_Receive (named recovered) method of the 34C3 CTF contract, which calls into address #2, a pre-compiled contract providing a fast implementation of SHA-256.

This contract calls address 2 to calculate the SHA-256 of a binary blob.

Ether send()

Solidity’s send can be translated into a lower-level call with a standard gas stipend and zero parameters. It is essentially used to send Ether to a contract through the target contract fallback function.

NOTE: Currently, JEB renders them as send(address, amount) instead of address.send(amount)

The contract below is live on mainnet. It is a simple forwarder, that does not store ether: it forwards the received amount to another contract.

This contract makes use of address.send(…) to send Ether

Ether transfer()

Solidity’s transfer is an even higher-level variant of send that checks and REVERTs with data if CALL failed. JEB identifies those calls as well.

NOTE: Currently, JEB renders them as transfer(address, amount) instead of address.transfer(amount)

This contract makes use of address.transfer(…) to send Ether

Event emission

JEB attempts to partially reconstruct LOGx (x in 1..4) opcodes back into high-level Solidity “emit Event(…)”. The event name is resolved by reversing the Event method prototype hash. At the time of writing, our dictionary contains more than 20,000 entries.

If JEB cannot reverse a LOGx instruction, or if LOG0 is used, then a lower-level log(…) call will be used.

NOTE: currently, the event parameters are not processed; therefore, the emit construct used in the decompiled code has the following form: emit Event(memory, size[, topic2[, topic3[, topic4]]]). topic1 is always used to store the event prototype hash.

An Invocation of LOG4 reversed to an “emit Deposit(…)” event emission

API

JEB API allows automation of complex or repetitive tasks. Back-end plugins or complex scripts can be written in Python or Java. The API update that ship with JEB 3.0-beta.6 allow users to query decompiled contract code:

  • access to the intermediate representation (IR)
  • access to the final Solidity-like representation (AST)

API use is out-of-scope here. We will provide examples either in a subsequent blog post or on our public GitHub repository.

Conclusion

As said in the introduction, if you are reverse engineering opaque contracts (that is, most contracts on Ethereum’s mainnet), we believe you will find JEB useful.

You may give a try to the pre-release by downloading the demo here. Please let us know your feedback: we are planning a full release before the end of the year.

As always, thank you to all our users and supporters. -Nicolas

  1. EVM: Ethereum Virtual Machine
  2. This Open plugin uses Etherscan to retrieve the contract code

Reverse Engineering WebAssembly

Note: Download the demo of “JEB Decompiler for WebAssembly” here.

We published a paper deep-diving into WebAssembly from a reverse engineer point of view (wasm format, bytecode, execution environment, implementation details, etc.).

The paper annex details how JEB can be used to analyze and decompiler WebAssembly modules.

Code and decompilation view of a WebAssembly module

Thank you – Nicolas.

Red October Malware for Android

Blue Coat Systems recently released a paper about the Inception APT (also dubbed Cloud Atlas, it may be connected to the Red October APT). One component of this APT is an Android trojan, masquerading as a Whatsapp update package. It is able to record audio calls, as well as gather, encrypt and exfiltrate user information.

The 4 strings partially written in Hindi that have been speculated on are those:

redoctober-android-img1

redoctober-android-img2

redoctober-android-img3

For researchers wanting to have a peak inside the APK, we are providing JEB decompiled Java code for one such sample.

Download is here: cloudatlas-android-malware-decompiled.zip

FinFisher FinSpy Mobile app for Android decompiled

The fully decompiled code and assets of 421and.apk can be found here: FinSpyMobileAndroid-decompiled.zip (no password).

This particular APK, although not the latest, is not obfuscated and easily reveals most capabilities of the malware:

  • Location tracker
  • Information stealer (calendar, contact list, text messages, Whatsapp databases, etc.)
  • Remotely controlled through encrypted communication over SMS and data

A great recap of the full story can be read on Netzpolitik. Real time updates are on Twitter.

Decompiled Java code for Android MisoSMS

Yesterday was eventful on the Android malware front. After Mouabad reported by Lookout, FireEye reported MisoSMS. It might also have been reported by Sophos at roughly the same time.

The malicious application is used in several campaigns to steal SMS and send them to China, according to FireEye’s blog post.

Many of you would like to examine and study its code, that’s why I uploaded an archive with the source code decompiled by JEB 1.4, as well as a cleaned-up manifest. Link: MisoSMS_JEB_decomp_20131217

misosms_mainact

Decompiled Java Code Manipulation using JEB API – Part 3: Defeating Reflection

This is the third and final part of our series of blogs showing how to use JEB’s API to manipulate decompiled Java syntax trees. (See Part 1, Part 2.)

Today, we will show how to leverage the API to defeat the main obfuscation scheme used to protect the infamous OBad trojan: generalized reflection.

Want a visual TL;DR? Have a look at the following demo video.

Download the scripts: 1, 2, 3
Demo video

Reflection is a powerful feature used by interpreted languages to query information about what is currently loaded and executed by the virtual machine. Using reflection, a program can find references to classes and items within classes, and act on those items, for example, execute methods.

Example:

java.lang.System.exit(3);

can be rewritten to:

java.lang.Class.forName("java.lang.System")
        .getMethod("exit", Integer.TYPE).invoke(null, 3);

Combined with string encryption, reflection can seriously bloat and obscure a program, slowing down the reverse-engineering process.

Based on the above code example, it appears that a solution to remove reflection code automatically or semi-automatically is both useful and realistic. Let’s see how we can to achieve this goal using JEB’s AST API.

As said in the introduction, consider the Android trojan OBad. The video shows the use of a preliminary script to decrypt the scripts. Refer to the script ObadDecrypt.py linked above; we won’t cover the details of string decryption here, as they have been covered in a previous blog.

After string decryption, OclIIOlC.onCreate looks like the following piece of Java code:

    protected void onCreate(Bundle arg9) {
        Object v1_2;
        Object v9;
        super.onCreate(arg9);
        if(Class.forName("android.os.Build").getField("MODEL").get(null).equals(new String(CIOIIolc.IoOoOIOI(CIOIIolc.cOIcOOo(IoOoOIOI.cOIcOOo("cmA4"), CIOIIolc.cOIcOOo("ÞÜëÇØÚâØÞÜÄØåØÞÜéê×èêÉÛè".getBytes())))))) {
            System.exit(0);
        }

        Context v0 = OcooIclc.cOIcOOo;
        Class v2 = MainService.class;
        try {
            v9 = Class.forName("android.content.Intent").getDeclaredConstructor(Class.forName("android.content.Context"), Class.class).newInstance(v0, v2);
        }
        catch(Throwable v0_1) {
            throw v0_1.getCause();
        }

        try {
            Class.forName("android.content.Intent").getMethod("addFlags", Integer.TYPE).invoke(v9, Integer.valueOf(268435456));
        }
        catch(Throwable v0_1) {
            throw v0_1.getCause();
        }

        Context v1_1 = OcooIclc.cOIcOOo;
        try {
            Class.forName("android.content.Context").getMethod("startService", Class.forName("android.content.Intent")).invoke(v1_1, v9);
        }
        catch(Throwable v0_1) {
            throw v0_1.getCause();
        }

        v1_1 = this.getApplicationContext();
        try {
            v1_2 = Class.forName("android.content.Context").getMethod("getPackageManager", null).invoke(v1_1, null);
        }
        catch(Throwable v0_1) {
            throw v0_1.getCause();
        }

        ComponentName v0_2 = this.getComponentName();
        try {
            Class.forName("android.content.pm.PackageManager").getMethod("setComponentEnabledSetting", Class.forName("android.content.ComponentName"), Integer.TYPE, Integer.TYPE).invoke(v1_2, v0_2, Integer.valueOf(2), Integer.valueOf(1));
        }
        catch(Throwable v0_1) {
            throw v0_1.getCause();
        }

        this.finish();
    }

Let’s remove reflection. The steps are:

  1. Recursively walk the AST and check the statements
    Note: we could enumerate all elements instead, however, the script is intended as a demo, not an exhaustive solution to this problem
  2. Look for Call statements (eg, foo()), or Assignments whose right part is a Call (eg, r = bar())
  3. Check if the Call matches the following nested Call pattern:
    Class.forName(…).getMethod(…).invoke(…)
    Note: the script does not take care of class instantiation or field access through reflection, for the same reasons stated above.
  4. Extract the reflection information:
    1. Fully-qualified name of the class
    2. Method name and prototype
    3. Invocation arguments
  5. Create a new method, register it to the DEX object
  6. Create a Call element that accurately mirrors the reflection calls
    Note: There are limitations, especially considering the return type
  7. Finally, replace the reflection call by the direct method call

A deobfuscated / “unreflected” version of the source code above looks like:

    protected void onCreate(Bundle arg9) {
        // ...
        // ...

        try {
            v9.addFlags(Integer.valueOf(268435456));
        }
        catch(Throwable v0_1) {
            throw v0_1.getCause();
        }

        Context v1_1 = OcooIclc.cOIcOOo;
        try {
            v1_1.startService(v9);
        }
        catch(Throwable v0_1) {
            throw v0_1.getCause();
        }

        v1_1 = this.getApplicationContext();
        try {
            v1_2 = v1_1.getPackageManager();
        }
        catch(Throwable v0_1) {
            throw v0_1.getCause();
        }

        ComponentName v0_2 = this.getComponentName();
        try {
            v1_2.setComponentEnabledSetting(v0_2, Integer.valueOf(2),
                    Integer.valueOf(1));
        }
        catch(Throwable v0_1) {
            throw v0_1.getCause();
        }

        this.finish();
    }

We can now remove the try-catchall. This is what the third script is doing.

At this stage, the value and potential of the AST API package should have been clearly demonstrated. We encourage users of JEB to experiment with it, tweak our sample scripts, create their own, and eventually contribute by sending us their useful deobfuscation and/or optimization scripts. We will be happy to make them available to our user base through the Resources page.

Decompiled Java Code Manipulation using JEB API – Part 2: Decrypting Strings

This is part 2 of our series of blogs showing how to use JEB’s API to manipulate decompiled Java syntax trees. (Missed Part 1?)

Let’s see how the API can be leveraged to decrypt strings, and plug the decrypted strings back into the source code.

Download the script
Demo video

As shown in the video, we are going to focus on a protected version of Cyanide. The strings are encrypted, and that the decompiled Java code does not look pretty:

    ...
    protected void onCreate(Bundle arg5) {
        super.onCreate(arg5);
        this.setContentView(2130903040);
        if(new File(MainActivity.鷭(-387, -15, 608)).exists()) {
            MainActivity.鷭(MainActivity.鷭(-389, 52, 159));
            MainActivity.鷭(MainActivity.鷭(-333, 37, 17));
            MainActivity.鷭(MainActivity.鷭(-407, 53, 629),
                    MainActivity.鷭(-395, -15, 0), this);
            MainActivity.鷭(MainActivity.鷭(-398, 53, 92),
                    MainActivity.鷭(-386, -15, 586), this);
            MainActivity.鷭(MainActivity.鷭(-402, 52, 102),
                    MainActivity.鷭(-378, -15, 665), this);
            MainActivity.鷭(MainActivity.鷭(-368, 37, 119));
            MainActivity.鷭(this);
            return;
        }

        ...
        ...

MainActivity.鷭(x, y, z) is the decryptor method. The parameters indirectly reference a static array of bytes, that contains the encrypted strings for the class.

Our script is going to do the following:

  1. Search the encrypted byte array
    1. Enumerate the fields of the class
    2. Look for a byte[] field marked private static final
    3. Verify that this field is referenced in <clinit>, the static {…} initializer for the class
    4. The field should also be referenced in another method: the decryptor
  2. Check the structure of <clinit>
    1. It should look like: encrypted_strings = new byte[]{………}
    2. Retrieve the encrypted bytes
  3. The decryptor was analyzed in a previous blog post
    1. The decryptor constants need to be extracted manually (let’s keep the script simple)
  4. Then, for every method of the class, we will:
    1. Enumerate the statements and sub-elements of the AST recursively
    2. Look for Call elements
    3. If the Call matches the decryptor method, we extract the argument provided to the Call
    4. We use these arguments to decrypt the string
    5. Finally, we replace the Call by a newly created Constant element that represent the decrypted string

(Note: The JEB python script is just a little over 100 lines, and took less than 1 hour to write. It could be greatly improved, for instance, the decryptor constants could be found programmatically, but this added complexity is out of the scope of this introductory blog post.)

Here what the deobfuscated code snippet looks like:

    ...
    protected void onCreate(Bundle arg5) {
        super.onCreate(arg5);
        this.setContentView(2130903040);
        if(new File("/data/last_alog/onboot").exists()) {
            MainActivity.鷭("rm /data/last_alog/*");
            MainActivity.鷭("cat /system/etc/install-recovery.sh > /system/etc/install-recovery.sh.backup");
            MainActivity.鷭("su", "/system/etc/su", this);
            MainActivity.鷭("supersu.apk", "/system/etc/supersu.apk", this);
            MainActivity.鷭("root.sh", "/system/etc/install-recovery.sh", this);
            MainActivity.鷭("chmod 755 /system/etc/install-recovery.sh");
            MainActivity.鷭(this);
            return;
        }
        ...
        ...

In part 3, we will show how to defeat a complex obfuscation scheme used by many bytecode protectors: reflection.

Decompiled Java Code Manipulation using JEB API – Part 1: Removing Junk Code

This is the first post of a 3-part blogs series that will demonstrate the new features of JEB’s jeb.api.ast API package.

Classes of this package allow read and write access on the Abstract Syntax Trees (AST) of the decompiled Java code produced by JEB. In a  nutshell, it allows power users to implement complex deobfuscation schemes or their own optimizations strategies.

Download the script
Demo video

Let’s jump straight to the crux of the matter: this piece of code has been obfuscating by a well-known Android/Java protector software:

/*.method public constructor (Context, AttributeSet, I)V
          .registers 8
          const/4                 v3, 0x1
          const/4                 v2, 0x0
          invoke-direct           View->(Context, AttributeSet, I)V, p0, p1, p2, p3
          new-instance            v0, Paint
:E
          packed-switch           v3, :90
:14
          packed-switch           v2, :A0
:1A
          goto                    :14
:1C
          invoke-direct           Paint->()V, v0
          iput-object             v0, p0, TileView->b0431бб0431б0431:Paint
:26
          packed-switch           v2, :B0
:2C
          packed-switch           v2, :C0
:32
          goto                    :2C
:34
          sget-object             v0, xxxkkk$xkkxkk->b04310431б0431б0431:[I
          invoke-virtual          Context->obtainStyledAttributes(AttributeSet, [I)TypedArray, p1, p2, v0
          move-result-object      v0
          const/16                v1, 0xC
          invoke-virtual          TypedArray->getInt(I, I)I, v0, v2, v1
          move-result             v1
:4C
          packed-switch           v2, : D0
:52
          packed-switch           v2, :E0
:58
          goto                    :52
:5A
          packed-switch           v2, :F0
:60
          packed-switch           v3, :FC
:66
          packed-switch           v3, :10C
:6C
          goto                    :66
:6E
          packed-switch           v2, :11C
:74
          packed-switch           v3, :12C
:7A
          goto                    :74
:7C
          packed-switch           v2, :13C
:82
          sput                    v1, TileView->bб0431ббб0431:I
          invoke-virtual          TypedArray->recycle()V, v0
          return-void
          .packed-switch 0x0
              :E
              :1C
          .end packed-switch
          .packed-switch 0x0
              :1C
              :E
          .end packed-switch
          .packed-switch 0x0
              :34
              :26
          .end packed-switch
          .packed-switch 0x0
              :34
              :26
          .end packed-switch
          .packed-switch 0x0
              :5A
              :4C
          .end packed-switch
          .packed-switch 0x0
              :5A
              :4C
          .end packed-switch
          .packed-switch 0x0
              :60
          .end packed-switch
          .packed-switch 0x0
              :4C
              :6E
          .end packed-switch
          .packed-switch 0x0
              :4C
              :6E
          .end packed-switch
          .packed-switch 0x0
              :7C
              :4C
          .end packed-switch
          .packed-switch 0x0
              :4C
              :7C
          .end packed-switch
          .packed-switch 0x0
              :82
          .end packed-switch
.end method*/

JEB decompiles this Dalvik bytecode to the following Java code:

    public TileView(Context arg5, AttributeSet arg6, int arg7) {
        super(arg5, arg6, arg7);
    label_3:
        switch(1) {
            case 0: {
                goto label_3;
            }
            case 1: {
                goto label_6;
            }
        }

        while(true) {
            switch(0) {
                case 0: {
                    goto label_6;
                }
                case 1: {
                    goto label_3;
                }
            }
        }

    label_6:
        this.b0431бб0431б0431 = new Paint();
    label_8:
        switch(0) {
            case 0: {
                goto label_11;
            }
            case 1: {
                goto label_8;
            }
        }

        while(true) {
            switch(0) {
                case 0: {
                    goto label_11;
                }
                case 1: {
                    goto label_8;
                }
            }
        }

    label_11:
        TypedArray v0 = arg5.obtainStyledAttributes(arg6,
                xkkxkk.b04310431б0431б0431);
        int v1 = v0.getInt(0, 12);
    label_15:
        switch(0) {
            case 0: {
                goto label_18;
            }
            case 1: {
                goto label_15;
            }
        }

        while(true) {
            switch(0) {
                case 0: {
                    goto label_18;
                }
                case 1: {
                    goto label_15;
                }
            }
        }

    label_18:
        switch(1) {
            case 0: {
                goto label_15;
            }
            case 1: {
                goto label_21;
            }
        }

        while(true) {
            switch(1) {
                case 0: {
                    goto label_15;
                }
                case 1: {
                    goto label_21;
                }
            }
        }

    label_21:
        switch(0) {
            case 0: {
                goto label_24;
            }
            case 1: {
                goto label_15;
            }
        }

        while(true) {
            switch(1) {
                case 0: {
                    goto label_15;
                }
                case 1: {
                    goto label_24;
                }
            }
        }

    label_24:
        TileView.bб0431ббб0431 = v1;
        v0.recycle();
    }

As one can see, dummy switches as well as pseudo-infinite loops have been inserted within the original Java code, in order to produce flow obfuscation. Using the AST API, we’re going to implement a JEB plugin that cleans the obfuscated code.

1

A dummy switch construct looks like the following:

switch(X) {
case X:
  goto next;
case Y:
  goto label_fake1:
case Z:
  goto label_fake2:
}
...
next:

The above piece of code is equivalent to:

goto next;
...
next:

Which can be reduced to a single label:

next:

In order to find the dummy switches, the JEB script is going to do the following:

  1. Recursively enumerate the statements of a method body, looking for SwitchStm elements
  2. Check that the switch is a dummy switch:
    1. The switched expression must be a Constant
    2. The case block associated with that constant must start with a Goto statement
  3. Replace the switch by the goto
  4. Find the first Label that follows the (now replaced) switch
  5. If a label is found, is at the same block level as the switch, and is the label pointed to by the goto that replaced the switch, then all the expressions between the goto and the label can be discarded
  6. Finally, apply standard JEB optimizations that remove the remaining useless gotos and labels

This algorithm fits in a less than a 100-line Python script. Download the script, experiment with it, and get accustomed to the API.

The cleaned-up code is this very simple, more readable method:

    public TileView(Context arg5, AttributeSet arg6, int arg7) {
        super(arg5, arg6, arg7);
        this.b0431бб0431б0431 = new Paint();
        TypedArray v0 = arg5.obtainStyledAttributes(arg6,
                xkkxkk.b04310431б0431б0431);
        int v1 = v0.getInt(0, 12);
        TileView.bб0431ббб0431 = v1;
        v0.recycle();
    }

In Part Deux, we will show how the AST API can be leveraged to decrypt encrypted strings of a protected piece of code.