Android JNI and Native Code Emulation

JEB 4.29 finally bridges the gap between the dex analysis modules in charge of code emulation (dexdec‘s IDState and co.) and their counterparts in the native code analysis pipeline (gendec‘s EEmulator, EState and co.).

The emulation of JNI routines from dexdec unlocks use-cases that are now becoming commonplace, such as:

  • Object consumption relying on native code calls to make reverse-engineering harder. The typical case is the retrieval of encrypted strings where part of the decryption code is bytecode, part is native code.
  • General app tweaking done on the native side, such as field setting, field reading, method invocation, object creation, etc.

Example

Here is an example of what could not be done by JEB <4.29:

//
// dex code:
//

package a.b;

class X {
  ...
  native String decrypt(char[] array, int key1, int key2);
  ...
  void f() {
    return decrypt(new char[]{'K', 'F', 'C'}, 4, 3);
  }
  ...
}

//
// native code:
//

// pseudo-code for method `dec` mapping to `a.b.X.decrypt`
jstring dec(JNIEnv* env, jobject this, jcharArray array, int a, int b) {
  int len = (*env)->GetArrayLength(env, array);
  uint16_t out[len];
  for(int i = 0; i < len; i++) {
    out[i] = array[i] - (a - b);
  }
  return (*env)->NewString(env, out, len);
}

JEB used to decompile X.f() to:

void f() {
  return decrypt(new char[]{'K', 'F', 'C'}, 4, 3);
}

JEB 4.29, if the native emulator is enabled, is able to return a simpler version:

void f() {
  return "JEB";
}

Preparation

Currently, the native emulator is disabled by default. In order to let dexdec use it, edit your dexdec-emu.cfg file (located in your coreplugins/ folder, or in the GUI, Android menu, handler Emulator Settings…):

  • Mandatory: set enable_native_code_emulator to true
  • Recommended: increase the values of emu_max_duration and emu_max_itercount (the reason being the the analysis of native images by the native code plugins can be quite time-consuming).

You will also need a JEB Pro license to use this feature.

Output

As usual, the auto-decryption of an item will also emit an event, which can be collected programmatically, and visible in the Decompiler’s “Events” fragment in the GUI.

Items whose address is formatted as @LIB:<lib.so>@NativeAddress are decrypted native items that were found in the SO image at some point.

Decrypted strings collected by the decompiler

Similarly, decrypted items found in decompiled code are rendered using a purple’ish pink (by default) in the GUI.

If native code was involved in the decryption, the on-hover pop-up will let you know:

Decryption of that string required emulation of native code

API

The native emulator(s) managed by a dexdec‘s IDState can be customized with the following newly-added methods and types:

  • enableNativeCodeEmulator / isNativeCodeEmulatorEnabled : enable or disable the native emulator (the master setting is pulled from your config file, dexdec-emu.cfg)
  • registerNativeEmulatorHooks / unregisterNativeEmulatorHooks : hooks into the evaluation (emulation) of the native code – refer to the appropriate hooks interfaces. The hooks receives a reference to the controlling EEmulator.
  • unregisterNativeEmulatorHooks / ununregisterNativeEmulatorHooks : hooks into the memory accesses of the emulator’s state – refer to the appropriate hooks interfaces. The hooks receives a reference to the target EState object.

Conclusion

Interfacing both emulators offers many possibilities to improve the reverse-engineering experience of complex binaries and applications.

There is more that can be done, which will be discussed further blog posts:

  • Retrieval of statically registered natives (through JNIEnv’s RegisterNatives) as opposed to native routines automatically resolved using the JNI naming conventions.
  • Automatic unpacking of native code.
  • Use of the native emulator in custom scripts and plugins.

Note that this feature is currently limited to JEB Pro.

The JNI native code emulator will work with x86, x64, and arm64 code (we may add support for arm in the near future). Needless to say, it is still in experimental mode! Therefore, you may encounter strange results or problems while analyzing code making use of it. Please send us error reports to support@pnfsoftware.com.

Until next time, and once again, thank you to our amazing users for their continued support and kind words 🙂 — Nicolas.

Published by

Nicolas Falliere

Author of JEB.

One thought on “Android JNI and Native Code Emulation”

Leave a Reply

Your email address will not be published. Required fields are marked *


The reCAPTCHA verification period has expired. Please reload the page.

*