Android安全学习笔记2-Dalvik虚拟机

本文详细介绍了Dalvik虚拟机的特点及其实现原理,包括其体积小、执行速度快、基于寄存器等特点,并通过代码示例对比了Dalvik与Java虚拟机的字节码差异。此外,还介绍了Dalvik虚拟机的执行流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Dalvik虚拟机学习


一、Dalvik虚拟机特点:

1)体积小,占用内存小

2)使用DEX可执行文件,执行速度快

3)常量池32位,寻址类方法名、字段、常量更快

4)基于寄存器,并拥有完整的指令系统

5)提供对象生命周期、堆栈、线程、安全、异常、垃圾回收等重要功能

6)每个Android程序对应一个Dalvik虚拟机实例

与JAVA虚拟机的区别

1)Dalvik字节码与JAVA字节码的不同

2)dx工具对class文件中方法签名、常量池等进行压缩精简

实验

构造这样的代码:

public class Java_Dalvik_Byte_Code_Compare{
    public int foo(int a, int b){
        return (a+b)*(a-b);
    }
    public static void main(String[] args) {
        Java_Dalvik_Byte_Code_Compare first = new Java_Dalvik_Byte_Code_Compare();
        System.out.println(first.foo(5, 3));
    }
}
  • 使用javac xxx.java 编译生成class文件

  • 使用dx --dex --output=xxx.dex xxx.class 生成dex文件

  • 使用javap -c xxx.class 反编译Java字节码

    Compiled from "Java_Dalvik_Byte_Code_Compare.java"
    public class Java_Dalvik_Byte_Code_Compare {
    public Java_Dalvik_Byte_Code_Compare();
      Code:
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
    
    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
    
    public static void main(java.lang.String[]);
      Code:
         0: new           #2                  // class Java_Dalvik_Byte_Code_Compare
         3: dup
         4: invokespecial #3                  // Method "<init>":()V
         7: astore_1
         8: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
        11: aload_1
        12: iconst_5
        13: iconst_3
        14: invokevirtual #5                  // Method foo:(II)I
        17: invokevirtual #6                  // Method java/io/PrintStream.println:(I)V
        20: return
    }
    • 使用dexdump.exe -d xxx.dex 反编译dex文件
    Processing '.\Java_Dalvik_Byte_Code_Compare.dex'...
    Opened '.\Java_Dalvik_Byte_Code_Compare.dex', DEX version '035'
    Class #0            -
      Class descriptor  : 'LJava_Dalvik_Byte_Code_Compare;'
      Access flags      : 0x0001 (PUBLIC)
      Superclass        : 'Ljava/lang/Object;'
      Interfaces        -
      Static fields     -
      Instance fields   -
      Direct methods    -
        #0              : (in LJava_Dalvik_Byte_Code_Compare;)
          name          : '<init>'
          type          : '()V'
          access        : 0x10001 (PUBLIC CONSTRUCTOR)
          code          -
          registers     : 1
          ins           : 1
          outs          : 1
          insns size    : 4 16-bit code units
    00014c:                                        |[00014c] Java_Dalvik_Byte_Code_Compare.<init>:()V
    00015c: 7010 0400 0000                         |0000: invoke-direct {v0}, Ljava/lang/Object;.<init>:()V // method@0004
    000162: 0e00                                   |0003: return-void
          catches       : (none)
          positions     :
            0x0000 line=1
          locals        :
            0x0000 - 0x0004 reg=0 this LJava_Dalvik_Byte_Code_Compare;
    
        #1              : (in LJava_Dalvik_Byte_Code_Compare;)
          name          : 'main'
          type          : '([Ljava/lang/String;)V'
          access        : 0x0009 (PUBLIC STATIC)
          code          -
          registers     : 5
          ins           : 1
          outs          : 3
          insns size    : 17 16-bit code units
    000164:                                        |[000164] Java_Dalvik_Byte_Code_Compare.main:([Ljava/lang/String;)V
    000174: 2200 0100                              |0000: new-instance v0, LJava_Dalvik_Byte_Code_Compare; // type@0001
    000178: 7010 0000 0000                         |0002: invoke-direct {v0}, LJava_Dalvik_Byte_Code_Compare;.<init>:()V // method@0000
    00017e: 6201 0000                              |0005: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0000
    000182: 1252                                   |0007: const/4 v2, #int 5 // #5
    000184: 1233                                   |0008: const/4 v3, #int 3 // #3
    000186: 6e30 0100 2003                         |0009: invoke-virtual {v0, v2, v3}, LJava_Dalvik_Byte_Code_Compare;.foo:(II)I // method@0001
    00018c: 0a00                                   |000c: move-result v0
    00018e: 6e20 0300 0100                         |000d: invoke-virtual {v1, v0}, Ljava/io/PrintStream;.println:(I)V // method@0003
    000194: 0e00                                   |0010: return-void
          catches       : (none)
          positions     :
            0x0000 line=6
            0x0005 line=7
            0x0010 line=8
          locals        :
    
      Virtual methods   -
        #0              : (in LJava_Dalvik_Byte_Code_Compare;)
          name          : 'foo'
          type          : '(II)I'
          access        : 0x0001 (PUBLIC)
          code          -
          registers     : 5
          ins           : 3
          outs          : 0
          insns size    : 6 16-bit code units
    000198:                                        |[000198] Java_Dalvik_Byte_Code_Compare.foo:(II)I
    0001a8: 9000 0304                              |0000: add-int v0, v3, v4
    0001ac: 9101 0304                              |0002: sub-int v1, v3, v4
    0001b0: b210                                   |0004: mul-int/2addr v0, v1
    0001b2: 0f00                                   |0005: return v0
          catches       : (none)
          positions     :
            0x0000 line=3
          locals        :
            0x0000 - 0x0006 reg=2 this LJava_Dalvik_Byte_Code_Compare;
    
      source_file_idx   : 3 (Java_Dalvik_Byte_Code_Compare.java)

对比两边foo()函数的代码,可以很明显看出基于寄存器的Dalvik虚拟机执行步骤相较于基于栈的JVM精简了很多。

另外注意,Dalvik反编译的汇编中参数顺序与入栈顺序一致。

Dalvik虚拟机执行程序流程

Zygote

  1. 系统启动
  2. init进程运行
  3. 读取inic.rc并启动重要孵化器进程Zygote
  4. Zygote初始化Dalvik虚拟机
  5. 启动system_server并进入Zygote模式,通过socket等待命令
  6. 当执行应用程序时,system_server通过socket通知Zygote,Zygote立刻fork自身创建一个Dalvik虚拟机实例来执行目标程序的入口函数。

Dalvik

  1. Dalvik虚拟机运行loadClassFromDec()完成类装载,类数据结构为ClassObject
  2. 使用gDvm.loadedClasses全局哈希表来存储/查询装载进来的类
  3. 字节码验证器使用dvmVerifyCodeFlow()函数对载入的代码进行校验
  4. 调用FindClass()函数查找并装载main方法类
  5. 调用dvmInterpret()初始化解释器并执行字节码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值