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' 即可。

Android 通过 JNI 获取应用包名、签名 MD5 和 SHA1 信息

原文地址: https://www.cveoy.top/t/topic/nyv9 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录