最近发现有人破解我们的应用,于是研究了一下如何在应用被破解以后,让应用退出的简单实现方案。
很多应用可能会选择加固的方式来实现,但是在海外Google Play上是不允许加固的,因此需要其他策略。
应用被破解以后一般会被修改然后重签名,所以可以在签名上做一些针对性。
这里的方案是通过NDK的方式来把验证过程放到so包里面进行拦截,做了一些特殊的处理,因为应用的这个so是必须依赖的,否则应用里面很多功能都是无法使用的,因此将验证过程进行整合。
static const char *applicationClassPath = "com/demo/zhupeng/app/DemoApplication";// 应用签名
static const char *appSign = "Java端获取的签名";// 验证签名是否被修改
jint verifySignature(JavaVM *vm) {JNIEnv *env;if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) != JNI_OK) {return JNI_ERR;}jclass contextClass = env->FindClass("android/content/Context");jmethodID getPackageManagerMethodID = env->GetMethodID(contextClass, "getPackageManager","()Landroid/content/pm/PackageManager;");jmethodID getPackageNameMethodID = env->GetMethodID(contextClass, "getPackageName","()Ljava/lang/String;");jclass packageManagerClass = env->FindClass("android/content/pm/PackageManager");jmethodID getPackageInfoMethodID = env->GetMethodID(packageManagerClass, "getPackageInfo","(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;");jclass packageInfoClass = env->FindClass("android/content/pm/PackageInfo");jfieldID signaturesFieldID = env->GetFieldID(packageInfoClass, "signatures","[Landroid/content/pm/Signature;");jclass signatureClass = env->FindClass("android/content/pm/Signature");jmethodID toByteArrayMethodID = env->GetMethodID(signatureClass, "toByteArray", "()[B");jmethodID toCharsStringMethodId = env->GetMethodID(signatureClass, "toCharsString","()Ljava/lang/String;");jclass applicationClass = env->FindClass(applicationClassPath);jmethodID getInstanceStaticMethodID = env->GetStaticMethodID(applicationClass, "getInstance","()Landroid/app/Application;");// 获取当前的Context对象jobject context = env->CallStaticObjectMethod(applicationClass, getInstanceStaticMethodID);jobject packageManager = env->CallObjectMethod(context, getPackageManagerMethodID);jstring packageName = (jstring) env->CallObjectMethod(context, getPackageNameMethodID);jobject packageInfo = env->CallObjectMethod(packageManager, getPackageInfoMethodID, packageName,0x00000040);jobjectArray signatures = reinterpret_cast<jobjectArray>(env->GetObjectField(packageInfo,signaturesFieldID));jobject signature = env->GetObjectArrayElement(signatures, 0);jbyteArray signatureBytes = (jbyteArray) env->CallObjectMethod(signature, toByteArrayMethodID);jobject signatureObj = env->CallObjectMethod(signature, toCharsStringMethodId);// 将签名字节数组转换为C++字符串// jsize length = env->GetArrayLength(signatureBytes);// jbyte *bytes = env->GetByteArrayElements(signatureBytes, NULL);// std::string signatureString(reinterpret_cast<char *>(bytes), length);// env->ReleaseByteArrayElements(signatureBytes, bytes, JNI_ABORT);// 将签名字符串打印出来// __android_log_print(ANDROID_LOG_INFO, "JNI", "App Signature 方法二: %s \n", signatureString.c_str());jstring signatureString = reinterpret_cast<jstring>(signatureObj);const char *signatureChars = env->GetStringUTFChars(signatureString, 0);// 将签名字符串打印出来__android_log_print(ANDROID_LOG_INFO, "JNI", "App Signature: %s \n", signatureChars);jclass buildConfigClass = env->FindClass("com/demo/zhupeng/BuildConfig");jfieldID isOverSeasFieldID = env->GetStaticFieldID(buildConfigClass, "isOverSeas","Ljava/lang/Boolean;");jobject isOverSeasObj = env->GetStaticObjectField(buildConfigClass, isOverSeasFieldID);jboolean isOverSeas = env->CallBooleanMethod(isOverSeasObj, env->GetMethodID(env->GetObjectClass(isOverSeasObj), "booleanValue", "()Z"));jboolean equals = (strcmp(appSign, signatureChars) == 0) ? JNI_TRUE : JNI_FALSE;return equals ? JNI_VERSION_1_6 : JNI_ERR;
}jint JNI_OnLoad(JavaVM *vm, void *reserved) {return verifySignature(vm);
}
感谢大家的支持,如有错误请指正,如需转载请标明原文出处!