天天看点

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

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(, ));
    }
}
           
  • 使用

    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:
         : aload_0
         : invokespecial #1                  // Method java/lang/Object."<init>":()V
         : return
    
    public int foo(int, int);
      Code:
         : iload_1
         : iload_2
         : iadd
         : iload_1
         : iload_2
         : isub
         : imul
         : ireturn
    
    public static void main(java.lang.String[]);
      Code:
         : new           #2                  // class Java_Dalvik_Byte_Code_Compare
         : dup
         : invokespecial #3                  // Method "<init>":()V
         : astore_1
         : getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
        : aload_1
        : iconst_5
        : iconst_3
        : invokevirtual #5                  // Method foo:(II)I
        : invokevirtual #6                  // Method java/io/PrintStream.println:(I)V
        : 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      : x0001 (PUBLIC)
      Superclass        : 'Ljava/lang/Object;'
      Interfaces        -
      Static fields     -
      Instance fields   -
      Direct methods    -
        #0              : (in LJava_Dalvik_Byte_Code_Compare;)
          name          : '<init>'
          type          : '()V'
          access        : x10001 (PUBLIC CONSTRUCTOR)
          code          -
          registers     : 
          ins           : 
          outs          : 
          insns size    :  -bit code units
    c:                                        |[c] Java_Dalvik_Byte_Code_Compare.<init>:()V
    c:                            |: invoke-direct {v0}, Ljava/lang/Object;.<init>:()V // [email protected]
    : e00                                   |: return-void
          catches       : (none)
          positions     :
            x0000 line=
          locals        :
            x0000 - x0004 reg= this LJava_Dalvik_Byte_Code_Compare;
    
        #1              : (in LJava_Dalvik_Byte_Code_Compare;)
          name          : 'main'
          type          : '([Ljava/lang/String;)V'
          access        : x0009 (PUBLIC STATIC)
          code          -
          registers     : 
          ins           : 
          outs          : 
          insns size    :  -bit code units
    :                                        |[] Java_Dalvik_Byte_Code_Compare.main:([Ljava/lang/String;)V
    :                                |: new-instance v0, LJava_Dalvik_Byte_Code_Compare; // [email protected]
    :                            |: invoke-direct {v0}, LJava_Dalvik_Byte_Code_Compare;.<init>:()V // [email protected]
    e:                                |: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // [email protected]
    :                                    |: const/ v2, #int  // #5
    :                                    |: const/ v3, #int  // #3
    : e30                           |: invoke-virtual {v0, v2, v3}, LJava_Dalvik_Byte_Code_Compare;.foo:(II)I // [email protected]
    c: a00                                   |c: move-result v0
    e: e20                           |d: invoke-virtual {v1, v0}, Ljava/io/PrintStream;.println:(I)V // [email protected]
    : e00                                   |: return-void
          catches       : (none)
          positions     :
            x0000 line=
            x0005 line=
            x0010 line=
          locals        :
    
      Virtual methods   -
        #0              : (in LJava_Dalvik_Byte_Code_Compare;)
          name          : 'foo'
          type          : '(II)I'
          access        : x0001 (PUBLIC)
          code          -
          registers     : 
          ins           : 
          outs          : 
          insns size    :  -bit code units
    :                                        |[] Java_Dalvik_Byte_Code_Compare.foo:(II)I
    a8:                                |: add-int v0, v3, v4
    ac:                                |: sub-int v1, v3, v4
    b0: b210                                   |: mul-int/addr v0, v1
    b2: f00                                   |: return v0
          catches       : (none)
          positions     :
            x0000 line=
          locals        :
            x0000 - x0006 reg= this LJava_Dalvik_Byte_Code_Compare;
    
      source_file_idx   :  (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()初始化解释器并执行字节码

继续阅读