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.

JEB Plugin How-To: Jump to an Activity

The API that shipped with JEB 1.3 allows direct access to the Android Manifest. Here, we are just demonstrating how some of the new methods that shipped with the API. This plugin allows a user to jump from an Activity tag in the manifest to the corresponding code in the Assembly view:

#? name=Jump to an Activity, shortcut=Ctrl+Shift+J

from jeb.api import IScript
from jeb.api.ui import View
from jeb.api.ui import CodePosition


class JumpToActivity(IScript):

  def run(self, jeb):

    # basic requirements
    ui = jeb.getUI()
    if not ui:
      return

    if jeb.getApiVersion() < 2:
      print 'Please upgrade to JEB 1.3'
      return

    ui.focusView(View.Type.MANIFEST)
    v = ui.getView(View.Type.MANIFEST)
    if not v:
      print 'No Manifest'
      return

    # whole copy of the Manifest
    text = v.getText()

    # retrieve the package name
    pname = ''
    pos = text.find('package="')
    if pos >= 0:
      pos += 9
      pos1 = text.find('"', pos)
      if pos1 >= 0:
        pname = text[pos:pos1]

    # the Activity name should be the on-caret item
    aname = v.getActiveItem()
    if not aname:
      print 'Please position the caret on the Activity name'
      return

    # absolute class classname
    if aname.startswith('.'):
      if not pname:
        print 'Package name not found'
        return
      aname = pname + aname

    ui.focusView(View.Type.ASSEMBLY)
    a = ui.getView(View.Type.ASSEMBLY)
    if not a:
      print 'No Assembly view'
      return

    # internal class name
    classname = 'L' + aname.replace('.', '/') + ';'
    if not a.setCodePosition(CodePosition(classname)):
      print 'Class not found: '+aname
      ui.focusView(View.Type.MANIFEST)

Feel free to experiment with the script, and customize it to your needs. Leave a comment if you have any questions. More sample scripts will be posted in the next week to showcase more other capabilities of API v2.

JEB 1.3: How to Sign and Match Third-Party Library Code

JEB 1.3 ships with two plugins that allow users to create signatures for library code, and apply signatures onto DEX files. (Note: we are not talking about digital signatures here, but rather, binary strings that are used to identify a method or body of code.)

Combined with the new navigation bar, portions of a DEX file that contain third-party frameworks (such as those ubiquitous ad libraries) or already analyzed code, can be easily identified: such areas will be marked using a light-green color in the navigation bar.

Applying signatures

In practice, applying signatures is extremely easy:

1- Load the file in JEB: as can be seen below, the navigation bar is mostly blue, which means no library code has been spotted yet. (Note: The orange marks identify public constant fields – public static final.)

1

2- Fire up the Library Recognition plugin. (Menu: Action / Custom Action / Library Recognition.)

2

3- By default, the plugin looks for library signature files (*.sig extension) stored in the “sigs” sub-directory.

4- The signatures are applied where they can be applied, and the results are visible both in the navigation bar (the light-green portions) and the console window. Here, many Google AdMob routines were recognized; it appears they make up for more than half of the entire DEX file.

3

Close examination of the navigation bar shows that it is divided into two parts:

  • The upper half concerns methods and fields.
  • The lower half concerns classes as a whole.

Due to how the matching algorithm works, an entire class may be marked as library code, when not all corresponding methods and fields may be.

Creating signatures

JEB ships with library signatures for popular Google and Android frameworks. But it is also extremely easy to create your own library signatures.

Let’s take an example. That same APK file contains the Android Support classes; let’s sign them.

1- Execute the Signature Generator plugin. (Menu: Action / Custom Action / Signature Generator.) Note that the plugin may also be executed from the command line and take arguments from the command line, in Automation mode. This is particularly useful for bulk signature creation.

4

2- The plugin asks the user for two pieces of information:

  • The library name: it is recommended to use the format “<libraryname>-<version>”. Here, we will go for: android-support-13
  • The regular expression that identifies which methods should be signed. We want to sign all methods of the android.support.v4 package, so we will input: Landroid/support/v4/.* (Java internal name convention)

After proceeding, the plugin signs the target code. The signing results appears in the Console window:

5

3- The signature file is created in the “sigs” directory. Later on, when you apply signatures to other DEX files, the android-support signatures will be automatically checked and matched against those DEX files.

If you were to re-apply signatures to the currently examined APK file, the android-support methods and classes would obviously be matched, and the navigation bar would reveal that most of this APK is library code:

6

In a future blog post, we will spend some time describing how the signing and matching algorithms work. Keep in mind the library code signing/matching system is plugins-based, which means it can be customized or tweaked by JEB users. Just have a look at the ApplySigs.py and GenSig.py files in the plugins directory if you’re curious about that.

Stay tuned.

Android OBad decompiled sources

