zoukankan      html  css  js  c++  java
  • ndk学习20: jni之OnLoad动态注册函数


    一.原理
    当在系统中调用System.loadLibrary函数时,该函数会找到对应的动态库,
    然后首先试图找到"JNI_OnLoad"函数,如果该函数存在,则调用它

    JNI_OnLoad可以和JNIEnv的registerNatives函数结合起来,实现动态的函数替换


    二. 实战
    用ndk学习17的例子继续, 下面演示动态替换TestJni中的sayHello
    jstring JNICALL Java_org_bing_testjni_MainActivity_sayHello
    (JNIEnvenvjobject objjstring name)
    {
        const charpname = env->GetStringUTFChars(nameNULL);
        string str_info = "Hello World:";
        str_info += pname;
        jstring ret_str = env->NewStringUTF(str_info.c_str());
        // C文件使用(*env)->Fun(env,xxx,...)的方式传递
        // (*env)->NewStringUTF(env, "Hello World");
        return ret_str;
    }  

    1.jni目录下新建一个cpp文件jni_replace.cpp
    Android.mk中添加选项:
    include $(CLEAR_VARS)
    LOCAL_MODULE    := jni_replace
    LOCAL_SRC_FILES := jni_replace.cpp
    LOCAL_LDFLAGS += -llog
    include $(BUILD_SHARED_LIBRARY)  


    2. 编写代码如下
    #include "org_bing_testjni_MainActivity.h"
    #include <stdio.h>
    #include <string>
    #include <android/log.h>
    using namespace std;
    __attribute__((visibility("hidden")))  jstring JNICALL sayHello (JNIEnv *, jobjectjstring);
    __attribute__((visibility("hidden")))  JNINativeMethod g_Methods[] = {
            "sayHello",
            "(Ljava/lang/String;)Ljava/lang/String;",
            (void*) sayHello
    };
    JNIEXPORT jint JNICALL JNI_OnLoad(JavaVMvmvoidreserved) {
        __android_log_print(ANDROID_LOG_DEBUG"__BING__""JNI_OnLoad");
        JNIEnv *pEnv = NULL;
        //获取环境
        jint ret = vm->GetEnv((void**) &pEnv, JNI_VERSION_1_6);
        if (ret != JNI_OK) {
            __android_log_print(ANDROID_LOG_DEBUG"__BING__""jni_replace JVM ERROR:GetEnv");
            return -1;
        }
        jclass cls = pEnv->FindClass("org/bing/testjni/MainActivity");
        if (cls == NULL) {
            __android_log_print(ANDROID_LOG_DEBUG"__BING__""jni_replace:FindClass Error");
            return -1;
        }
        //动态注册本地方法
        ret = pEnv->RegisterNatives(cls, g_Methods,sizeof(g_Methods) / sizeof(g_Methods[0]));
        if (ret != JNI_OK) {
            __android_log_print(ANDROID_LOG_DEBUG"__BING__""jni_replace:FindClass Error");
            return -1;
        }
        //返回java版本
        return JNI_VERSION_1_6;
    }
    __attribute__((visibility("hidden")))  jstring JNICALL sayHello(JNIEnvenv,jobject objjstring name) {
        const charpname = env->GetStringUTFChars(nameNULL);
        string str_info = "replace say hello function:";
        str_info += pname;
        jstring ret_str = env->NewStringUTF(str_info.c_str());
        return ret_str;
    }

    3.运行结果
    字符串被成功替换


    三.NDK中使用Log
    1.添加链接选项
    LOCAL_LDFLAGS += -llog

    这些库是在platform/android-xx/xxx/usr/lib目录下的


    包含头文件:
    #include <android/log.h>  

    函数:
    __android_log_print(ANDROID_LOG_DEBUG"TAG""Hello");  

    日志输出选项是一个枚举
    typedef enum android_LogPriority {
        ANDROID_LOG_UNKNOWN = 0,
        ANDROID_LOG_DEFAULT,    /* only for SetMinPriority() */
        ANDROID_LOG_VERBOSE,
        ANDROID_LOG_DEBUG,
        ANDROID_LOG_INFO,
        ANDROID_LOG_WARN,
        ANDROID_LOG_ERROR,
        ANDROID_LOG_FATAL,
        ANDROID_LOG_SILENT,     /* only for SetMinPriority(); must be last */
    android_LogPriority;  


    四.总结
    这种JNI Onload的方法,在把Onload函数的在导出表里面抹掉
    在动态初始化导出表

    这样会增加逆向静态分析的成本






  • 相关阅读:
    Linux 修改最大线程数
    Openresty+Nginx+Lua+Nginx_http_upstream_check_module 搭建
    SSDB 性能测试
    面向对象:类的成员
    封装,多态,类的约束,super()深入了解
    面向对象:继承
    面向对象:类的空间问题,类之间关系
    面向对象初识
    软件开发规范
    模块(四)包和logging日志
  • 原文地址:https://www.cnblogs.com/bingghost/p/5755662.html
Copyright © 2011-2022 走看看