Android 通过 JNI 获取应用包名、签名 MD5 和 SHA1 信息
Android 通过 JNI 获取应用包名、签名 MD5 和 SHA1 信息
本文介绍如何在 Android 应用中通过 JNI 获取应用的包名、签名 MD5 和 SHA1 信息,并提供相应的 Java 和 C++ 代码示例。
1. 获取包名
在 Java 代码中,可以通过以下方式获取当前应用的包名:
String packageName = getPackageName();
在 JNI 代码中,可以使用 JNIEnv 的 GetObjectClass 方法获取当前类的类对象,再使用 GetMethodID 方法获取包名方法的方法 ID,最后调用 CallObjectMethod 方法获取名字符串对象。具体代码如下:
jstring getPackageName(JNIEnv *env, jobject thiz) {
jclass clazz = env->GetObjectClass(thiz);
jmethodID methodID = env->GetMethodID(clazz, 'getPackageName', '()Ljava/lang/String;');
return (jstring) env->CallObjectMethod(thiz, methodID);
}
2. 获取应用签名的 MD5 信息
在 Java 代码中,可以通过以下方式获取当前应用签名的 MD5 信息:
String md5 = getSignature('MD5');
其中 getSignature 方法的实现如下:
private String getSignature(String algorithm) {
try {
PackageInfo packageInfo = getPackageManager().getPackageInfo(getPackageName(), PackageManager.GET_SIGNATURES);
byte[] signature = packageInfo.signatures[0].toByteArray();
MessageDigest md = MessageDigest.getInstance(algorithm);
byte[] digest = md.digest(signature);
return bytesToHexString(digest);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private String bytesToHexString(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
String hex = Integer.toHexString(0xFF & b);
if (hex.length() == 1) {
sb.append('0');
}
sb.append(hex);
}
return sb.toString();
}
在 JNI 代码中,可以使用 JNIEnv 的 GetObjectClass 方法获取当前类的类对象,再使用 GetMethodID 方法获取应用签名方法的方法 ID,最后调用 CallObjectMethod 方法获取签名字符串对象。具体代码如下:
jstring getSignature(JNIEnv *env, jobject thiz, jstring algorithm) {
jclass contextClass = env->GetObjectClass(thiz);
jclass packageManagerClass = env->FindClass('android/content/pm/PackageManager');
jfieldID packageManagerFieldID = env->GetStaticFieldID(contextClass, 'GET_SIGNATURES', 'I');
jint getSignatures = env->GetStaticIntField(contextClass, packageManagerFieldID);
jmethodID getPackageManagerMethodID = env->GetMethodID(contextClass, 'getPackageManager', '()Landroid/content/pm/PackageManager;');
jobject packageManager = env->CallObjectMethod(thiz, getPackageManagerMethodID);
jmethodID getPackageInfoMethodID = env->GetMethodID(packageManagerClass, 'getPackageInfo', '(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;');
jstring packageName = getPackageName(env, thiz);
jobject packageInfo = env->CallObjectMethod(packageManager, getPackageInfoMethodID, packageName, getSignatures);
jclass signatureClass = env->FindClass('android/content/pm/Signature');
jfieldID signaturesFieldID = env->GetFieldID(packageInfoClass, 'signatures', '[Landroid/content/pm/Signature;');
jobjectArray signatures = (jobjectArray) env->GetObjectField(packageInfo, signaturesFieldID);
jobject signature = env->GetObjectArrayElement(signatures, 0);
jmethodID toByteArrayMethodID = env->GetMethodID(signatureClass, 'toByteArray', '()[B');
jbyteArray signatureBytes = (jbyteArray) env->CallObjectMethod(signature, toByteArrayMethodID);
jstring result = hash(env, signatureBytes, algorithm);
env->DeleteLocalRef(packageName);
env->DeleteLocalRef(packageInfo);
env->DeleteLocalRef(signatures);
env->DeleteLocalRef(signature);
env->DeleteLocalRef(signatureBytes);
return result;
}
其中,hash 方法是计算 MD5 或 SHA1 值的通用方法,实现代码如下:
jstring hash(JNIEnv *env, jbyteArray data, jstring algorithm) {
jsize size = env->GetArrayLength(data);
jbyte *bytes = env->GetByteArrayElements(data, nullptr);
const char *algorithmChars = env->GetStringUTFChars(algorithm, nullptr);
const EVP_MD *md = EVP_get_digestbyname(algorithmChars);
unsigned char digest[EVP_MAX_MD_SIZE];
unsigned int digestLength;
EVP_MD_CTX *mdCtx = EVP_MD_CTX_new();
EVP_DigestInit_ex(mdCtx, md, nullptr);
EVP_DigestUpdate(mdCtx, bytes, size);
EVP_DigestFinal_ex(mdCtx, digest, &digestLength);
EVP_MD_CTX_free(mdCtx);
env->ReleaseByteArrayElements(data, bytes, JNI_ABORT);
env->ReleaseStringUTFChars(algorithm, algorithmChars);
return bytesToHexString(env, digest, digestLength);
}
jstring bytesToHexString(JNIEnv *env, const unsigned char *bytes, int length) {
char hex[length * 2 + 1];
for (int i = 0; i < length; i++) {
sprintf(&hex[i * 2], '%02x', bytes[i]);
}
hex[length * 2] = '\0';
return env->NewStringUTF(hex);
}
3. 获取应用签名的 SHA1 信息
在 Java 代码中,可以通过以下方式获取当前应用签名的 SHA1 信息:
String sha1 = getSignature('SHA1');
在 JNI 代码中,可以使用 hash 方法计算 SHA1 值,具体代码同上,只需将 getSignature 方法中的 algorithm 参数改为 'SHA1' 即可。
原文地址: https://www.cveoy.top/t/topic/nyv9 著作权归作者所有。请勿转载和采集!