Android安全与逆向之Dalvik虚拟机架构和如何执行程序以及JIT(即时编译)

简介: Android安全与逆向之Dalvik虚拟机架构和如何执行程序以及JIT(即时编译)

1、Dalvik虚拟机架构和Java虚拟机的架构不同

1、Java虚拟机基于栈结构,需要频繁从栈读取或写入数据,这个过程需要更多的指令与内存访问次数,会消耗cpu时间

2、Dalvik虚拟机基于寄存器,数据访问通过寄存器直接传递,比栈方式快。

public class Hello {

    public int foo(int a, int b) {

    return (a + b) * (a - b);

}



public static void main(String[] args) {

 Hello hello = new Hello();

 System.out.println(hello.foo(5, 3));

}

}


保存为Hello.java文件,打开终端执行

javac Hello.java 编译生存Hello.class文件

然后再执行 dx --dex --output=Hello.dex Hello.class 生存dex文件

javap -c -classpath .Hello 命令执行后得到下面代码:


public int foo(int, int);

Code:

0: iload_1

1: iload_2;

  2: iadd

  3: iload_1

  4: iload_2

  5: isub

  6: imul

  7: ireturn

使用dexdump.exe查看foo()函数的Dalvik字节码,执行下面命令

dexdump.exe -d Hello.dex

得到如下代码

  0000:add-int v0, v3, v4

  0002:sub-int v1, v3, v4

  0004:mul-int/2addr v0, v1

  0005:return v0


Java字节码分析:8个命令 8个字节,至于怎么压栈进栈就不详细讲了

Dalvik字节码分析:4条命令完成操作

代码指令减少,速度更快。

2、Dalvik虚拟机如何执行程序的

Android系统有Linux内核、函数库、Android运行时、应用程序框架和应用层组成。Dalvik虚拟机属于Android运行时环境

1.png

Android系统启动加载完成内核后,第一个执行的是init进程,init进程首要做的是设备初始化工作,然后读取inic.rc文件并启动系统中的重要的外部程序Zygote

Zygote是所有进程的孵化器,它启动会初始化Dalvik虚拟机,然后启动system_server并进入Zygote模式,通过socket等候命令,当执行一个Android应用程序时,system_server

进程通过socket方式发送命令给Zygote,Zygote收到命令后通过fork自身创建一个Dalvik虚拟机的实例来执行应用程序的入口函数,这样程序启动完成,流程图如下

2.png

Zygote提供3种创建进程的方法

1、fork(),创建一个Zygote进程

2、forkAndSpecialize()创建一个非Zygote进程

3、forSystemServer()创建一个系统服务进程

Zygote可以再fork()出其他进程,非Zygote进程不可以fork其它进程,而系统服务进程在终止后它的子进程也必须终止

当进程fork()成功之后,执行的工作就交给Dalvik虚拟机,Dalvik虚拟机首先通过loadClassfromDex()函数完成类的装载工作,每个类成功解析后会拥有一个classObject

类型的数据结构存储在运行时环境中,虚拟机使用gDvm.loadedClasses全局哈希表来存储与查询所有装载进来的类,然后字节码验证器是有那个dvmVerifyCodeFlow()函数对装入的daim进行

校验,然后虚拟机调用FindClass()函数查找并装载main方法类,随后调用dvmInterpret()函数初始化解释器并执行字节码流,过程如下


3.png

3.png

3、Dalvik虚拟机JIT(既时编译)


JIT(既时编译),又为动态编译,是一种通过运行时将字节码编译为机器猫的技术,让程序执行更快Android2.2以上

JIT包含2两字节码编译方式

1、method方式:以函数或方法为单位进行编译

2、trace方式:以trace为单位进行编译

trace方式解释:函数的有些路径在实际运行过程中很少被执行的,这部分代码为“冷路径”,而执行比较频繁的路径为“热路径”传统的method方式会编译整个方法的代码,这

