jniテクノロジーによるandroidアプリケーション署名情報のチェックと機密情報保護


最近、余暇に「揺れ」というアプリを書いたが、安智、安卓、360などいくつかのアプリストアが続々と審査を通過し、オンラインになった.アイデアから最終的に製品を作って発表するまで、2ヶ月半近くの余暇を断続的に費やし、全体的には順調で、期間もいくつかの小さな技術的な難点に遭遇したが、最後に解決したのは満足している.今日その中の1つの小さい技術の難点を言って、今この小さい技術の難点を考えても普通ですが、やはり分かち合って、同じ疑問のある同級生に役に立つことを望んでいます.
Java言語自体の特性のためandroidプログラムは逆コンパイルされやすく、コード混同の方式を採用することができるが、サードパーティライブラリを使用すると、混同の足取りがうまくいかず、コード混同後にプログラムの運行が不安定になる問題がある.混同されていないプログラムが逆コンパイルされると、ソースコードに大量の機密情報が明らかになります.例えばサーバと対話するurlアドレス情報は,動的リンクライブラリを用いるとnativeメソッドも露出し,さらに混同するとnativeメソッドは混同されない.他の人はnativeの方法を見て、自分でsoファイルをロードすることができて、そんなに多くの核心のもの、他の人は間接的に使用することができて、彼は必ずしも使うことができるとは限らないが、少なくとも呼び出すことができます.上の林林総プログラムが逆コンパイルされた後に発生する可能性のある問題に対して、私の解決方法はjni技術を使って、ndk環境の下でパッケージ署名情報のチェックをして、ndk環境なので、これは逆コンパイルしにくくて、このチェックを迂回するのも難しいです.理論的には,署名ファイルkeystoreは唯一であり,プログラム作成者のみが所有する.具体的には、すべてのnativeメソッド内で、署名情報の照合判断を増やし、署名情報の照合が通過してこそ、プログラムがさらに操作され、そうでなければNULLに戻ることができる.このように、他の人がsoファイルを手に入れて、nativeメソッドのパラメータと使い方を明らかにしたとしても、署名情報が一致しないため、nativeメソッドはすべてNULLに戻り、soファイルは瞬時にレンガになる.同様にurlアドレスなどの機密情報については,署名情報の照合を増やし,照合が通過した場合にのみプログラムが正しい文字列を返し,そうでなければNULLを直接返すことで,機密情報の隠蔽と保護を良好に行うことができる.半日話したが,肝心なステップはndk環境下でパケット署名情報をどのように取得するかであり,以下のコードが関連実装である.
jstring loadSignature(JNIEnv* env, jobject obj)
{
	//   Context 
    jclass cls = (*env)->GetObjectClass(env, obj);
    //   getPackageManager   ID
    jmethodID mid = (*env)->GetMethodID(env, cls, "getPackageManager", "()Landroid/content/pm/PackageManager;");

    //          
    jobject pm = (*env)->CallObjectMethod(env, obj, mid);

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

    //   PackageManager 
    cls = (*env)->GetObjectClass(env, pm);
    //   getPackageInfo   ID
    mid  = (*env)->GetMethodID(env, cls, "getPackageInfo", "(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;");
    //         
    jobject packageInfo = (*env)->CallObjectMethod(env, pm, mid, packageName, 0x40); //GET_SIGNATURES = 64;
    //   PackageInfo  
    cls = (*env)->GetObjectClass(env, packageInfo);
    //          ID
    jfieldID fid = (*env)->GetFieldID(env, cls, "signatures", "[Landroid/content/pm/Signature;");
    //       
    jobjectArray signatures = (jobjectArray)(*env)->GetObjectField(env, packageInfo, fid);
    //     
    jobject sign = (*env)->GetObjectArrayElement(env, signatures, 0);

    //   Signature 
    cls = (*env)->GetObjectClass(env, sign);
    //   toCharsString   ID
    mid = (*env)->GetMethodID(env, cls, "toCharsString", "()Ljava/lang/String;");

    //           
    return (jstring)(*env)->CallObjectMethod(env, sign, mid);
}

上記のコードで得られたパケット署名情報は、実際には長い文字列であり、より効率的に署名情報の比較を行うためにmd 5暗号化を行い、32ビット文字列形式に暗号化することもできる.また、私は資料を調べる過程で、バッグで署名したhashcode値を比較するという資料を見たことがあります.この方法はもっと簡単ですが、私はこのような方法を採用していません.いつもこの方法は正確ではないかもしれません.個人的には、興味のある学生はもっと関連資料を調べることができます.ここでさらに、上記のコードで得られたパケット署名文字列情報は、md 5を用いて暗号化された後、得られた暗号化結果がパケット署名の実際のmd 5 fingerprintと一致しないことを説明する.主に、署名情報をtoCharsString()を使用して文字列に変換してmd 5暗号化を行うため、toByteArray()を使用して配列に変換して暗号化すると、暗号化結果はパッケージ署名の実際のmd 5 fingerprintと一致します.