android通过ndk加解密和防apk反编译

android通过ndk加解密和防apk反编译

作为开发者的我们除了为软件各种功能的实现而发愁,在发布以后也会为软件的安全发愁,这里分享一个用JNI实现的签名校验。
下面是效果图

android通过ndk加解密和防apk反编译_第1张图片

1.获取签名信息

        jclass context_class = env->GetObjectClass(context_object);

        //context.getPackageManager()
        jmethodID methodId = env->GetMethodID(context_class, "getPackageManager", "()Landroid/content/pm/PackageManager;");
        jobject package_manager_object = env->CallObjectMethod(context_object, methodId);
        if (package_manager_object == NULL) {
            __android_log_print(ANDROID_LOG_INFO, "JNITag","getPackageManager() Failed!");
            return NULL;
        }

        //context.getPackageName()
        methodId = env->GetMethodID(context_class, "getPackageName", "()Ljava/lang/String;");
        jstring package_name_string = (jstring)env->CallObjectMethod(context_object, methodId);
        if (package_name_string == NULL) {
            __android_log_print(ANDROID_LOG_INFO, "JNITag","getPackageName() Failed!");
            return NULL;
        }

        env->DeleteLocalRef(context_class);

        //PackageManager.getPackageInfo(Sting, int)
        jclass pack_manager_class = env->GetObjectClass(package_manager_object);
        methodId = env->GetMethodID(pack_manager_class, "getPackageInfo", "(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;");
        env->DeleteLocalRef(pack_manager_class);
        jobject package_info_object = env->CallObjectMethod(package_manager_object, methodId, package_name_string, 64);
        if (package_info_object == NULL) {
            __android_log_print(ANDROID_LOG_INFO, "JNITag","getPackageInfo() Failed!");
            return NULL;
        }

        env->DeleteLocalRef(package_manager_object);

        //PackageInfo.signatures[0]
        jclass package_info_class = env->GetObjectClass(package_info_object);
        jfieldID fieldId = env->GetFieldID(package_info_class, "signatures", "[Landroid/content/pm/Signature;");
        env->DeleteLocalRef(package_info_class);
        jobjectArray signature_object_array = (jobjectArray)env->GetObjectField(package_info_object, fieldId);
        if (signature_object_array == NULL) {
            __android_log_print(ANDROID_LOG_INFO, "JNITag","PackageInfo.signatures[] is null");
            return NULL;
        }
        jobject signature_object = env->GetObjectArrayElement(signature_object_array, 0);

        env->DeleteLocalRef(package_info_object);

        //Signature.toCharsString()
        jclass signature_class = env->GetObjectClass(signature_object);
//        methodId = env->GetMethodID(signature_class, "toCharsString", "()Ljava/lang/String;");
//        env->DeleteLocalRef(signature_class);
//        jstring signature_string = (jstring) env->CallObjectMethod(signature_object, methodId);
//        return signature_string;

        //Signature.hashCode()
        jmethodID methodID_hc = env->GetMethodID(signature_class, "hashCode", "()I");
        int hash_code = env->CallIntMethod(signature_object, methodID_hc);
        char str[32];
        sprintf(str, "%u", hash_code);

2.检查签名是否被更改过

这里把校验码写死了的,注意要用私钥才有效果

jstring signature = Java_com_innotechx_jni_NativeUtils_getSignature(env, clazz, context_object);
const char *orginalSignature = "244699197";
const char *currentSignature = jstringTostring(env, signature);
int result = strcmp(orginalSignature, currentSignature);
int result == 0 ? true : false;

3.获取私有密钥的key

这是用与加解密或者和服务器约定好的key

if (false == checkSignature) {
            checkSignature = Java_com_innotechx_jni_NativeUtils_checkSignature(env, clazz, context_object);
        }
        if (checkSignature) {
            return env->NewStringUTF("获取privateKey成功");
        }
        return env->NewStringUTF("获取失败");

4.最后附上完整代码

#include 
#include 
#include 
#include 

#define LOG_TAG "AesUtils"
#define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, fmt, ##args)

