JNI的简单动态注册及反编译查看

2 篇文章 0 订阅
1 篇文章 0 订阅

给我搞晕了,国内的文章说的动态注册和国外的文章说的动态注册恰恰相反,JNI的文档里面也没看出来,我也确定不了到底那种是动态,那种是静态,感觉上国内文章的说法更符合直觉,就这么用吧.

在常规的JNI静态注册中,用IDA打开对应的so(share object)库后就能直接在Exports选项卡中找到对应的方法入口:

external fun staticRegister(f1:Float,f2:Float):Float

JNIEXPORT jfloat JNICALL
Java_com_longforus_testdynamicndk_MainActivityKt_staticRegister(JNIEnv *env, jclass clazz, jfloat f1, jfloat f2) {
    return f1 + f2;
}

在这里插入图片描述

比较容易被找到切入点,除了静态注册这种方法外,还有一种动态注册的方式,相对来说可以隐秘一些,增加逆向难度.

实现

kt

//as这里会爆红:Cannot resolve corresponding JNI function Java_com_longforus_testdynamicndk_MainActivityKt_dynamicRegister.  不用生成,不用处理
external fun dynamicRegister(f1:Float,f2:Float):Float

JNI

CMakeLists.txt
cmake_minimum_required(VERSION 3.10.2)
project("cppjni")
add_library( # Sets the name of the library. 需要和System.loadLibrary("cppjni")一致
        cppjni
        # Sets the library as a shared library.
        SHARED
        # Provides a relative path to your source file(s). 不能每个文件都要手动来这里加吧?那也太麻烦了
        jisuan.h
        jisuan.c
        )

find_library( # Sets the name of the path variable.
        log-lib
        log)

target_link_libraries( # Specifies the target library.
        cppjni
        # Links the target library to the log library
        # included in the NDK.
        ${log-lib})
jisuan.h
#include <jni.h>
//定义真正的实现功能的方法
jfloat add(JNIEnv* env,jclass obj,jfloat f1,jfloat f2);
jfloat sub(JNIEnv* env,jclass obj,jfloat f1,jfloat f2);

const JNINativeMethod realImplMethods[] = {
        {"f2f","(FF)F",(void *)sub},
    	//external fun name,signature,真实实现的方法指针
        {"dynamicRegister","(FF)F",(void *)add}//注册到kotlin定义的external fun
};

jint registerNM(JNIEnv* env);
jisuan.c
#include "jisuan.h"
//实际实现方法
jfloat add(JNIEnv *env, jclass obj, jfloat f1, jfloat f2) {
    return f1 + f2;
}
jfloat sub(JNIEnv *env, jclass obj, jfloat f1, jfloat f2) {
    return f1 - f2;
}

//动态注册方法到env
jint registerNM(JNIEnv *env) {
    jclass clazz = (*env)->FindClass(env, "com/longforus/testdynamicndk/MainActivityKt");
    jint result = (*env)->RegisterNatives(env, clazz, realImplMethods, sizeof(realImplMethods) / sizeof(realImplMethods[0]));
    if (result != JNI_OK) {
        return JNI_ERR;
    }
    return JNI_OK;
}

//该so库在被load的时候的会回调,注意要返回JNI_VERSION否则会报错
JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
    JNIEnv *env;
    (*vm)->GetEnv(vm, (void **) &env, JNI_VERSION_1_6);
    registerNM(env);
    return JNI_VERSION_1_6;
}

//传统的静态注册
JNIEXPORT jfloat JNICALL
Java_com_longforus_testdynamicndk_MainActivityKt_staticRegister(JNIEnv *env, jclass clazz, jfloat f1, jfloat f2) {
    return f1 + f2;
}

对比

使用动态注册native方法后就不能在Exports中找到本来静态注册时存在的dynamicRegister了.但是根据Exports中暴露的JNI_OnLoad方法,F5查看伪代码,还是能找到一些端倪:

jint JNI_OnLoad(JavaVM *vm, void *reserved)
{
  int v3; // [sp+18h] [bp-10h] BYREF

  (*vm)->GetEnv(vm, (void **)&v3, 65542);
  j_registerNM(v3);//这里引用了注册的方法
  return 65542;
}


int __fastcall registerNM(int a1)
{
  int v1; // r0
  int v4; // [sp+14h] [bp-Ch]
  	//这里暴露了类名
  v1 = (*(int (__fastcall **)(int, const char *))(*(_DWORD *)a1 + 24))(a1,"com/longforus/testdynamicndk/MainActivityKt");
    //直白的变量名 realImplMethods 也有点暴露意图
  if ( (*(int (__fastcall **)(int, int, void **, int))(*(_DWORD *)a1 + 860))(a1, v1, &realImplMethods, 2) )
    v4 = -1;
  else
    v4 = 0;
  return v4;
}

//导入JNIEvn后
int __fastcall registerNM(_JNIEnv *a1)
{
  jclass v1; // r0
  int v4; // [sp+14h] [bp-Ch]
    //还是直接暴露了意图,知道这里有动态注册了
  v1 = a1->functions->FindClass(a1, "com/longforus/testdynamicndk/MainActivityKt");
  if ( a1->functions->RegisterNatives((JNIEnv *)a1, v1, (const JNINativeMethod *)&realImplMethods, 2) )
    v4 = -1;
  else
    v4 = 0;
  return v4;
}

双击realImplMethods进入后:

在这里插入图片描述

直接就发现了真实做实现的sub指针,而且可以双击进入:

float __fastcall sub(int a1, int a2, float a3, float a4)
{
  return a3 - a4;
}

修改dynamicRegister的真实实现为add后,再次反编译:

在这里插入图片描述

直接就变成了add.

总结

目前了解到的这个简单的动态注册相对于静态注册,安全性有一点的提升,如果使用模糊的命名,项目够大的话,安全性应该能再提升一些.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值