数据类型:
原始类型:
V void (只能用于返回值类型)
Z boolean
B byte
S short
C char
I int
J long
F float
D Double
引用类型:
对象: L + 包名.对象 + ;
对象的表示则以L作为开头,格式是LpackageName/objectName;(注意必须有个分号跟在最后),例如String对象在smali中为:Ljava/lang/String;,其中java/lang对应java.lang包,String就是定义在该包中的一个对象。
数组:
[ + 数据类型
数组的表示方式是:在基本类型前加上前中括号“[”,例如int数组和float数组分别表示为:[I、[F
[I——表示一个整型一维数组,相当于java中的int[]。
对于多维数组,只要增加[就行了。[[I相当于int[][],[[[I相当于int[][][]。注意每一维的最多255个。
对象数组的表示:[Ljava/lang/String;表示一个String对象数组。
语法:
1.方法定义:
表示形式:Lpackage/name/ObjectName;->MethodName(III)Z
Lpackage/name/ObjectName;表示类型,MethodName是方法名。III为参数(在此是3个整型参数), Z是返回类型(bool型)。
方法的参数是一个接一个的,中间没有隔开。
例子:
method(I[[IILjava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;
在java中则为:
String method(int, int[][], int, String, Object[])
2.内部类:
既然类是用LpackageName/objectName;来表示,那类里面的内部类又如何在smali中引用呢?答案是:LpackageName/objectName$subObjectName;。也就是在内部类前加“$”符号
3.字段:
表示形式: Lpackage/name/ObjectName;->FieldName:Ljava/lang/String; 即包名,字段名和各字段类型。
4.标记说明:
# static fields 定义静态变量的标记
# instance fields 定义实例变量的标记
# direct methods 定义静态方法的标记
# virtual methods 定义非静态方法的标记
构造函数的返回类型为V,名字为<init>。
5.语法: If语句
if-eq p1, v0, :cond_0表示如果p1和v0相等,则执行cond_0的流程:
:cond_0
invoke-direct {p0}, Lcom/paul/test/a;->d()V调用com.paul.test.a的d()方法
if-ne p1, v0, :cond_b 表示不相等则执行cond_b的流程:
:cond_b
const/4 v0, 0x0
invoke-virtual {p0, v0}, Lcom/paul/test/a;->setPressed(Z)V
invoke-super {p0, p1, p2}, Landroid/view/View;->onKeyUp(ILandroid/view/KeyEvent;)Z
move-result v0
大概意思就是调用com.paul.test.a的setPressed方法,然后再调用父类View的onKeyUp方法,最后 return v0
寄存器:
概念:
在dalvik字节码中,寄存器都是32位的,能够支持任何类型。64位类型(Long和Double型)用2个寄存器表示。
有两种方式指定一个方法中有多少寄存器是可用的。
.registers指令指定了方法中寄存器的总数。
.locals指令表明了方法中非参寄存器的数量。
v0 第一个本地寄存器
v1 第二个本地寄存器
v2 p0 (this)
v3 p1 第一个参数
v4 p2 第二个参数
v5 p3 第三个参数
Long/Double值
Long和double类型是64位的,需要2个寄存器
例如,对于非静态方法LMyObject;->MyMethod(IJZ)V,参数分别是LMyObject;,int,long,bool。故该方法需要5个寄存器来存储参数。
p0 this
p1 I
p2,p3 J
p4 Z
smail操作:
.field private isFlag:z 定义变量
.method 方法
.parameter 方法参数
.prologue 方法开始
.line 12 此方法位于第12行
invoke-super 调用父函数
const/high16 v0, 0x7fo3 把0x7fo3赋值给v0
invoke-direct 调用函数
return-void 函数返回void
.end method 函数结束
new-instance 创建实例
iput-object 对象赋值
iget-object 调用对象
invoke-static 调用静态函数
smali中的函数调用也分为direct和virtual两种类型,direct method就是private函数,public和protected函数都属于virtual method。在调用函数时,有invoke-direct,invoke-virtual,invoke-static、invoke-super以及invoke-interface等几种不同的指令。还有invoke-XXX/range 指令的,这是参数多于4个的时候调用的指令,比较少见。
invoke-static:就是调用static函数的,示例:
invoke-static {}, Lcom/disney/Class1;->fun()Z
上句invoke-static后面有一对大括号“{}”,内部是调用该方法的实例和参数列表,由于这是static方法也不需要参数,所以{}内为空。
invoke-super:调用父类方法,在onCreate、onDestroy等方法都能看到。
invoke-direct:调用private函数,示例:
invoke-direct {p0}, Lcom/disney/Class1;->getGlobalIapHandler()Lcom/disney/config/GlobalPurchaseHandler;
上句即this->getGlobalIapHandler(),函数GlobalPurchaseHandler getGlobalIapHandler()是定义在Class1中的一个private函数。
invoke-virtual:用于调用protected或public函数,示例:
sget-object v0, Lcom/disney/Class1;->shareHandler:Landroid/os/Handler; invoke-virtual {v0, v3}, Landroid/os/Handler;->removeCallbacksAndMessages(Ljava/lang/Object;)V
上句v0是shareHandler android/os/Handler,v3是传递给removeCallbackAndMessage方法的Ljava/lang/Object参数。
1.If语句
if-nez v0,:cond_0 如果结果不为0,就跳转到cond_0标号处
if-eqz v0,:cond_1 如果结果为0,就跳转到cond_1标号处
2.数据操作指令
move v0,v1 将v1的值赋给v0 ,两个寄存器都为4位
move-result v0 将上一个invoke类型指令操作的单字非对象结果赋给v0
move-result-object v0 将上一个invoke类型指令操作的对象结果(返回值)赋给v0
3.返回指令
return-void
return v0
return-object v0
4.实例操作指令
check-cast v1, Landroid/widget/TextView; 将v1寄存器中的对象引用转化成指定的类型(这里是 TextView)
new-instance v1, Ljava/lang/StringBuilder; 构造一个指定类型对象的新实例
5.数组操作指令
new-array v0,v0,[I 构造Int类型,大小是v0的数组,并将值赋给v0寄存器
array-length v1,v0 获取v0数组的长度且将值赋给v1
6.异常指令
throw vAA 抛出vAA寄存器中指定类型的异常
7.跳转指令
1,goto :goto_0 偏移量goto_0不能为0
2,If语句
3,switch
packed-switch v0, :pswitch_data_0 v0是switch需要判断的值 :pswitch_data_0 偏移表,表中值是有规律递增的。
sparse-switch v0, :pswitch_data_0 偏移表中值是无规律的。
8.比较指令
cmpl-float v0,v2,v3 比较v2和v3,如果v2>v3,v0=-1;反之,v0=1;相等,v0=0
cmpg-float v0,v2,v3 比较v2和v3,如果v2>v3,v0=1;反之,v0=-1;相等,v0=0
cmpl-double v0,v2,v3 同理
cmpg-double v0,v2,v3 同理
cmp-long v0,v2,v3 比较v2和v3,如果v2>v3,v0=1;反之,v0=-1;相等,v0=0