你的位置:首页 > 操作系统

[操作系统]apk 加密


为了防止apk被轻易破解,想办法对java层的代码进行加密,防止反编译,代码混淆基本没什么效果,一般情况下我会对dex进行加密,通过动态加载的方法实现java层的代码尽量被隐藏,而动态加载的实现通过jni来完成,最大化的保护代码安全,其实java层这个时候只剩下继承于Application的启动类。

.h文件

 1 #ifndef __ANDROID_JNI_BOOT_HELPER_H__ 2 #define __ANDROID_JNI_BOOT_HELPER_H__ 3  4 #include <jni.h> 5 #include <string> 6 #include "android/asset_manager.h" 7 #include "android/asset_manager_jni.h" 8  9 typedef struct JniMethodInfo_10 {11   JNIEnv *  env;12   jclass   classID;13   jmethodID  methodID;14 } JniMethodInfo;15 16 class JniBootHelper17 {18 public:19   static void       setJavaVM(JavaVM *javaVM);20   static JavaVM*     getJavaVM();21   static JNIEnv*     getEnv();22 23   static bool       setassetmanager(jobject activityinstance);24   static AAssetManager*  getAssetManager() { return _assetmanager; }25 26   static bool       setFileDir(jobject activityinstance);27   static bool       setCacheDir(jobject activityinstance);28 29   static bool       loadDexFile(jobject context,30                     const char* dexPath, 31                     const char* dexOptDir);32 33   static bool       loadClass(jobject context);34 35   static jobject     invokeStaticMethod(JNIEnv *env, 36                         const char* className, 37                         const char* methodName, 38                         jobjectArray pareTyple, 39                         jobjectArray pareVaules);40 41   static jobject     getFieldOjbect(JNIEnv *env, 42                      const char* className, 43                      const char* fieldName,44                       jobject obj);45   static void       setFieldOjbect(JNIEnv *env, 46                      const char* className, 47                      const char* fieldName, 48                       jobject obj, 49                       jobject filedVaule);50 51   static std::string   jstring2string(jstring str);52 53   static std::string FileDir;54   static std::string CacheDir;55 56 private:57   static JNIEnv*     cacheEnv(JavaVM* jvm);58 59   static bool       getMethodInfo(JniMethodInfo &methodinfo,60                     const char *className,61                     const char *methodName,62                     const char *paramCode);63 64   static JavaVM*     _psJavaVM;65   static AAssetManager*  _assetmanager;66   static jmethodID    _loadclassMethod_methodID;67   static jobject     _classloader;68 };69 70 #endif // __ANDROID_JNI_BOOT_HELPER_H__

