前言

Android应用中JNI代码,是作为本地方法运行的。而大部分情况下,这些JNI方法均需要传递Dalvik虚拟机实例作为第一个参数。例如,你需要用虚拟机实例来创建jstring和其他的Java对象、查找类或成员变量等。大部分情况下,在你用JNI接口从Java层调用Native层中的代码时,你并不需要在native代码中自己初始化一个Dalvik虚拟机实例。但是,如果你在搞逆向或者写exp,你总是需要钻研各种非常规的情况。

最近,我在逆向时需要在native代码中手动创建虚拟机实例用于在JNI接口函数中传递Java对象。在本文中,我将分享我是如何实现这种方法的。

标准方法

在JNI中创建JVM虚拟机实例的官方文档在地址How to Create a JVM Instance in JNI。但是,不幸的是这种方法在Android上面是不能正常运行的,因为jint JNI_CreateJavaVM(JavaVM**, JNIEnv**, void*)函数不是导出函数,无法直接调用。假如你不熟悉这个方法的话,可以根据它的名字在jni.h文件中查找一下,确认是否是导出函数。在我这里,jni.h文件位于android-sdk/ ndk-bundle/platforms/android-9/arch-x86/usr/include/jni.h。相关代码如下:

如果你尝试编译调用上述截图中函数的代码,你可能会得到下面的错误:

官方文档中介绍的如何创建JVM的方法在这里可以用来理解上述的API函数和它们的选项和参数的用途。如果你想在Android中使用这些方法,你必须显示从so库中调用这些方法。

官方文档中介绍的如何初始化虚拟机的类路径,在此处是非常有用的。其内容如下:

上面的配置,设置当前的类路径为当前目录(.)。如果你想要虚拟机访问系统或者app的类,这是必须设置的。实验表明,将该值设置为一个目录并不会起作用。我尝试将其设置为/data/local/tmp,同时在该目录下放置了一个dex文件、含有dex文件的jar包和apk文件。只有在设置jar包、dex文件或apk文件的全路径时,上述选项才起作用。奇怪的是,当类路径中没有一个合法的文件时,系统类(例如java.lang.String)都不能访问。换句话说,除非类路径中至少有一个文件,否则语句(*env)->FindClass(env, "java.lang.String")返回0,甚至java.lang.String这样定义在框架中的类都无法访问。

为了测试,下面将一个apk文件push到模拟器或真机设备中。

JavaVMOption的使用如下:

你现在可以使用FindClass函数来加载系统或者app的类。此外,如果你需要加载本地库到你的虚拟机中,例如在静态初始化器中加载一个库文件,你可以使用optionString = "-Djava.library.path=/data/local/tmp"这样的设置。这有个样例代码

UniccUnlock方法

从文件UniccUnlock.cpp中,展示了另外一种创建虚拟机的类似技巧。我不敢说我完全理解了它在做什么,但是其中吸引我的是get_transaction_code部分。下面是它的做的事:

1
<ol class="linenums"><li class="L0"><span class="pln">creates a </span><span class="typ">Java</span><span class="pln"> VM</span></li><li class="L1"><span class="kwd">use</span><span class="pln"> the VM to </span><span class="kwd">get</span><span class="pln"> reference to com</span><span class="pun">.</span><span class="pln">android</span><span class="pun">.</span><span class="kwd">internal</span><span class="pun">.</span><span class="pln">telephony</span><span class="pun">.</span><span class="typ">ITelephony$Stub</span><span class="pln"> </span><span class="kwd">class</span></li><li class="L2"><span class="kwd">get</span><span class="pln"> the TRANSACTION_sendOemRilRequestRaw field value</span></li><li class="L3"><span class="pln">destroy the VM</span></li><li class="L4"><span class="kwd">return</span><span class="pln"> field value</span></li></ol>

代码看起来像是根据成员值判断当前设备是否已经解锁或者是解锁方法是否成功。反正我是不很确定,不过我也就想抽取其中创建虚拟机的代码而已。

该方法是通过在库文件libnativehelper.so或者libdvm.so中加载创建虚拟机相关的方法。但是,下面几行代码看起来很奇怪:

任何地方都无法找到这几个方法的文档说明。不过,发现这些方法调用的人相当聪明。如果不调用这些方法,你就会得到下面奇怪的错误信息:

除了这几个奇怪的方法,这种方式创建虚拟机对我很好使。但是,我想知道_ZN13JniInvocationC1Ev方法都做了什么,在不同版本间的Android系统中是否可移植。我的直觉告诉我,硬编码的方法名可能会导致在不同的设备或者Android版本间的不兼容性。

Surfaceflinger 方法

最终,我在谷歌的Surfaceflinger服务的源码中找到了:DdmConnection.cpp

它默认查找了在libdvm.so中的函数JNI_CreateJavaVM。它没有调用方法_ZN13JniInvocation,而是调用了库libandroid_runtime.so中的Java_com_android_internal_util_WithFramework_registerNatives方法。registerNatives方法的内容在此描述了。

同时,感兴趣的是创建虚拟机的选项:

这些选项在这篇文档中详细描述了。根据文档,它仅仅用于调试JVM时使用。

同时,我注意到它JNI的版本是1_4,但是我设置为1_6了,因为谷歌的样例代码中就是这样设置的。下面就是jni.h中支持的版本号:

