備忘録

備忘録

Androidの共有ライブラリをAndroid以外のOSで利用する方法

Ⅰ. はじめに

AndroidLinuxがベースのOSですが共有ライブラリをLinuxで利用する事が出来ません。

C言語ライブラリの実装が異なる為です。

OS C言語ライブラリ
Linux glibc
Android Bionic libc

この記事ではunidbgを利用して任意のOSでAndroidの共有ライブラリを利用する方法を紹介します。

Ⅱ. やり方

本記事のプロジェクトファイルはこちら

1. 共有ライブラリのサンプルプログラムを書く
#include <jni.h>

extern "C" {
JNIEXPORT jstring JNICALL Java_com_example_hellojni_MainActivity_helloworld(JNIEnv* env, jobject thiz)
{
  return env->NewStringUTF("Hello World!");
}
}
2. 1をコンパイルする
> ndk-build
[armeabi-v7a] Compile++ thumb: helloworld <= main.cpp
[armeabi-v7a] SharedLibrary  : libhelloworld.so
3. 共有ライブラリを利用するサンプルプログラムを書く
import com.github.unidbg.linux.android.AndroidEmulatorBuilder;
import com.github.unidbg.linux.android.AndroidResolver;
import com.github.unidbg.linux.android.dvm.AbstractJni;
import java.io.File;

class NativeTest extends AbstractJni {
  public void callFunction(){
    var emulator = AndroidEmulatorBuilder
        .for32Bit()
        .setProcessName("com.example.hellojni")
        .build();
    var memory = emulator.getMemory();
    memory.setLibraryResolver(new AndroidResolver(19));
    var vm = emulator.createDalvikVM(null);
    vm.setJni(this);

    var library = vm.loadLibrary(new File("src/main/resources/libhelloworld.so"), false);
    library.callJNI_OnLoad(emulator);
    var result = vm
        .resolveClass("com/example/hellojni/MainActivity")
        // Java VM型のシグネチャ
        // https://docs.oracle.com/javase/jp/8/docs/technotes/guides/jni/spec/types.html
        .callStaticJniMethodObject(emulator, "helloworld()Ljava/lang/String;");
    System.out.println(result.toString());
  }
}

public class Main extends AbstractJni {
  public static void main(String[] args){
    var nativeTest = new NativeTest();
    nativeTest.callFunction();
  }
}

実行結果

Hello World!

FAQ

Q. unidbgはスレッドセーフですか?

A.いいえ
https://github.com/zhkl0228/unidbg/issues/181#issuecomment-689734652

Q. Java以外はありますか?

A. はい。Python版があります。
また、Unicorn Engineとunidbgの仕様を理解して実装する事でその他言語でも利用可能です。