This threat was initially reported by Kaspersky and seems to have gathered quite some amount of attention lately.

I’m attaching the sources decompiled by JEB 1.2 to this post, for analysts who’d like to take a look at it. One particularity of OBad: it’s been protected by the commercial obfuscator Dexguard (which I briefly mentioned here and there). Dexguard employs generalized string encryption and calls methods through reflection, which makes raw source code a bit difficult to read – the sources have not been refactored and marked-up, the usefulness of it all is very limited: you be warned.

Archive: obad_decomp.zip

Sample MD5: f7be25e4f19a3a82d2e206de8ac979c8

Edit (June 11)

Jurriaan Bremer was kind enough to provide oboy.dex, a version of OBad with encrypted strings replaced by their decoded versions. JEB handles the file okay, despite the multiple string duplicates (which is one of the reasons why it could not be loaded on a phone.) I’ve attached the decompiled sources for his version below. (I also disabled the try-catch support for improved clarity.)

Archive: oboy_decompiled.zip

JEB’s decompiled sources for Android/BadNews.A

This Android malware was referenced in a recent blog post (http://www.xchg.info/?p=46) and I thought analysts would be interested in checking out the decompiled bytecode.

Java files for live.photo.savanna and com.androways.advsystem: BadNewsA_Src.zip

Sample MD5: 98cfa989d78eb85b86c497ae5ce8ca19

SMS Spy ZertSecurity with decompiled, analyzed Java sources

The implementation of this Android malware is strong and clean. Nothing really innovative though.

0

Here’s a short summary:

  • Masquerades as a German certificate installer app. The fake login/pin is used to uniquely identify the phone (on top of the phone number and IMEI.)
  • Achieves SMS interception, most likely to break 2-factor authentication. There are 3 modes of operation: do nothing, intercept and proceed, intercept and cancel SMS broadcast.
  • Multiple command-and-control servers. Two hard-coded domains are hxxp://app-smartsystem.(com|net)/sms/d_m009.php
  • The C&C urls can be updated, either by contacting the existing the existing C&C, or via SMS sent by the master. Such SMS contain the string “&Sign28tepXXX”.
  • The communication with the C&C is encrypted using AES-ECB, with the static key “0523850789a8cfed”. The server also base64-encodes its payloads. (The client does not.)
  • The malware will try to start at boot time (BOOT_COMPLETED receiver), and also registers a 15-minute timer to query the server for updated C&C urls.

 

1

The APK was run through a name obfuscator. I’m attaching the sources decompiled using JEB 1.1, and with most of the refactoring/renaming/commenting work done. For JEB users, here is the JDB file. Enjoy.

Sample MD5: 1cf41bdc0fdd409774eb755031a6f49d

Dexguard’s assets encryption

Continuing the post on Dexguard’s protection mechanisms, let’s have a look at another feature advertised on Saikoa’s website, assets encryption:

Encrypt assets. Hide important data as well. DexGuard can encrypt your asset files transparently, so hackers won’t just run away with them.”

Let’s have a look at an app containing a protected asset, 1.png. The hexdump below shows the encrypted 1.png. The PNG header is gone, as this is the encrypted version of the file.

1

The decryption routine is easy to spot: it appears the AssetManager.open() call was replaced by inline code that uses encrypted strings and reflection to instantiate a Cipher class and decrypt the asset file. We will use the script from the previous post to decode the strings and determine exactly what is happening. The screenshot below shows the decompiled routine in question, after it was marked up and commented using JEB (try-catch have been disabled for improved clarity, as they do not help understand how the routine works):

1

The references to the AssetManager class, open method, asset filename 1.png as well as cipher type AES-CFB have been encrypted using the string encryption feature. The decryption is achieved using standard Android classes, and the scheme used is AES with a random key and IV (outlined in red in.)

The final call to InputStream.available() is actually what the original method was doing. Therefore, the protection mechanism replaced AssetManager.open() by the following section of code:

2

We conclude that manually restoring protected assets is not difficult, although it cannot be easily automated. One way to improve that protection scheme would be to use custom decryption routines instead of SDK-provided classes, and/or generalize the use of reflection to reference the decryption code.

A look inside Dexguard

Dexguard is the commercial alter-ego of Proguard, for Android applications. While Proguard provides name obfuscation and unused code paths removal, Dexguard can also encrypt strings, classes, and assets, add tamper detection code, and use Java reflection facility to deeply obfuscate what a piece of code does.

Let’s have a quick look at one feature of Dexguard, the string encryption mechanism. The app in question is a Dexguard’ed version of Cyanide.

First, access to strings inside a protected class are replaced by calls to a static private decryption routine. That routine accesses a static private array containing all protected strings within the class. That array is created by the class initializer upon loading:

1

The decryption routine usually takes 3 arguments, although in some simpler cases, it may only take two arguments. The arguments may also be shuffled. (Note: from a Dalvik standpoint, that routine is oddly structured. Although JEB’s decompiled output is structurally fine, a for-loop construct cannot be created, mainly because of the irregular jump inside the first if-cond branch.)

The screenshot below represents that decryption routine. The name was obfuscated by Dexguard. Notice the constant numerals that have been circled in that code snippet: they are the decryption routine characteristics.

2

The following screenshot shows the same piece of code after marking it up. As you can see, the encryption algorithm is fairly simple: the current output character is derived from the previous character as well as the current byte of the encryptedStrings array. A constant (-8 in this case) is added to yield the final character. The initial length (length) as well as initial character (curChar) are also offset by hard-coded constants. These three constants (0x3E, 0x199, -8) characterize the decryption routine, and are unique for each routine. The curChar parameter acts as the decryption key.

3

You may customize this Python script to decrypt Dexguard strings:

#!/usr/bin/python
# decryptor for Dexguard encrypted strings

# customize
strings = [0x4C, 0xE, 2, 9, -7, 0x10, -54, 0x3E, 0x17, -9, -44, 0x4C, 0xA, ...]
c0, c1, c2 = (0x199, 0x3E, -8)

def decrypt(length, curChar, pos):
  length += c0
  curChar += c1
  r = ''
  for i in range(length):
    r += chr(curChar & 0xFF)
    curEncodedChar = strings[pos]
    pos += 1
    curChar = curChar + curEncodedChar + c2
  return r

Combined with reflection (another feature of the protector), the protection can be pretty effective.

Help for the Bluebox challenge

The Bluebox fellows have posted an interesting Android crackme a few days ago.

The APK presents several oddities, including:

  • APK entries marked as password-protected.
  • Reuse of java.lang.String to confuse tools and analysts.
  • Some basic cryptography in the APK.
  • The most interesting part: a native library that replaces the bytecode for the custom String.add() upon loading the main activity class

As Jurriaan Bremer pointed out, the replacement bytecode in question can be found at offset 4004h of libnet.so, and is E0h bytes long. The original String.add() is only A6h bytes long, and references exception handlers. Replacing the bytecode is not trivial, but annoying.

addbc

After reassembly, JEB decompiles the real String.add() to clean code: (marked-up in the screenshot below)

addfixed

I’m providing the sources for both com.bluebox.lab.poc.Action and the fixed java.lang.String if you want to complete the challenge.

Enjoy.

Bad Java decompilation means erroneous statement in research paper

Back in July 9, 2012, Martin Georgiev et al. published a paper entitled “The Most Dangerous Code in the World: Validating SSL Certificates in Non-Browser Software” (download) that points out broken SSL certificates validation in various applications and third-party libraries.

One of the case studied is the Chase mobile banking app for Android. It turns out the version studied by the authors was 2.5 or earlier, released on April 23, 2012. (The APK can be found on Android-Drawer.) In paragraph 10.1, the authors wrote:

“Decompilation and analysis of this app’s code show that it overrides the default X509TrustManager. The replacement code simply returns without checking the server’s certificate. The code below is the result of reverse-engineering, thus variable names and other details may differ from the actual code.”

While the first statement is true (X509Certificate.checkServerTrusted() is overriden), the second is false. The claim was made because of improper decompilation to Java:

public final void checkServerTrusted(X509Certificate[]paramArrayOfX509Certificate,    String paramString)
{
  if ((paramArrayOfX509Certificate != null)
    && (paramArrayOfX509Certificate.length == 1))
    paramArrayOfX509Certificate[0].checkValidity();
  while (true)
  {
    return;  // makes checkServerTrusted unreachable
    this.a.checkServerTrusted(paramArrayOfX509Certificate, paramString);
  }
}

The decompiled code is incorrect: the “while(true) { return; …” is a misconstruct that lets the reverse engineer believe that this.a.checkServerTrusted() is never called.

Unfortunately, the authors relied in part on this faulty piece of Java code to claim that:

“Note the unreachable invocation of checkServerTrusted. We conjecture that this was a temporary plug during development that somehow found its way into the production version of the app.

Chase [is] completely insecure against a man-in-the-middle attack.”

Note that the conclusion that Chase is insecure to MiTM attacks is not disputed here. Martin Georgiev confirmed that the app was tested and was vulnerable to such attacks.

The authors may have run out of time and probably skipped the Dalvik bytecode verification step.

In fact, the routine in question is pretty simple, and JEB decompiles it to a clean:1

Now, it looks clear that the original checkServerTrusted() gets called, if and only if the certificates’ array is null or the array does not contain just one certificate.

Decompilation is not a guaranteed process, but one should use professional tools to minimize exposure to bugs. A manual check of the low-level bytecode or assembly is also a requirement before making claims that a particular code path is or is not executed.

Thanks to Juliano Rizzo for pointing out this potential issue.