APP重签名是指黑客通过修改APP的签名信息,使得APP看起来像是由原开发者签名发布的,但实际上是被黑客篡改过的。这种行为会破坏APP的完整性和安全性,给用户带来不必要的风险。因此,开发者需要采取一些措施来防止APP重签名,保护APP的安全性。其中一种常见的方式是基于NDK验签的方式实现APP重签名校验方案。
基于NDK验签的方式实现APP重签名校验方案的原理如下:
需要注意的是,基于NDK验签的方式实现APP重签名校验方案并不能完全防止所有的破解行为,但可以有效地提高APP的安全性,减少被破解的风险。因此,开发者需要根据自己的实际情况选择合适的安全措施来保护自己的APP。
总的来说,基于NDK验签的方式实现APP重签名校验方案是一种有效的安全保护手段,可以帮助开发者提高APP的安全性,避免被重签名的风险。希望开发者们能够重视APP安全问题,采取一些有效的措施来保护自己的APP。
static const char *applicationClassPath = "com/zhupeng/demo/app/CoreApplication";
// 应用签名
static const char *appSign = "加密后的应用签名";
//加密
jstring encrypt(JNIEnv *env, jbyteArray data) {
jclass messageDigestClass = env->FindClass("java/security/MessageDigest");
jmethodID getInstanceStaticMethodID = env->GetStaticMethodID(messageDigestClass,
"getInstance",
"(Ljava/lang/String;)Ljava/security/MessageDigest;");
jobject digest = env->CallStaticObjectMethod(messageDigestClass, getInstanceStaticMethodID,
env->NewStringUTF("SHA1"));
jmethodID digestMethodID = env->GetMethodID(messageDigestClass, "digest", "([B)[B");
jbyteArray sha1Bytes = (jbyteArray) env->CallObjectMethod(digest, digestMethodID, data);
// 将字节数组转换为十六进制字符串
jsize sha1BytesLen = env->GetArrayLength(sha1Bytes);
jbyte *sha1BytesData = env->GetByteArrayElements(sha1Bytes, NULL);
char *hexChars = "0123456789ABCDEF";
char *sha1Hex = static_cast<char *>(malloc(sha1BytesLen * 2 + 1));
for (int i = 0; i < sha1BytesLen; i++) {
sha1Hex[i * 2] = hexChars[(sha1BytesData[i] & 0xf0) >> 4];
sha1Hex[i * 2 + 1] = hexChars[sha1BytesData[i] & 0x0f];
}
sha1Hex[sha1BytesLen * 2] = 0;
env->ReleaseByteArrayElements(sha1Bytes, sha1BytesData, JNI_ABORT);
return env->NewStringUTF(sha1Hex);
}
// 验证签名是否被修改
jint verifySignature(JavaVM *vm) {
try {
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(bytes), length);
// env->ReleaseByteArrayElements(signatureBytes, bytes, JNI_ABORT);
// 将签名字符串打印出来
// __android_log_print(ANDROID_LOG_INFO, "JNI", "App Signature: %s", signatureString.c_str());
jstring signatureString = reinterpret_cast<jstring>(signatureObj);
const char *signatureChars = env->GetStringUTFChars(encrypt(env, signatureBytes), 0);
// 将签名字符串打印出来
__android_log_print(ANDROID_LOG_INFO, "JNI", "App Signature: %s", signatureChars);
jclass buildConfigClass = env->FindClass("com/virtual/video/BuildConfig");
jfieldID channelFieldID = env->GetStaticFieldID(buildConfigClass, "channel",
"Ljava/lang/String;");
jstring channel= env->GetStaticObjectField(buildConfigClass, channelFieldID);
jboolean equals = (strcmp(appSign, signatureChars) == 0) ? JNI_TRUE : JNI_FALSE;
if (!equals) {
// 签名不一致,退出应用
// 似乎无效,会停留在启动页,直接返回JNI_ERR
jclass systemClass = env->FindClass("java/lang/System");
jmethodID exitMethod = env->GetStaticMethodID(systemClass, "exit", "(I)V");
env->CallStaticVoidMethod(systemClass, exitMethod, 0);
return JNI_ERR;
}
} catch (const char *msg) {
}
return JNI_VERSION_1_6;
}
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
global_jvm = vm;
return verifySignature(vm);
}
感谢大家的支持,如有错误请指正,如需转载请标明原文出处!