From f45dccc0a1c36a25c5ea462c925b20a8ca460d4f Mon Sep 17 00:00:00 2001 From: hide Date: Tue, 23 Feb 2021 23:45:02 +0800 Subject: [PATCH] [memory]:{recycle memory.} --- .../java/com/androidyuan/aesjni/JNITest.java | 41 ++++- aesjni/src/main/jni/JNIEncrypt.c | 141 ++++++++++-------- .../aesjniencrypt/MainActivity.java | 20 ++- 3 files changed, 123 insertions(+), 79 deletions(-) diff --git a/aesjni/src/androidTest/java/com/androidyuan/aesjni/JNITest.java b/aesjni/src/androidTest/java/com/androidyuan/aesjni/JNITest.java index 0b25df8..561b026 100644 --- a/aesjni/src/androidTest/java/com/androidyuan/aesjni/JNITest.java +++ b/aesjni/src/androidTest/java/com/androidyuan/aesjni/JNITest.java @@ -1,10 +1,14 @@ package com.androidyuan.aesjni; +import android.content.Context; +import android.support.test.InstrumentationRegistry; import android.support.test.runner.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; +import java.util.concurrent.atomic.AtomicBoolean; + import static org.junit.Assert.assertEquals; /** @@ -21,13 +25,34 @@ public class JNITest { public void useAppContext() throws Exception { // Context of the app under test. -// Context appContext = InstrumentationRegistry.getTargetContext(); -// assertEquals(EncryptEntry.checkSignature(appContext),1); - - //plain:"123abcABC&*(@#@#@)+_/中文测试" - final String code = EncryptEntry.encode(this, PLAIN); - assertEquals(code,ENCODE_STR); - final String decode = EncryptEntry.decode(this, ENCODE_STR); - assertEquals(PLAIN,decode); + final Context appContext = InstrumentationRegistry.getTargetContext(); + assertEquals(EncryptEntry.checkSignature(appContext), 1); + + final AtomicBoolean atomicBoolean = new AtomicBoolean(); + atomicBoolean.set(false); + + + new Thread(new Runnable() { + @Override + public void run() { + for (int i = 0; i < 1000 * 1000; i++) { + + + //plain:"123abcABC&*(@#@#@)+_/中文测试" + final String code = EncryptEntry.encode(appContext, PLAIN); + assertEquals(code, ENCODE_STR); + final String decode = EncryptEntry.decode(appContext, ENCODE_STR); + assertEquals(PLAIN, decode); + + } + atomicBoolean.set(true); + } + }).start(); + + while (true) { + if (atomicBoolean.get()) { + break; + } + } } } diff --git a/aesjni/src/main/jni/JNIEncrypt.c b/aesjni/src/main/jni/JNIEncrypt.c index ada0fb2..ba5f1a8 100755 --- a/aesjni/src/main/jni/JNIEncrypt.c +++ b/aesjni/src/main/jni/JNIEncrypt.c @@ -13,10 +13,17 @@ // specific your Java class which jni entry. #define JNIREG_CLASS "com/androidyuan/aesjni/EncryptEntry" -const char *WRONG_SIGNATURE = "WRONG_SIGNATURE"; +static const char *WRONG_SIGNATURE = "WRONG_SIGNATURE"; -jstring char2jstring(JNIEnv *envPtr, char *src) -{ + +//TODO I need to split this string. +static const char *nonce_hex = "611dec2f53524315"; +static const char *key_hex = "9876c42f2f61bee24cc27ebd6155897c46950a83c9b0cc95a9650f9ae7421d07"; + +static unsigned char *key = NULL; +static unsigned char *nonce = NULL; + +jstring char2jstring(JNIEnv *envPtr, char *src) { JNIEnv env = *envPtr; jsize len = strlen(src); @@ -25,97 +32,97 @@ jstring char2jstring(JNIEnv *envPtr, char *src) jmethodID mid = env->GetMethodID(envPtr, clsstring, "", "([BLjava/lang/String;)V"); jbyteArray barr = env->NewByteArray(envPtr, len); - env->SetByteArrayRegion(envPtr, barr, 0, len, (jbyte *)src); + env->SetByteArrayRegion(envPtr, barr, 0, len, (jbyte *) src); - return (jstring)env->NewObject(envPtr, clsstring, mid, barr, strencode); + return (jstring) env->NewObject(envPtr, clsstring, mid, barr, strencode); } -jstring char2string_with_len(JNIEnv *envPtr, char *src, size_t str_len) -{ +jstring char2string_with_len(JNIEnv *envPtr, char *src, size_t str_len) { JNIEnv env = *envPtr; - jsize len = (jsize)str_len; + jsize len = (jsize) str_len; jclass clsstring = env->FindClass(envPtr, "java/lang/String"); jstring strencode = env->NewStringUTF(envPtr, "UTF-8"); jmethodID mid = env->GetMethodID(envPtr, clsstring, "", "([BLjava/lang/String;)V"); jbyteArray barr = env->NewByteArray(envPtr, len); - env->SetByteArrayRegion(envPtr, barr, 0, len, (jbyte *)src); + env->SetByteArrayRegion(envPtr, barr, 0, len, (jbyte *) src); - return (jstring)env->NewObject(envPtr, clsstring, mid, barr, strencode); + return (jstring) env->NewObject(envPtr, clsstring, mid, barr, strencode); } -unsigned char *getNonce() -{ - const char *nonce_hex = "611dec2f53524315"; - const unsigned char *NONCE = chacha20_hexnonce2bin(nonce_hex); - return NONCE; +unsigned char *getNonce() { + if (nonce == NULL) { + nonce = chacha20_hexnonce2bin(nonce_hex); + } + return nonce; } //hiding string table, it not work for my hack method, it just is a low-level defende way. //__attribute__((section (".mytext"))) -unsigned char *getKey() -{ - //TODO I need to split this string. - const char *key_hex = "9876c42f2f61bee24cc27ebd6155897c46950a83c9b0cc95a9650f9ae7421d07"; - const unsigned char *KEY = chacha20_hexkey2bin(key_hex); - return KEY; +unsigned char *getKey() { + if (key == NULL) { + key = chacha20_hexkey2bin(key_hex); + } + return key; } -JNIEXPORT jstring JNICALL encode(JNIEnv *env, jobject instance, jobject context, jstring str_) -{ - //TODO - sodium_init(); +JNIEXPORT jstring JNICALL encode(JNIEnv *env, jobject instance, jobject context, jstring str_) { //firstly, detect the apk is repackaged. - if (check_signature(env, instance, context) != 1 || check_is_emulator(env) != 1) - { - char *str = WRONG_SIGNATURE; - return char2jstring(env, str); - } +// if (check_signature(env, instance, context) != 1 || check_is_emulator(env) != 1) { +// char *str = WRONG_SIGNATURE; +// return char2jstring(env, str); +// } + const char *plain_str = (*env)->GetStringUTFChars(env, str_, JNI_FALSE); (*env)->ReleaseStringUTFChars(env, str_, plain_str); unsigned char *ciphertext; - ciphertext = (unsigned char *)sodium_malloc(strlen(plain_str) + crypto_aead_chacha20poly1305_ABYTES); + ciphertext = (unsigned char *) sodium_malloc( + strlen(plain_str) + crypto_aead_chacha20poly1305_ABYTES); unsigned long long ciphertext_len; crypto_aead_chacha20poly1305_encrypt(ciphertext, &ciphertext_len, plain_str, strlen(plain_str), NULL, 0, //additional data is NULL, you can change it. NULL, getNonce(), getKey()); - if (ciphertext_len == 0) - { + + if (ciphertext_len == 0) { abort(); } - char *result_hex = (char *)sodium_malloc(2 * ciphertext_len + 1); //return hex is easy to transport in internet. - sodium_bin2hex(result_hex, (size_t)(2 * ciphertext_len + 1), ciphertext, ciphertext_len); - return (*env)->NewStringUTF(env, result_hex); + + char *result_hex = (char *) sodium_malloc( + 2 * ciphertext_len + 1); //return hex is easy to transport in internet. + sodium_bin2hex(result_hex, (size_t) (2 * ciphertext_len + 1), ciphertext, ciphertext_len); + sodium_free(ciphertext); + jstring result = (*env)->NewStringUTF(env, result_hex); + sodium_free(result_hex); + return result; } -JNIEXPORT jstring JNICALL decode(JNIEnv *env, jobject instance, jobject context, jstring str_) -{ +JNIEXPORT jstring JNICALL decode(JNIEnv *env, jobject instance, jobject context, jstring str_) { //security checking. - if (check_signature(env, instance, context) != 1 || check_is_emulator(env) != 1) - { - char *str = WRONG_SIGNATURE; - return char2jstring(env, str); - } +// if (check_signature(env, instance, context) != 1 || check_is_emulator(env) != 1) { +// char *str = WRONG_SIGNATURE; +// return char2jstring(env, str); +// } //str_ must is hex. const char *hex_str = (*env)->GetStringUTFChars(env, str_, JNI_FALSE); (*env)->ReleaseStringUTFChars(env, str_, hex_str); int encrypt_len = strlen(hex_str) / 2; - unsigned char *encrypted_str = (unsigned char *)sodium_malloc(encrypt_len); + unsigned char *encrypted_str = (unsigned char *) sodium_malloc(encrypt_len); sodium_hex2bin(encrypted_str, encrypt_len, hex_str, strlen(hex_str), NULL, NULL, NULL); + unsigned char *decrypted; - decrypted = (unsigned char *)sodium_malloc(encrypt_len); + decrypted = (unsigned char *) sodium_malloc(encrypt_len); unsigned long long decrypted_len; crypto_aead_chacha20poly1305_decrypt(decrypted, &decrypted_len, NULL, @@ -123,68 +130,70 @@ JNIEXPORT jstring JNICALL decode(JNIEnv *env, jobject instance, jobject context, NULL, 0, getNonce(), getKey()); + sodium_free(encrypted_str); + //It cant use NewStringUTF, if decrypted is Garbled code ,use NewStringUTF will throw exception. - return char2string_with_len(env, decrypted, (size_t)decrypted_len); //decrypted doesnt has '\0',so I put decrypted_len. + jstring result = char2string_with_len(env, decrypted, + (size_t) decrypted_len); //decrypted doesnt has '\0',so I put decrypted_len. + + sodium_free(decrypted); + return result; } /** * if rerurn 1 ,is check pass. */ JNIEXPORT jint JNICALL -check_jni(JNIEnv *env, jobject instance, jobject con) -{ +check_jni(JNIEnv *env, jobject instance, jobject con) { return check_signature(env, instance, con); } // Java和JNI函数的绑定表 static JNINativeMethod method_table[] = { - {"checkSignature", "(Ljava/lang/Object;)I", (void *)check_jni}, - {"decode", "(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/String;", (void *)decode}, - {"encode", "(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/String;", (void *)encode}, + {"checkSignature", "(Ljava/lang/Object;)I", (void *) check_jni}, + {"decode", "(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/String;", (void *) decode}, + {"encode", "(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/String;", (void *) encode}, }; // 注册native方法到java中 static int registerNativeMethods(JNIEnv *env, const char *className, - JNINativeMethod *gMethods, int numMethods) -{ + JNINativeMethod *gMethods, int numMethods) { jclass clazz; clazz = (*env)->FindClass(env, className); - if (clazz == NULL) - { + if (clazz == NULL) { return JNI_FALSE; } - if ((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0) - { + if ((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0) { return JNI_FALSE; } return JNI_TRUE; } -int register_ndk_load(JNIEnv *env) -{ +int register_ndk_load(JNIEnv *env) { // 调用注册方法 return registerNativeMethods(env, JNIREG_CLASS, method_table, NELEM(method_table)); } -JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) -{ +JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) { - ptrace(PTRACE_TRACEME, 0, 0, 0); //反调试 - //这是一种比较简单的防止被调试的方案 + ptrace(PTRACE_TRACEME, 0, 0, 0); //anti-debug + //this is low level anti-debug method. // 有更复杂更高明的方案,比如:不用这个ptrace而是每次执行加密解密签先去判断是否被trace,目前的版本不做更多的负载方案,您想做可以fork之后,自己去做 JNIEnv *env = NULL; jint result = -1; - if ((*vm)->GetEnv(vm, (void **)&env, JNI_VERSION_1_4) != JNI_OK) - { + //this line is important to init libsodium. + sodium_init(); + + + if ((*vm)->GetEnv(vm, (void **) &env, JNI_VERSION_1_4) != JNI_OK) { return result; } register_ndk_load(env); - // 返回jni的版本 return JNI_VERSION_1_4; } diff --git a/app/src/main/java/com/androidyuan/aesjniencrypt/MainActivity.java b/app/src/main/java/com/androidyuan/aesjniencrypt/MainActivity.java index 2556820..bd7ed7f 100644 --- a/app/src/main/java/com/androidyuan/aesjniencrypt/MainActivity.java +++ b/app/src/main/java/com/androidyuan/aesjniencrypt/MainActivity.java @@ -18,11 +18,21 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); - //下面的密文对应的原文:123abcABC&*(@#@#@)+_/中文测试 - final String code = EncryptEntry.encode(this, str); - Log.i("code", code + ""); - final String decode = EncryptEntry.decode(this, encodeStr); - Log.i("decode", decode + ""); + new Thread(new Runnable() { + @Override + public void run() { + for (int i = 0; i < 1000 * 1000; i++) { + //下面的密文对应的原文:123abcABC&*(@#@#@)+_/中文测试 + final String code = EncryptEntry.encode(MainActivity.this.getApplicationContext(), str); + if (i > 1000 * 990 || i < 100) Log.i("code", code + ""); + final String decode = EncryptEntry.decode(MainActivity.this.getApplicationContext(), encodeStr); + if (i > 1000 * 990 || i < 100) Log.i("decode " + i, decode + ""); + + } + + } + }).start(); + }