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文件我这里也有做加密处理,加载之前我是先做解密的,大家也可以自己实现自己的加密方式。
zxz3121@gmail.com