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

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


二. 实战

用ndk学习17的例子继续, 下面演示动态替换TestJni中的sayHello

jstring JNICALL Java_org_bing_testjni_MainActivity_sayHello
(JNIEnv* env, jobject obj, jstring name)
{
    const char* pname = env->GetStringUTFChars(name, NULL);
    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 *, jobject, jstring);
__attribute__((visibility("hidden")))  JNINativeMethod g_Methods[] = {
        "sayHello",
        "(Ljava/lang/String;)Ljava/lang/String;",
        (void*) sayHello
};
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
    __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(JNIEnv* env,jobject obj, jstring name) {
    const char* pname = env->GetStringUTFChars(name, NULL);
    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函数的在导出表里面抹掉
在动态初始化导出表

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


ndk学习20: jni之OnLoad动态注册函数的更多相关文章

  1. frida- registernatives获取so层动态注册函数

    frida获取so层动态注册函数 谢谢大佬的无私奉献https://github.com/lasting-yang/frida_hook_libart 一.js模板一 function hook_Re ...

  2. Android JNI和NDK学习(06)--JNI的数据类型(转)

    本文转自:http://www.cnblogs.com/skywang12345/archive/2013/05/23/3094037.html 本文介绍JNI的数据类型.NDK中关于JNI数据类型的 ...

  3. Android JNI和NDK学习(09)--JNI实例二 传递类对象

    1 应用层代码 NdkParam.java是JNI函数的调用类,它的代码如下:   package com.skywang.ndk; import android.app.Activity; impo ...

  4. ndk学习17: jni之Java调用C&C++

    一.Hello World 1. 定义函数原型 native关键字定义的函数即为jni函数 2.生成头文件 切换到src目录执行: (这个过程可以写脚本自动完成,比如自动拷贝到jni目录) javah ...

  5. NDK学习笔记-JNI多线程

    前面讲到记录到ffmpeg音视频解码的时候,采用的是在主线程中进行操作,这样是不行的,在学习了POSIX多线程操作以后,就可以实现其在子线程中解码了,也可以实现音视频同步了 简单示例 在native实 ...

  6. NDK学习笔记-使用现有so动态库

    前面将的都是如何使用C/C++文件生成so动态库,那么在使用别人的so动态库的时候应该怎么做呢?这篇文章就是使用一个变声功能的动态库,完成对于以有so动态库的说明. 动态库来源 在互联网中,有着许许多 ...

  7. NDK学习笔记-JNI的异常处理与缓存策略

    在使用JNI的时候,可能会产生异常,此时就需要对异常进行处理 异常处理 JNI抛出Throwable异常,在Java层可以用Throwable捕捉 而在C只有清空异常这种处理 但如果在JNI中通过Th ...

  8. NDK学习笔记-JNI数据类型和属性方法的访问

    JNI实现了C/C++与Java的相互访问,那么这篇文章就从C/C++访问Java开始说起 native函数说明 每个native函数,都至少有两个参数(JNIEnv *和jclass或jobject ...

  9. NDK学习笔记-JNI开发流程

    JNI(Java Native Interface)Java本地化接口,Java调用C/C++,C/C++调用Java的一套API接口 实现步骤 在Java源文件中编写native方法 public ...

随机推荐

  1. ecshop 订单编号 get_order_sn

    文件地址include/lib_order.php ,要引用需要先导入 lib_order.php require_once(ROOT_PATH . 'includes/lib_order.php') ...

  2. SCI答复审稿人的策略和答复信的写作技巧

    SCI论文被录用的最后一步 –---答复审稿人的策略和答复信的写作技巧 [好文转载] : 一篇稿子从酝酿到成型历经艰辛,投出去之后又是漫长的等待,好容易收到编辑的回信,得到的往往又是审稿人不留情面的一 ...

  3. Linux--文件查找命令

    一.简介查找文件的几个命令: 1.which :查找可执行文件的位置 2.whereis:查找文件的位置,可以找到可执行命令和man page 3.locate:配合数据库查看文件位置 4.find: ...

  4. How to get http response.

    public class HttpWebResponseUtility { public static string CreateGetHttpResponse(string url) { var r ...

  5. Autofac IContainer 测试

    using Autofac; using System; using System.Collections.Generic; using System.Linq; using System.Text; ...

  6. asp.net mvc 4 高级编程学习笔记:第三章 视图(1)

    1.基础规则 视图的职责是向用户提供用户界面. 视图位于View目录下:有普通的需要控制器渲染的视图,有局部视图,有布局视图等各种视图. 2.视图渲染 控制器默认情况下渲染与控制器同名的目录内的与Ac ...

  7. 管理员必备的Linux系统监控工具

    管理员必备的Linux系统监控工具 #1: top - 进程活动 top提供一个当前运行系统实时动态的视图, 也就是正在运行进程.在默认情况下,显示系统 中CPU使用率最高的任务,并每5秒钟刷新一次. ...

  8. 2015年11月26日 Java基础系列(四)class的定义,继承和实现interface

    序,类的设计是JAVA操作的核心,面对对象思想中一切皆对象. 一.类定义中的变量 静态成员变量,为类所有,称为类变量:只有一份,编译时即分配值,使用关键字static声明. 非静态成员变量,每个实例一 ...

  9. 开源一个动态解析protobuf的工具

    好久没写博客了,主要是这一年技术没啥长进都打杂了,还有就是生活琐事越来越多,人也越来越懒了…… 之前项目中用到了Protobuf,然后测试发现这玩意不好测,总不能每次定个协议或者改下都要编译Java代 ...

  10. Unix时间戳转换怎样在Excel批量修改?

    最近在操作项目的时候碰到一个Unix时间戳转换的问题."date_time":1393031347这个是什么,你知道吗?如果你对Unix时间戳了解的话一眼就看出来.但我们本着科普的 ...