SMALI

来源:互联网 发布:服装裁剪排版软件 编辑:程序博客网 时间:2024/04/28 11:10

初识SMALI

摘自:http://www.ztx.me/archives/115

  前面我们说,apk文件可以解包成smali文件。那么smali是什么?这还要从dalvik说起。dalvik是google专门为android操作系统设计的虚拟机,经过深度优化。虽然android程序也是用java语言来编写,不过dalvik与标准java虚拟机JVM还是两码事。前者是基于寄存器的而后者是基于栈的,前者拥有其专属的文件格式dex(dalvik executable)而后者执行的是java字节码,所以dalvik比jvm速度更快,占用空间更小。

  我们从apk中解出的smali,其实质是把dex转换为smali,dex文件格式相当紧凑,里面包含着指令,只不过都是16进制的看起来相当不便。介绍了一些背景,总结起来一句话,smali是dalvik虚拟机内部执行的核心代码,他也有自己的语法,下面先来看一下他的基本类型:

  • B (byte)
  • C (char)
  • D (double)
  • F (float)
  • I (int)
  • J (long)
  • S (short)
  • V (void)
  • Z (boolean)
  • [XXX (array)
  • LXXX (object)

  这里需要解释的是数组和对象,数组以[开头,如整数数组[I,对象以L开头,格式为LpackageName/objectName;(分号结尾),如字符串对象Ljava/lang/String;,字符串对象数组[Ljava/lang/String;。知道了这些基本类型,再了解方法时就能一目了然:

function (Z[I[ILjava/lang/String;J)Ljava/lang/String;

有点晕?没关系,这个方法的声明相当于:

String function (boolean, int[], int[], String, long)

在调用的时候要遵循下面的格式:

LpackageName/objectName;->functionName (ZI[I)V

在一个类中我们声明域的方法跟上面的都很类似,只是在前面加上.field,就不再多说了,了解一下即可。

.field LpackageName/objectName;->fieldName:Ljava/lang/String;


  之前说过,dalvik是基于寄存器的,所以在函数内部避免不了的就是操作寄存器,那么在dalvik里是如何定义寄存器的呢?目前最流行的一种方法是,本地寄存器用v开头数字结尾表示,如v0、v1、v2...,参数寄存器用p开头数字结尾,如p0、p1、p2...。在使用寄存器之前,要在函数内部用.locals声明本函数内公用了多少个本地寄存器,结合下面的例子就清楚了:

# virtual methods.method public static printfStr(ZLjava/lang/String;)V.locals 1      //声明此函数需要一个本地寄存器v0if-eqz p0, :cond_0      //判断参数1若为假则跳转到:cond_0//下面两句相当于System.out.println(String)sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream; invoke-virtual {v0, p1}, Ljava/io/PrintStream;->print(Ljava/lang/String;)V:cond_0return-void      //返回.end method


  最后需要做几个额外的说明,上面的例子我把它声明为static,本身没有this方法,所以参数寄存器是从p0开始计数,若非static方法,参数寄存器则是从p1开始对应,而p0则是隐含的this所用。若变量为double或long方法,则此变量需要两个寄存器来存储。smali最基本语法大致就是如此,我们先做一个简单的了解,含有非常多的指令我们没有用到,贴一个官方的介绍,dalvik操作码,先看一下,具体在后面实战时边用边说。