一.原理
当在系统中调用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. 入门:HTML表单与Java 后台交互(复选框提交)

    仅仅给出部分关键代码: HTML form code: <form action="JavaFormTest" method="post" name=&q ...

  2. JSONModel 嵌套字典数组 JSONModel nest NSDictionary NSArray

    JSONModel 嵌套字典数组  JSONModel nest NSDictionary NSArray

  3. linux下解压命令大全

    .tar 解包:tar xvf FileName.tar打包:tar cvf FileName.tar DirName(注:tar是打包,不是压缩!)———————————————.gz解压1:gun ...

  4. mysql max_allowed_packet查询和修改

    http://www.2cto.com/database/201303/195830.html mysql根据配置文件会限制server接受的数据包大小. 有时候大的插入和更新会被max_allowe ...

  5. winxp可以禁用的服务

    要注意的是: 虽然某个服务你设置成了手动, 而且在services.msc中好像也没有启动, 但是并不表示这个服务不可以被启动 因为某些软件, 可能在程序内部进行了编程的设置, 它可以在内部去启动 服 ...

  6. nodejs开发指南读后感

    nodejs开发指南读后感 阅读目录 使用nodejs创建http服务器; supervisor的使用及nodejs常见的调式代码命令了解; 了解Node核心模块; ejs模板引擎 Express 理 ...

  7. ASP.NET 5与MVC 6中的新特性

    差点忘了提一句,MVC 6中默认的渲染引擎Razor也将得到更新,以支持C# 6中的新语法.而Razor中的新特性还不只这一点. 在某些情况下,直接在Web页面中嵌入某些JSON数据的方式可能比向服务 ...

  8. LYDSY模拟赛day3 平均数

    [ 问题描述]有一天, 小 A 得到了一个长度为 n 的序列.他把这个序列的所有连续子序列都列了出来, 并对每一个子序列都求了其平均值, 然后他把这些平均值写在纸上, 并对它们进行排序,最后他报出了第 ...

  9. PHP命名空间入门教程

    PHP5.3当中就引入了“命名空间”的概念,一直都没怎么关注和使用,其实学习它也挺简单的,看官方的教程就行了: 命名空间概述 定义命名空间 定义子命名空间 在同一个文件中定义多个命名空间 使用命名空间 ...

  10. 如何让网页在浏览器标题栏显示自己制作的图标ico

    第一步,制作一个尺寸16x16大小的PNG图片,可以用photoshop等图片处理工具来设计,然后保存到本地电脑上,通过ico在线制作或使用IconWorkshop工具制作ICO图标,ico图标命名为 ...