-
Notifications
You must be signed in to change notification settings - Fork 19
/
Copy pathKey.cpp
155 lines (132 loc) · 6.79 KB
/
Key.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#include <jni.h>
#include <string.h>
#include <assert.h>
#include <cstdlib>
#include "log.h"
// 需要被验证应用的包名
const char *APP_PACKAGE_NAME = "me.key.protection.demo";
// 应用签名,通过 JNIDecryptKey.getSignature(getApplicationContext()) 获取,注意开发版和发布版的区别,发布版需要使用正式签名打包后获取
const char *SIGNATURE_KEY = "308201dd30820146020101300d06092a864886f70d010105050030373116301406035504030c0d416e64726f69642044656275673110300e060355040a0c07416e64726f6964310b3009060355040613025553301e170d3138313031353033343532325a170d3438313030373033343532325a30373116301406035504030c0d416e64726f69642044656275673110300e060355040a0c07416e64726f6964310b300906035504061302555330819f300d06092a864886f70d010101050003818d003081890281810083f9d6810d4f93d1a3bd882f77e123853221dda2a52fe916b41c6d88e07b49c7f36e53c2b7d8d7d6cecdf933236fd43b50dea0d8c01f726056c02d5f9f4a4dfc8470aeae0c4b393067dbe954c16ec18427763df1ccacac4ca81251663c77e91194945b4bde3cc9fe70ecbcb49313e217793254b9e8513813dbb290775b9a9be70203010001300d06092a864886f70d0101050500038181002372375ff84ce8652762ec23020313ba1953d1fb9e47214f9150c750ddd06fac4048353a34e2501c4e2aa44748053e296c93dda8e491eff13c863286b94df5528234291985eb19a203c734c342206147586bf82451680d13d562008ae68c00edee2a775efbf4b6e63d4d9499aeee172cb8cd6024aaa8a9c50a83005a74cebc30";
// 需要被保护的密钥,请修改成你自己的密钥
const char *DECRYPT_KEY = "successful return key!";
// native 方法所在类的路径
const char *NATIVE_CLASS_PATH = "me/key/protection/JNIKey";
// 验证是否通过
static jboolean auth = JNI_FALSE;
#ifdef __cplusplus
extern "C" {
#endif
/*
* 获取全局 Application
*/
jobject getApplicationContext(JNIEnv *env) {
jclass activityThread = env->FindClass("android/app/ActivityThread");
jmethodID currentActivityThread = env->GetStaticMethodID(activityThread, "currentActivityThread", "()Landroid/app/ActivityThread;");
jobject at = env->CallStaticObjectMethod(activityThread, currentActivityThread);
jmethodID getApplication = env->GetMethodID(activityThread, "getApplication", "()Landroid/app/Application;");
return env->CallObjectMethod(at, getApplication);
}
/*
* 初始化并判断当前 APP 是否为合法应用,只需调用一次
*/
JNICALL jboolean init(JNIEnv *env, jclass) {
jclass binderClass = env->FindClass("android/os/Binder");
jclass contextClass = env->FindClass("android/content/Context");
jclass signatureClass = env->FindClass("android/content/pm/Signature");
jclass packageNameClass = env->FindClass("android/content/pm/PackageManager");
jclass packageInfoClass = env->FindClass("android/content/pm/PackageInfo");
jmethodID packageManager = env->GetMethodID(contextClass, "getPackageManager", "()Landroid/content/pm/PackageManager;");
jmethodID packageName = env->GetMethodID(contextClass, "getPackageName", "()Ljava/lang/String;");
jmethodID toCharsString = env->GetMethodID(signatureClass, "toCharsString", "()Ljava/lang/String;");
jmethodID packageInfo = env->GetMethodID(packageNameClass, "getPackageInfo", "(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;");
jmethodID nameForUid = env->GetMethodID(packageNameClass, "getNameForUid", "(I)Ljava/lang/String;");
jmethodID callingUid = env->GetStaticMethodID(binderClass, "getCallingUid", "()I");
jint uid = env->CallStaticIntMethod(binderClass, callingUid);
// 获取全局 Application
jobject context = getApplicationContext(env);
jobject packageManagerObject = env->CallObjectMethod(context, packageManager);
jstring packNameString = (jstring) env->CallObjectMethod(context, packageName);
jobject packageInfoObject = env->CallObjectMethod(packageManagerObject, packageInfo, packNameString, 64);
jfieldID signaturefieldID = env->GetFieldID(packageInfoClass, "signatures", "[Landroid/content/pm/Signature;");
jobjectArray signatureArray = (jobjectArray) env->GetObjectField(packageInfoObject, signaturefieldID);
jobject signatureObject = env->GetObjectArrayElement(signatureArray, 0);
jstring runningPackageName = (jstring) env->CallObjectMethod(packageManagerObject, nameForUid, uid);
if (runningPackageName) {// 正在运行应用的包名
const char *charPackageName = env->GetStringUTFChars(runningPackageName, 0);
if (strcmp(charPackageName, APP_PACKAGE_NAME) != 0) {
return JNI_FALSE;
}
env->ReleaseStringUTFChars(runningPackageName, charPackageName);
} else {
return JNI_FALSE;
}
jstring signatureStr = (jstring) env->CallObjectMethod(signatureObject, toCharsString);
const char *signature = env->GetStringUTFChars((jstring) env->CallObjectMethod(signatureObject, toCharsString), NULL);
env->DeleteLocalRef(binderClass);
env->DeleteLocalRef(contextClass);
env->DeleteLocalRef(signatureClass);
env->DeleteLocalRef(packageNameClass);
env->DeleteLocalRef(packageInfoClass);
LOGE("current apk signature %s", signature);
LOGE("reserved signature %s", SIGNATURE_KEY);
if (strcmp(signature, SIGNATURE_KEY) == 0) {
LOGE("verification passed");
env->ReleaseStringUTFChars(signatureStr, signature);
auth = JNI_TRUE;
return JNI_TRUE;
} else {
LOGE("verification failed");
auth = JNI_FALSE;
return JNI_FALSE;
}
}
/*
* 获取 Key
*/
JNIEXPORT jstring JNICALL getKey(JNIEnv *env, jclass) {
if (auth) {
return env->NewStringUTF(DECRYPT_KEY);
} else {// 你没有权限,验证没有通过。
return env->NewStringUTF("You don't have permission, the verification didn't pass.");
}
}
/*
* 动态注册 native 方法数组,可以不受方法名称的限制,与 Java native 方法一一对应
*/
static JNINativeMethod registerMethods[] = {
{"init", "()Z", (jboolean *) init},
{"getKey", "()Ljava/lang/String;", (jstring *) getKey},
};
/*
* 动态注册 native 方法
*/
static int registerNativeMethods(JNIEnv *env, const char *className, JNINativeMethod *gMethods, int numMethods) {
jclass clazz = env->FindClass(className);
if (clazz == NULL) {
return JNI_FALSE;
}
if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) {
return JNI_FALSE;
}
return JNI_TRUE;
}
/*
* 默认执行的初始化方法
*/
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
LOGE("JNI_OnLoad");
JNIEnv *env = NULL;
if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
return -1;
}
LOGE("register native methods");
if (!registerNativeMethods(env, NATIVE_CLASS_PATH, registerMethods, sizeof(registerMethods) / sizeof(registerMethods[0]))) {
LOGE("register native methods failed");
return -1;
}
LOGE("register native methods success");
return JNI_VERSION_1_6;
}
#ifdef __cplusplus
}
#endif