最后,我使用上面的方式来创建虚拟机,因为它来自谷歌,具有很好的健壮性和兼容性。

最终代码

下面就是最终的创建虚拟机的代码:

下面是其使用方法:

本文由 安全客 翻译,转载请注明“转自安全客”,并附上链接。
原文链接:https://calebfenton.github.io/2017/04/05/creating_java_vm_from_android_native_code/

 

在Android Native层中创建Java虚拟机实例的更多相关文章

  1. Android Native层异步消息处理框架

     *本文系作者工作学习总结,尚有不完善及理解不恰当之处,欢迎批评指正* 一.前言 在NuPlayer中,可以发现许多类似于下面的代码: //============================== ...

  2. Android native层动态库注射

    1.简单介绍 本文解说在Android native层.root权限下.注射动态库到目标进程,从而hook目标进程中动态库的函数的实现方式. 文中的源代码所有来源于网络.我仅仅是略微加以整理. 环境: ...

  3. Android内核sysfs中switch类使用实例

    Android内核sysfs中switch类使用实例 最终在这个周末,能够干点自己想要干的事了. 由我这个二流的内核驱动开发人员来解析一下sysfs中的switch类.先猜測一下来历,在普通的嵌入式L ...

  4. 在Android源码中查找Java代码中native函数对应的C++实现

    Android源码中很多关键代码都是C++实现的,java通过jni来调用,经常会看到java中这样的代码: static native Thread currentThread(); 如何根据方法名 ...

  5. 本地C代码中创建Java对象

    作者:唐老师,华清远见嵌入式学院讲师. 创建Java域的对象就是创建Java类的实例,再调用Java类的构造方法. 以Bitmap的构建为例,Bitmap中并没有Java对象创建的代码及外部能访问的构 ...

  6. [Android]Android SDk Manager中创建模拟器无法选择CPU问题解析

    方法一.正常下载所需sdk包 启动 Android SDK Manager ,打开主界面,依次选择「Tools」.「Options...」,弹出『Android SDK Manager - Setti ...

  7. Java中JNI的使用详解第四篇:C/C++中创建Java对象和String字符串对象及对字符串的操作方法

    首先来看一下C/C++中怎么创建Java对象:在JNIEnv中有两种方法是用来创建Java对象的: 第一种方法: jobject  NewObject(jclass clazz  , jmethodI ...

  8. 如何使用 Packer 在 Azure 中创建 Windows 虚拟机映像

    Azure 中的每个虚拟机 (VM) 都是基于定义 Windows 分发和操作系统版本的映像创建的. 映像可以包括预安装的应用程序和配置. Azure 应用商店为最常见的操作系统和应用程序环境提供了许 ...

  9. 面试中关于Java虚拟机(jvm)的问题看这篇就够了

    最近看书的过程中整理了一些面试题,面试题以及答案都在我的文章中有所提到,希望你能在以问题为导向的过程中掌握虚拟机的核心知识.面试毕竟是面试,核心知识我们还是要掌握的,加油~~~ 下面是按jvm虚拟机知 ...

随机推荐

  1. [LeetCode] 206. Reverse Linked List_Easy tag: Linked List

    Reverse a singly linked list. Example: Input: 1->2->3->4->5->NULL Output: 5->4-> ...

  2. 在Ubuntu 16.04上利用Jexus+.Net Core+Linux版SQL Server部署ZKEACMS.Core

    百度传课视频地址:https://chuanke.baidu.com/v5849090-223278-1498090.html 一.SQL Server on Linux的安装 官方文档:https: ...

  3. 全网最详细的CentOS7里安装MySQL时出现No package mysql-server available错误的解决办法(图文详解)

    不多说,直接上干货! 直接yum install mysql的话会报错,原因在于yum安装库里没有直接可以用的安装包,此时需要用到MariaDB了,MariaDB是MySQL社区开发的分支,也是一个增 ...

  4. Vue源码翻译之组件初始化。

    废话不多说. 我们先来看看Vue的入口文件. import { initMixin } from './init' import { stateMixin } from './state' impor ...

  5. kmp模式串匹配

    大二的时候百度看不懂,现在大三下学期了百度也看不懂.(实在是不能理解这个next数组究竟是怎么样工作的,为什么会得出那样的结果.)如果有好心人知道的话希望可以联系我告诉我(邮箱:4609019410@ ...

  6. docker网络之overlay

    使用docker network的好处是:在同一个网络上的容器之间可以相互通信,而无需使用expose端口特性 本文使用docker-swarm进行overlay网络的分析.使用2个vmware模拟2 ...

  7. Nginx限制访问次数和并发数

    Nginx限制访问速率和最大并发连接数模块--limit (防止DDOS攻击) http: ##zone=one或allips 表示设置名为"one"或"allips&q ...

  8. shell脚本补缺

    一.执行脚本的三种方法. chmod  +x  添加执行权限 ./example.sh        相对路径 root/test/example.sh  绝对路径 bash example.sh   ...

  9. 【IT笔试面试题整理】二叉树中和为某一值的路径--所有可能路径

    [试题描述] You are given a binary tree in which each node contains a value. Design an algorithm to print ...

  10. mongodb备份策略

    概述 数据库的备份非常非常非常重要!!!否则出问题连哭的机会有没有(欲哭无泪)今天主要是做一个mongodb的数据库备份. 1.关于备份 备份其实很简单,这里选择的是对mongodb中的某个库进行全备 ...