动态注册jni方法的好处就是增加逆向的分析难度
两个对比较就会很容易发现没有加密的很容易就会知道那个方法是干啥的
箭头1是根据javah自动生成的方法名
箭头2是自定义方法名的,上面是加密过后的方法名
用动态注册的方式最主要的是建立一个映射表
//映射方法表 static JNINativeMethod methods[] = { {"testJNI","(Ljava/lang/String;)Ljava/lang/String;",(void *) native_f525698a2bbb571e5a65b446256e656d}, {"testJNINoReturn","(Ljava/lang/String;)V",(void *) native_cf990492a44877a527d052c2c262c920}, };
第一个变量name是Java中函数的名字。(为了安全起见,可以用加密过后的参数进行解密处理)
第二个变量signature,用字符串是描述了函数的参数和返回值
第三个变量函数指针,指向C函数。直接说就是C函数里面的方法名
扫描二维码关注公众号,回复:
2155027 查看本文章
例如这个C里面的方法:
JNIEXPORT void JNICALL native_cf990492a44877a527d052c2c262c920
(JNIEnv *env, jclass,jstring b){
LOGE("没有返回:native_cf990492a44877a527d052c2c262c920");
}
重写JNI_OnLoad方法
JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved)
{
JNIEnv *env = NULL;
//获取环境
jint ret = vm->GetEnv((void**) &env, JNI_VERSION_1_6);
if (ret != JNI_OK) {
return -1;
}
LOGE(">>>>>>>>>>>>>JNI_OnLoad<<<<<<<<<<<<<");
//用于反调试
ptrace(PTRACE_TRACEME,0 ,0 ,0);
//动态注册,自定义函数
if (!registerNatives(env)) {
return -1;
}
return JNI_VERSION_1_6;
}
传入要进行动态注册的class文件路径
static int registerNatives(JNIEnv *env){
const char *className="com/kawa/bookkeeping/utils/Md5Utils";
return registerNativeMethods(env,className,methods, sizeof(methods)/ sizeof(methods[0]));
}
根据路径进行对应的方法动态注册进jni
static int registerNativeMethods(JNIEnv *env, const char *className, JNINativeMethod *gMethods,
int numMethods) {
jclass clazz;
clazz = (*env)->FindClass(env, className);
if (clazz == NULL) {
return JNI_FALSE;
}
if ((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0) {
return JNI_FALSE;
}
return JNI_TRUE;
}