Skip to content

Commit

Permalink
[memory]:{recycle memory.}
Browse files Browse the repository at this point in the history
  • Loading branch information
hide committed Feb 23, 2021
1 parent ce12aaf commit f45dccc
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 79 deletions.
41 changes: 33 additions & 8 deletions aesjni/src/androidTest/java/com/androidyuan/aesjni/JNITest.java
Original file line number Diff line number Diff line change
@@ -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;

/**
Expand All @@ -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;
}
}
}
}
141 changes: 75 additions & 66 deletions aesjni/src/main/jni/JNIEncrypt.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -25,166 +32,168 @@ jstring char2jstring(JNIEnv *envPtr, char *src)
jmethodID mid = env->GetMethodID(envPtr, clsstring, "<init>",
"([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, "<init>",
"([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,
encrypted_str, encrypt_len,
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;
}
20 changes: 15 additions & 5 deletions app/src/main/java/com/androidyuan/aesjniencrypt/MainActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -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();


}

Expand Down

0 comments on commit f45dccc

Please sign in to comment.