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 JniBootHelper
17 {
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_size
192                                       );
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 environment
308     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 attached
318         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 error
331         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             else
111                 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文件我这里也有做加密处理,加载之前我是先做解密的,大家也可以自己实现自己的加密方式。

 

posted @ 2015-08-31 16:05  AndyZheng  阅读(1919)  评论(0编辑  收藏  举报