一.原理
当在系统中调用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. Http请求之--C#的HttpWebRequest实现POST方式请求

    1.添加头信息和请求方法.有两种方式添加             req = (HttpWebRequest)WebRequest.Create("http://zhidao.baidu.c ...

  2. json_encode详解,转义

    1.json_encod基本用法:数组转字符串 <?php $arr = array (,,,,); echo json_encode($arr); ?> 以上例程会输出: {,,,,} ...

  3. div文字超出

    效果一:div文字超出处理 <div style="width:200px; white-space:nowrap;overflow:hidden;text-overflow:elli ...

  4. The method below converts an array of objects to a DataTable object in C#.

    http://www.c-sharpcorner.com/blogs/dynamic-objects-conveting-into-data-table-in-c-sharp1 public stat ...

  5. 使用 Elasticsearch ik分词实现同义词搜索(转)

    1.首先需要安装好Elasticsearch 和elasticsearch-analysis-ik分词器 2.配置ik同义词 Elasticsearch 自带一个名为 synonym 的同义词 fil ...

  6. RQNOJ659 计算系数

    http://www.rqnoj.cn/problem/659 描述 给定一个多项式(ax + by)^k,请求出多项式展开后x^n * y^m项的系数. 格式 输入格式 共一行,包含5个整数,分别为 ...

  7. 导航菜单:jQuery粘性滚动导航栏效果

    粘性滚动是当导航在滚动过程中会占粘于浏览器上,达到方便网站页面浏览的效果,也是一种用户体验,下面我们看一下是怎么实现的: jQuery的 smint插件,也是一个导航菜单固定插件.当页滚动时,导航菜单 ...

  8. 从svn检出项目---------不是web项目

    javaweb项目从svn检出变成java项目 javaweb项目从svn检出后变成java项目,解决办法是: 1.项目右键–properties–Project Facets,勾选上Dynamic ...

  9. mock.js-无需等待,让前端独立于后端进行开发

    概述 首先啦,我不认识mock.js的作者,带着需求找到mock.js让我觉得很惊艳. 相对于其他同类的框架的实现,mock.js超出了我的意料. 基于 数据模板 生成模拟数据. 基于 HTML模板 ...

  10. [译]View components and Inject in ASP.NET MVC 6

    原文:http://www.asp.net/vnext/overview/aspnet-vnext/vc 介绍view components view components (VCs) 类似于part ...