android使用C/C++呼叫SO庫

jia635發表於2014-09-29
有時候,我們反編譯apk得到一個so庫,如果直接使用這個so庫的話,必須使用原來so庫同樣的package名字,才能用。

這樣人家反編譯你的apk,就知道你侵犯了人家的版權。為了達到混淆的目的,我們可以再寫一個so庫呼叫人家的so庫,即把人家的so庫放到root的某個路徑下,用c/c++語言呼叫這個so庫。比如說,我得到一個APK,反編譯這個APK看到下面的程式碼:

    static {
        try {
            System.loadLibrary("NativeExampleActivity");
        } catch (Throwable t) {
        }
    }
    public native int addFunction(int a, int b);
    public native String getString(String name);

很明顯,這個so庫是libNativeExampleActivity.so, 庫裡面有兩個native函式addFunction和getString。
雖然知道了這兩個native函式,但是我們還不能直接使用,因為這兩個native函式在so庫裡面的真實函式名不是addFunction和getString,
它在native函式名之前還有包名,所以必須使用nm命令,檢視so庫裡面的函式名。
顯示so庫函式的命令:
nm -A libNativeExampleActivity.so
或者
nm -D libNativeExampleActivity.so
這樣我們看到so庫裡的主要資訊:
Java_org_natives_example_NativeExampleActivity_addFunction
Java_org_natives_example_NativeExampleActivity_getString
看到沒有,在addFunction函式前面還有包名,這就是為什麼直接使用人家的so庫的時候,一定要使用原來的package名字!
好了,現在是怎麼呼叫這兩個函式了,4個步驟完成。
1.用Eclipse建立一個專案
package so.hello;

import android.app.Activity;
import android.os.Bundle;

public class SoHelloActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
    static {
        try {
            System.loadLibrary("soHello");
        } catch (Throwable t) {
        }
    }
    public native int addFunction1(int a, int b);
    public native String getString1(String name);
}

2.在終端進入到專案的路徑soHello/bin/classes,執行命令:
guo@guo-desktop:~/workspace/soHello/bin/classes$ javah -jni so.hello.SoHelloActivity
在soHello/bin/classes目錄下會生成一個檔案so_hello_SoHelloActivity.h

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class so_hello_SoHelloActivity */

#ifndef _Included_so_hello_SoHelloActivity
#define _Included_so_hello_SoHelloActivity
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     so_hello_SoHelloActivity
 * Method:    addFunction1
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_so_hello_SoHelloActivity_addFunction1
  (JNIEnv *, jobject, jint, jint);

/*
 * Class:     so_hello_SoHelloActivity
 * Method:    getString1
 * Signature: (Ljava/lang/String;)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_so_hello_SoHelloActivity_getString1
  (JNIEnv *, jobject, jstring);

#ifdef __cplusplus
}
#endif
#endif

3.寫一個so_hello_SoHelloActivity.cpp檔案

#include "so_hello_SoHelloActivity.h" 
#include <stdlib.h>
#include <fcntl.h>
#include <android/log.h>
#include <stdio.h>  
#include <stdarg.h>  
#include <dlfcn.h> 

void *filehandle = NULL;
jint (*addFunc)(JNIEnv *,jobject,jint,jint) = NULL;
jstring (*getStringFunc)(JNIEnv *, jobject, jstring) = NULL;

JNIEXPORT jint JNICALL Java_so_hello_SoHelloActivity_addFunction1
  (JNIEnv *env, jobject obj, jint a, jint b);
{
	jint mun = 0;
	//事先把libNativeExampleActivity放到root/system/lib/目錄下
	filehandle = dlopen("/system/lib/libNativeExampleActivity.so", RTLD_LAZY);
	if(filehandle)
	{
		addFunc = (jint (*)(JNIEnv *,jobject,jint,jint))dlsym(filehandle, "Java_org_natives_example_NativeExampleActivity_addFunction");
		if(addFunc)
			mun = addFunc(env, obj, a, b);
		dlclose(filehandle); 
		filehandle = NULL;
	}
	return mun
}

/*
 * Class:     so_hello_SoHelloActivity
 * Method:    getString1
 * Signature: (Ljava/lang/String;)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_so_hello_SoHelloActivity_getString1
  (JNIEnv *, jobject, jstring name)
{
	jstring mun = 0;
	//事先把libNativeExampleActivity放到root/system/lib/目錄下
	filehandle = dlopen("/system/lib/libNativeExampleActivity.so", RTLD_LAZY);
	if(filehandle)
	{
		getStringFunc = (jstring (*)(JNIEnv *,jobject,jstring))dlsym(filehandle, "Java_org_natives_example_NativeExampleActivity_getString");
		if(getStringFunc)
		{
			mun = getStringFunc(env, obj, name);
		}
		dlclose(filehandle); 
		filehandle = NULL;
	}
	return mun
}

4.編寫Android.mk

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_LDLIBS := -llog
LOCAL_C_INCLUDES += system/core/include/cutils
LOCAL_SHARED_LIBRARIES := \
    libdl \
    libcutils

LOCAL_PRELINK_MODULE := false
LOCAL_MODULE      := libsoHello
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES   := so_hello_SoHelloActivity.cpp
LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -llog

include $(BUILD_SHARED_LIBRARY)
使用mm命令編譯so_hello_SoHelloActivity.cpp,便可以生成libsoHello.so庫。
然後這個so庫就可以用啦!

綜述:
這裡主要使用了dlopen、dlsym、dlclose三個函式來載入so庫:
void *filehandle = NULL;
jint (*addFunc)(JNIEnv *,jobject,jint,jint) = NULL;
jint mun = 0
//事先把libNativeExampleActivity放到root/system/lib/目錄下
filehandle = dlopen("/system/lib/libNativeExampleActivity.so", RTLD_LAZY);
if(filehandle)
{
    addFunc = (jint (*)(JNIEnv *,jobject,jint,jint))dlsym(filehandle, "Java_org_natives_example_NativeExampleActivity_addFunction");
    if(addFunc)
        mun = addFunc(env, obj, a, b);
    dlclose(filehandle); 
    filehandle = NULL;
}


相關文章