.cpp文件

 1 #include "JniBootHelper.h" 2 #include <android/log.h> 3 #include <string.h> 4 #include <pthread.h> 5  6 #include "DexMarcoDef.h" 7  8 static pthread_key_t g_key; 9  10  11 void _detachCurrentThread(void* a) { 12   LOGD("DetachCurrentThread"); 13   JniBootHelper::getJavaVM()->DetachCurrentThread(); 14 } 15  16  17 JavaVM* JniBootHelper::_psJavaVM = nullptr; 18 std::string JniBootHelper::FileDir = ""; 19 std::string JniBootHelper::CacheDir = ""; 20 AAssetManager* JniBootHelper::_assetmanager = nullptr; 21 jmethodID JniBootHelper::_loadclassMethod_methodID = nullptr; 22 jobject JniBootHelper::_classloader = nullptr; 23  24 bool JniBootHelper::setassetmanager(jobject activityinstance) { 25   JniMethodInfo _getassetsMethod; 26   if (!JniBootHelper::getMethodInfo(_getassetsMethod, 27                           "android/content/Context", 28                           "getAssets", 29                           "()Landroid/content/res/AssetManager;")) { 30     LOGE("getmethod getAssets() failed."); 31     return false; 32   } 33  34   jobject _am = JniBootHelper::getEnv()->CallObjectMethod(activityinstance, 35                                 _getassetsMethod.methodID); 36  37   if (nullptr == _am) { 38     LOGE("CallObjectMethod getAssets() failed."); 39     return false; 40   } 41  42   JniBootHelper::_assetmanager = AAssetManager_fromJava(JniBootHelper::getEnv(), _am); 43   return true; 44 } 45  46 bool JniBootHelper::setFileDir(jobject activityinstance) 47 { 48   JniMethodInfo _getFileDirMethod; 49   if (!JniBootHelper::getMethodInfo(_getFileDirMethod, 50                           "android/content/Context", 51                           "getFilesDir", 52                           "()Ljava/io/File;")) { 53     LOGE("getmethod getFilesDir() failed."); 54     return false; 55   } 56   jobject _f = JniBootHelper::getEnv()->CallObjectMethod(activityinstance, 57                                 _getFileDirMethod.methodID); 58   if (nullptr == _f) { 59     LOGE("CallObjectMethod getFilesDir() failed."); 60     return false; 61   } 62   JniMethodInfo _getFilePathMethod; 63   if (!JniBootHelper::getMethodInfo(_getFilePathMethod, 64                           "java/io/File", 65                           "getAbsolutePath", 66                           "()Ljava/lang/String;")) { 67     LOGE("getmethod getAbsolutePath() failed."); 68     return false; 69   } 70   jstring _p = (jstring)JniBootHelper::getEnv()->CallObjectMethod(_f, 71                                 _getFilePathMethod.methodID); 72   if (nullptr == _p) { 73     LOGE("CallObjectMethod getAbsolutePath() failed."); 74     return false; 75   } 76  77   JniBootHelper::FileDir.assign(JniBootHelper::jstring2string(_p)); 78   LOGD("apk FileDir : %s", JniBootHelper::FileDir.c_str()); 79   JniBootHelper::getEnv()->DeleteLocalRef(_p); 80   return true; 81 } 82  83 bool JniBootHelper::setCacheDir(jobject activityinstance) 84 { 85   JniMethodInfo _getFileDirMethod; 86   if (!JniBootHelper::getMethodInfo(_getFileDirMethod, 87                           "android/content/Context", 88                           "getCacheDir", 89                           "()Ljava/io/File;")) { 90     LOGE("getmethod getCacheDir() failed."); 91     return false; 92   } 93   jobject _f = JniBootHelper::getEnv()->CallObjectMethod(activityinstance, 94                                 _getFileDirMethod.methodID); 95   if (nullptr == _f) { 96     LOGE("CallObjectMethod getCacheDir() failed."); 97     return false; 98   } 99   JniMethodInfo _getFilePathMethod;100   if (!JniBootHelper::getMethodInfo(_getFilePathMethod,101                           "java/io/File",102                           "getAbsolutePath",103                           "()Ljava/lang/String;")) {104     LOGE("getmethod getAbsolutePath() failed.");105     return false;106   }107   jstring _p = (jstring)JniBootHelper::getEnv()->CallObjectMethod(_f,108                                 _getFilePathMethod.methodID);109   if (nullptr == _p) {110     LOGE("CallObjectMethod getAbsolutePath() failed.");111     return false;112   }113 114   JniBootHelper::CacheDir.assign(JniBootHelper::jstring2string(_p));115   LOGD("apk CacheDir : %s", JniBootHelper::CacheDir.c_str());116   JniBootHelper::getEnv()->DeleteLocalRef(_p);117   return true;118 }119 120 bool JniBootHelper::loadClass(jobject context)121 {122   JNIEnv *env = JniBootHelper::getEnv();123   if (!env) {124     return false;125   }126 127   jstring _jstrClassName = env->NewStringUTF("com/origingame/InApplicationMethod");128   jclass _classid = (jclass) env->CallObjectMethod(JniBootHelper::_classloader,129                           JniBootHelper::_loadclassMethod_methodID,130                           _jstrClassName);131   if(!_classid)132   {133     LOGE("can not find class com/origingame/InApplicationMethod");134   }135   jmethodID _mid = env->GetStaticMethodID(_classid, "onCreate", "(Landroid/content/Context;)V");136   if(!_mid)137   {138     LOGE("failed to find methodID onCreate");139   }140   env->CallStaticVoidMethod(_classid, _mid, context);141   env->DeleteLocalRef(_jstrClassName);142   env->DeleteGlobalRef(JniBootHelper::_classloader);143 }144 145 bool JniBootHelper::loadDexFile(jobject context,146                 const char* dexPath, 147                 const char* dexOptDir)148 {149   JNIEnv *env = JniBootHelper::getEnv();150   if (!env) {151     return false;152   }153   154   jstring dexPathString, dexOptDirString;155   dexPathString = env->NewStringUTF(dexPath);156   dexOptDirString = env->NewStringUTF(dexOptDir);157 158   jclass native_clazz = env->GetObjectClass(context);159   jmethodID methodID_func = env->GetMethodID(native_clazz, 160                        "getPackageName", 161                        "()Ljava/lang/String;");162   jstring packagename = (jstring) (env->CallObjectMethod(context, methodID_func));163   std::string _packagename = JniBootHelper::jstring2string(packagename);164   LOGD("packagename: %s",_packagename.c_str());165   char libsDir[256];166   sprintf(libsDir, "/data/data/%s/lib", _packagename.c_str());167   jstring jlibsDir = env->NewStringUTF(libsDir);168 169   170   jclass jActivityThread = env->FindClass("android/app/ActivityThread");171   if(!jActivityThread)172   {173     LOGE("can not find class android/app/ActivityThread");174   }175   jmethodID jcATmid = env->GetStaticMethodID(jActivityThread, "currentActivityThread", "()Landroid/app/ActivityThread;");176   jobject currentActivityThread = env->CallStaticObjectMethod(jActivityThread, jcATmid);177   178   179   jclass class_hashmap = env->FindClass("java/util/Map");180 181   182   jobject obj_hashmap = JniBootHelper::getFieldOjbect(env, 183                         "android.app.ActivityThread", 184                         "mPackages",185                         currentActivityThread);186   /*187   jmethodID map_size = env->GetMethodID(class_hashmap, 188                      "size", 189                      "()I");190   jint size = (jint)env->CallObjectMethod(obj_hashmap, 191                    map_size192                    );193   LOGD("map size : %d", (int)size);194   */195   if(!obj_hashmap)196   {197     LOGE("obj_hashmap is null");198   }199 200   jclass class_WeakReference = env->FindClass("java/lang/ref/WeakReference");201   if (!class_WeakReference) 202   {203     LOGE("class_WeakReference Not Found ");204   }205 206   jmethodID WeakReference_get_method = env->GetMethodID(class_WeakReference, 207                              "get", 208                              "()Ljava/lang/Object;");209   if (!WeakReference_get_method) 210   {211     LOGE("WeakReference_get_method Not Found ");212   }213 214   jmethodID get_func = env->GetMethodID(class_hashmap, 215                      "get", 216                      "(Ljava/lang/Object;)Ljava/lang/Object;");217   if (!get_func) {218     LOGE("method get Not Found ");219   }220   221   jobject get_obj = env->CallObjectMethod(obj_hashmap, 222                       get_func, 223                       packagename);224   if (!get_obj) {225     LOGE("get_obj Not Found ");226   }227   228   jobject get_get_obj = env->CallObjectMethod(get_obj, 229                         WeakReference_get_method);230   if (!get_get_obj) {231     LOGE("get_get_obj Not Found ");232   }233   234   /*235   jclass class_DexClassloader = env->FindClass("dalvik/system/DexClassLoader");236   if (!class_DexClassloader) {237     LOGE("class_DexClassloader Not Found ");238   }239 240   jmethodID DexClassloader_construct_method = env->GetMethodID(class_DexClassloader, 241                                  "<init>",242                                  "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/ClassLoader;)V");243   if (!DexClassloader_construct_method) {244     LOGE("DexClassloader_construct_method Not Found ");245   }246   247   jobject obj_DexClassloader = env->NewObject(class_DexClassloader,248                         DexClassloader_construct_method, 249                         dexPathString, 250                         dexOptDirString,251                         jlibsDir,252                         JniBootHelper::getFieldOjbect(env, "android.app.LoadedApk", "mClassLoader", get_get_obj));253   if (!obj_DexClassloader) {254     LOGE("obj_DexClassloader Not Found ");255   }256   */257   jclass class_DexClassloader = env->FindClass("dalvik/system/PathClassLoader");258   if (!class_DexClassloader) {259     LOGE("class_DexClassloader Not Found ");260   }261 262   jmethodID DexClassloader_construct_method = env->GetMethodID(class_DexClassloader, 263                                 "<init>",264                                 "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/ClassLoader;)V");265   if (!DexClassloader_construct_method) {266     LOGE("DexClassloader_construct_method Not Found ");267   }268   269   jobject obj_DexClassloader = env->NewObject(class_DexClassloader,270                         DexClassloader_construct_method, 271                         dexPathString,272                         jlibsDir,273                         JniBootHelper::getFieldOjbect(env, "android.app.LoadedApk", "mClassLoader", get_get_obj));274   if (!obj_DexClassloader) {275     LOGE("obj_DexClassloader Not Found ");276   }277 278   JniBootHelper::_classloader = env->NewGlobalRef(obj_DexClassloader);279   JniBootHelper::_loadclassMethod_methodID = env->GetMethodID(class_DexClassloader,280                                 "loadClass",281                                 "(Ljava/lang/String;)Ljava/lang/Class;");282 283   JniBootHelper::setFieldOjbect(env, "android.app.LoadedApk", "mClassLoader", get_get_obj, obj_DexClassloader);284   env->DeleteLocalRef(dexPathString);285   env->DeleteLocalRef(dexOptDirString);286   env->DeleteLocalRef(jlibsDir);287   LOGD("finish.");288   return true;289 }290 291 JavaVM* JniBootHelper::getJavaVM() {292   pthread_t thisthread = pthread_self();293   LOGD("JniBootHelper::getJavaVM(), pthread_self() = %ld", thisthread);294   return _psJavaVM;295 }296 297 void JniBootHelper::setJavaVM(JavaVM *javaVM) {298   pthread_t thisthread = pthread_self();299   LOGD("JniBootHelper::setJavaVM(%p), pthread_self() = %ld", javaVM, thisthread);300   _psJavaVM = javaVM;301 302   pthread_key_create(&g_key, _detachCurrentThread);303 }304 305 JNIEnv* JniBootHelper::cacheEnv(JavaVM* jvm) {306   JNIEnv* _env = nullptr;307   // get jni environment308   jint ret = jvm->GetEnv((void**)&_env, JNI_VERSION_1_4);309   310   switch (ret) {311   case JNI_OK :312     // Success!313     pthread_setspecific(g_key, _env);314     return _env;315       316   case JNI_EDETACHED :317     // Thread not attached318     if (jvm->AttachCurrentThread(&_env, nullptr) < 0)319       {320         LOGE("Failed to get the environment using AttachCurrentThread()");321 322         return nullptr;323       } else {324       // Success : Attached and obtained JNIEnv!325       pthread_setspecific(g_key, _env);326       return _env;327     }328       329   case JNI_EVERSION :330     // Cannot recover from this error331     LOGE("JNI interface version 1.4 not supported");332   default :333     LOGE("Failed to get the environment using GetEnv()");334     return nullptr;335   }336 }337 338 JNIEnv* JniBootHelper::getEnv() {339   JNIEnv *_env = (JNIEnv *)pthread_getspecific(g_key);340   if (_env == nullptr)341     _env = JniBootHelper::cacheEnv(_psJavaVM);342   return _env;343 }344 345 bool JniBootHelper::getMethodInfo(JniMethodInfo &methodinfo,346                  const char *className,347                  const char *methodName,348                  const char *paramCode) 349 {350   if ((nullptr == className) ||351     (nullptr == methodName) ||352     (nullptr == paramCode)) {353     return false;354   }355 356   JNIEnv *env = JniBootHelper::getEnv();357   if (!env) {358     return false;359   }360 361   jclass classID = env->FindClass(className);362   if (! classID) {363     LOGE("Failed to find class %s", className);364     env->ExceptionClear();365     return false;366   }367 368   jmethodID methodID = env->GetMethodID(classID, methodName, paramCode);369   if (! methodID) {370     LOGE("Failed to find method id of %s", methodName);371     env->ExceptionClear();372     return false;373   }374 375   methodinfo.classID = classID;376   methodinfo.env = env;377   methodinfo.methodID = methodID;378 379   return true;380 }381 382 std::string JniBootHelper::jstring2string(jstring jstr) {383   if (jstr == nullptr) {384     return "";385   }386   387   JNIEnv *env = JniBootHelper::getEnv();388   if (!env) {389     return nullptr;390   }391 392   const char* chars = env->GetStringUTFChars(jstr, nullptr);393   std::string ret(chars);394   env->ReleaseStringUTFChars(jstr, chars);395 396   return ret;397 }398 399 jobject JniBootHelper::invokeStaticMethod(JNIEnv *env, 400                      const char* className, 401                      const char* methodName, 402                      jobjectArray pareTyple, 403                      jobjectArray pareVaules)404 {405   jstring jclassName, jmethodName;406   jclassName = env->NewStringUTF(className);407   jmethodName = env->NewStringUTF(methodName);408   409   jclass _class = env->FindClass("java/lang/Class");410   if(!_class)411   {412     LOGE("invokeStaticMethod: Failed to find class java/lang/Class");413     env->ExceptionClear();414     return nullptr;415   }416   417   jmethodID forname_func = env->GetStaticMethodID(_class, 418                           "forName",419                           "(Ljava/lang/String;)Ljava/lang/Class;");420   if(!forname_func)421   {422     LOGE("invokeStaticMethod: Failed to find method forName");423     env->ExceptionClear();424     return nullptr;425   }426   427   jobject class_obj = env->CallStaticObjectMethod(_class, 428                           forname_func,429                           jclassName);430   431   jclass class_java = env->GetObjectClass(class_obj);432   433   jmethodID getmethod_func = env->GetMethodID(class_java, 434                         "getMethod",435                         "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;");436   if(!getmethod_func)437   {438     LOGE("invokeStaticMethod: Failed to find method getMethod");439     env->ExceptionClear();440     return nullptr;441   }442                        443   jobject method_obj = env->CallObjectMethod(class_obj, 444                         getmethod_func,445                         jmethodName, 446                         pareTyple);447   if(!method_obj)448   {449     LOGE("invokeStaticMethod: Failed to CallObjectMethod.%s,  %s",className, methodName);450     env->ExceptionClear();451     return nullptr;452   }453   454   jclass class_method_obj = env->GetObjectClass(method_obj);455   456   jmethodID invoke_func = env->GetMethodID(class_method_obj, 457                       "invoke",458                       "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;");459                       460   if(!invoke_func)461   {462     LOGE("invokeStaticMethod: Failed to find method invoke");463     env->ExceptionClear();464     return nullptr;465   }466   467   jobject invoke_obj = env->CallObjectMethod(method_obj, 468                         invoke_func, 469                         NULL,470                         pareVaules);471   472   env->DeleteLocalRef(jclassName);473   env->DeleteLocalRef(jmethodName);474   env->DeleteLocalRef(class_java);475   env->DeleteLocalRef(method_obj);476   LOGD("invokeStaticMethod finish.");477   return invoke_obj;478 }479 480 jobject JniBootHelper::getFieldOjbect(JNIEnv *env, 481                    const char* className, 482                    const char* fieldName,483                    jobject obj)484 {485   jstring jclassName, jfieldName;486   jclassName = env->NewStringUTF(className);487   jfieldName = env->NewStringUTF(fieldName);488 489   jclass _class = env->FindClass("java/lang/Class");490   jmethodID forname_func = env->GetStaticMethodID(_class, 491                           "forName",492                           "(Ljava/lang/String;)Ljava/lang/Class;");493   if(!forname_func)494   {495     LOGE("getFieldOjbect: Failed to find method forName");496     env->ExceptionClear();497     return nullptr;498   }499   jobject class_obj = env->CallStaticObjectMethod(_class, 500                           forname_func,501                           jclassName);502   jclass class_java = env->GetObjectClass(class_obj);503 504   jmethodID getfield_func = env->GetMethodID(class_java, 505                        "getDeclaredField",506                        "(Ljava/lang/String;)Ljava/lang/reflect/Field;");507   if(!getfield_func)508   {509     LOGE("getFieldOjbect: Failed to find method getDeclaredField");510     env->ExceptionClear();511     return nullptr;512   }513   jobject method_obj = env->CallObjectMethod(class_obj, 514                         getfield_func,515                         jfieldName);516   jclass class_method_obj = env->GetObjectClass(method_obj);517 518   jmethodID setaccess_func = env->GetMethodID(class_method_obj,519                         "setAccessible", 520                         "(Z)V");521   if(!setaccess_func)522   {523     LOGE("getFieldOjbect: Failed to find method setAccessible");524     env->ExceptionClear();525     return nullptr;526   }527   env->CallVoidMethod(method_obj, 528             setaccess_func, 529             true);530 531   jmethodID get_func = env->GetMethodID(class_method_obj, 532                      "get",533                      "(Ljava/lang/Object;)Ljava/lang/Object;");534   if(!get_func)535   {536     LOGE("getFieldOjbect: Failed to find method get");537     env->ExceptionClear();538     return nullptr;539   }540   jobject get_obj = env->CallObjectMethod(method_obj, 541                       get_func, 542                       obj);543 544   env->DeleteLocalRef(class_java);545   env->DeleteLocalRef(method_obj);546   env->DeleteLocalRef(jclassName);547   env->DeleteLocalRef(jfieldName);548   return get_obj;549 }550 551 void JniBootHelper::setFieldOjbect(JNIEnv *env, 552          const char* className, 553          const char* fieldName, 554           jobject obj, 555           jobject filedVaule)556 {557   jstring jclassName, jfieldName;558   jclassName = env->NewStringUTF(className);559   jfieldName = env->NewStringUTF(fieldName);560 561   jclass _class = env->FindClass("java/lang/Class");562   if(!_class)563   {564     LOGE("setFieldOjbect: Failed to find java/lang/Class");565     env->ExceptionClear();566     return;567   }568   jmethodID forName_func = env->GetStaticMethodID(_class, 569                           "forName",570                           "(Ljava/lang/String;)Ljava/lang/Class;");571   if(!forName_func)572   {573     LOGE("setFieldOjbect: Failed to find method forname");574     env->ExceptionClear();575     return;576   }577   jobject class_obj = env->CallStaticObjectMethod(_class, 578                           forName_func,579                           jclassName);580   jclass class_java = env->GetObjectClass(class_obj);581 582   jmethodID getField_func = env->GetMethodID(class_java, 583                        "getDeclaredField",584                         "(Ljava/lang/String;)Ljava/lang/reflect/Field;");585   if(!getField_func)586   {587     LOGE("setFieldOjbect: Failed to find method getDeclaredField");588     env->ExceptionClear();589     return;590   }591   jobject method_obj = env->CallObjectMethod(class_obj, 592                         getField_func,593                         jfieldName);594   jclass class_method_obj = env->GetObjectClass(method_obj);595 596   jmethodID setaccess_func = env->GetMethodID(class_method_obj,597                         "setAccessible", 598                         "(Z)V");599   if(!setaccess_func)600   {601     LOGE("setFieldOjbect: Failed to find method setAccessible");602     env->ExceptionClear();603     return;604   }605   env->CallVoidMethod(method_obj, setaccess_func, true);606 607   jmethodID set_func = env->GetMethodID(class_method_obj, 608                      "set",609                      "(Ljava/lang/Object;Ljava/lang/Object;)V");610   if(!set_func)611   {612     LOGE("setFieldOjbect: Failed to find method set");613     env->ExceptionClear();614     return;615   }616   env->CallVoidMethod(method_obj, 617             set_func, 618             obj, 619             filedVaule);620 621   env->DeleteLocalRef(class_java);622   env->DeleteLocalRef(method_obj);623   env->DeleteLocalRef(jclassName);624   env->DeleteLocalRef(jfieldName);625 }

