Android安全:onCreate()函数的Native化

Java

在Android开发一个Activity,常规Java写法如下:

package com.zyc.oncreate2native;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        TextView txt = findViewById(R.id.txt_main);
        txt.setText("onCreate-->Native success!");
    }
}

运行:
在这里插入图片描述
这样的写法放进反编译工具,分析起来几乎没有难度。
在这里插入图片描述
 

Native

上面的代码Native化之后:

#include <jni.h>
#include <string>
#include <android/log.h>

extern "C" JNIEXPORT void JNICALL
Java_com_zyc_oncreate2native_MainActivity_onCreate(JNIEnv *env, jobject thiz, jobject saved_instance_state) {
    //super.onCreate(savedInstanceState);
    jclass MainActivity = env->GetObjectClass(thiz);
    jclass AppCompatActivity = env->GetSuperclass(MainActivity);
    jmethodID onCreate = env->GetMethodID(AppCompatActivity, "onCreate", "(Landroid/os/Bundle;)V");
    env->CallNonvirtualVoidMethod(thiz, AppCompatActivity, onCreate, saved_instance_state); //调用父类方法

    //setContentView(R.layout.activity_main);
    jmethodID setContentView = env->GetMethodID(MainActivity, "setContentView", "(I)V");
    jclass Layout = env->FindClass("com/zyc/oncreate2native/R$layout"); //注意R类的写法
    jfieldID activity_main = env->GetStaticFieldID(Layout, "activity_main", "I");
    jint id_activity_main = env->GetStaticIntField(Layout, activity_main);
    env->CallVoidMethod(thiz, setContentView, id_activity_main);

    //TextView txt = findViewById(R.id.txt_main);
    jmethodID findViewById = env->GetMethodID(MainActivity, "findViewById","(I)Landroid/view/View;");
    jclass id = env->FindClass("com/zyc/oncreate2native/R$id");
    jfieldID txt_main = env->GetStaticFieldID(id, "txt_main", "I");
    jint id_txt_main = env->GetStaticIntField(id, txt_main);
    jobject txt = env->CallObjectMethod(thiz, findViewById, id_txt_main);

    //txt.setText("onCreate-->Native success by c++ !!!");
    jclass TextView = env->FindClass("android/widget/TextView");
    jmethodID setText = env->GetMethodID(TextView, "setText", "(Ljava/lang/CharSequence;)V");
    jstring text = env->NewStringUTF("onCreate-->Native success by c++ !!!");
    env->CallVoidMethod(txt, setText, text);
    env->DeleteLocalRef(text);
}

运行:
在这里插入图片描述
这时再反编译,Java层就无法看到有用信息了。
在这里插入图片描述
即使找到so文件分析伪C++代码,也头疼多了。

int __cdecl Java_com_zyc_oncreate2native_MainActivity_onCreate(_JNIEnv *a1, int a2, int a3)
{
  int v3; // eax
  int v4; // ST6C_4
  int v5; // eax
  int v6; // ST68_4
  int v7; // eax
  int v8; // ST60_4
  int v9; // eax
  int v10; // ST5C_4
  int v11; // eax
  char v12; // al
  int v13; // ST50_4
  int v14; // eax
  int v15; // ST4C_4
  int v16; // eax
  char v17; // al
  int v18; // ST40_4
  int v19; // eax
  int v20; // ST38_4
  int v21; // ST34_4

  v3 = _JNIEnv::GetObjectClass(a1, a2);
  v4 = v3;
  v5 = _JNIEnv::GetSuperclass(a1, v3);
  v6 = v5;
  v7 = _JNIEnv::GetMethodID(a1, v5, 4564, 4573);
  _JNIEnv::CallNonvirtualVoidMethod(a1, a2, v6, v7, a3);
  v8 = _JNIEnv::GetMethodID(a1, v4, "setContentView", "(I)V");
  v9 = _JNIEnv::FindClass(a1, "com/zyc/oncreate2native/R$layout");
  v10 = v9;
  v11 = _JNIEnv::GetStaticFieldID(a1, v9, 4649, 4663);
  v12 = _JNIEnv::GetStaticIntField(a1, v10, v11);
  _JNIEnv::CallVoidMethod(a1, a2, v8, v12);
  v13 = _JNIEnv::GetMethodID(a1, v4, "findViewById", "(I)Landroid/view/View;");
  v14 = _JNIEnv::FindClass(a1, "com/zyc/oncreate2native/R$id");
  v15 = v14;
  v16 = _JNIEnv::GetStaticFieldID(a1, v14, 4730, 4663);
  v17 = _JNIEnv::GetStaticIntField(a1, v15, v16);
  v18 = _JNIEnv::CallObjectMethod(a1, a2, v13, v17);
  v19 = _JNIEnv::FindClass(a1, "android/widget/TextView");
  v20 = _JNIEnv::GetMethodID(a1, v19, 4763, 4771);
  v21 = _JNIEnv::NewStringUTF(a1, "onCreate-->Native success by c++ !!!");
  _JNIEnv::CallVoidMethod(a1, v18, v20, v21);
  return _JNIEnv::DeleteLocalRef(a1, v21);
}

