Android应用混淆So库中的方法名

前言

在Android应用中,出于对安全性的考虑,开发者会把一些重要的逻辑放到native层,即so库中。但是so库也并非绝对的安全,在强大的IDA反编译下,so库中的逻辑也将无所遁形。今天,我们要说的就是混淆so库中的方法名。

正文

我们先来看下为什么要这么做。我们新建一个Android项目,添加NDK支持,默认项目中会有一个方法如下

external fun stringFromJNI(): String
companion object {
    // Used to load the 'native-lib' library on application startup.
    init {
        System.loadLibrary("native-lib")
    }
}

然后我们编译运行,在app/build/intermediates/cmake/debug/obj/armeabi/libnative-lib.so目录下找到我们编译出来的so库,在IDA中打开,我们可以很轻易的找到这个方法对应的地方

image.png

为什么会这样的?因为我们在写JNI的时候,采用javah命令生成的头文件,里面的方法名默认就是java_com_xxxx这种形式。所以我们现在要做的就是改变这种映射关系。

当虚拟机加载这个这个库的时候,从java层进入本地层首先会执行JNI_Onload这个函数,java层的方法就是在这个方法中注册的,使用的方法为registerNativeMethods,我们在这一步将注册我们自定义的方法,这样方法名就可以由我们自己来定义。接下来看代码实现。

  • 重写JNI_Onload方法
extern "C"
jint JNI_OnLoad(JavaVM* vm,void* reserved){
    JNIEnv* env;
    if (vm->GetEnv((void**)(&env), JNI_VERSION_1_6) != JNI_OK)
    {
        return -1;
    }
    //这一步,注册我们的方法
    if (!registerNatives(env)) {
        return -1;
    }
    return JNI_VERSION_1_6;
}
  • 接下来看registerNatives方法的实现
static JNINativeMethod gMethods[] = {
        //第一个参数为Java层的方法名
        //第二个参数为方法的签名,括号内为参数类型,后面为返回类型
        //第三个参数即为我们需要重新注册的方法名
        { "stringFromJNI", "()Ljava/lang/String;", (void*)getStr},
};

extern "C"
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;
}

extern "C"
int registerNatives(JNIEnv* env)
{
    if (!registerNativeMethods(env, JNIREG_CLASS, gMethods,
                               sizeof(gMethods) / sizeof(gMethods[0])))
        return JNI_FALSE;

    return JNI_TRUE;
}

到这里我们成功的替换了注册的方法,重新用IDA打开so库,发现我们这次找不到形如java_com_xxxx的方法了最后,还有一步,我们还得实现替换后的方法

extern "C"
//这里指定该代码所在的段,编译的时候就会把这个函数编译到自定义的名叫”.mytext“的section里面
//由于我们在java层没有定义这个函数因此要写到一个自定义的section里面。
__attribute__((section (".mytext")))  JNICALL jstring getStr
        (JNIEnv *env, jobject obj)
{
    return (env)->NewStringUTF("abc");
}

至此,我们就完成了所有混淆方法的操作。

后记

这只是一步基础的安全操作,也很容破解。比如通过IDA动态调试找到RegisterNatives方法,就能直接找到所对应的方法,也能通过直接找额外的段来找到这个方法,但是这些就不在本文详细说明了,有兴趣的同学可以自己去尝试下。

你可能感兴趣的:(Android应用混淆So库中的方法名)