主入口

 1 #include "JniBootHelper.h" 2 #include "BootFileUtils.h" 3 #include "CPakReader.h" 4  5 #include <android/log.h> 6 #include <jni.h> 7  8 #include "DexMarcoDef.h" 9  10 #define Dex_asstesPath "assets/OriginAPP.jar" 11 #define Dex_NAME "OriginClasses.jar" 12 #define Dex_RELEASEFLODER "OriginBoot" 13 #define Dex_CACHEFLODER "OriginBootCache" 14  15 extern "C" 16 { 17   JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) 18   { 19     LOGD("JNI_OnLoad has been called."); 20     JniBootHelper::setJavaVM(vm); 21  22     return JNI_VERSION_1_4; 23   } 24  25   JNIEXPORT void JNI_OnUnLoad(JavaVM *vm, void *reserved) 26   { 27     LOGD("JNI_OnUnLoad has been called."); 28   } 29  30   JNIEXPORT void Java_com_origingame_OriginShell_nativeLoadClass(JNIEnv* env, jobject thiz, jobject context) 31   { 32     JniBootHelper::loadClass(context); 33   } 34  35   JNIEXPORT void Java_com_origingame_OriginShell_nativeBoot(JNIEnv* env, jobject thiz, jobject context) 36   { 37     bool _initsuccess = true; 38  39     if(!JniBootHelper::setassetmanager(context)){ 40       LOGE("setassetmanager failed!"); 41       _initsuccess = false; 42     } 43  44     if(!JniBootHelper::setFileDir(context)){ 45       LOGE("setFileDir failed!"); 46       _initsuccess = false; 47     } 48  49     if(!JniBootHelper::setCacheDir(context)){ 50       LOGE("setCacheDir failed!"); 51       _initsuccess = false; 52     } 53  54     if(_initsuccess) 55     { 56       LOGD("init success."); 57       bool _dirExist = false; 58       bool _exist = false; 59       BootFileUtils* fileutils = BootFileUtils::getInstance(); 60       std::string _path = JniBootHelper::FileDir; 61       _path.append("/"); 62       _path.append(Dex_RELEASEFLODER); 63       LOGD("check dir: %s", _path.c_str()); 64       if(fileutils->isDirectoryExistInternal(_path)) 65       { 66         _dirExist = true; 67         std::string _file = JniBootHelper::FileDir; 68         _file.append("/"); 69         _file.append(Dex_RELEASEFLODER); 70         _file.append("/"); 71         _file.append(Dex_NAME); 72         if(fileutils->isFileExistInternal(_file)) 73           _exist = true; 74       } 75  76       std::string _cachedirpath = JniBootHelper::FileDir; 77       _cachedirpath.append("/"); 78       _cachedirpath.append(Dex_CACHEFLODER); 79  80       if(!_dirExist) 81       { 82         LOGD("create dir."); 83         std::string _filedirpath = JniBootHelper::FileDir; 84         _filedirpath.append("/"); 85         _filedirpath.append(Dex_RELEASEFLODER); 86         fileutils->createDirectory(_filedirpath); 87  88         fileutils->createDirectory(_cachedirpath); 89       } 90  91  92       std::string _dexPath = JniBootHelper::FileDir; 93       _dexPath.append("/"); 94       _dexPath.append(Dex_RELEASEFLODER); 95       _dexPath.append("/"); 96       _dexPath.append(Dex_NAME); 97  98       if(!_exist) 99       {100         LOGD("needed file is not exist.");101         CPakReader* PakReader = CPakReader::Create(Dex_asstesPath, true);102         TFileBlock fb;103         PakReader->GetBlock(Dex_NAME, fb);104         105         LOGD("destfile: %s", _dexPath.c_str());106         fileutils->writeData2File(_dexPath.c_str(), fb.oData, fb.index.oSize);107         delete PakReader;108         BootFileUtils::destroyInstance();109       }110       else111         LOGD("needed file is exist.");112 113       114       JniBootHelper::loadDexFile(context, _dexPath.c_str(), _cachedirpath.c_str());115     }116   }117 }

 

