Dynamic JNI Detection Plugin

Update (Nov 29): the plugin was open-sourced on our GitHub repository. JEB 3.0.7+ is required to load and run it.

Java applications can call native methods stored in dynamic libraries via the Java Native Interface (JNI) framework. Android apps can do the same: developers can use the NDK to write their own .so library to use and distribute.

In this post, we briefly present how the binding mechanisms work, allowing a piece of bytecode to invoke native code routines.

Named Convention Method

The easiest way to call native method is as such:

In Java, class com.example.hellojni.HelloJni:

In C:

The native method name adheres to the standard JNI naming convention, allowing automatic resolution and binding.

The corresponding Dalvik bytecode is:

and here are the the corresponding ARM instructions:

JEB automatically binds those methods together, to allow easy debugging from bytecode to native code.

However, there is another way to bind native code to Java.

Dynamic JNI Method

One can decide to bind any function to Java without adhering to the naming convention, by using the JNIEnv->RegisterNatives method.

For example, the following line of code dynamically binds the Java method add(II)I to the native method add():

Due to its dynamic nature, statically resolving those bindings can prove difficult in practice, e.g. if names were removed or mangled, or if the code is obfuscated. Therefore, not all calls to RegisterNatives may be found and/or successfully processed.

However, JEB 3.0-beta.2 (to  be released this week) ships with an EnginesPlugin to heuristically detect – some of – these methods, and perform binding – and of course, you will also be able to debug into them.

Execute the plugin via the File, Plugins menu

Once run, it will :

  • annotate the dex code with the target addresses:

  • rename targets (prefixing names with __jni_) :

  • enable you to seamlessly debug into them (jump from Java to this JNI method)

 

Heuristics

As of this writing, the plugin uses several heuristics, implemented for ARM and ARM64 (Aarch64):

  • The first is the simplest one: the JNIEnv->RegisterNatives method is commonly called from the standard JNI initialization function JNI_OnLoad, so JEB searches for this method and attempt to find calls to RegisterNatives.

Once the ‘BL RegisterNatives‘ is found, JEB uses the decompiler to create an IR representation of the block, and determines the values of R2 and R3 (X2 and X3 on Aarch64). R3 indicates the number of native methods to register, R2 is a pointer to the array of JNI native methods (structure with a pointer to method name, a pointer to method signature and a pointer to the native function bound):

Even if accurate, this method does not work when a Branch is issued via a register (BL R4) or method name is hidden.

  • The second heuristic is based on method name. First, in Dalvik, we search for all invocations to native methods. Then, for each method found, we search in binaries if there is a String reference matching the method name. (This heuristic is dangerous but yields decent results. A future plugin update may allow users to disable it.)

If found, the plugin looks at cross references of this String and checks if it looks like the expected JNI structure.

  • The third and last heuristic is the same as the previous one, but based on arguments. Since names can be shortened, they may not be interpreted as String, and thus not referenced, whereas it is easier to find argument signatures.

These three heuristics only work when methods are defined as a static array variable. Dynamic variables would need some emulation of the JNI_OnLoad method to be resolved.

As you can see, detection is currently based on heuristics, so obfuscated methods may be missing. Feel free to tweak and improve the plugin, it is available on our GitHub repository. As usual, feel free to reach out to us (email, Twitter, Slack) if you have questions or suggestions.

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.

JEB3 Beta is available

The demo builds of JEB3 Beta are available for download on our website. The full builds are also available, however, you will need to make that demand explicit by emailing us.

What’s new in JEB3? This major release contains hundreds of changes, which can be roughly categorized as follows:

  • New desktop client. The JEB3 client is leaner and faster than the client that shipped with JEB2. It also comes with a Dark theme, supports configurable keyboard shortcuts, and easily supports multiple instances.
  • Interactive global graphs. On top of the interactive control flow graphs, JEB3 presents the user with additional smart, global graphs, such as call graphs and class graphs.
  • Improved native decompilation pipeline. A large bulk of the update as well as future trend for JEB3 is refining and opening access to our native code decompilers. We will publish several blogs regarding advanced use of decompilers, including how to use the API to customize a decompilation, write intermediate optimization passes, or even write a custom decompiler or custom analysis modules.
  • Intel x86 decompilers. JEB Pro ships with our Intel x86 32-bit decompiler and Intel x86 64-bit decompiler modules. You can already try them out in the demos.
  • Additional decompilers. We are planning to ship additional decompilers. In fact JEB3 Beta already ships with a WebAssembly decompiler. It can be used to decompile web apps or EOS smart contracts to C. We will soon provide an Ethereum decompiler as well.
  • C++ class reconstruction. The full builds will ship with experimental support for class hierarchy discovery and reconstruction of Visual Studio-compiled x86 stripped programs, as well as C++ decompilation, as was demo’ed in this YouTube video.
  • More Type Libraries. Our type library system was improved, and we generated typelibs for the following environments:
    • Android NDK on ARM 32-bit
    • Android NDK on ARM 64-bit
    • Android NDK on x86 32-bit
    • Android NDK on x86 64-bit
    • Windows win32 on Intel x86 32-bit
    • Windows win32 on Intel x86 64-bit
    • Windows win32 on ARM 32-bit
    • Windows win32 on ARM 64-bit
    • Windows DDK on Intel x86 32-bit
    • Windows DDK on Intel x86 64-bit
    • Linux glibc on Intel x86 32-bit
    • Linux glibc on ARM 32-bit
    • Linux glibc on MIPS 32-bit
  • More Signature Libraries. JEB3 ships with complete library signature sets for:
    • Android NDK libraries. Common libraries (libc, libc++, zlib, etc.) are signed from from NDK v11 up to the latest version (v17 as of 08/18).
    • Visual Studio compiled binaries. This system allows the recognition of statically linked library code in binaries compiled for x86 and x86-64 architectures.
  • Full support for Windows malware analysis. The Intel decompilers, Windows type libraries and signature libraries make JEB a great platform to analyze win32 malware or malicious kernel drivers.

If you are a registered user, you can request to be put on the early adopters list and use JEB3 right now. You may also decide to wait and automatically receive your build when it becomes publicly available for all. The release date is scheduled for the early Fall.