1、Smali语言基础语法-数据类型与描述符
smali中有两类数据类型:基本类型和引用类型。引用类型是指数组和对象,其它都是基础类型。
基本类型以及每种类型的描述符:
Java类型 | 类型描述符 | 说明 |
boolean | Z | 布尔型 |
byte | B | 字节型 |
short | S | 短整型 |
char | C | 字符型 |
int | I | 整型 |
long | J | 长整型 |
float | F | 双精度型 |
void | V | 返回类型 |
引用类型分两种,对象类型与数组类型:
对象类型表示形式为L包名/对象类型;,即Lpackagename/ObjectName;(注意分号)
(1) 开始的L表明这是一个对象类型 (2) packagename 使用"/"代替”.“
(3) ObjectName是对象的名称 (4) 分号表明对象名的结束
例:smali代码中String类型的表示:Ljava/lang/String;
数组类型以 ‘[’ 数据类型加上类型描述符的形式表示:
例:[I 表示一维整型数组,[[I表示二维数组, [Ljava/lang/String; 表示String数组
字段的描述
Davilk中对字段的描述分为两种,对基本类型字段的描述和对引用类型的描述,但是两者的描述格式一样:
对象类型描述符->字段名:类型描述符;
例:com.baidu.Test类中存在String类型的name字段及int类型的age字段,那么其描述为:
Lcom/baidu/Test;->name:Ljava/lang/String; Lcom/baidu/Test;->age:I
方法的描述
java中方法的签名包括方法名,参数及返回值,在Davilk相应的描述规则为:
对象类型描述符->方法名(参数类型描述符)返回值类型描述符
以java.lang.String举例:
java方法:public char charAt(int index){......} Davilk描述:Ljava/lang/String;->charAt(I)C java方法:public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin){......} Davilk描述:Ljava/lang/String;->getChars(II[CI)V java方法:public boolean equals(Object anObject){......} Davilk描述:Ljava/lang/String;->equals(Ljava/lang/Object;)Z
2、Smali语言基础语法-寄存器与传参以及局部变量
在smali汇编语言中,同样也有寄存器,寄存器都是32位的,能够支持任何类型。64位类型(Long和Double型)用两个寄存器表示。
有两种方式指定一个方法中有多少寄存器是可用的。
.registers指令指定了方法中寄存器的总数 .locals指令表明了方法中非参寄存器的数量
在方法中使用寄存器传递参数的默认规则如下:
(1)当一个方法被调用的时候,方法的参数被置于最后N个寄存器中。如果一个方法有2个参数,5个寄存器(v0-v4),那么参数将置于最后2个寄存器--v3和v4中。 (2)非静态方法中的第一个参数总是调用该方法的对象。
例:非静态方法LMyobject;->callMe(II)V 有2个整型参数,另外还有一个隐含的LMyobject;参数,所有总共有三个参数。假如在该方法中指定了5个寄存器(v0-v4),以.registers指定5个或者以.locals方式指定2个(即2个local寄存器+3个参数寄存器),当该方法被调用的时候,调用该方法的对象(即this指针引用)存放在v2中,第一个整型参数存放在v3中,第二个整型参数存放在v4中。
对于静态方法除了没有隐含的this参数外其它都是一样的。
寄存器的命名方式有两种:
在下表中我们用两种方式表示上一个例子中有5个寄存器和3个参数的方法:
V命名方式 | P命名方式 | 说明 |
v0 | v0 | 局部变量 |
v1 | v1 | 局部变量 |
v2 | p0 | 参数0,this指针 |
v3 | p1 | 参数1 |
v4 | p2 | 参数2 |
可以使用任何一种方式来引用参数寄存器----他们没有任何区别。 注意:Baksmali默认对参数寄存器使用P命名方式。
使用P命名方式是为了防止以后如果在方法中增加寄存器,需要对参数寄存器重新进行编号的缺点。
看一个成员方法的例子:
public void callMe0(int a, int b) { System.out.println(a + b); }
反编译之后的smali汇编代码 smali 代码中#后面是注释
# virtual methods .method public callMe0(II)V .locals 2 # 定义局部变量寄存器 .param p1, "a" # I 声明参数 .param p2, "b" # I .line 16 # 源码所在行数 # 获取out对象 sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream; # 将参数累加 add-int v1, p1, p2 # 输出信息 invoke-virtual {v0, v1}, Ljava/io/PrintStream;->println(I)V .line 17 return-void .end method
关于Long/Double值:
Long和double类型是64位的,需要两个寄存器。
例:对于非静态方法LMyObject;->MyMethod(IJZ)V,参数分别是LMyObject;,int,long,bool。所有该方法至少需要5个寄存器来存储参数。
寄存器 | 说明 |
p0 | this |
p1 | I |
p2,p3 | J |
p4 | Z |