java层代码

 1 package com.origingame; 2  3 import android.app.Application; 4 import android.content.Context; 5 import android.util.Log; 6  7 public class OriginApplication extends Application { 8   @Override 9   protected void attachBaseContext(Context context){10     super.attachBaseContext(context);11     OriginShell.nativeBoot(context);12   }13   14   @Override 15   public void onCreate() {16     super.onCreate();17     Log.d("OriginGame", "running......");18     OriginShell.nativeLoadClass(getApplicationContext());19   }20 }

OriginShell实现

 1 package com.origingame; 2  3 import android.content.Context; 4  5 public class OriginShell { 6   static{ 7     System.loadLibrary("originshell"); 8   } 9   public static native void nativeBoot(Context context);10   public static native void nativeLoadClass(Context context);11 }

 

由于没怎么注释,所以讲一下基本的原理。

大致原理就是通过重写Application的attachBaseContext方法在c++层new一个PathClassLoader或者DexClassLoader对象,两者的具体区别网上已经有很多说明不在详解,通过new的新对象来加载包含dex的jar文件,最后通过反射机制替换掉app启动时原有的classloader,也就是重新给mClassLoader这个成员变量赋值我们最新的classloader

包含dex的jar文件我这里也有做加密处理,加载之前我是先做解密的,大家也可以自己实现自己的加密方式。