so库中JNI方法混淆
- 关于如何配置NDK环境和测试C++方法是否调用成功,请参照@callxkj的简书 http://www.jianshu.com/p/289c0b227902 这里就不在进行赘述
例如java中调用jni方法的类如下图所示
此方法的C++代码如下图所示
我们将运行后生成的so库文件进行反汇编得到如下内容
即能看到调用的so库中的C++代码的方法名
接下来要做的就是混淆这个方法名,将方法隐藏起来,反汇编之后找不到对应的方法,类似于Android中的混淆,加大了破解的难度。
这种方法的特点是:
- 源码改动少,只需要添加JNI_Onload函数
- 无需加解密so,就可以实现混淆so中的JNI函数
- 后续可以添加so加解密,使破解难度更大
混淆步骤如下
一、在jni目录下新建一个.cpp文件,文件名任意
二、.cpp文件的内容如下:
#include <assert.h>
#include <stdio.h>
#include "longrise_phone_xjbjjt_com_myrecyclerviewapp_JniUtils.h"
#define JNIREG_CLASS "longrise/phone/xjbjjt/com/myrecyclerviewapp/JniUtils"//指定要注册的类
__attribute__((section (".mytext"))) JNICALL jstring getStringc(JNIEnv *env, jclass obj) {
return (env)->NewStringUTF("hello world2");
}
/**
* Table of methods associated with a single class.
*/
//绑定,注意,V,Z签名的返回值不能有分号“;”
//这里就是把JAVA层的getStringFromC()函数绑定到Native层的getStringc()函数,就无需使用原生的Java_com_xx_xx_classname_methodname这种恶心的函数命名方式了
static JNINativeMethod gMethods[] = {
{ "getStringFromC", "()Ljava/lang/String;", (void*)getStringc},
};
/*
* Register several native methods for one class.
*/
static int registerNativeMethods(JNIEnv* env, const char* className,
JNINativeMethod* gMethods, int numMethods)
{
jclass clazz;
clazz = (env)->FindClass(className);
if (clazz == NULL) {
return JNI_FALSE;
}
if ((env)->RegisterNatives(clazz, gMethods, numMethods) < 0) {
return JNI_FALSE;
}
return JNI_TRUE;
}
/*
* Register native methods for all classes we know about.
*/
static int registerNatives(JNIEnv* env)
{
if (!registerNativeMethods(env, JNIREG_CLASS, gMethods,
sizeof(gMethods) / sizeof(gMethods[0])))
return JNI_FALSE;
return JNI_TRUE;
}
/*
* Set some test stuff up.
*
* Returns the JNI version on success, -1 on failure.
*/
jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
JNIEnv* env = NULL;
jint result = -1;
if ((vm)->GetEnv( (void**) &env, JNI_VERSION_1_4) != JNI_OK) {
return -1;
}
assert(env != NULL);
if (!registerNatives(env)) {//注册
return -1;
}
/* success -- return valid version number */
result = JNI_VERSION_1_4;
return result;
}
这里的关键是,在函数前加上attribute((section (“.mytext”))),这样的话,编译的时候就会把这个函数编译到自定义的名叫”.mytext“的section里面去了。
网友评论