一.原理
当在系统中调用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. 欧几里德算法 GCD

    递归: int gcd(int a,int b) { ?a:gcd(b,a%b); } 非递归: int gcd(int m,int n) { int r; ) { m=n; n=r; } retur ...

  2. cmake 编译 c++ dll 的一个例子(更新2:增加 python 调用方法)

    CMakeLists.txt project(xxx) add_library(xxx SHARED xxx.cpp) add_executable(yyy yyy.cpp) target_link_ ...

  3. Visual Studio CLR Profiler

    http://blogs.msdn.com/b/dotnet/archive/2013/04/04/net-memory-allocation-profiling-with-visual-studio ...

  4. Visual Studio 2012优化

    http://msdn.microsoft.com/en-us/library/ms182372.aspx

  5. js取float型小数点后两位数的方法

    四舍五入以下处理结果会四舍五入:' var num =2.446242342; num = num.toFixed(2); // 输出结果为 2.45   不四舍五入以下处理结果不会四舍五入:第一种, ...

  6. Http常用状态码

    HTTP状态码(HTTP Status Code) 一些常见的状态码为: 200 - 服务器成功返回网页 404 - 请求的网页不存在 503 - 服务不可用 所有状态解释:点击查看 1xx(临时响应 ...

  7. org.apache.http.client.HttpClient; HttpClient 4.3超时设置

    可用的code import org.apache.commons.lang.StringUtils;import org.apache.http.HttpEntity;import org.apac ...

  8. c# 中使用memcached

    1.首先下载memcached 服务端 2.使用Enyim.Caching .Net 客户端 3.配置web.config    <sectionGroup name="QuickBo ...

  9. CF453C Little Pony and Summer Sun Celebration (DFS)

    http://codeforces.com/contest/456  CF454E Codeforces Round #259 (Div. 1) C Codeforces Round #259 (Di ...

  10. 利用PHP从淘宝采集评论和成交数据

    如果不想通过淘宝开放平台API获取数据,那么另外一个很好的办法就是采集了.一般来说,采集一个网页上的内容,只需要用CURL获取源代码,然后用正则表达式取出需要的内容就可以,不过如果这样载入一个淘宝的页 ...