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方式能快速获取“热路径”,更短时间和内存编译代码。


相关文章
|
25天前
|
安全 Java Android开发
05. 【Android教程】Android 程序签名打包
05. 【Android教程】Android 程序签名打包
18 1
|
8天前
|
Android开发 iOS开发
android自动化编译
android自动化编译
|
2天前
|
Java API 开发工具
如何将python应用编译到android运行
【6月更文挑战第27天】本文介绍在Ubuntu 20上搭建Android开发环境,包括安装JRE/JDK,设置环境变量,添加i386架构,安装依赖和编译工具。并通过`p4a`命令行工具进行apk构建和清理。
20 6
如何将python应用编译到android运行
|
5天前
|
存储 Java C++
Java虚拟机(JVM)在执行Java程序时,会将其管理的内存划分为几个不同的区域
【6月更文挑战第24天】Java JVM管理内存分7区:程序计数器记录线程执行位置;虚拟机栈处理方法调用,每个线程有独立栈;本地方法栈服务native方法;Java堆存储所有对象实例,垃圾回收管理;方法区(在Java 8后变为元空间)存储类信息;运行时常量池存储常量;直接内存不属于JVM规范,通过`java.nio`手动管理,不受GC直接影响。
16 5
|
5天前
|
存储 Java C++
Java虚拟机(JVM)管理内存划分为多个区域:程序计数器记录线程执行位置;虚拟机栈存储线程私有数据
Java虚拟机(JVM)管理内存划分为多个区域:程序计数器记录线程执行位置;虚拟机栈存储线程私有数据,如局部变量和操作数;本地方法栈支持native方法;堆存放所有线程的对象实例,由垃圾回收管理;方法区(在Java 8后变为元空间)存储类信息和常量;运行时常量池是方法区一部分,保存符号引用和常量;直接内存非JVM规范定义,手动管理,通过Buffer类使用。Java 8后,永久代被元空间取代,G1成为默认GC。
16 2
|
9天前
|
监控 算法 Java
Java虚拟机(JVM)使用多种垃圾回收算法来管理内存,以确保程序运行时不会因为内存不足而崩溃。
【6月更文挑战第20天】Java JVM运用多种GC算法,如标记-清除、复制、标记-压缩、分代收集、增量收集、并行收集和并发标记,以自动化内存管理,防止因内存耗尽导致的程序崩溃。这些算法各有优劣,适应不同的性能和资源需求。垃圾回收旨在避免手动内存管理,简化编程。当遇到内存泄漏,可以借助VisualVM、JConsole或MAT等工具监测内存、生成堆转储,分析引用链并定位泄漏源,从而解决问题。
22 4
|
7天前
|
C# Android开发 开发者
Android gradle编译时字节码处理
Android gradle编译时字节码处理
13 1
|
1天前
|
Java Android开发
程序与技术分享:Android使用Dagger注入的方式初始化对象的简单使用
程序与技术分享:Android使用Dagger注入的方式初始化对象的简单使用
|
1天前
|
安全 网络协议 网络安全
程序与技术分享:Android应用安全之数据传输安全
程序与技术分享:Android应用安全之数据传输安全
|
2天前
|
开发工具 Android开发
技术经验分享:Android编译命令m、mm、mmm区别及工程搭建示例
技术经验分享:Android编译命令m、mm、mmm区别及工程搭建示例