- 对本书的赞誉
- 前言
- 基础篇
- 第 1 章 Android 中锁屏密码加密算法分析
- 第 2 章 Android 中 NDK 开发
- 第 3 章 Android 中开发与逆向常用命令总结
- 第 4 章 so 文件格式解析
- 第 5 章 AndroidManifest.xml 文件格式解析
- 第 6 章 resource.arsc 文件格式解析
- 第 7 章 dex 文件格式解析
- 防护篇
- 第 8 章 Android 应用安全防护的基本策略
- 第 9 章 Android 中常用权限分析
- 第 10 章 Android 中的 run-as 命令
- 第 11 章 Android 中的 allowBackup 属性
- 第 12 章 Android 中的签名机制
- 第 13 章 Android 应用加固原理
- 第 14 章 Android 中的 so 加固原理
- 工具篇
- 第 15 章 Android 逆向分析基础
- 第 16 章 反编译神器 apktool 和 Jadx
- 第 17 章 Hook 神器 Xposed
- 第 18 章 脱壳神器 ZjDroid
- 第 19 章 Native 层 Hook 神器 Cydia Substrate
- 操作篇
- 第 20 章 静态方式逆向应用
- 第 21 章 动态调试 smali 源码
- 第 22 章 IDA 工具调试 so 源码
- 第 23 章 逆向加固应用
- 第 24 章 逆向应用经典案例分析
- 第 25 章 Android 中常见漏洞分析
- 第 26 章 文件加密病毒 Wannacry 样本分析
2.4 JNIEnv 类型中方法的使用
前面说到 JNIEnv 类型,下面通过例子来看一下这些方法的使用。第一个例子是在 Java 代码中定义一个属性,然后再从 C++代码中将其设置成另外的值,并且输出来。
2.4.1 native 中获取方法的 Id
先来看一下 Java 代码:
再来看一下 C++代码:
编译成功后,在 Eclipse 运行后的结果如图 2-24 所示。
图 2-24 运行成功效果图
第一个 0 是在 C++代码中的 cout<<number<<endl。
第二个 100 是在 Java 中的 System.out.println(jniDemo.number)。
JNIEnv 提供了众多的 Call<Type>Method 和 CallStatic<Type>Method,还有 CallNonvirtual<Type>Method 函数,需要通过 GetMethodID 取得相应方法的 jmethodID 来传入到上述函数的参数中。
调用示例方法的三种形式如下:
第一种是最常用的方式。第二种是当调用这个函数的时候有一个指向参数表的 va_list 变量时使用的(很少使用)。第三种是当调用这个函数的时候有一个指向 jvalue 或 jvalue 数组的指针时用的。
jvalue 在 jni.h 头文件中定义是一个 union 联合体,在 C/C++中,union 可以存放不同类型的值,但是当你给其中一个类型赋值之后,这个 union 就是这种类型了,比如你给 jvalue 中的 s 赋值的话,jvalue 就变成了 jshort 类型了,所以可以定义一个 jvalue 数组(这样就可以包含多种类型的参数了)传递到方法中,如下所示:
假如现在 Java 中有这样的一个方法:
1)在 C++中使用第一种方式调用 function 方法:
obj 是方法 funtion 的对象。id_function 是方法 function 的 id,可以通过 GetMethodID()方法获取。然后就是对应的参数,这和 Java 中的可变参数类似。最后一个 char 类型的参数 L'a'为什么前面要加一个 L 呢?原因是 Java 中的字符是 Unicode 双字节的,而 C++中的字符是单字节的,所以要变成宽字符,即前面加一个 L。
2)在 C++中使用第三种方式调用 function 方法:
例子:C++中调用 Java 中的方法。
Java 代码如下:
这时候用 javap 获取 max 方法的签名,如下所示。
max 方法的签名是(DD)D。在 C++中的代码如下:
编译成动态文件后,到 Eclipse 中执行 sayHello 方法,运行结果如图 2-25 所示。
图 2-25 运行成功效果图
可见,成功地输出了最大值。
2.4.2 Java 和 C++中的多态机制
JNIEnv 中有一个特殊的方法 CallNonvirtual<Type>Method,如下所示:
首先来了解一下,上面调用的 function 是子类的 function 方法,但是在 C++中就不一样了:
这段 C++代码中执行的是父类的 function 方法,如果想执行子类的 function 方法怎么办呢?就需要将父类的 function 方法定义成 virtual 虚函数:
所以,C++和 Java 对于继承后执行的是父类还是子类的方法是有区别的,在 Java 中所有的方法都是虚拟的,所以总是调用子类的方法,因此 CallNonVirtual<Type>Method 方法就出来了,这个方法可以帮助调用 Java 中父类的方法。
在 JNI 中定义的 CallNonvirtual<Type>Method 能够实现子类对象调用父类方法的功能,如果想要调用一个对象的父类方法,而不是子类的方法,就可以使用 CallNonvirtual<Type>Method。要使用它,首先要获得父类及其要调用的父类方法的 jmethodID,然后传入到这个函数就能通过子类对象调用被覆写的父类方法了。
例如:在 Java 中定义 Father 类:
定义一个子类 Child,继承 Father 类,重写父类中的 function 方法:
在 JNIDemo 代码,定义 Father 类型的属性:
再来看一下 C++中的代码:
编译成功.dll 文件,回到 Eclipse 中运行结果参如图 2-26 所示。
图 2-26 运行结果
其中:
·Child:function 是调用 env->CallVoidMethod(...)方法的。
·Father:function 是调用 env->CallNonvirtualMethod(...)方法的。
这样就能够控制到底调用哪个类的 function 方法了。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论