Android逆向学习67——JNI与NDK

admin 2024年5月14日20:09:05评论3 views字数 2165阅读7分13秒阅读模式

JNI与NDK

1.JNI接口的介绍

jni接口是将java层与c/c++层联系起来,使得它们相互的协调来完成某些任务。 通常在几种情况使用JNI:

(1) 注重处理速度

与本地代码相比,java代码的执行速度更慢,对某段程序执行有较高要求,可以用C/C++来编写,这样往往运行的速度更快。
Android逆向学习67——JNI与NDK

(2) 硬件控制

硬件控制代码常常由C/C++编写

(3) 既有C/C++代码的复用

编写一些C/C++代码,确保程序的安全性和健壮性,用JNI接口实现。
Android应用开发过程中,使用SDK来开发java程序,使用NDK来开发C/C++。

2.JNI的基本原理

java中调用C库函数的过程

Android逆向学习67——JNI与NDK

第一步,编写java代码

Android逆向学习67——JNI与NDK

第二步,编译java代码

Android逆向学习67——JNI与NDK

编译前看是否设置好JDK,将JDK配置到环境变量中

Android逆向学习67——JNI与NDK

第三步,生成C语言头文件

创建hellojni.dll运行库文件,具体实现类中声明的两个本地方法
HelloJNI类中声明了printHello()本地方法——>实现相同签名printHello()函数——>System.loadLibrary()方法加载hellojin.dll运行库。Android逆向学习67——JNI与NDK
Android逆向学习67——JNI与NDK

需要创建本地方法的映射C函数,生成头文件。

Android逆向学习67——JNI与NDK
Android逆向学习67——JNI与NDK

JNI头文件:

Android逆向学习67——JNI与NDK

JNI提供了一套与Java数据类型相对应的Java本地类型,使得本地语言可以使用Java数据类型
Android逆向学习67——JNI与NDK
Android逆向学习67——JNI与NDK
Android逆向学习67——JNI与NDK

使用javah命令生成的函数原型的第二个参数是jobject类型或者jclass类型

第四步,编写C/C++代码

在C函数原型生成后,开始编写hellojni.c文件,具体的实现JNI本地函数

Android逆向学习67——JNI与NDK
第五步,生成C共享库

可以使用VSC++或命令生成hellojni.dll文件库

Android逆向学习67——JNI与NDK

第六步,运行java程序

java HelloJNI  运行HelloJNI类

Android逆向学习67——JNI与NDK

3.调用JNI函数

Android逆向学习67——JNI与NDK

(1)Java层代码

  1. JniFuncMain类
Android逆向学习67——JNI与NDK
  1. JniTest类

Android逆向学习67——JNI与NDK
Android逆向学习67——JNI与NDK

(2) 分析JNI本地函数代码

1.JniFunMain.h头文件

使用javah生成JniFunMain.h头文件

Android逆向学习67——JNI与NDK

2.Jnifunc.cpp文件

生成头文件后,我们开始实现函数原型

Android逆向学习67——JNI与NDK

3.通过JNI,获取成员变量值

Android逆向学习67——JNI与NDK

程序通过JNI访问Java类/对象的成员变量按如下顺序:
(1)查找含待访问的成员变量的Java类的jclass值 (2)获取该类成员变量的jfieldID值,静态变量:调用名称为GetStaticFieldID()的JNI函数。普通对象:GetFieldID()的JNI函数 (3)使用上文中获得jclass和jfield值,获取或1设置1成员变量值

获取jclass值,调用JNI函数FindClass()即可

Android逆向学习67——JNI与NDK
Android逆向学习67——JNI与NDK
可能缺少env参数,这是与C/C++风格有关

Android逆向学习67——JNI与NDK

生成对象

(1) 首先调用JNI函数FindClass(),查找生成对象的类

Android逆向学习67——JNI与NDK
Android逆向学习67——JNI与NDK
Android逆向学习67——JNI与NDK

(2) 查找类的构造方法ID,保存在jmethodID变量中

Android逆向学习67——JNI与NDK

(3) 用获得的jclass与构造方法的ID参数,调用JNI函数 NewOject(),生成JniTest类的对象。

Android逆向学习67——JNI与NDK

局部引用和全局引用

Android逆向学习67——JNI与NDK
当全局引用使用完毕,应调用名称为DeleteGlobalRef()函数,将全局引用销毁

4.调用Java方法

顺序: (1)获取待调方法的Java类的jclass(若为java对象,则  用该方法获取java类对象的jobject) (2)调用GetMethond函数,获取待调方法的ID(使用jclass与GetMethondID()函数) (3)静态方法:CallStaticMethond() 类对象:CallMethond()

Android逆向学习67——JNI与NDK
Android逆向学习67——JNI与NDK

4.通过JNI设置变量成员的值

Android逆向学习67——JNI与NDK
Android逆向学习67——JNI与NDK

(3) 编译及运行结果

1.编译.java文件 2.编译.cpp文件 3.运行JniFunMain类

4.在C程序中运行Java类

Invocation API应用示例

Android逆向学习67——JNI与NDK
执行顺序: (1)主程序InvokeJava.cpp使用Invocation API加载Java虚拟机 (2)加载InvocationTest类至内存中 (3)执行被加载的InvocationTest类的main()方法

分析java代码和C代码

Android逆向学习67——JNI与NDK
Android逆向学习67——JNI与NDK
Android逆向学习67——JNI与NDK

java虚拟机结构体

Android逆向学习67——JNI与NDK
JavaVMInitArgs结构体的version成员用来指定传递虚拟机的选项的变量的形式 nOptions指定JavaVMOption结构体数组元素的个数,option用来指向JavaVMOption结构体的地址

Android逆向学习67——JNI与NDK
Android逆向学习67——JNI与NDK
Android逆向学习67——JNI与NDK

5.直接注册JNI本地函数

Java虚拟机中运行Java应用程序的步骤: 1.调用System.loadLibrary()方法,将本地方法具体实现的C/C++运行库加载到内存中。 2.Java虚拟机检索库函数,并建立映射关系。

为了解决映射问题,JNI机制提供了RegisterNatives()的JNI函数,建立映射关系。

加载本地库时,注册JNI本地函数

System.loadLibrary()方法的执行过程: 调用System.loadLibrary方法——>java虚拟机会加载其参数指定的共享库——>Java虚拟机检索共享库的函数符号,检查JNI_OnLoad()函数是否被实现(含相关函数,JNI_OnLoad会自动的实现)

开发者若想手工映射本地方法与JNI本地函数,需要在JNI_OnLoad()函数内调用RegisterNatives()函数进行映射匹配

Android逆向学习67——JNI与NDK
Android逆向学习67——JNI与NDK
Android逆向学习67——JNI与NDK
Android逆向学习67——JNI与NDK
Android逆向学习67——JNI与NDK

原文始发于微信公众号(安全后厨):Android逆向学习67——JNI与NDK

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年5月14日20:09:05
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Android逆向学习67——JNI与NDKhttps://cn-sec.com/archives/2739573.html

发表评论

匿名网友 填写信息