extern "C" {

    static bool checkSignature = false;

    JNIEXPORT jstring JNICALL Java_com_innotechx_jni_NativeUtils_getSignature
    (JNIEnv *env, jclass clazz, jobject context_object) {
jclass context_class = env->GetObjectClass(context_object);
jmethodID methodId = env->GetMethodID(context_class, "getPackageManager", "()Landroid/content/pm/PackageManager;");
jobject package_manager_object = env->CallObjectMethod(context_object, methodId);
if (package_manager_object == NULL) {
    __android_log_print(ANDROID_LOG_INFO, "JNITag","getPackageManager() Failed!");
    return NULL;
}
methodId = env->GetMethodID(context_class, "getPackageName", "()Ljava/lang/String;");
jstring package_name_string = (jstring)env->CallObjectMethod(context_object, methodId);
if (package_name_string == NULL) {
    __android_log_print(ANDROID_LOG_INFO, "JNITag","getPackageName() Failed!");
    return NULL;
}
env->DeleteLocalRef(context_class);
jclass pack_manager_class = env->GetObjectClass(package_manager_object);
methodId = env->GetMethodID(pack_manager_class, "getPackageInfo", "(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;");
env->DeleteLocalRef(pack_manager_class);
jobject package_info_object = env->CallObjectMethod(package_manager_object, methodId, package_name_string, 64);
if (package_info_object == NULL) {
    __android_log_print(ANDROID_LOG_INFO, "JNITag","getPackageInfo() Failed!");
    return NULL;
}
env->DeleteLocalRef(package_manager_object);
jclass package_info_class = env->GetObjectClass(package_info_object);
jfieldID fieldId = env->GetFieldID(package_info_class, "signatures", "[Landroid/content/pm/Signature;");
env->DeleteLocalRef(package_info_class);
jobjectArray signature_object_array = (jobjectArray)env->GetObjectField(package_info_object, fieldId);
if (signature_object_array == NULL) {
    __android_log_print(ANDROID_LOG_INFO, "JNITag","PackageInfo.signatures[] is null");
    return NULL;
}
jobject signature_object = env->GetObjectArrayElement(signature_object_array, 0);
env->DeleteLocalRef(package_info_object);
jclass signature_class = env->GetObjectClass(signature_object);
jmethodID methodID_hc = env->GetMethodID(signature_class, "hashCode", "()I");
int hash_code = env->CallIntMethod(signature_object, methodID_hc);
char str[32];
sprintf(str, "%u", hash_code);
return env->NewStringUTF(str);
    }

    // jstring转char*
    char* jstringTostring(JNIEnv* env, jstring jstr) {
char* rtn = NULL;
jclass clsstring = env->FindClass("java/lang/String");
jstring strencode = env->NewStringUTF("utf-8");
jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");
jbyteArray barr= (jbyteArray)env->CallObjectMethod(jstr, mid, strencode);
jsize alen = env->GetArrayLength(barr);
jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);
if (alen > 0) {
    rtn = (char*)malloc(alen + 1);
    memcpy(rtn, ba, alen);
    rtn[alen] = 0;
}
env->ReleaseByteArrayElements(barr, ba, 0);
return rtn;
    }

    JNIEXPORT jboolean JNICALL Java_com_innotechx_jni_NativeUtils_checkSignature
    (JNIEnv *env, jclass clazz, jobject context_object) {
jstring signature = Java_com_innotechx_jni_NativeUtils_getSignature(env, clazz, context_object);
const char *orginalSignature = "244699197";
const char *currentSignature = jstringTostring(env, signature);
int result = strcmp(orginalSignature, currentSignature);
return result == 0 ? true : false;
    }

    JNIEXPORT jstring JNICALL Java_com_innotechx_jni_NativeUtils_getPrivateKey
    (JNIEnv *env, jclass clazz, jobject context_object) {
LOGI("-----> : checkSignature  %d", checkSignature);

if (false == checkSignature) {
    checkSignature = Java_com_innotechx_jni_NativeUtils_checkSignature(env, clazz, context_object);
}
if (checkSignature) {
    return env->NewStringUTF("获取privateKey成功");
}
return env->NewStringUTF("获取失败");
    }
}

NativeUtils.java

public class NativeUtils {
     

    static {
     
        System.loadLibrary("nativeUtils");
    }

    /**
     * 获取签名信息.
     * @param context
     * @return
     */
    public static native String getSignature(Context context);

    /**
     * 检查签名是否被更改过。
     * @param context
     * @return
     */
    public static native boolean checkSignature(Context context);

    /**
     * 获取私有的key(用与加解密或者和服务器约定好的key).
     * @param context
     * @return
     */
    public static native String getPrivateKey(Context context);

}

MainActivity.java

public class MainActivity extends AppCompatActivity {
     

    @Override
    protected void onCreate(Bundle savedInstanceState) {
     
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        boolean isDebuggable = (0 != (getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE));
        Log.i("test", "isDebuggable : " + isDebuggable);
    }

    public void getPrivateKey(View view) {
     
        String privateKey = NativeUtils.getPrivateKey(this);
        Toast.makeText(this, privateKey, Toast.LENGTH_SHORT).show();
    }

    public void checkSignature(View view) {
     
        boolean flag = NativeUtils.checkSignature(this);
        if (flag) {
     
            Toast.makeText(this, "签名没问题", Toast.LENGTH_SHORT).show();
        } else {
     
            Toast.makeText(this, "签名被篡改", Toast.LENGTH_SHORT).show();
        }
    }

    public void getSignature(View view) {
     
        TextView textView1 = (TextView) findViewById(R.id.text);
        textView1.setText("Signature的hashCode=" + NativeUtils.getSignature(this));
    }
}

你可能感兴趣的:(笔记)