Capstone Engine on Android

  1. Creating your Android project
  2. Compiling the Capstone Engine
  3. Compiling JNA
  4. Putting it all together
  5. Conclusion

While doing some reading on Reverse Engineering, it occurred to me that there are no tools for Android that allow for disassembly of binaries. After doing some research, I settled on the Capstone Engine. Here is how I've integrated the Capstone Engine to run on my Android device.

Creating your Android project

For this, I'm going to use Android Studio. I've created a fresh project with a blank activity - so nothing interesting here. One thing to note however, is that I'm going to create a directory in the 'app/src/main/' directory, called 'jniLibs'. This will contain our compiled C libraries, for use later.

Note that I've installed the NDK via the Android Studio SDK Manager.

Compiling the Capstone Engine

Now, let's cross compile the Capstone Engine for Android.

# git clone https://github.com/aquynh/capstone.git
Cloning into 'capstone'...
remote: Counting objects: 16805, done.
remote: Compressing objects: 100% (12/12), done.
remote: Total 16805 (delta 4), reused 0 (delta 0), pack-reused 16789
Receiving objects: 100% (16805/16805), 26.10 MiB | 3.01 MiB/s, done.
Resolving deltas: 100% (12089/12089), done.
Checking connectivity... done.
# cd capstone
# NDK=~/Library/Android/sdk/ndk-bundle/ ./make.sh cross-android arm

We should have a file named 'libcapstone.so' available in the current directory. Copy this to the 'jniLibs' directory that we created above.

While we're here, download a copy of the Capstone Java bindings from https://capstone-engine.github.io/download/3.0.4/capstone.jar, and place it in the 'app/libs/' directory of your Android Studio project. These provide the methods and classes that we'll use to interact with the Capstone Engine.

Compiling JNA

The Capstone Java bindings utilize the JNA library to load and communicate with the Capstone prebuilt library. We'll need to compile the JNA JAR for Android, and extract the platform specific binary library that supports JNA.

You'll need ant installed for this step.

# git clone https://github.com/twall/jna.git
Cloning into 'jna'...
remote: Counting objects: 41416, done.
remote: Total 41416 (delta 0), reused 0 (delta 0), pack-reused 41416
Receiving objects: 100% (41416/41416), 213.06 MiB | 4.51 MiB/s, done.
Resolving deltas: 100% (26780/26780), done.
Checking connectivity... done.
# cd jna
# PATH=$PATH:~/Library/Android/sdk/ NDK_PLATFORM=~/Library/Android/sdk/ndk-bundle/platforms/android-21/ ant -Dos.prefix=android-arm dist

Once JNA has finished compiling, we need to copy a few files to our Android Studio project. First of all, copy 'dist/jna.jar' to the 'app/libs/' directory in our project. Secondly, extract the file 'dist/android-arm.jar' as if it were a ZIP file, and copy the file 'libjnidispatch.so' to the 'app/src/main/jniLibs' directory in our project. This is the library used by JNA to interact with native libraries via JNI.

Putting it all together

Now that we've compiled all of our libraries, and copied them to the corresponding directories in our project, we can give the Capstone Engine a go. Before we start using it, we will need to ensure the two Java libraries we've copied to our project are being included. To do this, add them both as a File Dependency in Android Studio (right click on your Module, and click on 'Open Module Settings', click on the 'Dependencies' tab, and click on the '+' button to add them both).

Once we've added the Java libraries as dependencies, we should be able to use Capstone in our Android project. The below example code should output to the log the example instructions from our Byte Array, interpreted by Capstone.

import capstone.Capstone;
public class MainActivity extends Activity {
    private byte [] CODE = { 0x55, 0x48, (byte) 0x8b, 0x05, (byte) 0xb8, 0x13, 0x00, 0x00 };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Capstone cs = new Capstone(Capstone.CS_ARCH_X86, Capstone.CS_MODE_64);
        Capstone.CsInsn[] allInsn = cs.disasm(CODE, 0x1000);
        for (int i=0; i<allInsn.length; i++) {
            Log.e("CAPSTONE", allInsn[i].address + " " + allInsn[i].mnemonic + " " + allInsn[i].opStr);
        }
    }
}</pre>

Conclusion

That's it! I hope this has been useful. Before re-visiting using the Java wrapper for the Capstone Engine, I attempted to create JNI wrappers for it with the Swig project, compiling Capstone directly in the NDK, however this proved to be very difficult. This solution provides an easy to reproduce environment for using Capstone across ARM Android devices.