android APK加固篇-3.使用JNI加载dex和调用方法

来源:互联网 发布:淘宝免费申请试用几次 编辑:程序博客网 时间:2024/05/23 01:25

1.首先需要把assets中的test.dex复制到应用的files空间下。

string copyDexToData(JNIEnv* env, jobject asset, string dexName,string dataPath){AAssetManager* asMg = AAssetManager_fromJava(env, asset);AAsset* as = AAssetManager_open(asMg, dexName.c_str(), AASSET_MODE_UNKNOWN);if (as == NULL){LOGE("%s not found in assets!",dexName.c_str());return "";}string strDexPath = dataPath + "/files/" + dexName;int len = AAsset_getLength(as);int file = open(strDexPath.c_str(), O_WRONLY | O_CREAT, 0755);if (file < 0){AAsset_close(as);LOGE("Open %s File Error!",strDexPath.c_str());return "";}char* buf = new char[1024];while (len > 0){memset(buf, 0, 1024);int n = AAsset_read(as, buf, 1024);if (n < 0)break;write(file, buf, n);len -= n;}delete[] buf;AAsset_close(as);close(file);return strDexPath;}

2.使用JNI方法创建出dexLoaderClass对象赋值给java的dexLoaderClass成员变量

void Java_com_example_dexload_NativeLoad_loadDex(JNIEnv* env, jobject obj,jstring dexName, jstring dataPath, jobject asset){JavaVM* jvm;env->GetJavaVM(&jvm);JNIUtil::SetJavaVm(jvm);JNIUtil util;string strDexName = util.Jstring2String(dexName);string strdataPath = util.Jstring2String(dataPath);string strDexPath = copyDexToData(env, asset, strDexName, strdataPath);string strDestDexPath = strdataPath + "/cache";LOGI("%s",strDexPath.c_str());LOGI("%s",strDestDexPath.c_str());jstring jDexPath = util.String2Jstring(strDexPath.c_str());jstring jDestDexPath = util.String2Jstring(strDestDexPath.c_str());//查找ClassLoader类并调用静态方法获取系统的classloader对象jclass classloaderClass = env->FindClass("java/lang/ClassLoader");jmethodID getsysloaderMethod = env->GetStaticMethodID(classloaderClass,"getSystemClassLoader", "()Ljava/lang/ClassLoader;");jobject loader = env->CallStaticObjectMethod(classloaderClass,getsysloaderMethod);//查找DexClassLoader类并且创建对象生成优化后的dexjclass dexLoaderClass = env->FindClass("dalvik/system/DexClassLoader");jmethodID initDexLoaderMethod = env->GetMethodID(dexLoaderClass, "<init>","(Ljava/lang/String;Ljava/lang/String;""Ljava/lang/String;Ljava/lang/ClassLoader;)V");jobject dexLoader = env->NewObject(dexLoaderClass, initDexLoaderMethod,jDexPath, jDestDexPath , NULL, loader);//赋值给java端的DexClassLoader对象jclass native = env->GetObjectClass(obj);jfieldID loadID = env->GetFieldID(native, "mDex","Ldalvik/system/DexClassLoader;");env->SetObjectField(obj, loadID, dexLoader);}


3.调用test.dex中的Test1类的方法test.

void Java_com_example_dexload_NativeLoad_test(JNIEnv* env, jobject obj,jobject ac){//获取java端的ClassLoader对象jclass native = env->GetObjectClass(obj);jfieldID loadID = env->GetFieldID(native, "mDex","Ldalvik/system/DexClassLoader;");jobject load = env->GetObjectField(obj, loadID);//调用ClassLoader的方法loadClass加载dex中的Test1类jclass classloaderClass = env->GetObjectClass(load);jmethodID loadClassMethod = env->GetMethodID(classloaderClass, "loadClass","(Ljava/lang/String;)Ljava/lang/Class;");JNIUtil util;jstring Test1ClassName = util.String2Jstring("com.example.dextest.Test1");jclass javaClientClass = (jclass) env->CallObjectMethod(load,loadClassMethod, Test1ClassName);//创建Test1类的对象并且调用其中的test方法jmethodID initFuncTest = env->GetMethodID(javaClientClass, "<init>", "()V"); //构造函数IDjobject objTest1 = env->NewObject(javaClientClass, initFuncTest);jmethodID Test_method = env->GetMethodID(javaClientClass, "test","(Landroid/app/Activity;)V");if (Test_method != NULL)env->CallVoidMethod(objTest1, Test_method, ac);}


4.二种方法的对比和一些加密的说明。

用java方法来加载dex,使用更加简单,但是代码容易被查看,会使很多操作明面显示出来。


用JNI/C++加载dex,比使用java加载dex要麻烦很多,但是在安全性上会更高点,而且可以对assets中的dex进行加密和分块处理,

在copy到data空间的时候进行解密和重新制作出来原始的dex,加密代码都为汇编内容,想要明白具体的操作是非常困难的。


当然具体在加载了类和dex后最好直接把data空间生成的2个dex给删除掉,避免代码被别人看到,这样能更好的为apk进行加固,

防止别人对APK的反编译和破解。

二种方式的源代码链接:http://download.csdn.net/detail/csdn49532/9425977




0 0