博文转自http://www.tuicool.com/articles/UVjme2r,感谢博主的分享
为了防止被反编译,打算把关键代码写到so里(比如加解密),在so里加上判断APk包签名是否一致的代码,避免so被二次打包。其实用JNI读签名就是用了Java的反射机制。
先看Java读取签名的方法:
1 try { 2 PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 64); 3 Signature sign = info.signatures[0]; 4 Log.i("test", "hashCode : " + sign.hashCode()); 5 } catch (NameNotFoundException e) { 6 e.printStackTrace(); 7 }
然后我们用JNI c语言实现,同样需要传递Context:
1 int getSignHashCode(JNIEnv *env, jobject context) { 2 //Context的类 3 jclass context_clazz = (*env)->GetObjectClass(env, context); 4 // 得到 getPackageManager 方法的 ID 5 jmethodID methodID_getPackageManager = (*env)->GetMethodID(env, context_clazz, 6 "getPackageManager", "()Landroid/content/pm/PackageManager;"); 7 8 // 获得PackageManager对象 9 jobject packageManager = (*env)->CallObjectMethod(env, context, 10 methodID_getPackageManager); 11 // // 获得 PackageManager 类 12 jclass pm_clazz = (*env)->GetObjectClass(env, packageManager); 13 // 得到 getPackageInfo 方法的 ID 14 jmethodID methodID_pm = (*env)->GetMethodID(env, pm_clazz, "getPackageInfo", 15 "(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;"); 16 // 17 // // 得到 getPackageName 方法的 ID 18 jmethodID methodID_pack = (*env)->GetMethodID(env, context_clazz, 19 "getPackageName", "()Ljava/lang/String;"); 20 21 // 获得当前应用的包名 22 jstring application_package = (*env)->CallObjectMethod(env, context, 23 methodID_pack); 24 const char *str = (*env)->GetStringUTFChars(env, application_package, 0); 25 __android_log_print(ANDROID_LOG_DEBUG, "JNI", "packageName: %s ", str); 26 27 // 获得PackageInfo 28 jobject packageInfo = (*env)->CallObjectMethod(env, packageManager, 29 methodID_pm, application_package, 64); 30 31 jclass packageinfo_clazz = (*env)->GetObjectClass(env, packageInfo); 32 jfieldID fieldID_signatures = (*env)->GetFieldID(env, packageinfo_clazz, 33 "signatures", "[Landroid/content/pm/Signature;"); 34 jobjectArray signature_arr = (jobjectArray)(*env)->GetObjectField(env, 35 packageInfo, fieldID_signatures); 36 //Signature数组中取出第一个元素 37 jobject signature = (*env)->GetObjectArrayElement(env, signature_arr, 0); 38 //读signature的hashcode 39 jclass signature_clazz = (*env)->GetObjectClass(env, signature); 40 jmethodID methodID_hashcode = (*env)->GetMethodID(env, signature_clazz, 41 "hashCode", "()I"); 42 jint hashCode = (*env)->CallIntMethod(env, signature, methodID_hashcode); 43 __android_log_print(ANDROID_LOG_DEBUG, "JNI", "hashcode: %d ", hashCode); 44 return hashCode; 45 }
第二个参数jobject不是JNI函数的默认参数,而是传入的Context实例。