当然, Java_com_zyc_oncreate2native_MainActivity_onCreate() 的方法名还是容易暴露,换成改成动态注册:

#include <jni.h>
#include <string>
#include <android/log.h>

#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, "Tag", __VA_ARGS__)

void ffff(JNIEnv *env, jobject thiz, jobject saved_instance_state) {
    //super.onCreate(savedInstanceState);
    jclass MainActivity = env->GetObjectClass(thiz);
    jclass AppCompatActivity = env->GetSuperclass(MainActivity);
    jmethodID onCreate = env->GetMethodID(AppCompatActivity, "onCreate", "(Landroid/os/Bundle;)V");
    env->CallNonvirtualVoidMethod(thiz, AppCompatActivity, onCreate, saved_instance_state); //调用父类方法

    //setContentView(R.layout.activity_main);
    jmethodID setContentView = env->GetMethodID(MainActivity, "setContentView", "(I)V");
    jclass Layout = env->FindClass("com/zyc/oncreate2native/R$layout");
    jfieldID activity_main = env->GetStaticFieldID(Layout, "activity_main", "I");
    jint id_activity_main = env->GetStaticIntField(Layout, activity_main);
    env->CallVoidMethod(thiz, setContentView, id_activity_main);

    //TextView txt = findViewById(R.id.txt_main);
    jmethodID findViewById = env->GetMethodID(MainActivity, "findViewById",
                                              "(I)Landroid/view/View;");
    jclass id = env->FindClass("com/zyc/oncreate2native/R$id");
    jfieldID txt_main = env->GetStaticFieldID(id, "txt_main", "I");
    jint id_txt_main = env->GetStaticIntField(id, txt_main);
    jobject txt = env->CallObjectMethod(thiz, findViewById, id_txt_main);

    //txt.setText("onCreate-->Native success by c++ !!!");
    jclass TextView = env->FindClass("android/widget/TextView");
    jmethodID setText = env->GetMethodID(TextView, "setText", "(Ljava/lang/CharSequence;)V");
    jstring text = env->NewStringUTF("onCreate-->Native success by c++ ffff!!!");
    env->CallVoidMethod(txt, setText, text);
    env->DeleteLocalRef(text);
}

static JNINativeMethod methods[] = {
        {"onCreate", "(Landroid/os/Bundle;)V", (void*)ffff}
};

static int registerNatives(JNIEnv *env) {
    //找到声明native方法的类
    const char *className = "com/zyc/oncreate2native/MainActivity";
    jclass clazz = env->FindClass(className);
    if (clazz == NULL) {
        return JNI_FALSE;
    }

    //注册函数 参数:java类 所要注册的函数数组 注册函数的个数
    int methodsNum = sizeof(methods) / sizeof(methods[0]);
    if (env->RegisterNatives(clazz, methods, methodsNum) < 0) {
        return JNI_FALSE;
    }
    return JNI_TRUE;
}

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
    JNIEnv *env = NULL;
    //获取JNIEnv
    if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) != JNI_OK) {
        return -1;
    }

    assert(env != NULL);

    if (!registerNatives(env)) {
        return -1;
    }
    //返回jni 的版本
    return JNI_VERSION_1_6;
}

这样一来定位 onCreate() 就更加困难了。
在这里插入图片描述
 

总 结

由上面不难看出, onCreate() 函数在Native化后逆向分析起来就困难多了。同理,其他Java函数也可以如法炮制,当然这一方法在提高安全性的同时也降低了开发效率。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值