会在“冷路径”上浪费很多编译世家,消耗内存,trace方式能快速获取“热路径”,更短时间和内存编译代码。


相关文章
程序计数器和虚拟机栈
这篇文章介绍了Java虚拟机(JVM)的内存结构,特别解释了程序计数器(Program Counter Register)的作用,即用来记录下一条JVM指令的执行地址和行号。
程序计数器和虚拟机栈
|
SQL 运维 Java
蚂蚁 Flink 实时计算编译任务 Koupleless 架构改造
本文介绍了对Flink实时计算编译任务的Koupleless架构改造。为解决进程模型带来的响应慢、资源消耗大等问题,团队将进程模型改为线程模型,并借助Koupleless的类加载隔离能力实现版本和包的隔离。通过动态装配Plugin及其Classpath,以及Biz运行时仅对依赖Plugin可见的设计,大幅优化了编译任务的性能。结果表明,新架构使编译耗时降低50%,吞吐量提升5倍以上。
蚂蚁 Flink 实时计算编译任务 Koupleless 架构改造
|
Java Android开发 C++
Android Studio JNI 使用模板:c/cpp源文件的集成编译,快速上手
本文提供了一个Android Studio中JNI使用的模板,包括创建C/C++源文件、编辑CMakeLists.txt、编写JNI接口代码、配置build.gradle以及编译生成.so库的详细步骤,以帮助开发者快速上手Android平台的JNI开发和编译过程。
1394 1
|
存储 人工智能 缓存
DeepSeek 开源周第三弹!DeepGEMM:FP8矩阵计算神器!JIT编译+Hopper架构优化,MoE性能飙升
DeepGEMM 是 DeepSeek 开源的专为 FP8 矩阵乘法设计的高效库,支持普通和混合专家(MoE)分组的 GEMM 操作,基于即时编译技术,动态优化矩阵运算,显著提升计算性能。
1390 3
DeepSeek 开源周第三弹!DeepGEMM:FP8矩阵计算神器!JIT编译+Hopper架构优化,MoE性能飙升
|
Linux API 开发工具
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
ijkplayer是由B站研发的移动端播放器,基于FFmpeg 3.4,支持Android和iOS。其源码托管于GitHub,截至2024年9月15日,获得了3.24万星标和0.81万分支,尽管已停止更新6年。本文档介绍了如何在Linux环境下编译ijkplayer的so库,以便在较新的开发环境中使用。首先需安装编译工具并调整/tmp分区大小,接着下载并安装Android SDK和NDK,最后下载ijkplayer源码并编译。详细步骤包括环境准备、工具安装及库编译等。更多FFmpeg开发知识可参考相关书籍。
836 0
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
|
编译器 Android开发
配置环境变量,使CMakeLists.txt可直接使用Android NDK工具链编译项目
配置环境变量,使CMakeLists.txt可直接使用Android NDK工具链编译项目
|
Ubuntu Shell API
Ubuntu 64系统编译android arm64-v8a 的openssl静态库libssl.a和libcrypto.a
Ubuntu 64系统编译android arm64-v8a 的openssl静态库libssl.a和libcrypto.a
|
Android开发 Docker 容器
docker中编译android aosp源码,出现Build sandboxing disabled due to nsjail error
在使用Docker编译Android AOSP源码时,如果遇到"Build sandboxing disabled due to nsjail error"的错误,可以通过在docker run命令中添加`--privileged`参数来解决权限不足的问题。
3134 1
|
Java Android开发 芯片
使用Android Studio导入Android源码:基于全志H713 AOSP,方便解决编译、编码问题
本文介绍了如何将基于全志H713芯片的AOSP Android源码导入Android Studio以解决编译和编码问题,通过操作步骤的详细说明,展示了在Android Studio中利用代码提示和补全功能快速定位并修复编译错误的方法。
1637 0
使用Android Studio导入Android源码:基于全志H713 AOSP,方便解决编译、编码问题

热门文章

最新文章