如何在 Android 原生 C 中获取 APK signing 签名?

How to get APK signing signature in Android native C ?

出于安全目的,我需要在本机 C 代码中获取 App signing 签名以检查 Apk 签名。

经过多次研究,我找到了这个可以获取签名和 IssuerDN 的代码。

JNIEXPORT void JNICALL
Java_org_telegram_messenger_ApplicationLoader_st(JNIEnv *env, jobject obj)
{
    jclass cls = (*env)->GetObjectClass(env, obj);
    jmethodID mid = (*env)->GetMethodID(env, cls,"getPackageManager"  ,"()Landroid/content/pm/PackageManager;");
    jobject packageManager = (*env)->CallObjectMethod(env, obj, mid);

    // this.getPackageName()
    mid = (*env)->GetMethodID(env, cls, "getPackageName", "()Ljava/lang/String;");//
    jstring packageName = (jstring) (*env)->CallObjectMethod(env, obj, mid);

    // packageManager->getPackageInfo(packageName, GET_SIGNATURES);
    cls = (*env)->GetObjectClass(env, packageManager);
    mid = (*env)->GetMethodID(env, cls, "getPackageInfo", "(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;");
    jint flags = 0x00000040;
    jobject packageInfo = (*env)->CallObjectMethod(env, packageManager, mid, packageName, flags);

    // packageInfo->signatures
    cls = (*env)->GetObjectClass(env, packageInfo);
    jfieldID fid = (*env)->GetFieldID(env, cls, "signatures", "[Landroid/content/pm/Signature;");
    jobject signatures = (*env)->GetObjectField(env, packageInfo, fid);

    // signatures[0]
    jobject signature = (*env)->GetObjectArrayElement(env, signatures, 0);

    // signature->toByteArray()
    cls = (*env)->GetObjectClass(env, signature);
    mid = (*env)->GetMethodID(env, cls, "toByteArray", "()[B");
    jbyteArray appSig = (*env)->CallObjectMethod(env, signature, mid);

    // X509Certificate appCertificate = X509Certificate.getInstance(appSignature.toByteArray());
    cls = (*env)->FindClass(env,"javax/security/cert/X509Certificate" );
    if(cls !=0) {
        int mid_static = (*env)->GetStaticMethodID(env, cls, "getInstance", "([B)Ljavax/security/cert/X509Certificate;");
        if (mid_static != 0) {
            jobject  cerObj = (jstring) (*env)->CallStaticObjectMethod(env, cls, mid_static,appSig );//
            jclass tmpCls = (*env)->GetObjectClass(env, cerObj);
            jmethodID mid = (*env)->GetMethodID(env, tmpCls, "getIssuerDN","()Ljava/security/Principal;");            

            //Principal tmpObj = appCertificate.getIssuerDN();
            jobject tmpObj = (*env)->CallObjectMethod(env, cerObj, mid);

            cls = (*env)->GetObjectClass(env, tmpObj);
            int mid2 = (*env)->GetMethodID(env, cls, "toString", "()Ljava/lang/String;");
            jstring ow = (jstring) (*env)->CallObjectMethod(env, tmpObj, mid2);//get app Owner

            const char *tmpOW = (*env)->GetStringUTFChars(env, ow, 0);           
        }
    }
}

签出 this GitHub link。这是迄今为止我得到的最好的解决方案。它对我有用。它returns一个应用程序的签名。

JNIEXPORT jstring JNICALL Java_com_example_gist_SignatureChecker_getKey(JNIEnv* env, jobject thizz, jobject thiz)
{
    // context
    jclass native_context = env->GetObjectClass(thiz);

    // context.getPackageManager()
    jmethodID methodID_func = env->GetMethodID(native_context, "getPackageManager", "()Landroid/content/pm/PackageManager;");
    jobject package_manager  = env->CallObjectMethod(thiz,methodID_func);
    jclass pm_clazz = env->GetObjectClass(package_manager);

    //packageManager.getPackageInfo()
    jmethodID methodId_pm = env->GetMethodID(pm_clazz,"getPackageInfo (Ljava/lang/String;I)Landroid/content/pm/PackageInfo;");

    //context.getPackageName()
    jmethodID methodID_packagename = env->GetMethodID(native_context,"getPackageName","()Ljava/lang/String;");
    jstring name_str = static_cast<jstring>(env->CallObjectMethod(thiz,methodID_packagename));
    jobject package_info = env->CallObjectMethod(package_manager,methodId_pm,name_str,64);
    jclass pi_clazz = env->GetObjectClass(package_info);

    //packageInfo.signatures
    jfieldID fieldID_signatures = env->GetFieldID(pi_clazz,"signatures","[Landroid/content/pm/Signature;");
    jobject signatur = env->GetObjectField(package_info,fieldID_signatures);
    jobjectArray  signatures = reinterpret_cast<jobjectArray>(signatur);

    //signatures[0]
    jobject signature = env->GetObjectArrayElement(signatures,0);
    jclass s_clazz = env->GetObjectClass(signature);

    //signatures[0].toCharString()
    jmethodID methodId_ts = env->GetMethodID(s_clazz,"toCharsString","()Ljava/lang/String;"); 
    jobject ts = env->CallObjectMethod(signature,methodId_ts);

    //return signature
    return reinterpret_cast<jstring>(ts);
}